Project Diff 2 (#23891)

This adds a new version of the project diff editor to go alongside the
new git panel.

The basics seem to be working, but still todo:

* [ ] Fix untracked files
* [ ] Fix deleted files
* [ ] Show commit message editor at top
* [x] Handle empty state
* [x] Fix panic where locator sometimes seeks to wrong excerpt

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2025-02-03 13:18:50 -07:00 committed by GitHub
parent 27a413a5e3
commit 45708d2680
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 1023 additions and 125 deletions

View file

@ -12,7 +12,7 @@ use gpui::{App, Context, Entity, EventEmitter, SharedString, Subscription, WeakE
use rpc::{proto, AnyProtoClient};
use settings::WorktreeId;
use std::sync::Arc;
use util::maybe;
use util::{maybe, ResultExt};
use worktree::{ProjectEntryId, RepositoryEntry, StatusEntry};
pub struct GitState {
@ -332,7 +332,7 @@ impl GitState {
impl RepositoryHandle {
pub fn display_name(&self, project: &Project, cx: &App) -> SharedString {
maybe!({
let path = self.unrelativize(&"".into())?;
let path = self.repo_path_to_project_path(&"".into())?;
Some(
project
.absolute_path(&path, cx)?
@ -367,11 +367,18 @@ impl RepositoryHandle {
self.repository_entry.status()
}
pub fn unrelativize(&self, path: &RepoPath) -> Option<ProjectPath> {
pub fn repo_path_to_project_path(&self, path: &RepoPath) -> Option<ProjectPath> {
let path = self.repository_entry.unrelativize(path)?;
Some((self.worktree_id, path).into())
}
pub fn project_path_to_repo_path(&self, path: &ProjectPath) -> Option<RepoPath> {
if path.worktree_id != self.worktree_id {
return None;
}
self.repository_entry.relativize(&path.path).log_err()
}
pub fn stage_entries(
&self,
entries: Vec<RepoPath>,

View file

@ -158,7 +158,7 @@ pub struct Project {
fs: Arc<dyn Fs>,
ssh_client: Option<Entity<SshRemoteClient>>,
client_state: ProjectClientState,
git_state: Option<Entity<GitState>>,
git_state: Entity<GitState>,
collaborators: HashMap<proto::PeerId, Collaborator>,
client_subscriptions: Vec<client::Subscription>,
worktree_store: Entity<WorktreeStore>,
@ -701,7 +701,7 @@ impl Project {
)
});
let git_state = Some(cx.new(|cx| GitState::new(&worktree_store, None, None, cx)));
let git_state = cx.new(|cx| GitState::new(&worktree_store, None, None, cx));
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
@ -821,14 +821,14 @@ impl Project {
});
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
let git_state = Some(cx.new(|cx| {
let git_state = cx.new(|cx| {
GitState::new(
&worktree_store,
Some(ssh_proto.clone()),
Some(ProjectId(SSH_PROJECT_ID)),
cx,
)
}));
});
cx.subscribe(&ssh, Self::on_ssh_event).detach();
cx.observe(&ssh, |_, _, cx| cx.notify()).detach();
@ -1026,15 +1026,14 @@ impl Project {
SettingsObserver::new_remote(worktree_store.clone(), task_store.clone(), cx)
})?;
let git_state = Some(cx.new(|cx| {
let git_state = cx.new(|cx| {
GitState::new(
&worktree_store,
Some(client.clone().into()),
Some(ProjectId(remote_id)),
cx,
)
}))
.transpose()?;
})?;
let this = cx.new(|cx| {
let replica_id = response.payload.replica_id as ReplicaId;
@ -4117,7 +4116,6 @@ impl Project {
this.update(cx, |project, cx| {
let repository_handle = project
.git_state()
.context("missing git state")?
.read(cx)
.all_repositories()
.into_iter()
@ -4332,19 +4330,16 @@ impl Project {
&self.buffer_store
}
pub fn git_state(&self) -> Option<&Entity<GitState>> {
self.git_state.as_ref()
pub fn git_state(&self) -> &Entity<GitState> {
&self.git_state
}
pub fn active_repository(&self, cx: &App) -> Option<RepositoryHandle> {
self.git_state()
.and_then(|git_state| git_state.read(cx).active_repository())
self.git_state.read(cx).active_repository()
}
pub fn all_repositories(&self, cx: &App) -> Vec<RepositoryHandle> {
self.git_state()
.map(|git_state| git_state.read(cx).all_repositories())
.unwrap_or_default()
self.git_state.read(cx).all_repositories()
}
}