mirror of
https://github.com/extrawurst/gitui.git
synced 2024-12-28 03:22:51 +03:00
Support stage/unstage hunk
This commit is contained in:
parent
15ee7b8f87
commit
b71f39fbb3
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -293,8 +293,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef222034f2069cfc5af01ce423574d3d9a3925bd4052912a14e5bcfd7ca9e47a"
|
||||
source = "git+https://github.com/rust-lang/git2-rs.git?rev=617499d7fcf315cf92faa1ffde425666d3edd500#617499d7fcf315cf92faa1ffde425666d3edd500"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@ -404,8 +403,7 @@ checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.12.2+1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a12c878ccc1a49ff71e264233a66d2114cdcc7fdc44c0ebe2b54075240831238"
|
||||
source = "git+https://github.com/rust-lang/git2-rs.git?rev=617499d7fcf315cf92faa1ffde425666d3edd500#617499d7fcf315cf92faa1ffde425666d3edd500"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
3
Makefile
3
Makefile
@ -4,6 +4,9 @@
|
||||
debug:
|
||||
GITUI_LOGGING=true cargo run --features=timing
|
||||
|
||||
build-release:
|
||||
cargo build --release
|
||||
|
||||
test:
|
||||
cargo test --workspace
|
||||
|
||||
|
@ -56,10 +56,8 @@ to enable logging to `~/.gitui/gitui.log`:
|
||||
GITUI_LOGGING=true gitui
|
||||
```
|
||||
|
||||
# todo for 0.1 (first release)
|
||||
# todo for 0.2 (first release)
|
||||
|
||||
* [ ] make staging/unstaging async
|
||||
* [ ] (un)staging selected hunks
|
||||
* [ ] publish as homebrew-tap
|
||||
|
||||
# inspiration
|
||||
|
@ -10,7 +10,8 @@ license = "MIT"
|
||||
categories = ["concurrency","asynchronous"]
|
||||
|
||||
[dependencies]
|
||||
git2 = "0.13"
|
||||
# git2 = "0.13"
|
||||
git2 = { git = "https://github.com/rust-lang/git2-rs.git", rev = "617499d7fcf315cf92faa1ffde425666d3edd500" }
|
||||
rayon-core = "1.7"
|
||||
crossbeam-channel = "0.4"
|
||||
log = "0.4"
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{hash, sync, AsyncNotification, Diff, CWD};
|
||||
use crate::{hash, sync, AsyncNotification, FileDiff, CWD};
|
||||
use crossbeam_channel::Sender;
|
||||
use log::trace;
|
||||
use std::{
|
||||
@ -21,8 +21,8 @@ struct LastResult<P, R> {
|
||||
|
||||
///
|
||||
pub struct AsyncDiff {
|
||||
current: Arc<Mutex<Request<u64, Diff>>>,
|
||||
last: Arc<Mutex<Option<LastResult<DiffParams, Diff>>>>,
|
||||
current: Arc<Mutex<Request<u64, FileDiff>>>,
|
||||
last: Arc<Mutex<Option<LastResult<DiffParams, FileDiff>>>>,
|
||||
sender: Sender<AsyncNotification>,
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ impl AsyncDiff {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn last(&mut self) -> Option<Diff> {
|
||||
pub fn last(&mut self) -> Option<FileDiff> {
|
||||
let last = self.last.lock().unwrap();
|
||||
if let Some(res) = last.clone() {
|
||||
Some(res.result)
|
||||
@ -55,7 +55,10 @@ impl AsyncDiff {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn request(&mut self, params: DiffParams) -> Option<Diff> {
|
||||
pub fn request(
|
||||
&mut self,
|
||||
params: DiffParams,
|
||||
) -> Option<FileDiff> {
|
||||
trace!("request");
|
||||
|
||||
let hash = hash(¶ms);
|
||||
|
@ -12,7 +12,7 @@ pub use crate::{
|
||||
diff::{AsyncDiff, DiffParams},
|
||||
status::AsyncStatus,
|
||||
sync::{
|
||||
diff::{Diff, DiffLine, DiffLineType},
|
||||
diff::{DiffLine, DiffLineType, FileDiff},
|
||||
status::{StatusItem, StatusItemType},
|
||||
utils::is_repo,
|
||||
},
|
||||
|
@ -1,8 +1,10 @@
|
||||
//! sync git api for fetching a diff
|
||||
|
||||
use super::utils;
|
||||
use crate::hash;
|
||||
use git2::{
|
||||
Delta, DiffDelta, DiffFormat, DiffHunk, DiffOptions, Patch,
|
||||
Delta, Diff, DiffDelta, DiffFormat, DiffHunk, DiffOptions, Patch,
|
||||
Repository,
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
use std::{fs, path::Path};
|
||||
@ -35,9 +37,8 @@ pub struct DiffLine {
|
||||
pub line_type: DiffLineType,
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Default, Clone, Copy, PartialEq)]
|
||||
struct HunkHeader {
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Hash)]
|
||||
pub(crate) struct HunkHeader {
|
||||
old_start: u32,
|
||||
old_lines: u32,
|
||||
new_start: u32,
|
||||
@ -57,20 +58,31 @@ impl From<DiffHunk<'_>> for HunkHeader {
|
||||
|
||||
///
|
||||
#[derive(Default, Clone, Hash)]
|
||||
pub struct Hunk(pub Vec<DiffLine>);
|
||||
pub struct Hunk {
|
||||
///
|
||||
pub header_hash: u64,
|
||||
///
|
||||
pub lines: Vec<DiffLine>,
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Default, Clone, Hash)]
|
||||
pub struct Diff(pub Vec<Hunk>, pub u16);
|
||||
|
||||
///
|
||||
pub fn get_diff(repo_path: &str, p: String, stage: bool) -> Diff {
|
||||
scope_time!("get_diff");
|
||||
|
||||
let repo = utils::repo(repo_path);
|
||||
pub struct FileDiff {
|
||||
/// list of hunks
|
||||
pub hunks: Vec<Hunk>,
|
||||
/// lines total summed up over hunks
|
||||
pub lines: u16,
|
||||
}
|
||||
|
||||
pub(crate) fn get_diff_raw<'a>(
|
||||
repo: &'a Repository,
|
||||
p: &str,
|
||||
stage: bool,
|
||||
reverse: bool,
|
||||
) -> (Diff<'a>, DiffOptions) {
|
||||
let mut opt = DiffOptions::new();
|
||||
opt.pathspec(p);
|
||||
opt.reverse(reverse);
|
||||
|
||||
let diff = if stage {
|
||||
// diff against head
|
||||
@ -98,13 +110,27 @@ pub fn get_diff(repo_path: &str, p: String, stage: bool) -> Diff {
|
||||
repo.diff_index_to_workdir(None, Some(&mut opt)).unwrap()
|
||||
};
|
||||
|
||||
let mut res: Diff = Diff::default();
|
||||
(diff, opt)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_diff(repo_path: &str, p: String, stage: bool) -> FileDiff {
|
||||
scope_time!("get_diff");
|
||||
|
||||
let repo = utils::repo(repo_path);
|
||||
|
||||
let (diff, mut opt) = get_diff_raw(&repo, &p, stage, false);
|
||||
|
||||
let mut res: FileDiff = FileDiff::default();
|
||||
let mut current_lines = Vec::new();
|
||||
let mut current_hunk: Option<HunkHeader> = None;
|
||||
|
||||
let mut adder = |lines: &Vec<DiffLine>| {
|
||||
res.0.push(Hunk(lines.clone()));
|
||||
res.1 += lines.len() as u16;
|
||||
let mut adder = |header: &HunkHeader, lines: &Vec<DiffLine>| {
|
||||
res.hunks.push(Hunk {
|
||||
header_hash: hash(header),
|
||||
lines: lines.clone(),
|
||||
});
|
||||
res.lines += lines.len() as u16;
|
||||
};
|
||||
|
||||
let mut put = |hunk: Option<DiffHunk>, line: git2::DiffLine| {
|
||||
@ -114,7 +140,7 @@ pub fn get_diff(repo_path: &str, p: String, stage: bool) -> Diff {
|
||||
match current_hunk {
|
||||
None => current_hunk = Some(hunk_header),
|
||||
Some(h) if h != hunk_header => {
|
||||
adder(¤t_lines);
|
||||
adder(&h, ¤t_lines);
|
||||
current_lines.clear();
|
||||
current_hunk = Some(hunk_header)
|
||||
}
|
||||
@ -184,7 +210,7 @@ pub fn get_diff(repo_path: &str, p: String, stage: bool) -> Diff {
|
||||
}
|
||||
|
||||
if !current_lines.is_empty() {
|
||||
adder(¤t_lines);
|
||||
adder(¤t_hunk.unwrap(), ¤t_lines);
|
||||
}
|
||||
|
||||
res
|
||||
@ -243,8 +269,8 @@ mod tests {
|
||||
let diff =
|
||||
get_diff(repo_path, "foo/bar.txt".to_string(), false);
|
||||
|
||||
assert_eq!(diff.0.len(), 1);
|
||||
assert_eq!(diff.0[0].0[1].content, "test\n");
|
||||
assert_eq!(diff.hunks.len(), 1);
|
||||
assert_eq!(diff.hunks[0].lines[1].content, "test\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -270,7 +296,7 @@ mod tests {
|
||||
true,
|
||||
);
|
||||
|
||||
assert_eq!(diff.0.len(), 1);
|
||||
assert_eq!(diff.hunks.len(), 1);
|
||||
}
|
||||
|
||||
static HUNK_A: &str = r"
|
||||
@ -345,6 +371,6 @@ mod tests {
|
||||
|
||||
let res = get_diff(repo_path, "bar.txt".to_string(), false);
|
||||
|
||||
assert_eq!(res.0.len(), 2)
|
||||
assert_eq!(res.hunks.len(), 2)
|
||||
}
|
||||
}
|
||||
|
108
asyncgit/src/sync/hunks.rs
Normal file
108
asyncgit/src/sync/hunks.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use super::{
|
||||
diff::{get_diff_raw, HunkHeader},
|
||||
utils::repo,
|
||||
};
|
||||
use crate::hash;
|
||||
use git2::{ApplyLocation, ApplyOptions, Diff};
|
||||
use log::error;
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn stage_hunk(
|
||||
repo_path: &str,
|
||||
file_path: String,
|
||||
hunk_hash: u64,
|
||||
) -> bool {
|
||||
scope_time!("stage_hunk");
|
||||
|
||||
let repo = repo(repo_path);
|
||||
|
||||
let (diff, _) = get_diff_raw(&repo, &file_path, false, false);
|
||||
|
||||
let mut opt = ApplyOptions::new();
|
||||
opt.hunk_callback(|hunk| {
|
||||
let header = HunkHeader::from(hunk.unwrap());
|
||||
hash(&header) == hunk_hash
|
||||
});
|
||||
|
||||
repo.apply(&diff, ApplyLocation::Index, Some(&mut opt))
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option<usize> {
|
||||
let mut result = None;
|
||||
|
||||
let mut hunk_count = 0;
|
||||
|
||||
let foreach_result = diff.foreach(
|
||||
&mut |_, _| true,
|
||||
None,
|
||||
Some(&mut |_, hunk| {
|
||||
let header = HunkHeader::from(hunk);
|
||||
if hash(&header) == hunk_hash {
|
||||
result = Some(hunk_count);
|
||||
}
|
||||
hunk_count += 1;
|
||||
true
|
||||
}),
|
||||
None,
|
||||
);
|
||||
|
||||
if foreach_result.is_ok() {
|
||||
result
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn revert_hunk(
|
||||
repo_path: &str,
|
||||
file_path: String,
|
||||
hunk_hash: u64,
|
||||
) -> bool {
|
||||
scope_time!("revert_hunk");
|
||||
|
||||
let repo = repo(repo_path);
|
||||
|
||||
let (diff, _) = get_diff_raw(&repo, &file_path, true, false);
|
||||
let diff_count_positive = diff.deltas().len();
|
||||
|
||||
let hunk_index = find_hunk_index(&diff, hunk_hash);
|
||||
|
||||
if hunk_index.is_none() {
|
||||
error!("hunk not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
let (diff, _) = get_diff_raw(&repo, &file_path, true, true);
|
||||
|
||||
assert_eq!(diff.deltas().len(), diff_count_positive);
|
||||
|
||||
let mut count = 0;
|
||||
{
|
||||
let mut hunk_idx = 0;
|
||||
let mut opt = ApplyOptions::new();
|
||||
opt.hunk_callback(|_hunk| {
|
||||
let res = if hunk_idx == hunk_index.unwrap() {
|
||||
count += 1;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
hunk_idx += 1;
|
||||
|
||||
res
|
||||
});
|
||||
if repo
|
||||
.apply(&diff, ApplyLocation::Index, Some(&mut opt))
|
||||
.is_err()
|
||||
{
|
||||
error!("apply failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
count == 1
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
//! sync git api
|
||||
|
||||
pub mod diff;
|
||||
mod hunks;
|
||||
mod reset;
|
||||
pub mod status;
|
||||
pub mod utils;
|
||||
|
||||
pub use hunks::{revert_hunk, stage_hunk};
|
||||
pub use reset::{reset_stage, reset_workdir};
|
||||
pub use utils::{commit, stage_add};
|
||||
|
||||
|
34
src/app.rs
34
src/app.rs
@ -82,7 +82,7 @@ impl App {
|
||||
false,
|
||||
queue.clone(),
|
||||
),
|
||||
diff: DiffComponent::default(),
|
||||
diff: DiffComponent::new(queue.clone()),
|
||||
git_diff: AsyncDiff::new(sender.clone()),
|
||||
git_status: AsyncStatus::new(sender),
|
||||
current_commands: Vec::new(),
|
||||
@ -216,13 +216,7 @@ impl App {
|
||||
// private impls
|
||||
impl App {
|
||||
fn update_diff(&mut self) {
|
||||
let (idx, is_stage) = match self.diff_target {
|
||||
DiffTarget::Stage => (&self.index, true),
|
||||
DiffTarget::WorkingDir => (&self.index_wd, false),
|
||||
};
|
||||
|
||||
if let Some(i) = idx.selection() {
|
||||
let path = i.path;
|
||||
if let Some((path, is_stage)) = self.selected_path() {
|
||||
let diff_params = DiffParams(path.clone(), is_stage);
|
||||
|
||||
if self.diff.current() == (path.clone(), is_stage) {
|
||||
@ -245,6 +239,19 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
if let Some(i) = idx.selection() {
|
||||
Some((i.path, is_stage))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn update_commands(&mut self) {
|
||||
self.help.set_cmds(self.commands(true));
|
||||
self.current_commands = self.commands(false);
|
||||
@ -284,6 +291,17 @@ impl App {
|
||||
self.reset.open_for_path(p);
|
||||
self.update_commands();
|
||||
}
|
||||
InternalEvent::AddHunk(hash) => {
|
||||
if let Some((path, is_stage)) = self.selected_path() {
|
||||
if is_stage {
|
||||
if sync::revert_hunk(CWD, path, *hash) {
|
||||
self.update();
|
||||
}
|
||||
} else if sync::stage_hunk(CWD, path, *hash) {
|
||||
self.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
use super::{CommandBlocking, DrawableComponent, EventUpdate};
|
||||
use crate::{
|
||||
components::{CommandInfo, Component},
|
||||
queue::{InternalEvent, Queue},
|
||||
strings,
|
||||
};
|
||||
use asyncgit::{hash, Diff, DiffLine, DiffLineType};
|
||||
use asyncgit::{hash, DiffLine, DiffLineType, FileDiff};
|
||||
use crossterm::event::{Event, KeyCode};
|
||||
use std::{borrow::Cow, cmp, convert::TryFrom};
|
||||
use strings::commands;
|
||||
@ -16,57 +17,113 @@ use tui::{
|
||||
Frame,
|
||||
};
|
||||
|
||||
///
|
||||
#[derive(Default)]
|
||||
struct Current {
|
||||
path: String,
|
||||
is_stage: bool,
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
///
|
||||
pub struct DiffComponent {
|
||||
diff: Diff,
|
||||
diff: FileDiff,
|
||||
scroll: u16,
|
||||
focused: bool,
|
||||
current: (String, bool),
|
||||
current_hash: u64,
|
||||
current: Current,
|
||||
selected_hunk: Option<u16>,
|
||||
queue: Queue,
|
||||
}
|
||||
|
||||
impl DiffComponent {
|
||||
///
|
||||
pub fn new(queue: Queue) -> Self {
|
||||
Self {
|
||||
focused: false,
|
||||
queue,
|
||||
current: Current::default(),
|
||||
selected_hunk: None,
|
||||
diff: FileDiff::default(),
|
||||
scroll: 0,
|
||||
}
|
||||
}
|
||||
///
|
||||
fn can_scroll(&self) -> bool {
|
||||
self.diff.1 > 1
|
||||
self.diff.lines > 1
|
||||
}
|
||||
///
|
||||
pub fn current(&self) -> (String, bool) {
|
||||
(self.current.0.clone(), self.current.1)
|
||||
(self.current.path.clone(), self.current.is_stage)
|
||||
}
|
||||
///
|
||||
pub fn clear(&mut self) {
|
||||
self.current.0.clear();
|
||||
self.diff = Diff::default();
|
||||
self.current_hash = 0;
|
||||
self.current = Current::default();
|
||||
self.diff = FileDiff::default();
|
||||
self.scroll = 0;
|
||||
|
||||
self.selected_hunk =
|
||||
Self::find_selected_hunk(&self.diff, self.scroll);
|
||||
}
|
||||
///
|
||||
pub fn update(
|
||||
&mut self,
|
||||
path: String,
|
||||
is_stage: bool,
|
||||
diff: Diff,
|
||||
diff: FileDiff,
|
||||
) {
|
||||
let hash = hash(&diff);
|
||||
|
||||
if self.current_hash != hash {
|
||||
self.current = (path, is_stage);
|
||||
self.current_hash = hash;
|
||||
if self.current.hash != hash {
|
||||
self.current = Current {
|
||||
path,
|
||||
is_stage,
|
||||
hash,
|
||||
};
|
||||
self.diff = diff;
|
||||
self.scroll = 0;
|
||||
|
||||
self.selected_hunk =
|
||||
Self::find_selected_hunk(&self.diff, self.scroll);
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll(&mut self, inc: bool) {
|
||||
let old = self.scroll;
|
||||
if inc {
|
||||
self.scroll = cmp::min(
|
||||
self.diff.1.saturating_sub(1),
|
||||
self.diff.lines.saturating_sub(1),
|
||||
self.scroll.saturating_add(1),
|
||||
);
|
||||
} else {
|
||||
self.scroll = self.scroll.saturating_sub(1);
|
||||
}
|
||||
|
||||
if old != self.scroll {
|
||||
self.selected_hunk =
|
||||
Self::find_selected_hunk(&self.diff, self.scroll);
|
||||
}
|
||||
}
|
||||
|
||||
fn find_selected_hunk(
|
||||
diff: &FileDiff,
|
||||
line_selected: u16,
|
||||
) -> Option<u16> {
|
||||
let mut line_cursor = 0_u16;
|
||||
for (i, hunk) in diff.hunks.iter().enumerate() {
|
||||
let hunk_len = u16::try_from(hunk.lines.len()).unwrap();
|
||||
let hunk_min = line_cursor;
|
||||
let hunk_max = line_cursor + hunk_len;
|
||||
|
||||
let hunk_selected =
|
||||
hunk_min <= line_selected && hunk_max > line_selected;
|
||||
|
||||
if hunk_selected {
|
||||
return Some(u16::try_from(i).unwrap());
|
||||
}
|
||||
|
||||
line_cursor += hunk_len;
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_text(&self, width: u16, height: u16) -> Vec<Text> {
|
||||
@ -79,19 +136,21 @@ impl DiffComponent {
|
||||
let mut line_cursor = 0_u16;
|
||||
let mut lines_added = 0_u16;
|
||||
|
||||
for hunk in &self.diff.0 {
|
||||
for (i, hunk) in self.diff.hunks.iter().enumerate() {
|
||||
let hunk_selected = self
|
||||
.selected_hunk
|
||||
.map_or(false, |s| s == u16::try_from(i).unwrap());
|
||||
|
||||
if lines_added >= height {
|
||||
break;
|
||||
}
|
||||
|
||||
let hunk_len = u16::try_from(hunk.0.len()).unwrap();
|
||||
let hunk_len = u16::try_from(hunk.lines.len()).unwrap();
|
||||
let hunk_min = line_cursor;
|
||||
let hunk_max = line_cursor + hunk_len;
|
||||
|
||||
if Self::hunk_visible(hunk_min, hunk_max, min, max) {
|
||||
let hunk_selected =
|
||||
hunk_min <= selection && hunk_max > selection;
|
||||
for (i, line) in hunk.0.iter().enumerate() {
|
||||
for (i, line) in hunk.lines.iter().enumerate() {
|
||||
if line_cursor >= min {
|
||||
Self::add_line(
|
||||
&mut res,
|
||||
@ -219,6 +278,17 @@ impl DiffComponent {
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn add_hunk(&self) {
|
||||
if let Some(hunk) = self.selected_hunk {
|
||||
let hash = self.diff.hunks
|
||||
[usize::try_from(hunk).unwrap()]
|
||||
.header_hash;
|
||||
self.queue
|
||||
.borrow_mut()
|
||||
.push_back(InternalEvent::AddHunk(hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for DiffComponent {
|
||||
@ -255,6 +325,18 @@ impl Component for DiffComponent {
|
||||
self.focused,
|
||||
));
|
||||
|
||||
let cmd_text = if self.current.is_stage {
|
||||
commands::DIFF_HUNK_ADD
|
||||
} else {
|
||||
commands::DIFF_HUNK_REMOVE
|
||||
};
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
cmd_text,
|
||||
self.selected_hunk.is_some(),
|
||||
self.focused,
|
||||
));
|
||||
|
||||
CommandBlocking::PassingOn
|
||||
}
|
||||
|
||||
@ -270,6 +352,10 @@ impl Component for DiffComponent {
|
||||
self.scroll(false);
|
||||
Some(EventUpdate::None)
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
self.add_hunk();
|
||||
Some(EventUpdate::None)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ pub enum InternalEvent {
|
||||
ConfirmResetFile(String),
|
||||
///
|
||||
ResetFile(String),
|
||||
///
|
||||
AddHunk(u64),
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -18,6 +18,7 @@ pub mod commands {
|
||||
use crate::components::CommandText;
|
||||
|
||||
static CMD_GROUP_GENERAL: &str = "General";
|
||||
static CMD_GROUP_DIFF: &str = "Diff";
|
||||
static CMD_GROUP_CHANGES: &str = "Changes";
|
||||
static CMD_GROUP_COMMIT: &str = "Commit";
|
||||
|
||||
@ -34,6 +35,18 @@ pub mod commands {
|
||||
CMD_GROUP_GENERAL,
|
||||
);
|
||||
///
|
||||
pub static DIFF_HUNK_ADD: CommandText = CommandText::new(
|
||||
"Add hunk [enter]",
|
||||
"adds selected hunk to stage",
|
||||
CMD_GROUP_DIFF,
|
||||
);
|
||||
///
|
||||
pub static DIFF_HUNK_REMOVE: CommandText = CommandText::new(
|
||||
"Remove hunk [enter]",
|
||||
"removes selected hunk from stage",
|
||||
CMD_GROUP_DIFF,
|
||||
);
|
||||
///
|
||||
pub static CLOSE_POPUP: CommandText = CommandText::new(
|
||||
"Close [esc]",
|
||||
"close overlay (e.g commit, help)",
|
||||
|
Loading…
Reference in New Issue
Block a user