Cargo.lock 🔗
@@ -2350,6 +2350,7 @@ dependencies = [
"serde_derive",
"serde_json",
"smol",
+ "sum_tree",
"tempfile",
"util",
]
Mikayla Maki and petros created
co-authored-by: petros <petros@zed.dev>
Cargo.lock | 1
crates/fs/Cargo.toml | 1
crates/fs/src/repository.rs | 82 +++++++++++++++++++++++++++++++++++
crates/project/src/worktree.rs | 37 ++++-----------
4 files changed, 94 insertions(+), 27 deletions(-)
@@ -2350,6 +2350,7 @@ dependencies = [
"serde_derive",
"serde_json",
"smol",
+ "sum_tree",
"tempfile",
"util",
]
@@ -13,6 +13,7 @@ gpui = { path = "../gpui" }
lsp = { path = "../lsp" }
rope = { path = "../rope" }
util = { path = "../util" }
+sum_tree = { path = "../sum_tree" }
anyhow.workspace = true
async-trait.workspace = true
futures.workspace = true
@@ -1,9 +1,10 @@
use anyhow::Result;
use collections::HashMap;
use parking_lot::Mutex;
+use sum_tree::TreeMap;
use std::{
path::{Component, Path, PathBuf},
- sync::Arc,
+ sync::Arc, ffi::OsStr, os::unix::prelude::OsStrExt,
};
use util::ResultExt;
@@ -16,6 +17,8 @@ pub trait GitRepository: Send {
fn load_index_text(&self, relative_file_path: &Path) -> Option<String>;
fn branch_name(&self) -> Option<String>;
+
+ fn statuses(&self) -> Option<TreeMap<RepoPath, GitStatus>>;
}
impl std::fmt::Debug for dyn GitRepository {
@@ -61,6 +64,79 @@ impl GitRepository for LibGitRepository {
let branch = String::from_utf8_lossy(head.shorthand_bytes());
Some(branch.to_string())
}
+
+ fn statuses(&self) -> Option<TreeMap<RepoPath, GitStatus>> {
+ let statuses = self.statuses(None).log_err()?;
+
+ let mut map = TreeMap::default();
+
+ for status in statuses.iter() {
+ let path = RepoPath(PathBuf::from(OsStr::from_bytes(status.path_bytes())));
+
+ let status_data = status.status();
+
+ let status = if status_data.contains(git2::Status::CONFLICTED) {
+ GitStatus::Conflict
+ } else if status_data.intersects(git2::Status::INDEX_MODIFIED
+ | git2::Status::WT_MODIFIED
+ | git2::Status::INDEX_RENAMED
+ | git2::Status::WT_RENAMED) {
+ GitStatus::Modified
+ } else if status_data.intersects(git2::Status::INDEX_NEW | git2::Status::WT_NEW) {
+ GitStatus::Added
+ } else {
+ GitStatus::Untracked
+ };
+
+ map.insert(path, status)
+ }
+
+ Some(map)
+ }
+}
+
+#[derive(Debug, Clone, Default)]
+pub enum GitStatus {
+ Added,
+ Modified,
+ Conflict,
+ #[default]
+ Untracked,
+}
+
+#[derive(Clone, Debug, Ord, Hash, PartialOrd, Eq, PartialEq)]
+pub struct RepoPath(PathBuf);
+
+impl From<&Path> for RepoPath {
+ fn from(value: &Path) -> Self {
+ RepoPath(value.to_path_buf())
+ }
+}
+
+impl From<PathBuf> for RepoPath {
+ fn from(value: PathBuf) -> Self {
+ RepoPath(value)
+ }
+}
+
+impl Default for RepoPath {
+ fn default() -> Self {
+ RepoPath(PathBuf::new())
+ }
+}
+
+impl AsRef<Path> for RepoPath {
+ fn as_ref(&self) -> &Path {
+ self.0.as_ref()
+ }
+}
+
+impl std::ops::Deref for RepoPath {
+ type Target = PathBuf;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
}
#[derive(Debug, Clone, Default)]
@@ -93,6 +169,10 @@ impl GitRepository for FakeGitRepository {
let state = self.state.lock();
state.branch_name.clone()
}
+
+ fn statuses(&self) -> Option<TreeMap<RepoPath, GitStatus>>{
+ todo!()
+ }
}
fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> {
@@ -6,7 +6,7 @@ use anyhow::{anyhow, Context, Result};
use client::{proto, Client};
use clock::ReplicaId;
use collections::{HashMap, VecDeque};
-use fs::{repository::GitRepository, Fs, LineEnding};
+use fs::{repository::{GitRepository, RepoPath, GitStatus}, Fs, LineEnding};
use futures::{
channel::{
mpsc::{self, UnboundedSender},
@@ -117,10 +117,11 @@ pub struct Snapshot {
completed_scan_id: usize,
}
-#[derive(Clone, Debug, Eq, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RepositoryEntry {
pub(crate) work_directory: WorkDirectoryEntry,
pub(crate) branch: Option<Arc<str>>,
+ // pub(crate) statuses: TreeMap<RepoPath, GitStatus>
}
impl RepositoryEntry {
@@ -162,6 +163,13 @@ impl Default for RepositoryWorkDirectory {
}
}
+impl AsRef<Path> for RepositoryWorkDirectory {
+ fn as_ref(&self) -> &Path {
+ self.0.as_ref()
+ }
+}
+
+
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
pub struct WorkDirectoryEntry(ProjectEntryId);
@@ -178,7 +186,7 @@ impl WorkDirectoryEntry {
worktree.entry_for_id(self.0).and_then(|entry| {
path.strip_prefix(&entry.path)
.ok()
- .map(move |path| RepoPath(path.to_owned()))
+ .map(move |path| path.into())
})
}
}
@@ -197,29 +205,6 @@ impl<'a> From<ProjectEntryId> for WorkDirectoryEntry {
}
}
-#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
-pub struct RepoPath(PathBuf);
-
-impl AsRef<Path> for RepoPath {
- fn as_ref(&self) -> &Path {
- self.0.as_ref()
- }
-}
-
-impl Deref for RepoPath {
- type Target = PathBuf;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl AsRef<Path> for RepositoryWorkDirectory {
- fn as_ref(&self) -> &Path {
- self.0.as_ref()
- }
-}
-
#[derive(Debug, Clone)]
pub struct LocalSnapshot {
ignores_by_parent_abs_path: HashMap<Arc<Path>, (Arc<Gitignore>, usize)>,