Compare commits
2 Commits
fix-git-ht
...
open-recen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d97c881737 | ||
|
|
576d394e1a |
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -4451,6 +4451,16 @@ dependencies = [
|
|||||||
"util",
|
"util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "git_ui"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"git",
|
||||||
|
"gpui",
|
||||||
|
"serde",
|
||||||
|
"workspace",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ members = [
|
|||||||
"crates/fsevent",
|
"crates/fsevent",
|
||||||
"crates/fuzzy",
|
"crates/fuzzy",
|
||||||
"crates/git",
|
"crates/git",
|
||||||
|
"crates/git_ui",
|
||||||
"crates/git_hosting_providers",
|
"crates/git_hosting_providers",
|
||||||
"crates/go_to_line",
|
"crates/go_to_line",
|
||||||
"crates/google_ai",
|
"crates/google_ai",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::blame::Blame;
|
use crate::blame::Blame;
|
||||||
use crate::GitHostingProviderRegistry;
|
use crate::GitHostingProviderRegistry;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use collections::HashMap;
|
use collections::{HashMap, HashSet};
|
||||||
use git2::{BranchType, StatusShow};
|
use git2::{BranchType, StatusShow};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rope::Rope;
|
use rope::Rope;
|
||||||
@@ -62,6 +62,8 @@ pub trait GitRepository: Send {
|
|||||||
fn create_branch(&self, _: &str) -> Result<()>;
|
fn create_branch(&self, _: &str) -> Result<()>;
|
||||||
|
|
||||||
fn blame(&self, path: &Path, content: Rope) -> Result<crate::blame::Blame>;
|
fn blame(&self, path: &Path, content: Rope) -> Result<crate::blame::Blame>;
|
||||||
|
|
||||||
|
fn recently_changed_paths(&self, max: usize) -> Result<Vec<(SystemTime, PathBuf)>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for dyn GitRepository {
|
impl std::fmt::Debug for dyn GitRepository {
|
||||||
@@ -259,6 +261,44 @@ impl GitRepository for RealGitRepository {
|
|||||||
self.hosting_provider_registry.clone(),
|
self.hosting_provider_registry.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recently_changed_paths(&self, max: usize) -> Result<Vec<(SystemTime, PathBuf)>> {
|
||||||
|
let mut revwalk = self.repository.revwalk()?;
|
||||||
|
revwalk.push_head()?;
|
||||||
|
|
||||||
|
let mut included = HashSet::<PathBuf>::default();
|
||||||
|
let mut changed_paths = Vec::new();
|
||||||
|
for oid in revwalk {
|
||||||
|
let oid = oid?;
|
||||||
|
let commit = self.repository.find_commit(oid)?;
|
||||||
|
let tree = commit.tree()?;
|
||||||
|
let diff = self.repository.diff_tree_to_tree(None, Some(&tree), None)?;
|
||||||
|
diff.foreach(
|
||||||
|
&mut |delta, _| {
|
||||||
|
if let Some(path) = delta.new_file().path() {
|
||||||
|
if !included.contains(path) {
|
||||||
|
included.insert(path.into());
|
||||||
|
let time = commit.time().seconds();
|
||||||
|
let system_time =
|
||||||
|
SystemTime::UNIX_EPOCH + std::time::Duration::new(time as u64, 0);
|
||||||
|
changed_paths.push((system_time, path.to_path_buf()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if included.len() >= max {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed_paths.truncate(max);
|
||||||
|
Ok(changed_paths)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_index(repo: &LibGitRepository, path: &RepoPath, mtime: SystemTime) -> bool {
|
fn matches_index(repo: &LibGitRepository, path: &RepoPath, mtime: SystemTime) -> bool {
|
||||||
@@ -377,6 +417,10 @@ impl GitRepository for FakeGitRepository {
|
|||||||
.with_context(|| format!("failed to get blame for {:?}", path))
|
.with_context(|| format!("failed to get blame for {:?}", path))
|
||||||
.cloned()
|
.cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recently_changed_paths(&self, max: usize) -> Result<Vec<(SystemTime, PathBuf)>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> {
|
fn check_path_to_repo_path_errors(relative_file_path: &Path) -> Result<()> {
|
||||||
|
|||||||
20
crates/git_ui/Cargo.toml
Normal file
20
crates/git_ui/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "git_ui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "./src/git_ui.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gpui.workspace = true
|
||||||
|
git.workspace = true
|
||||||
|
workspace.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gpui = { workspace = true, features = ["test-support"] }
|
||||||
|
workspace = { workspace = true, features = ["test-support"] }
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
58
crates/git_ui/src/git_ui.rs
Normal file
58
crates/git_ui/src/git_ui.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::{self, Instant, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
|
use gpui::{AppContext, ViewContext};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use workspace::Workspace;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct OpenRecentlyChanged {
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
gpui::impl_actions!(git, [OpenRecentlyChanged]);
|
||||||
|
|
||||||
|
pub fn init(cx: &mut AppContext) {
|
||||||
|
cx.observe_new_views(
|
||||||
|
|workspace: &mut Workspace, cx: &mut ViewContext<Workspace>| {
|
||||||
|
workspace.register_action(open_recently_changed);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_recently_changed(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
action: &OpenRecentlyChanged,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) {
|
||||||
|
let worktrees = workspace.project().read(cx).worktrees().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut repos = Vec::new();
|
||||||
|
for worktree in worktrees {
|
||||||
|
if let Some(local_worktree) = worktree.read(cx).as_local() {
|
||||||
|
if let Some(local_repo) = local_worktree
|
||||||
|
.repository_for_path(Path::new(""))
|
||||||
|
.and_then(|repo| local_worktree.get_local_repo(&repo))
|
||||||
|
{
|
||||||
|
repos.push(local_repo.repo().clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !repos.is_empty() {
|
||||||
|
let recent_paths = cx.background_executor().spawn(async move {
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
for repo in repos {
|
||||||
|
paths.extend(repo.lock().recently_changed_paths(100))?;
|
||||||
|
}
|
||||||
|
anyhow::Ok(paths)
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.spawn(|this, cx| async move {
|
||||||
|
// let recent_paths =
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3139,6 +3139,7 @@ impl File {
|
|||||||
pub struct Entry {
|
pub struct Entry {
|
||||||
pub id: ProjectEntryId,
|
pub id: ProjectEntryId,
|
||||||
pub kind: EntryKind,
|
pub kind: EntryKind,
|
||||||
|
/// Relative path of the entry in the worktree.
|
||||||
pub path: Arc<Path>,
|
pub path: Arc<Path>,
|
||||||
pub inode: u64,
|
pub inode: u64,
|
||||||
pub mtime: Option<SystemTime>,
|
pub mtime: Option<SystemTime>,
|
||||||
|
|||||||
Reference in New Issue
Block a user