Detailed changes
@@ -1697,6 +1697,7 @@ dependencies = [
"env_logger",
"futures",
"fuzzy",
+ "git",
"gpui",
"indoc",
"itertools",
@@ -2224,6 +2225,23 @@ dependencies = [
"stable_deref_trait",
]
+[[package]]
+name = "git"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clock",
+ "git2",
+ "lazy_static",
+ "log",
+ "parking_lot 0.11.2",
+ "smol",
+ "sum_tree",
+ "text",
+ "unindent",
+ "util",
+]
+
[[package]]
name = "git2"
version = "0.15.0"
@@ -2853,7 +2871,7 @@ dependencies = [
"env_logger",
"futures",
"fuzzy",
- "git2",
+ "git",
"gpui",
"lazy_static",
"log",
@@ -3996,7 +4014,7 @@ dependencies = [
"fsevent",
"futures",
"fuzzy",
- "git2",
+ "git",
"gpui",
"ignore",
"language",
@@ -25,6 +25,7 @@ clock = { path = "../clock" }
collections = { path = "../collections" }
context_menu = { path = "../context_menu" }
fuzzy = { path = "../fuzzy" }
+git = { path = "../git" }
gpui = { path = "../gpui" }
language = { path = "../language" }
lsp = { path = "../lsp" }
@@ -16,6 +16,7 @@ use crate::{
};
use clock::ReplicaId;
use collections::{BTreeMap, HashMap};
+use git::diff::{DiffHunk, DiffHunkStatus};
use gpui::{
color::Color,
elements::*,
@@ -34,7 +35,6 @@ use gpui::{
WeakViewHandle,
};
use json::json;
-use language::git::{DiffHunk, DiffHunkStatus};
use language::{Bias, DiagnosticSeverity, OffsetUtf16, Selection};
use project::ProjectPath;
use settings::Settings;
@@ -4,13 +4,13 @@ pub use anchor::{Anchor, AnchorRangeExt};
use anyhow::Result;
use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet};
+use git::diff::DiffHunk;
use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
pub use language::Completion;
use language::{
- char_kind, git::DiffHunk, AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind,
- Chunk, DiagnosticEntry, Event, File, IndentSize, Language, OffsetRangeExt, Outline,
- OutlineItem, Selection, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _,
- TransactionId,
+ char_kind, AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk,
+ DiagnosticEntry, Event, File, IndentSize, Language, OffsetRangeExt, Outline, OutlineItem,
+ Selection, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId,
};
use smallvec::SmallVec;
use std::{
@@ -0,0 +1,22 @@
+[package]
+name = "git"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "src/git.rs"
+
+[dependencies]
+anyhow = "1.0.38"
+clock = { path = "../clock" }
+git2 = { version = "0.15", default-features = false }
+lazy_static = "1.4.0"
+sum_tree = { path = "../sum_tree" }
+text = { path = "../text" }
+util = { path = "../util" }
+log = { version = "0.4.16", features = ["kv_unstable_serde"] }
+smol = "1.2"
+parking_lot = "0.11.1"
+
+[dev-dependencies]
+unindent = "0.1.7"
@@ -259,7 +259,7 @@ mod tests {
use text::Buffer;
use unindent::Unindent as _;
- #[gpui::test]
+ #[test]
fn test_buffer_diff_simple() {
let head_text = "
one
@@ -308,8 +308,4 @@ mod tests {
);
}
}
-
- // use rand::rngs::StdRng;
- // #[gpui::test(iterations = 100)]
- // fn test_buffer_diff_random(mut rng: StdRng) {}
}
@@ -0,0 +1,12 @@
+use std::ffi::OsStr;
+
+pub use git2 as libgit;
+pub use lazy_static::lazy_static;
+
+pub mod diff;
+pub mod repository;
+
+lazy_static! {
+ pub static ref DOT_GIT: &'static OsStr = OsStr::new(".git");
+ pub static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
+}
@@ -1,7 +1,7 @@
use anyhow::Result;
-use git2::{Repository as LibGitRepository, RepositoryOpenFlags as LibGitRepositoryOpenFlags};
+use git2::Repository as LibGitRepository;
use parking_lot::Mutex;
-use std::{ffi::OsStr, path::Path, sync::Arc};
+use std::{path::Path, sync::Arc};
use util::ResultExt;
#[derive(Clone)]
@@ -53,21 +53,17 @@ impl GitRepository {
self.scan_id
}
- pub(super) fn set_scan_id(&mut self, scan_id: usize) {
+ pub fn set_scan_id(&mut self, scan_id: usize) {
+ println!("setting scan id");
self.scan_id = scan_id;
}
- pub fn with_repo<F: FnOnce(&mut git2::Repository)>(&mut self, f: F) {
- let mut git2 = self.libgit_repository.lock();
- f(&mut git2)
- }
-
- pub async fn load_head_text(&self, file_path: &Path) -> Option<String> {
- fn logic(repo: &LibGitRepository, file_path: &Path) -> Result<Option<String>> {
+ pub async fn load_head_text(&self, relative_file_path: &Path) -> Option<String> {
+ fn logic(repo: &LibGitRepository, relative_file_path: &Path) -> Result<Option<String>> {
let object = repo
.head()?
.peel_to_tree()?
- .get_path(file_path)?
+ .get_path(relative_file_path)?
.to_object(&repo)?;
let content = match object.as_blob() {
@@ -79,7 +75,7 @@ impl GitRepository {
Ok(Some(head_text))
}
- match logic(&self.libgit_repository.lock(), file_path) {
+ match logic(&self.libgit_repository.as_ref().lock(), relative_file_path) {
Ok(value) => return value,
Err(err) => log::error!("Error loading head text: {:?}", err),
}
@@ -25,6 +25,7 @@ client = { path = "../client" }
clock = { path = "../clock" }
collections = { path = "../collections" }
fuzzy = { path = "../fuzzy" }
+git = { path = "../git" }
gpui = { path = "../gpui" }
lsp = { path = "../lsp" }
rpc = { path = "../rpc" }
@@ -51,7 +52,6 @@ smol = "1.2"
tree-sitter = "0.20"
tree-sitter-rust = { version = "*", optional = true }
tree-sitter-typescript = { version = "*", optional = true }
-git2 = { version = "0.15", default-features = false }
[dev-dependencies]
client = { path = "../client", features = ["test-support"] }
@@ -1,4 +1,3 @@
-use crate::git;
pub use crate::{
diagnostic_set::DiagnosticSet,
highlight_map::{HighlightId, HighlightMap},
@@ -47,14 +46,14 @@ pub use {tree_sitter_rust, tree_sitter_typescript};
pub use lsp::DiagnosticSeverity;
struct GitDiffStatus {
- diff: git::BufferDiff,
+ diff: git::diff::BufferDiff,
update_in_progress: bool,
update_requested: bool,
}
pub struct Buffer {
text: TextBuffer,
- head_text: Option<Arc<String>>,
+ head_text: Option<String>,
git_diff_status: GitDiffStatus,
file: Option<Arc<dyn File>>,
saved_version: clock::Global,
@@ -83,7 +82,7 @@ pub struct Buffer {
pub struct BufferSnapshot {
text: text::BufferSnapshot,
- pub git_diff: git::BufferDiff,
+ pub git_diff: git::diff::BufferDiff,
pub(crate) syntax: SyntaxSnapshot,
file: Option<Arc<dyn File>>,
diagnostics: DiagnosticSet,
@@ -353,7 +352,7 @@ impl Buffer {
) -> Self {
Self::build(
TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()),
- head_text.map(|h| Arc::new(h.into())),
+ head_text.map(|h| h.into().into_boxed_str().into()),
Some(file),
)
}
@@ -364,7 +363,11 @@ impl Buffer {
file: Option<Arc<dyn File>>,
) -> Result<Self> {
let buffer = TextBuffer::new(replica_id, message.id, message.base_text);
- let mut this = Self::build(buffer, message.head_text.map(|text| Arc::new(text)), file);
+ let mut this = Self::build(
+ buffer,
+ message.head_text.map(|text| text.into_boxed_str().into()),
+ file,
+ );
this.text.set_line_ending(proto::deserialize_line_ending(
proto::LineEnding::from_i32(message.line_ending)
.ok_or_else(|| anyhow!("missing line_ending"))?,
@@ -420,11 +423,7 @@ impl Buffer {
self
}
- fn build(
- buffer: TextBuffer,
- head_text: Option<Arc<String>>,
- file: Option<Arc<dyn File>>,
- ) -> Self {
+ fn build(buffer: TextBuffer, head_text: Option<String>, file: Option<Arc<dyn File>>) -> Self {
let saved_mtime = if let Some(file) = file.as_ref() {
file.mtime()
} else {
@@ -440,7 +439,7 @@ impl Buffer {
text: buffer,
head_text,
git_diff_status: GitDiffStatus {
- diff: git::BufferDiff::new(),
+ diff: git::diff::BufferDiff::new(),
update_in_progress: false,
update_requested: false,
},
@@ -613,7 +612,7 @@ impl Buffer {
cx,
);
}
- self.update_git(cx);
+ self.git_diff_recalc(cx);
cx.emit(Event::Reloaded);
cx.notify();
}
@@ -663,9 +662,8 @@ impl Buffer {
task
}
- pub fn update_git(&mut self, cx: &mut ModelContext<Self>) {
- //Grab head text
-
+ pub fn update_head_text(&mut self, head_text: Option<String>, cx: &mut ModelContext<Self>) {
+ self.head_text = head_text;
self.git_diff_recalc(cx);
}
@@ -674,6 +672,7 @@ impl Buffer {
}
pub fn git_diff_recalc(&mut self, cx: &mut ModelContext<Self>) {
+ println!("recalc");
if self.git_diff_status.update_in_progress {
self.git_diff_status.update_requested = true;
return;
@@ -2221,7 +2220,7 @@ impl BufferSnapshot {
pub fn git_diff_hunks_in_range<'a>(
&'a self,
query_row_range: Range<u32>,
- ) -> impl 'a + Iterator<Item = git::DiffHunk<u32>> {
+ ) -> impl 'a + Iterator<Item = git::diff::DiffHunk<u32>> {
self.git_diff.hunks_in_range(query_row_range, self)
}
@@ -1,6 +1,5 @@
mod buffer;
mod diagnostic_set;
-pub mod git;
mod highlight_map;
mod outline;
pub mod proto;
@@ -24,6 +24,7 @@ collections = { path = "../collections" }
db = { path = "../db" }
fsevent = { path = "../fsevent" }
fuzzy = { path = "../fuzzy" }
+git = { path = "../git" }
gpui = { path = "../gpui" }
language = { path = "../language" }
lsp = { path = "../lsp" }
@@ -52,8 +53,6 @@ smol = "1.2.5"
thiserror = "1.0.29"
toml = "0.5"
rocksdb = "0.18"
-git2 = { version = "0.15", default-features = false }
-
[dev-dependencies]
client = { path = "../client", features = ["test-support"] }
@@ -1,11 +1,9 @@
use anyhow::{anyhow, Result};
use fsevent::EventStream;
use futures::{future::BoxFuture, Stream, StreamExt};
-use language::git::libgit::{Repository, RepositoryOpenFlags};
use language::LineEnding;
use smol::io::{AsyncReadExt, AsyncWriteExt};
use std::{
- ffi::OsStr,
io,
os::unix::fs::MetadataExt,
path::{Component, Path, PathBuf},
@@ -22,8 +20,6 @@ use futures::lock::Mutex;
#[cfg(any(test, feature = "test-support"))]
use std::sync::{Arc, Weak};
-use crate::git_repository::GitRepository;
-
#[async_trait::async_trait]
pub trait Fs: Send + Sync {
async fn create_dir(&self, path: &Path) -> Result<()>;
@@ -1,5 +1,4 @@
pub mod fs;
-mod git_repository;
mod ignore;
mod lsp_command;
pub mod search;
@@ -13,7 +12,7 @@ use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
use clock::ReplicaId;
use collections::{hash_map, BTreeMap, HashMap, HashSet};
use futures::{future::Shared, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt};
-use git_repository::GitRepository;
+use git::repository::GitRepository;
use gpui::{
AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle,
@@ -4538,6 +4537,7 @@ impl Project {
cx.subscribe(worktree, |this, worktree, event, cx| match event {
worktree::Event::UpdatedEntries => this.update_local_worktree_buffers(worktree, cx),
worktree::Event::UpdatedGitRepositories(updated_repos) => {
+ println!("{updated_repos:#?}");
this.update_local_worktree_buffers_git_repos(updated_repos, cx)
}
})
@@ -4649,24 +4649,35 @@ impl Project {
fn update_local_worktree_buffers_git_repos(
&mut self,
- updated_repos: &[GitRepository],
+ repos: &[GitRepository],
cx: &mut ModelContext<Self>,
) {
- for (buffer_id, buffer) in &self.opened_buffers {
+ //TODO: Produce protos
+
+ for (_, buffer) in &self.opened_buffers {
if let Some(buffer) = buffer.upgrade(cx) {
- buffer.update(cx, |buffer, cx| {
- let updated = updated_repos.iter().any(|repo| {
- buffer
- .file()
- .and_then(|file| file.as_local())
- .map(|file| repo.manages(&file.abs_path(cx)))
- .unwrap_or(false)
- });
+ let file = match buffer.read(cx).file().and_then(|file| file.as_local()) {
+ Some(file) => file,
+ None => return,
+ };
+ let path = file.path().clone();
+ let abs_path = file.abs_path(cx);
+ println!("got file");
- if updated {
- buffer.update_git(cx);
- }
- });
+ let repo = match repos.iter().find(|repo| repo.manages(&abs_path)) {
+ Some(repo) => repo.clone(),
+ None => return,
+ };
+ println!("got repo");
+
+ cx.spawn(|_, mut cx| async move {
+ let head_text = repo.load_head_text(&path).await;
+ buffer.update(&mut cx, |buffer, cx| {
+ println!("got calling update");
+ buffer.update_head_text(head_text, cx);
+ });
+ })
+ .detach();
}
}
}
@@ -1,10 +1,9 @@
-use crate::{copy_recursive, git_repository::GitRepository, ProjectEntryId, RemoveOptions};
-
use super::{
fs::{self, Fs},
ignore::IgnoreStack,
DiagnosticSummary,
};
+use crate::{copy_recursive, ProjectEntryId, RemoveOptions};
use ::ignore::gitignore::{Gitignore, GitignoreBuilder};
use anyhow::{anyhow, Context, Result};
use client::{proto, Client};
@@ -18,6 +17,8 @@ use futures::{
Stream, StreamExt,
};
use fuzzy::CharBag;
+use git::repository::GitRepository;
+use git::{DOT_GIT, GITIGNORE};
use gpui::{
executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext,
Task,
@@ -48,7 +49,7 @@ use std::{
time::{Duration, SystemTime},
};
use sum_tree::{Bias, Edit, SeekTarget, SumTree, TreeMap, TreeSet};
-use util::{ResultExt, TryFutureExt, DOT_GIT, GITIGNORE};
+use util::{ResultExt, TryFutureExt};
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub struct WorktreeId(usize);
@@ -523,7 +524,10 @@ impl LocalWorktree {
match self.scan_state() {
ScanState::Idle => {
let new_snapshot = self.background_snapshot.lock().clone();
- let updated_repos = self.list_updated_repos(&new_snapshot);
+ let updated_repos = Self::list_updated_repos(
+ &self.snapshot.git_repositories,
+ &new_snapshot.git_repositories,
+ );
self.snapshot = new_snapshot;
if let Some(share) = self.share.as_mut() {
@@ -541,7 +545,10 @@ impl LocalWorktree {
let is_fake_fs = self.fs.is_fake();
let new_snapshot = self.background_snapshot.lock().clone();
- let updated_repos = self.list_updated_repos(&new_snapshot);
+ let updated_repos = Self::list_updated_repos(
+ &self.snapshot.git_repositories,
+ &new_snapshot.git_repositories,
+ );
self.snapshot = new_snapshot;
self.poll_task = Some(cx.spawn_weak(|this, mut cx| async move {
@@ -573,16 +580,20 @@ impl LocalWorktree {
cx.notify();
}
- fn list_updated_repos(&self, new_snapshot: &LocalSnapshot) -> Vec<GitRepository> {
- let old_snapshot = &self.snapshot;
+ fn list_updated_repos(
+ old_repos: &[GitRepository],
+ new_repos: &[GitRepository],
+ ) -> Vec<GitRepository> {
+ println!("old repos: {:#?}", old_repos);
+ println!("new repos: {:#?}", new_repos);
fn diff<'a>(
- a: &'a LocalSnapshot,
- b: &'a LocalSnapshot,
+ a: &'a [GitRepository],
+ b: &'a [GitRepository],
updated: &mut HashMap<&'a Path, GitRepository>,
) {
- for a_repo in &a.git_repositories {
- let matched = b.git_repositories.iter().find(|b_repo| {
+ for a_repo in a {
+ let matched = b.iter().find(|b_repo| {
a_repo.git_dir_path() == b_repo.git_dir_path()
&& a_repo.scan_id() == b_repo.scan_id()
});
@@ -595,10 +606,10 @@ impl LocalWorktree {
let mut updated = HashMap::<&Path, GitRepository>::default();
- diff(old_snapshot, new_snapshot, &mut updated);
- diff(new_snapshot, old_snapshot, &mut updated);
+ diff(old_repos, new_repos, &mut updated);
+ diff(new_repos, old_repos, &mut updated);
- updated.into_values().collect()
+ dbg!(updated.into_values().collect())
}
pub fn scan_complete(&self) -> impl Future<Output = ()> {
@@ -653,7 +664,7 @@ impl LocalWorktree {
settings::GitFilesIncluded::All | settings::GitFilesIncluded::OnlyTracked
) {
let results = if let Some(repo) = snapshot.repo_for(&abs_path) {
- repo.load_head_text(&abs_path).await
+ repo.load_head_text(&path).await
} else {
None
};
@@ -1362,6 +1373,7 @@ impl LocalSnapshot {
}
pub(crate) fn in_dot_git(&mut self, path: &Path) -> Option<&mut GitRepository> {
+ println!("chechking {path:?}");
self.git_repositories
.iter_mut()
.rev() //git_repository is ordered lexicographically
@@ -1510,7 +1522,6 @@ impl LocalSnapshot {
parent_path: Arc<Path>,
entries: impl IntoIterator<Item = Entry>,
ignore: Option<Arc<Gitignore>>,
- fs: &dyn Fs,
) {
let mut parent_entry = if let Some(parent_entry) =
self.entries_by_path.get(&PathKey(parent_path.clone()), &())
@@ -2391,12 +2402,9 @@ impl BackgroundScanner {
new_entries.push(child_entry);
}
- self.snapshot.lock().populate_dir(
- job.path.clone(),
- new_entries,
- new_ignore,
- self.fs.as_ref(),
- );
+ self.snapshot
+ .lock()
+ .populate_dir(job.path.clone(), new_entries, new_ignore);
for new_job in new_jobs {
job.scan_queue.send(new_job).await.unwrap();
}
@@ -2595,7 +2603,7 @@ impl BackgroundScanner {
.git_repositories
.iter()
.cloned()
- .filter(|repo| git2::Repository::open(repo.git_dir_path()).is_ok())
+ .filter(|repo| git::libgit::Repository::open(repo.git_dir_path()).is_ok())
.collect();
snapshot.git_repositories = new_repos;
@@ -2,20 +2,13 @@
pub mod test;
use futures::Future;
-use lazy_static::lazy_static;
use std::{
cmp::Ordering,
- ffi::OsStr,
ops::AddAssign,
pin::Pin,
task::{Context, Poll},
};
-lazy_static! {
- pub static ref DOT_GIT: &'static OsStr = OsStr::new(".git");
- pub static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
-}
-
pub fn truncate(s: &str, max_chars: usize) -> &str {
match s.char_indices().nth(max_chars) {
None => s,
@@ -2,14 +2,15 @@ mod assertions;
mod marked_text;
use git2;
-use std::path::{Path, PathBuf};
+use std::{
+ ffi::OsStr,
+ path::{Path, PathBuf},
+};
use tempdir::TempDir;
pub use assertions::*;
pub use marked_text::*;
-use crate::DOT_GIT;
-
pub fn temp_tree(tree: serde_json::Value) -> TempDir {
let dir = TempDir::new("").unwrap();
write_tree(dir.path(), tree);
@@ -28,7 +29,7 @@ fn write_tree(path: &Path, tree: serde_json::Value) {
Value::Object(_) => {
fs::create_dir(&path).unwrap();
- if path.file_name() == Some(&DOT_GIT) {
+ if path.file_name() == Some(&OsStr::new(".git")) {
git2::Repository::init(&path.parent().unwrap()).unwrap();
}