Skip to content

Commit

Permalink
revert individual hunks (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephan Dilly committed Jun 13, 2020
1 parent 0a541a3 commit 25f7ea1
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 12 deletions.
1 change: 1 addition & 0 deletions asyncgit/src/sync/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub(crate) fn get_diff_raw<'a>(
// diff against head
if let Ok(ref_head) = repo.head() {
let parent = repo.find_commit(
//TODO: use new NoHead Error
ref_head.target().ok_or_else(|| {
let name = ref_head.name().unwrap_or("??");
Error::Generic(
Expand Down
41 changes: 34 additions & 7 deletions asyncgit/src/sync/hunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,38 @@ pub fn stage_hunk(
Ok(())
}

///
pub fn reset_hunk(
repo_path: &str,
file_path: String,
hunk_hash: u64,
) -> Result<()> {
scope_time!("reset_hunk");

let repo = repo(repo_path)?;

let diff = get_diff_raw(&repo, &file_path, false, false)?;

let hunk_index = find_hunk_index(&diff, hunk_hash);
if let Some(hunk_index) = hunk_index {
let mut hunk_idx = 0;
let mut opt = ApplyOptions::new();
opt.hunk_callback(|_hunk| {
let res = hunk_idx == hunk_index;
hunk_idx += 1;
res
});

let diff = get_diff_raw(&repo, &file_path, false, true)?;

repo.apply(&diff, ApplyLocation::WorkDir, Some(&mut opt))?;

Ok(())
} else {
Err(Error::Generic("hunk not found".to_string()))
}
}

fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option<usize> {
let mut result = None;

Expand Down Expand Up @@ -72,7 +104,6 @@ pub fn unstage_hunk(
let diff_count_positive = diff.deltas().len();

let hunk_index = find_hunk_index(&diff, hunk_hash);

if hunk_index.is_none() {
return Err(Error::Generic("hunk not found".to_string()));
}
Expand All @@ -97,12 +128,8 @@ pub fn unstage_hunk(

res
});
if repo
.apply(&diff, ApplyLocation::Index, Some(&mut opt))
.is_err()
{
return Err(Error::Generic("apply failed".to_string()));
}

repo.apply(&diff, ApplyLocation::Index, Some(&mut opt))?;
}

Ok(count == 1)
Expand Down
2 changes: 1 addition & 1 deletion asyncgit/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use commit_files::get_commit_files;
pub use commits_info::{get_commits_info, CommitId, CommitInfo};
pub use diff::get_diff_commit;
pub use hooks::{hooks_commit_msg, hooks_post_commit, HookResult};
pub use hunks::{stage_hunk, unstage_hunk};
pub use hunks::{reset_hunk, stage_hunk, unstage_hunk};
pub use ignore::add_to_ignore;
pub use logwalker::LogWalker;
pub use reset::{reset_stage, reset_workdir};
Expand Down
40 changes: 36 additions & 4 deletions src/components/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use super::{CommandBlocking, DrawableComponent, ScrollType};
use crate::{
components::{CommandInfo, Component},
keys,
queue::{InternalEvent, Queue},
queue::{InternalEvent, NeedsUpdate, Queue},
strings,
ui::{calc_scroll_top, style::Theme},
};
use asyncgit::{hash, DiffLine, DiffLineType, FileDiff};
use asyncgit::{hash, sync, DiffLine, DiffLineType, FileDiff, CWD};
use crossterm::event::Event;
use std::{borrow::Cow, cmp};
use strings::commands;
Expand Down Expand Up @@ -284,9 +284,29 @@ impl DiffComponent {
Ok(())
}

fn reset_hunk(&self) -> Result<()> {
if let Some(hunk) = self.selected_hunk {
let hash = self.diff.hunks[hunk].header_hash;

sync::reset_hunk(CWD, self.current.path.clone(), hash)?;

self.queue
.as_ref()
.expect("try using queue in immutable diff")
.borrow_mut()
.push_back(InternalEvent::Update(NeedsUpdate::ALL));
}

Ok(())
}

fn is_immutable(&self) -> bool {
self.queue.is_none()
}

const fn is_stage(&self) -> bool {
self.current.is_stage
}
}

impl DrawableComponent for DiffComponent {
Expand Down Expand Up @@ -350,12 +370,17 @@ impl Component for DiffComponent {
out.push(CommandInfo::new(
commands::DIFF_HUNK_REMOVE,
self.selected_hunk.is_some(),
self.focused && self.current.is_stage,
self.focused && self.is_stage(),
));
out.push(CommandInfo::new(
commands::DIFF_HUNK_ADD,
self.selected_hunk.is_some(),
self.focused && !self.current.is_stage,
self.focused && !self.is_stage(),
));
out.push(CommandInfo::new(
commands::DIFF_HUNK_REVERT,
self.selected_hunk.is_some(),
self.focused && !self.is_stage(),
));
}

Expand Down Expand Up @@ -394,6 +419,13 @@ impl Component for DiffComponent {
self.add_hunk()?;
Ok(true)
}
keys::DIFF_RESET_HUNK
if !self.is_immutable()
&& !self.is_stage() =>
{
self.reset_hunk()?;
Ok(true)
}
_ => Ok(false),
};
}
Expand Down
1 change: 1 addition & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub const STATUS_STAGE_FILE: KeyEvent = no_mod(KeyCode::Enter);
pub const STATUS_STAGE_ALL: KeyEvent = no_mod(KeyCode::Char('a'));
pub const STATUS_RESET_FILE: KeyEvent =
with_mod(KeyCode::Char('D'), KeyModifiers::SHIFT);
pub const DIFF_RESET_HUNK: KeyEvent = STATUS_RESET_FILE;
pub const STATUS_IGNORE_FILE: KeyEvent = no_mod(KeyCode::Char('i'));
pub const STASHING_SAVE: KeyEvent = no_mod(KeyCode::Char('s'));
pub const STASHING_TOGGLE_UNTRACKED: KeyEvent =
Expand Down
6 changes: 6 additions & 0 deletions src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ pub mod commands {
CMD_GROUP_DIFF,
);
///
pub static DIFF_HUNK_REVERT: CommandText = CommandText::new(
"Revert hunk [D]",
"reverts selected hunk",
CMD_GROUP_DIFF,
);
///
pub static DIFF_HUNK_REMOVE: CommandText = CommandText::new(
"Remove hunk [enter]",
"removes selected hunk from stage",
Expand Down

0 comments on commit 25f7ea1

Please sign in to comment.