Revert "Change diff renamed files (#1040)"

This reverts commit 5f466ff983.
This commit is contained in:
extrawurst 2022-04-24 22:30:40 +02:00
parent c3dbce1cd6
commit cce49a34b7
22 changed files with 121 additions and 496 deletions

View file

@ -63,7 +63,6 @@ This is was a immediate followup patch release to `0.20` see [release notes](htt
- support inspecting annotation of tag ([#1076](https://github.com/extrawurst/gitui/issues/1076))
- support deleting tag on remote ([#1074](https://github.com/extrawurst/gitui/issues/1074))
- support git credentials helper (https) ([#800](https://github.com/extrawurst/gitui/issues/800))
- Correct diff of renamed files [[@Mifom](https://github.com/Mifom)] ([#1038](https://github.com/extrawurst/gitui/issues/1038))
### Fixed
- Keep commit message when pre-commit hook fails ([#1035](https://github.com/extrawurst/gitui/issues/1035))

View file

@ -29,10 +29,8 @@ pub enum DiffType {
///
#[derive(Debug, Hash, Clone, PartialEq)]
pub struct DiffParams {
///
pub src_path: String,
/// path to the file to diff
pub dst_path: String,
pub path: String,
/// what kind of diff
pub diff_type: DiffType,
/// diff options
@ -163,28 +161,26 @@ impl AsyncDiff {
let res = match params.diff_type {
DiffType::Stage => sync::diff::get_diff(
repo_path,
&params.src_path,
&params.dst_path,
&params.path,
true,
Some(params.options),
)?,
DiffType::WorkDir => sync::diff::get_diff(
repo_path,
&params.src_path,
&params.dst_path,
&params.path,
false,
Some(params.options),
)?,
DiffType::Commit(id) => sync::diff::get_diff_commit(
repo_path,
id,
params.dst_path.clone(),
params.path.clone(),
Some(params.options),
)?,
DiffType::Commits(ids) => sync::diff::get_diff_commits(
repo_path,
ids,
params.dst_path.clone(),
params.path.clone(),
Some(params.options),
)?,
};

View file

@ -26,24 +26,21 @@ pub fn get_commit_files(
get_commit_diff(repo_path, &repo, id, None, None)?
};
let res =
diff.deltas()
.map(|delta| {
let status = StatusItemType::from(delta.status());
let res = diff
.deltas()
.map(|delta| {
let status = StatusItemType::from(delta.status());
StatusItem {
old_path: delta.old_file().path().map(|p| {
p.to_str().unwrap_or("").to_string()
}),
new_path: delta
.new_file()
.path()
.map(|p| p.to_str().unwrap_or("").to_string())
.unwrap_or_default(),
status,
}
})
.collect::<Vec<_>>();
StatusItem {
path: delta
.new_file()
.path()
.map(|p| p.to_str().unwrap_or("").to_string())
.unwrap_or_default(),
status,
}
})
.collect::<Vec<_>>();
Ok(res)
}

View file

@ -10,8 +10,7 @@ use crate::{
};
use easy_cast::Conv;
use git2::{
Delta, Diff, DiffDelta, DiffFindOptions, DiffFormat, DiffHunk,
Patch, Repository,
Delta, Diff, DiffDelta, DiffFormat, DiffHunk, Patch, Repository,
};
use scopetime::scope_time;
use std::{cell::RefCell, fs, path::Path, rc::Rc};
@ -150,8 +149,7 @@ impl Default for DiffOptions {
pub(crate) fn get_diff_raw<'a>(
repo: &'a Repository,
src: &str,
dst: &str,
p: &str,
stage: bool,
reverse: bool,
options: Option<DiffOptions>,
@ -164,11 +162,10 @@ pub(crate) fn get_diff_raw<'a>(
opt.ignore_whitespace(options.ignore_whitespace);
opt.interhunk_lines(options.interhunk_lines);
}
opt.pathspec(src);
opt.pathspec(dst);
opt.pathspec(p);
opt.reverse(reverse);
let mut diff = if stage {
let diff = if stage {
// diff against head
if let Ok(id) = get_head_repo(repo) {
let parent = repo.find_commit(id.into())?;
@ -192,17 +189,13 @@ pub(crate) fn get_diff_raw<'a>(
repo.diff_index_to_workdir(None, Some(&mut opt))?
};
diff.find_similar(Some(
DiffFindOptions::new().renames(true).for_untracked(true),
))?;
Ok(diff)
}
/// returns diff of a specific file either in `stage` or workdir
pub fn get_diff(
repo_path: &RepoPath,
src: &str,
dst: &str,
p: &str,
stage: bool,
options: Option<DiffOptions>,
) -> Result<FileDiff> {
@ -210,7 +203,7 @@ pub fn get_diff(
let repo = repo(repo_path)?;
let work_dir = work_dir(&repo)?;
let diff = get_diff_raw(&repo, src, dst, stage, false, options)?;
let diff = get_diff_raw(&repo, p, stage, false, options)?;
raw_diff_to_file_diff(&diff, work_dir)
}
@ -257,8 +250,8 @@ pub fn get_diff_commits(
///
//TODO: refactor into helper type with the inline closures as dedicated functions
#[allow(clippy::too_many_lines)]
fn raw_diff_to_file_diff(
diff: &Diff,
fn raw_diff_to_file_diff<'a>(
diff: &'a Diff,
work_dir: &Path,
) -> Result<FileDiff> {
let res = Rc::new(RefCell::new(FileDiff::default()));
@ -429,7 +422,7 @@ mod tests {
},
};
use std::{
fs::{self, remove_file, File},
fs::{self, File},
io::Write,
path::Path,
};
@ -451,14 +444,8 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 0));
let diff = get_diff(
repo_path,
"foo/bar.txt",
"foo/bar.txt",
false,
None,
)
.unwrap();
let diff =
get_diff(repo_path, "foo/bar.txt", false, None).unwrap();
assert_eq!(diff.hunks.len(), 1);
assert_eq!(&*diff.hunks[0].lines[1].content, "test");
@ -488,7 +475,6 @@ mod tests {
let diff = get_diff(
repo_path,
file_path.to_str().unwrap(),
file_path.to_str().unwrap(),
true,
None,
)
@ -544,8 +530,7 @@ mod tests {
let res = get_status(repo_path, StatusType::WorkingDir, None)
.unwrap();
assert_eq!(res.len(), 1);
assert_eq!(res[0].new_path, "bar.txt");
assert_eq!(res[0].old_path, Some("bar.txt".to_string()));
assert_eq!(res[0].path, "bar.txt");
stage_add_file(repo_path, Path::new("bar.txt")).unwrap();
assert_eq!(get_statuses(repo_path), (0, 1));
@ -561,8 +546,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 1));
let res =
get_diff(repo_path, "bar.txt", "bar.txt", false, None)
.unwrap();
get_diff(repo_path, "bar.txt", false, None).unwrap();
assert_eq!(res.hunks.len(), 2)
}
@ -584,7 +568,6 @@ mod tests {
let diff = get_diff(
&sub_path.to_str().unwrap().into(),
file_path.to_str().unwrap(),
file_path.to_str().unwrap(),
false,
None,
)
@ -613,7 +596,6 @@ mod tests {
let diff = get_diff(
repo_path,
file_path.to_str().unwrap(),
file_path.to_str().unwrap(),
false,
None,
)
@ -640,7 +622,6 @@ mod tests {
let diff = get_diff(
repo_path,
file_path.to_str().unwrap(),
file_path.to_str().unwrap(),
false,
None,
)
@ -684,50 +665,4 @@ mod tests {
Ok(())
}
#[test]
fn test_rename() {
let (_td, repo) = repo_init().unwrap();
let root = repo.path().parent().unwrap();
let repo_path: &RepoPath =
&root.as_os_str().to_str().unwrap().into();
assert_eq!(get_statuses(repo_path), (0, 0));
let file_path = root.join("bar.txt");
{
File::create(&file_path)
.unwrap()
.write_all(HUNK_A.as_bytes())
.unwrap();
}
let res = get_status(repo_path, StatusType::WorkingDir, None)
.unwrap();
assert_eq!(res.len(), 1);
assert_eq!(res[0].new_path, "bar.txt");
assert_eq!(res[0].old_path, Some("bar.txt".to_string()));
stage_add_file(repo_path, Path::new("bar.txt")).unwrap();
assert_eq!(get_statuses(repo_path), (0, 1));
// Move file
let other_file_path = root.join("baz.txt");
{
File::create(&other_file_path)
.unwrap()
.write_all(HUNK_A.as_bytes())
.unwrap();
remove_file(&file_path).unwrap();
}
assert_eq!(get_statuses(repo_path), (1, 1));
let res =
get_diff(repo_path, "bar.txt", "baz.txt", false, None)
.unwrap();
assert_eq!(res.hunks.len(), 0)
}
}

View file

@ -13,22 +13,14 @@ use scopetime::scope_time;
///
pub fn stage_hunk(
repo_path: &RepoPath,
src_file_path: &str,
dst_file_path: &str,
file_path: &str,
hunk_hash: u64,
) -> Result<()> {
scope_time!("stage_hunk");
let repo = repo(repo_path)?;
let diff = get_diff_raw(
&repo,
src_file_path,
dst_file_path,
false,
false,
None,
)?;
let diff = get_diff_raw(&repo, file_path, false, false, None)?;
let mut opt = ApplyOptions::new();
opt.hunk_callback(|hunk| {
@ -53,9 +45,7 @@ pub fn reset_hunk(
let repo = repo(repo_path)?;
let diff = get_diff_raw(
&repo, file_path, file_path, false, false, None,
)?;
let diff = get_diff_raw(&repo, file_path, false, false, None)?;
let hunk_index = find_hunk_index(&diff, hunk_hash);
if let Some(hunk_index) = hunk_index {
@ -67,9 +57,7 @@ pub fn reset_hunk(
res
});
let diff = get_diff_raw(
&repo, file_path, file_path, false, true, None,
)?;
let diff = get_diff_raw(&repo, file_path, false, true, None)?;
repo.apply(&diff, ApplyLocation::WorkDir, Some(&mut opt))?;
@ -108,22 +96,14 @@ fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option<usize> {
///
pub fn unstage_hunk(
repo_path: &RepoPath,
src_file_path: &str,
dst_file_path: &str,
file_path: &str,
hunk_hash: u64,
) -> Result<bool> {
scope_time!("revert_hunk");
let repo = repo(repo_path)?;
let diff = get_diff_raw(
&repo,
src_file_path,
dst_file_path,
true,
false,
None,
)?;
let diff = get_diff_raw(&repo, file_path, true, false, None)?;
let diff_count_positive = diff.deltas().len();
let hunk_index = find_hunk_index(&diff, hunk_hash);
@ -132,14 +112,7 @@ pub fn unstage_hunk(
Ok,
)?;
let diff = get_diff_raw(
&repo,
src_file_path,
dst_file_path,
true,
true,
None,
)?;
let diff = get_diff_raw(&repo, file_path, true, true, None)?;
if diff.deltas().len() != diff_count_positive {
return Err(Error::Generic(format!(
@ -201,7 +174,6 @@ mod tests {
let diff = get_diff(
sub_path,
file_path.to_str().unwrap(),
file_path.to_str().unwrap(),
false,
None,
)?;

View file

@ -42,7 +42,7 @@ pub fn abort_pending_state(repo_path: &RepoPath) -> Result<()> {
let repo = repo(repo_path)?;
reset_stage(repo_path, "*")?;
reset_workdir(repo_path, None, "*")?;
reset_workdir(repo_path, "*")?;
repo.cleanup_state()?;

View file

@ -18,7 +18,6 @@ pub(crate) fn get_file_diff_patch_and_hunklines<'a>(
let diff = get_diff_raw(
repo,
file,
file,
is_staged,
reverse,
Some(DiffOptions {

View file

@ -335,7 +335,7 @@ mod tests {
None
)
.unwrap()[0]
.new_path,
.path,
String::from("temp_file.txt")
);

View file

@ -22,11 +22,7 @@ pub fn reset_stage(repo_path: &RepoPath, path: &str) -> Result<()> {
}
///
pub fn reset_workdir(
repo_path: &RepoPath,
old_path: Option<&str>,
new_path: &str,
) -> Result<()> {
pub fn reset_workdir(repo_path: &RepoPath, path: &str) -> Result<()> {
scope_time!("reset_workdir");
let repo = repo(repo_path)?;
@ -36,11 +32,7 @@ pub fn reset_workdir(
.update_index(true) // windows: needs this to be true WTF?!
.remove_untracked(true)
.force()
.path(new_path);
if let Some(path) = old_path {
checkout_opts.path(path);
}
.path(path);
repo.checkout_index(None, Some(&mut checkout_opts))?;
Ok(())
@ -129,7 +121,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 1));
reset_workdir(repo_path, None, "bar.txt").unwrap();
reset_workdir(repo_path, "bar.txt").unwrap();
debug_cmd_print(repo_path, "git status");
@ -155,7 +147,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 0));
reset_workdir(repo_path, None, "foo/bar.txt").unwrap();
reset_workdir(repo_path, "foo/bar.txt").unwrap();
debug_cmd_print(repo_path, "git status");
@ -201,7 +193,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (4, 1));
reset_workdir(repo_path, None, "foo").unwrap();
reset_workdir(repo_path, "foo").unwrap();
assert_eq!(get_statuses(repo_path), (1, 1));
@ -241,7 +233,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 1));
reset_workdir(repo_path, None, file).unwrap();
reset_workdir(repo_path, file).unwrap();
debug_cmd_print(repo_path, "git status");
@ -293,7 +285,6 @@ mod tests {
reset_workdir(
&root.join("foo").as_os_str().to_str().unwrap().into(),
None,
"foo/bar.txt",
)
.unwrap();
@ -322,7 +313,7 @@ mod tests {
assert_eq!(get_statuses(repo_path), (1, 0));
reset_workdir(repo_path, None, "foo/bar").unwrap();
reset_workdir(repo_path, "foo/bar").unwrap();
debug_cmd_print(repo_path, "git status");

View file

@ -98,8 +98,7 @@ mod test {
)
.unwrap();
let diff = get_diff(path, "test.txt", "test.txt", true, None)
.unwrap();
let diff = get_diff(path, "test.txt", true, None).unwrap();
assert_eq!(diff.lines, 3);
assert_eq!(&*diff.hunks[0].lines[0].content, "@@ -1 +1,2 @@");
@ -138,8 +137,7 @@ c = 4";
)
.unwrap();
let diff = get_diff(path, "test.txt", "test.txt", true, None)
.unwrap();
let diff = get_diff(path, "test.txt", true, None).unwrap();
assert_eq!(diff.lines, 5);
assert_eq!(&*diff.hunks[0].lines[0].content, "@@ -1,2 +1 @@");
@ -170,8 +168,7 @@ c = 4";
assert_eq!(get_statuses(path), (0, 1));
let diff_before =
get_diff(path, "test.txt", "test.txt", true, None)
.unwrap();
get_diff(path, "test.txt", true, None).unwrap();
assert_eq!(diff_before.lines, 5);
@ -188,8 +185,7 @@ c = 4";
assert_eq!(get_statuses(path), (1, 1));
let diff = get_diff(path, "test.txt", "test.txt", true, None)
.unwrap();
let diff = get_diff(path, "test.txt", true, None).unwrap();
assert_eq!(diff.lines, 4);
}

View file

@ -5,9 +5,7 @@ use crate::{
error::Result,
sync::{config::untracked_files_config_repo, repository::repo},
};
use git2::{
Delta, DiffDelta, Status, StatusEntry, StatusOptions, StatusShow,
};
use git2::{Delta, Status, StatusOptions, StatusShow};
use scopetime::scope_time;
use std::path::Path;
@ -64,9 +62,7 @@ impl From<Delta> for StatusItemType {
#[derive(Clone, Hash, PartialEq, Debug)]
pub struct StatusItem {
///
pub old_path: Option<String>,
///
pub new_path: String,
pub path: String,
///
pub status: StatusItemType,
}
@ -98,18 +94,6 @@ impl From<StatusType> for StatusShow {
}
}
fn get_diff<'a>(
status_type: StatusType,
status_entry: &'a StatusEntry,
) -> Option<DiffDelta<'a>> {
(status_type != StatusType::WorkingDir)
.then(|| status_entry.head_to_index())
.or_else(|| {
(status_type != StatusType::Stage)
.then(|| status_entry.index_to_workdir())
})
.flatten()
}
///
pub fn is_workdir_clean(
repo_path: &RepoPath,
@ -167,8 +151,7 @@ pub fn get_status(
.show(status_type.into())
.update_index(true)
.include_untracked(show_untracked.include_untracked())
.renames_head_to_index(status_type != StatusType::WorkingDir)
.renames_index_to_workdir(status_type != StatusType::Stage)
.renames_head_to_index(true)
.recurse_untracked_dirs(
show_untracked.recurse_untracked_dirs(),
);
@ -180,7 +163,7 @@ pub fn get_status(
for e in statuses.iter() {
let status: Status = e.status();
let new_path = match get_diff(status_type, &e) {
let path = match e.head_to_index() {
Some(diff) => diff
.new_file()
.path()
@ -199,93 +182,16 @@ pub fn get_status(
)
})?,
};
let old_path = get_diff(status_type, &e)
.and_then(|diff| diff.old_file().path())
.map(|path| {
path.to_str().map(String::from).ok_or_else(|| {
Error::Generic(
"failed to get path to diff's new file."
.to_string(),
)
})
})
.transpose()?;
res.push(StatusItem {
old_path,
new_path,
path,
status: StatusItemType::from(status),
});
}
res.sort_by(|a, b| {
Path::new(a.new_path.as_str())
.cmp(Path::new(b.new_path.as_str()))
Path::new(a.path.as_str()).cmp(Path::new(b.path.as_str()))
});
Ok(res)
}
#[cfg(test)]
mod tests {
use crate::{
error::Result,
sync::{
commit, stage_add_file, stage_addremoved,
status::{get_status, StatusItemType, StatusType},
tests::repo_init_empty,
RepoPath,
},
};
use std::{
fs::{self, File},
io::Write,
path::Path,
};
#[test]
fn test_rename_file() -> Result<()> {
let bar = Path::new("bar");
let foo = Path::new("foo");
let (_td, repo) = repo_init_empty()?;
let root = repo.path().parent().unwrap();
let repo_path: &RepoPath =
&root.as_os_str().to_str().unwrap().into();
let mut file = File::create(&root.join(bar))?;
file.write_all(b"\x00")?;
let statuses =
get_status(repo_path, StatusType::Stage, None).unwrap();
for diff in statuses.iter() {
assert_eq!(diff.status, StatusItemType::New);
assert_eq!(diff.old_path, Some("bar".to_string()));
assert_eq!(diff.new_path, "bar".to_string());
}
stage_add_file(repo_path, bar)?;
let _id = commit(repo_path, "")?;
fs::rename(&root.join(bar), &root.join(foo))?;
stage_add_file(repo_path, foo)?;
stage_addremoved(repo_path, bar)?;
let statuses =
get_status(repo_path, StatusType::Stage, None).unwrap();
for diff in statuses.iter() {
assert_eq!(diff.status, StatusItemType::Renamed);
assert_eq!(diff.old_path, Some("bar".to_string()));
assert_eq!(diff.new_path, "foo".to_string());
}
fs::remove_file(&root.join(foo))?;
stage_addremoved(repo_path, foo)?;
let statuses =
get_status(repo_path, StatusType::Stage, None).unwrap();
for diff in statuses.iter() {
assert_eq!(diff.status, StatusItemType::Deleted);
assert_eq!(diff.old_path, Some("bar".to_string()));
assert_eq!(diff.new_path, "bar".to_string());
}
Ok(())
}
}

View file

@ -335,8 +335,7 @@ mod tests {
// And that file is test.txt
let diff =
get_diff(repo_path, "test.txt", "test.txt", true, None)
.unwrap();
get_diff(repo_path, "test.txt", true, None).unwrap();
assert_eq!(&*diff.hunks[0].lines[0].content, "@@ -1 +1 @@");
}

View file

@ -90,35 +90,18 @@ impl ChangesComponent {
fn index_add_remove(&mut self) -> Result<bool> {
if let Some(tree_item) = self.selection() {
if self.is_working_dir {
if let FileTreeItemKind::File(ref i) = tree_item.kind
{
let new_path = Path::new(i.new_path.as_str());
let old_path = i
.old_path
.as_ref()
.map(|path| Path::new(path.as_str()));
if let FileTreeItemKind::File(i) = tree_item.kind {
let path = Path::new(i.path.as_str());
match i.status {
StatusItemType::Deleted => {
sync::stage_addremoved(
&self.repo.borrow(),
new_path,
)?;
}
StatusItemType::Renamed => {
if let Some(old_path) = old_path {
sync::stage_addremoved(
&self.repo.borrow(),
old_path,
)?;
}
sync::stage_add_file(
&self.repo.borrow(),
new_path,
path,
)?;
}
_ => sync::stage_add_file(
&self.repo.borrow(),
new_path,
path,
)?,
};
} else {
@ -149,25 +132,6 @@ impl ChangesComponent {
sync::reset_stage(&self.repo.borrow(), path)?;
}
if let FileTreeItemKind::File(i) = tree_item.kind {
if i.status == StatusItemType::Renamed {
i.old_path
.map(|path| {
sync::reset_stage(
&self.repo.borrow(),
path.as_str(),
)
})
.transpose()?;
}
sync::reset_stage(
&self.repo.borrow(),
i.new_path.as_str(),
)?;
}
let path = tree_item.info.full_path.as_str();
sync::reset_stage(&self.repo.borrow(), path)?;
return Ok(true);
}
@ -196,14 +160,9 @@ impl ChangesComponent {
if let Some(tree_item) = self.selection() {
let is_folder =
matches!(tree_item.kind, FileTreeItemKind::Path(_));
let old_path = match tree_item.kind {
FileTreeItemKind::Path(_) => None,
FileTreeItemKind::File(status) => status.old_path,
};
self.queue.push(InternalEvent::ConfirmAction(
Action::Reset(ResetItem {
old_path,
new_path: tree_item.info.full_path,
path: tree_item.info.full_path,
is_folder,
}),
));

View file

@ -251,11 +251,7 @@ impl CompareCommitsComponent {
if let Some(f) = self.details.files().selection_file()
{
let diff_params = DiffParams {
src_path: f
.old_path
.clone()
.unwrap_or_else(|| f.new_path.clone()),
dst_path: f.new_path.clone(),
path: f.path.clone(),
diff_type: DiffType::Commits(ids),
options: DiffOptions::default(),
};
@ -264,10 +260,7 @@ impl CompareCommitsComponent {
self.git_diff.last()?
{
if params == diff_params {
self.diff.update(
f.old_path, f.new_path, f.status,
false, last,
);
self.diff.update(f.path, false, last);
return Ok(());
}
}

View file

@ -14,7 +14,7 @@ use anyhow::Result;
use asyncgit::{
hash,
sync::{self, diff::DiffLinePosition, RepoPathRef},
DiffLine, DiffLineType, Error, FileDiff, StatusItemType,
DiffLine, DiffLineType, FileDiff,
};
use bytesize::ByteSize;
use crossterm::event::Event;
@ -30,8 +30,7 @@ use tui::{
#[derive(Default)]
struct Current {
old_path: Option<String>,
new_path: String,
path: String,
is_stage: bool,
hash: u64,
}
@ -149,12 +148,8 @@ impl DiffComponent {
.unwrap_or_default()
}
///
pub fn current(&self) -> (Option<String>, String, bool) {
(
self.current.old_path.clone(),
self.current.new_path.clone(),
self.current.is_stage,
)
pub fn current(&self) -> (String, bool) {
(self.current.path.clone(), self.current.is_stage)
}
///
pub fn clear(&mut self, pending: bool) {
@ -168,9 +163,7 @@ impl DiffComponent {
///
pub fn update(
&mut self,
old_path: Option<String>,
new_path: String,
status: StatusItemType,
path: String,
is_stage: bool,
diff: FileDiff,
) {
@ -179,15 +172,10 @@ impl DiffComponent {
let hash = hash(&diff);
if self.current.hash != hash {
let reset_selection = self.current.new_path != new_path;
let reset_selection = self.current.path != path;
self.current = Current {
old_path: if status == StatusItemType::Renamed {
old_path
} else {
None
},
new_path,
path,
is_stage,
hash,
};
@ -475,11 +463,7 @@ impl DiffComponent {
let hash = diff.hunks[hunk].header_hash;
sync::unstage_hunk(
&self.repo.borrow(),
self.current
.old_path
.as_ref()
.unwrap_or(&self.current.new_path),
&self.current.new_path,
&self.current.path,
hash,
)?;
self.queue_update();
@ -495,17 +479,13 @@ impl DiffComponent {
if diff.untracked {
sync::stage_add_file(
&self.repo.borrow(),
Path::new(&self.current.new_path),
Path::new(&self.current.path),
)?;
} else {
let hash = diff.hunks[hunk].header_hash;
sync::stage_hunk(
&self.repo.borrow(),
self.current
.old_path
.as_ref()
.unwrap_or(&self.current.new_path),
&self.current.new_path,
&self.current.path,
hash,
)?;
}
@ -521,32 +501,25 @@ impl DiffComponent {
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
}
fn reset_hunk(&self) -> Result<()> {
if self.current.old_path.is_some() {
return Err(Error::Generic(
"Cannot reset in renamed files".to_string(),
)
.into());
}
fn reset_hunk(&self) {
if let Some(diff) = &self.diff {
if let Some(hunk) = self.selected_hunk {
let hash = diff.hunks[hunk].header_hash;
self.queue.push(InternalEvent::ConfirmAction(
Action::ResetHunk(
self.current.new_path.clone(),
self.current.path.clone(),
hash,
),
));
}
}
Ok(())
}
fn reset_lines(&self) {
self.queue.push(InternalEvent::ConfirmAction(
Action::ResetLines(
self.current.new_path.clone(),
self.current.path.clone(),
self.selected_lines(),
),
));
@ -563,7 +536,7 @@ impl DiffComponent {
"(un)stage lines:",
sync::stage_lines(
&self.repo.borrow(),
&self.current.new_path,
&self.current.path,
self.is_stage(),
&selected_lines,
)
@ -602,8 +575,7 @@ impl DiffComponent {
fn reset_untracked(&self) {
self.queue.push(InternalEvent::ConfirmAction(Action::Reset(
ResetItem {
old_path: self.current.old_path.clone(),
new_path: self.current.new_path.clone(),
path: self.current.path.clone(),
is_folder: false,
},
)));
@ -644,14 +616,9 @@ impl DrawableComponent for DiffComponent {
);
let title = format!(
"{}{}{}",
"{}{}",
strings::title_diff(&self.key_config),
self.current
.old_path
.as_ref()
.map(|path| format!("{} -> ", path))
.unwrap_or_default(),
self.current.new_path
self.current.path
);
let txt = if self.pending {
@ -800,11 +767,7 @@ impl Component for DiffComponent {
if diff.untracked {
self.reset_untracked();
} else {
try_or_popup!(
self,
"hunk error: ",
self.reset_hunk()
);
self.reset_hunk();
}
}
Ok(EventState::Consumed)

View file

@ -188,8 +188,7 @@ impl FileRevlogComponent {
if let Some(commit_id) = self.selected_commit() {
if let Some(open_request) = &self.open_request {
let diff_params = DiffParams {
src_path: open_request.file_path.clone(),
dst_path: open_request.file_path.clone(),
path: open_request.file_path.clone(),
diff_type: DiffType::Commit(commit_id),
options: self.options.borrow().diff,
};
@ -199,9 +198,7 @@ impl FileRevlogComponent {
{
if params == diff_params {
self.diff.update(
Some(params.src_path),
params.dst_path,
asyncgit::StatusItemType::Modified,
open_request.file_path.to_string(),
false,
last,
);

View file

@ -278,11 +278,7 @@ impl InspectCommitComponent {
if let Some(f) = self.details.files().selection_file()
{
let diff_params = DiffParams {
src_path: f
.old_path
.clone()
.unwrap_or_else(|| f.new_path.clone()),
dst_path: f.new_path.clone(),
path: f.path.clone(),
diff_type: DiffType::Commit(
request.commit_id,
),
@ -293,10 +289,7 @@ impl InspectCommitComponent {
self.git_diff.last()?
{
if params == diff_params {
self.diff.update(
f.old_path, f.new_path, f.status,
false, last,
);
self.diff.update(f.path, false, last);
return Ok(());
}
}

View file

@ -172,47 +172,21 @@ impl StatusTreeComponent {
FileTreeItemKind::File(status_item) => {
let status_char =
Self::item_status_char(status_item.status);
let file = Path::new(&status_item.new_path)
let file = Path::new(&status_item.path)
.file_name()
.and_then(std::ffi::OsStr::to_str)
.expect("invalid path.");
let old_file_prefix = if status_item.status
== StatusItemType::Renamed
{
status_item
.old_path
.as_ref()
.map(|path| {
Path::new(path)
.file_name()
.and_then(std::ffi::OsStr::to_str)
.map(|old_file| {
format!("{} -> ", old_file)
})
.expect("invalid path.")
})
.unwrap_or_default()
} else {
String::from("")
};
let txt = if selected {
format!(
"{} {}{}{:w$}",
"{} {}{:w$}",
status_char,
indent_str,
old_file_prefix,
file,
w = width as usize
)
} else {
format!(
"{} {}{}{}",
status_char,
indent_str,
old_file_prefix,
file
)
format!("{} {}{}", status_char, indent_str, file)
};
Some(Span::styled(
@ -455,8 +429,7 @@ impl Component for StatusTreeComponent {
queue.push(InternalEvent::OpenPopup(
StackablePopupOpen::BlameFile(
BlameFileOpen {
file_path: status_item
.new_path,
file_path: status_item.path,
commit_id: None,
selection: None,
},
@ -472,7 +445,7 @@ impl Component for StatusTreeComponent {
queue.push(InternalEvent::OpenPopup(
StackablePopupOpen::FileRevlog(
FileRevOpen::new(
status_item.new_path,
status_item.path,
),
),
));
@ -543,8 +516,7 @@ mod tests {
items
.iter()
.map(|a| StatusItem {
old_path: None,
new_path: String::from(*a),
path: String::from(*a),
status: StatusItemType::Modified,
})
.collect::<Vec<_>>()

View file

@ -58,7 +58,7 @@ pub struct FileTreeItem {
impl FileTreeItem {
fn new_file(item: &StatusItem) -> Result<Self> {
let item_path = Path::new(&item.new_path);
let item_path = Path::new(&item.path);
let indent = u8::try_from(
item_path.ancestors().count().saturating_sub(2),
)?;
@ -73,7 +73,7 @@ impl FileTreeItem {
info: TreeItemInfo::new(
indent,
path,
item.new_path.clone(),
item.path.clone(),
),
kind: FileTreeItemKind::File(item.clone()),
}),
@ -148,7 +148,7 @@ impl FileTreeItems {
for e in list {
{
let item_path = Path::new(&e.new_path);
let item_path = Path::new(&e.path);
Self::push_dirs(
item_path,
@ -267,8 +267,7 @@ mod tests {
items
.iter()
.map(|a| StatusItem {
old_path: None,
new_path: String::from(*a),
path: String::from(*a),
status: StatusItemType::Modified,
})
.collect::<Vec<_>>()
@ -287,8 +286,8 @@ mod tests {
res.items,
vec![FileTreeItem {
info: TreeItemInfo {
path: items[0].new_path.clone(),
full_path: items[0].new_path.clone(),
path: items[0].path.clone(),
full_path: items[0].path.clone(),
indent: 0,
visible: true,
},
@ -305,7 +304,7 @@ mod tests {
FileTreeItems::new(&items, &BTreeSet::new()).unwrap();
assert_eq!(res.items.len(), 2);
assert_eq!(res.items[1].info.path, items[1].new_path);
assert_eq!(res.items[1].info.path, items[1].path);
}
#[test]
@ -323,7 +322,7 @@ mod tests {
assert_eq!(
res,
vec![String::from("a"), items[0].new_path.clone(),]
vec![String::from("a"), items[0].path.clone(),]
);
}
@ -382,8 +381,8 @@ mod tests {
res,
vec![
String::from("a"),
items[0].new_path.clone(),
items[1].new_path.clone()
items[0].path.clone(),
items[1].path.clone()
]
);
}

View file

@ -438,8 +438,7 @@ mod tests {
items
.iter()
.map(|a| StatusItem {
old_path: None,
new_path: String::from(*a),
path: String::from(*a),
status: StatusItemType::Modified,
})
.collect::<Vec<_>>()

View file

@ -30,10 +30,8 @@ bitflags! {
/// data of item that is supposed to be reset
pub struct ResetItem {
/// old path to the item (folder/file)
pub old_path: Option<String>,
/// new path to the item (folder/file)
pub new_path: String,
/// path to the item (folder/file)
pub path: String,
/// are talking about a folder here? otherwise it's a single file
pub is_folder: bool,
}

View file

@ -19,7 +19,7 @@ use asyncgit::{
},
sync::{BranchCompare, CommitId},
AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams,
DiffType, PushType, StatusItemType, StatusParams,
DiffType, PushType, StatusParams,
};
use crossbeam_channel::Sender;
use crossterm::event::Event;
@ -377,7 +377,7 @@ impl Status {
self.index.focus_select(is_stage);
}
pub fn selected_data(&self) -> Option<DiffData> {
pub fn selected_path(&self) -> Option<(String, bool)> {
let (idx, is_stage) = match self.diff_target {
DiffTarget::Stage => (&self.index, true),
DiffTarget::WorkingDir => (&self.index_wd, false),
@ -385,12 +385,7 @@ impl Status {
if let Some(item) = idx.selection() {
if let FileTreeItemKind::File(i) = item.kind {
return Some(DiffData {
old_path: i.old_path,
new_path: i.new_path,
status: i.status,
is_stage,
});
return Some((i.path, is_stage));
}
}
None
@ -485,13 +480,7 @@ impl Status {
///
pub fn update_diff(&mut self) -> Result<()> {
if let Some(DiffData {
old_path,
new_path,
status,
is_stage,
}) = self.selected_data()
{
if let Some((path, is_stage)) = self.selected_path() {
let diff_type = if is_stage {
DiffType::Stage
} else {
@ -499,46 +488,30 @@ impl Status {
};
let diff_params = DiffParams {
src_path: old_path
.clone()
.unwrap_or_else(|| new_path.clone()),
dst_path: new_path.clone(),
path: path.clone(),
diff_type,
options: self.options.borrow().diff,
};
if self.diff.current()
== (old_path.clone(), new_path.clone(), is_stage)
{
if self.diff.current() == (path.clone(), is_stage) {
// we are already showing a diff of the right file
// maybe the diff changed (outside file change)
if let Some((params, last)) = self.git_diff.last()? {
if params == diff_params {
// all params match, so we might need to update
self.diff.update(
old_path, new_path, status, is_stage,
last,
);
self.diff.update(path, is_stage, last);
} else {
// params changed, we need to request the right diff
self.request_diff(
diff_params,
old_path,
new_path,
status,
path,
is_stage,
)?;
}
}
} else {
// we dont show the right diff right now, so we need to request
self.request_diff(
diff_params,
old_path,
new_path,
status,
is_stage,
)?;
self.request_diff(diff_params, path, is_stage)?;
}
} else {
self.diff.clear(false);
@ -550,14 +523,11 @@ impl Status {
fn request_diff(
&mut self,
diff_params: DiffParams,
old_path: Option<String>,
new_path: String,
status: StatusItemType,
path: String,
is_stage: bool,
) -> Result<(), anyhow::Error> {
if let Some(diff) = self.git_diff.request(diff_params)? {
self.diff
.update(old_path, new_path, status, is_stage, diff);
self.diff.update(path, is_stage, diff);
} else {
self.diff.clear(true);
}
@ -569,8 +539,7 @@ impl Status {
pub fn reset(&mut self, item: &ResetItem) -> bool {
if let Err(e) = sync::reset_workdir(
&self.repo.borrow(),
item.old_path.as_deref(),
item.new_path.as_str(),
item.path.as_str(),
) {
self.queue.push(InternalEvent::ShowErrorMsg(format!(
"reset failed:\n{}",
@ -732,13 +701,6 @@ impl Status {
}
}
pub struct DiffData {
old_path: Option<String>,
new_path: String,
status: StatusItemType,
is_stage: bool,
}
impl Component for Status {
fn commands(
&self,
@ -856,10 +818,10 @@ impl Component for Status {
&& (self.can_focus_diff()
|| self.is_focus_on_diff())
{
if let Some(diff_data) = self.selected_data() {
if let Some((path, _)) = self.selected_path() {
self.queue.push(
InternalEvent::OpenExternalEditor(Some(
diff_data.new_path,
path,
)),
);
}