Implement staging and unstaging hunks (#24606)
- [x] Staging hunks - [x] Unstaging hunks - [x] Write a randomized test - [x] Get test passing - [x] Fix existing bug in diff_base_byte_range computation - [x] Remote project support - [ ] ~~Improve performance of buffer_range_to_unchanged_diff_base_range~~ - [ ] ~~Bug: project diff editor scrolls to top when staging/unstaging hunk~~ existing issue - [ ] ~~UI~~ deferred - [x] Tricky cases - [x] Correctly handle acting on multiple hunks for a single file - [x] Remove path from index when unstaging the last staged hunk, if it's absent from HEAD, or staging the only hunk, if it's deleted in the working copy Release Notes: - Add `ToggleStagedSelectedDiffHunks` action for staging and unstaging individual diff hunks
This commit is contained in:
parent
ea8da43c6b
commit
eea6b526dc
18 changed files with 768 additions and 70 deletions
|
@ -8,6 +8,8 @@ use gpui::SharedString;
|
|||
use parking_lot::Mutex;
|
||||
use rope::Rope;
|
||||
use std::borrow::Borrow;
|
||||
use std::io::Write as _;
|
||||
use std::process::Stdio;
|
||||
use std::sync::LazyLock;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
|
@ -39,6 +41,8 @@ pub trait GitRepository: Send + Sync {
|
|||
/// Note that for symlink entries, this will return the contents of the symlink, not the target.
|
||||
fn load_committed_text(&self, path: &RepoPath) -> Option<String>;
|
||||
|
||||
fn set_index_text(&self, path: &RepoPath, content: Option<String>) -> anyhow::Result<()>;
|
||||
|
||||
/// Returns the URL of the remote with the given name.
|
||||
fn remote_url(&self, name: &str) -> Option<String>;
|
||||
fn branch_name(&self) -> Option<String>;
|
||||
|
@ -161,6 +165,50 @@ impl GitRepository for RealGitRepository {
|
|||
Some(content)
|
||||
}
|
||||
|
||||
fn set_index_text(&self, path: &RepoPath, content: Option<String>) -> anyhow::Result<()> {
|
||||
let working_directory = self
|
||||
.repository
|
||||
.lock()
|
||||
.workdir()
|
||||
.context("failed to read git work directory")?
|
||||
.to_path_buf();
|
||||
if let Some(content) = content {
|
||||
let mut child = new_std_command(&self.git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["hash-object", "-w", "--stdin"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
child.stdin.take().unwrap().write_all(content.as_bytes())?;
|
||||
let output = child.wait_with_output()?.stdout;
|
||||
let sha = String::from_utf8(output)?;
|
||||
|
||||
log::debug!("indexing SHA: {sha}, path {path:?}");
|
||||
|
||||
let status = new_std_command(&self.git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["update-index", "--add", "--cacheinfo", "100644", &sha])
|
||||
.arg(path.as_ref())
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(anyhow!("Failed to add to index: {status:?}"));
|
||||
}
|
||||
} else {
|
||||
let status = new_std_command(&self.git_binary_path)
|
||||
.current_dir(&working_directory)
|
||||
.args(["update-index", "--force-remove"])
|
||||
.arg(path.as_ref())
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(anyhow!("Failed to remove from index: {status:?}"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remote_url(&self, name: &str) -> Option<String> {
|
||||
let repo = self.repository.lock();
|
||||
let remote = repo.find_remote(name).ok()?;
|
||||
|
@ -412,6 +460,20 @@ impl GitRepository for FakeGitRepository {
|
|||
state.head_contents.get(path.as_ref()).cloned()
|
||||
}
|
||||
|
||||
fn set_index_text(&self, path: &RepoPath, content: Option<String>) -> anyhow::Result<()> {
|
||||
let mut state = self.state.lock();
|
||||
if let Some(content) = content {
|
||||
state.index_contents.insert(path.clone(), content);
|
||||
} else {
|
||||
state.index_contents.remove(path);
|
||||
}
|
||||
state
|
||||
.event_emitter
|
||||
.try_send(state.path.clone())
|
||||
.expect("Dropped repo change event");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remote_url(&self, _name: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue