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