WIP
This commit is contained in:
parent
4bee06e507
commit
231a348e69
6 changed files with 106 additions and 1 deletions
|
@ -320,6 +320,10 @@ impl GitRepository for FakeGitRepository {
|
|||
})
|
||||
}
|
||||
|
||||
fn stash_entries(&self) -> BoxFuture<'_, Result<git::stash::GitStash>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>> {
|
||||
self.with_state_async(false, move |state| {
|
||||
let current_branch = &state.current_branch_name;
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod commit;
|
|||
mod hosting_provider;
|
||||
mod remote;
|
||||
pub mod repository;
|
||||
pub mod stash;
|
||||
pub mod status;
|
||||
|
||||
pub use crate::hosting_provider::*;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::commit::parse_git_diff_name_status;
|
||||
use crate::stash::GitStash;
|
||||
use crate::status::{GitStatus, StatusCode};
|
||||
use crate::{Oid, SHORT_SHA_LENGTH};
|
||||
use anyhow::{Context as _, Result, anyhow, bail};
|
||||
|
@ -338,6 +339,8 @@ pub trait GitRepository: Send + Sync {
|
|||
|
||||
fn status(&self, path_prefixes: &[RepoPath]) -> Task<Result<GitStatus>>;
|
||||
|
||||
fn stash_entries(&self) -> BoxFuture<'_, Result<GitStash>>;
|
||||
|
||||
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>>;
|
||||
|
||||
fn change_branch(&self, name: String) -> BoxFuture<'_, Result<()>>;
|
||||
|
@ -974,6 +977,26 @@ impl GitRepository for RealGitRepository {
|
|||
})
|
||||
}
|
||||
|
||||
fn stash_entries(&self) -> BoxFuture<'_, Result<GitStash>> {
|
||||
let git_binary_path = self.git_binary_path.clone();
|
||||
let working_directory = self.working_directory();
|
||||
self.executor
|
||||
.spawn(async move {
|
||||
let output = new_std_command(&git_binary_path)
|
||||
.current_dir(working_directory?)
|
||||
.args(&["stash", "list", "--pretty=%gd:%H:%s"])
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
stdout.parse()
|
||||
} else {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
anyhow::bail!("git status failed: {stderr}");
|
||||
}
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>> {
|
||||
let working_directory = self.working_directory();
|
||||
let git_binary_path = self.git_binary_path.clone();
|
||||
|
|
56
crates/git/src/stash.rs
Normal file
56
crates/git/src/stash.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use crate::Oid;
|
||||
use anyhow::Result;
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct StashEntry {
|
||||
pub index: usize,
|
||||
pub oid: Oid,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub struct GitStash {
|
||||
pub entries: Arc<[StashEntry]>,
|
||||
}
|
||||
|
||||
impl FromStr for GitStash {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
// git stash list --pretty=%gd:%H:%s
|
||||
let entries = s
|
||||
.split('\n')
|
||||
.filter_map(|entry| {
|
||||
let mut parts = entry.splitn(3, ':');
|
||||
let raw_idx = parts.next().and_then(|i| {
|
||||
let trimmed = i.trim();
|
||||
if trimmed.starts_with("stash@{") && trimmed.ends_with('}') {
|
||||
trimmed
|
||||
.strip_prefix("stash@{")
|
||||
.and_then(|s| s.strip_suffix('}'))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let raw_oid = parts.next();
|
||||
let message = parts.next();
|
||||
|
||||
if let (Some(raw_idx), Some(raw_oid), Some(message)) = (raw_idx, raw_oid, message) {
|
||||
let index = raw_idx.parse::<usize>().ok()?;
|
||||
let oid = Oid::from_str(raw_oid).ok()?;
|
||||
let entry = StashEntry {
|
||||
index,
|
||||
oid,
|
||||
message: message.to_string(),
|
||||
};
|
||||
return Some(entry);
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<Arc<[StashEntry]>>();
|
||||
Ok(Self {
|
||||
entries: entries.clone(),
|
||||
})
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ use git::repository::{
|
|||
PushOptions, Remote, RemoteCommandOutput, ResetMode, Upstream, UpstreamTracking,
|
||||
UpstreamTrackingStatus, get_git_committer,
|
||||
};
|
||||
use git::stash::GitStash;
|
||||
use git::status::StageStatus;
|
||||
use git::{Amend, Signoff, ToggleStaged, repository::RepoPath, status::FileStatus};
|
||||
use git::{
|
||||
|
@ -119,6 +120,7 @@ struct GitMenuState {
|
|||
has_staged_changes: bool,
|
||||
has_unstaged_changes: bool,
|
||||
has_new_changes: bool,
|
||||
has_stash_items: bool,
|
||||
}
|
||||
|
||||
fn git_panel_context_menu(
|
||||
|
@ -146,7 +148,7 @@ fn git_panel_context_menu(
|
|||
"Stash All",
|
||||
StashAll.boxed_clone(),
|
||||
)
|
||||
.action("Stash Pop", StashPop.boxed_clone())
|
||||
.action_disabled_when(!state.has_stash_items, "Stash Pop", StashPop.boxed_clone())
|
||||
.separator()
|
||||
.action("Open Diff", project_diff::Diff.boxed_clone())
|
||||
.separator()
|
||||
|
@ -369,6 +371,7 @@ pub struct GitPanel {
|
|||
local_committer: Option<GitCommitter>,
|
||||
local_committer_task: Option<Task<()>>,
|
||||
bulk_staging: Option<BulkStaging>,
|
||||
stash_entries: GitStash,
|
||||
_settings_subscription: Subscription,
|
||||
}
|
||||
|
||||
|
@ -558,6 +561,7 @@ impl GitPanel {
|
|||
horizontal_scrollbar,
|
||||
vertical_scrollbar,
|
||||
bulk_staging: None,
|
||||
stash_entries: Default::default(),
|
||||
_settings_subscription,
|
||||
};
|
||||
|
||||
|
@ -2685,6 +2689,8 @@ impl GitPanel {
|
|||
|
||||
let repo = repo.read(cx);
|
||||
|
||||
self.stash_entries = repo.cached_stash();
|
||||
|
||||
for entry in repo.cached_status() {
|
||||
let is_conflict = repo.had_conflict_on_last_merge_head_change(&entry.repo_path);
|
||||
let is_new = entry.status.is_created();
|
||||
|
@ -3053,6 +3059,7 @@ impl GitPanel {
|
|||
let has_staged_changes = self.has_staged_changes();
|
||||
let has_unstaged_changes = self.has_unstaged_changes();
|
||||
let has_new_changes = self.new_count > 0;
|
||||
let has_stash_items = self.stash_entries.entries.len() > 0;
|
||||
|
||||
PopoverMenu::new(id.into())
|
||||
.trigger(
|
||||
|
@ -3068,6 +3075,7 @@ impl GitPanel {
|
|||
has_staged_changes,
|
||||
has_unstaged_changes,
|
||||
has_new_changes,
|
||||
has_stash_items,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
@ -4115,6 +4123,7 @@ impl GitPanel {
|
|||
has_staged_changes: self.has_staged_changes(),
|
||||
has_unstaged_changes: self.has_unstaged_changes(),
|
||||
has_new_changes: self.new_count > 0,
|
||||
has_stash_items: self.stash_entries.entries.len() > 0,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
|
|
@ -28,6 +28,7 @@ use git::{
|
|||
GitRepository, GitRepositoryCheckpoint, PushOptions, Remote, RemoteCommandOutput, RepoPath,
|
||||
ResetMode, UpstreamTrackingStatus,
|
||||
},
|
||||
stash::GitStash,
|
||||
status::{
|
||||
FileStatus, GitSummary, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode,
|
||||
},
|
||||
|
@ -248,6 +249,7 @@ pub struct RepositorySnapshot {
|
|||
pub merge: MergeDetails,
|
||||
pub remote_origin_url: Option<String>,
|
||||
pub remote_upstream_url: Option<String>,
|
||||
pub stash_entries: GitStash,
|
||||
}
|
||||
|
||||
type JobId = u64;
|
||||
|
@ -2744,6 +2746,7 @@ impl RepositorySnapshot {
|
|||
merge: Default::default(),
|
||||
remote_origin_url: None,
|
||||
remote_upstream_url: None,
|
||||
stash_entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3264,6 +3267,10 @@ impl Repository {
|
|||
self.snapshot.status()
|
||||
}
|
||||
|
||||
pub fn cached_stash(&self) -> GitStash {
|
||||
self.snapshot.stash_entries.clone()
|
||||
}
|
||||
|
||||
pub fn repo_path_to_project_path(&self, path: &RepoPath, cx: &App) -> Option<ProjectPath> {
|
||||
let git_store = self.git_store.upgrade()?;
|
||||
let worktree_store = git_store.read(cx).worktree_store.read(cx);
|
||||
|
@ -4539,6 +4546,7 @@ impl Repository {
|
|||
updates_tx: Option<mpsc::UnboundedSender<DownstreamUpdate>>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
println!("paths changed with updates_tx: {:?}", updates_tx);
|
||||
self.paths_needing_status_update.extend(paths);
|
||||
|
||||
let this = cx.weak_entity();
|
||||
|
@ -4561,6 +4569,7 @@ impl Repository {
|
|||
return Ok(());
|
||||
}
|
||||
let statuses = backend.status(&paths).await?;
|
||||
let stash_entries = backend.stash_entries().await?;
|
||||
|
||||
let changed_path_statuses = cx
|
||||
.background_spawn(async move {
|
||||
|
@ -4592,6 +4601,7 @@ impl Repository {
|
|||
.await;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.snapshot.stash_entries = stash_entries;
|
||||
if !changed_path_statuses.is_empty() {
|
||||
this.snapshot
|
||||
.statuses_by_path
|
||||
|
@ -4852,6 +4862,7 @@ async fn compute_snapshot(
|
|||
let statuses = backend
|
||||
.status(std::slice::from_ref(&WORK_DIRECTORY_REPO_PATH))
|
||||
.await?;
|
||||
let stash_entries = backend.stash_entries().await?;
|
||||
let statuses_by_path = SumTree::from_iter(
|
||||
statuses
|
||||
.entries
|
||||
|
@ -4902,6 +4913,7 @@ async fn compute_snapshot(
|
|||
merge: merge_details,
|
||||
remote_origin_url,
|
||||
remote_upstream_url,
|
||||
stash_entries,
|
||||
};
|
||||
|
||||
Ok((snapshot, events))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue