Skip to content

Commit cc55f43

Browse files
authored
Merge pull request #13165 from gitbutlerapp/dp-patch-hunk-picking
feat(tui): patch hunk picking
2 parents d03ba20 + ea023c7 commit cc55f43

103 files changed

Lines changed: 14666 additions & 6132 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ syntect = { version = "5.3.0", default-features = false, features = [
153153
"html",
154154
] }
155155
tracing-appender = "0.2.4"
156+
uuid.workspace = true
156157

157158
[dev-dependencies]
158159
but-graph.workspace = true

crates/but/src/command/legacy/status/tui/cursor/mod.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::sync::Arc;
22

3+
use gitbutler_stack::StackId;
4+
35
use crate::{
46
CliId,
57
command::legacy::status::{
@@ -94,6 +96,20 @@ impl Cursor {
9496
Some(Self(idx))
9597
}
9698

99+
/// Select the first line that points to the given branch name.
100+
pub(super) fn select_stack(stack_id: StackId, lines: &[StatusOutputLine]) -> Option<Self> {
101+
let idx = lines.iter().position(|line| {
102+
if let Some(CliId::Stack { stack_id: id, .. }) = line.data.cli_id().map(|id| &**id)
103+
&& stack_id == *id
104+
{
105+
true
106+
} else {
107+
false
108+
}
109+
})?;
110+
Some(Self(idx))
111+
}
112+
97113
/// Select the first line that points to the unassigned section.
98114
pub(super) fn select_unassigned(lines: &[StatusOutputLine]) -> Option<Self> {
99115
let idx = lines.iter().position(|line| {
@@ -381,7 +397,7 @@ pub(super) fn is_selectable_in_mode(
381397
match mode {
382398
Mode::Rub(rub_mode) | Mode::RubButApi(rub_mode) => {
383399
if let Some(cli_id) = line.data.cli_id()
384-
&& &rub_mode.source == cli_id
400+
&& rub_mode.source == **cli_id
385401
{
386402
return true;
387403
}
@@ -400,11 +416,15 @@ pub(super) fn is_selectable_in_mode(
400416
return true;
401417
}
402418
}
403-
Mode::Command(..) | Mode::InlineReword(..) | Mode::Normal | Mode::Branch => {}
419+
Mode::Command(..)
420+
| Mode::InlineReword(..)
421+
| Mode::Normal
422+
| Mode::Branch
423+
| Mode::Details => {}
404424
}
405425

406426
match mode {
407-
Mode::Normal => match show_files {
427+
Mode::Normal | Mode::Details => match show_files {
408428
FilesStatusFlag::None | FilesStatusFlag::All => true,
409429
FilesStatusFlag::Commit(object_id) => {
410430
if let Some(cli_id) = line.data.cli_id()

crates/but/src/command/legacy/status/tui/cursor/tests.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use crate::{
1111
CommitClassification, FilesStatusFlag,
1212
output::{StatusOutputContent, StatusOutputLine, StatusOutputLineData},
1313
tui::{
14-
CommitMode, CommitSource, InlineRewordMode, Mode, RubMode, mode::UnassignedCommitSource,
14+
CommitMode, CommitSource, InlineRewordMode, Mode, RubMode, RubSource,
15+
mode::UnassignedCommitSource,
1516
},
1617
},
1718
};
@@ -1023,8 +1024,9 @@ fn move_up_in_rub_mode_skips_unavailable_targets() {
10231024
}),
10241025
];
10251026
let mode = Mode::Rub(RubMode {
1026-
source: unassigned("source"),
1027+
source: RubSource::CliId(unassigned("source")),
10271028
available_targets: vec![allowed],
1029+
_unlock_details: None,
10281030
});
10291031

10301032
let mut cursor = Cursor(2);
@@ -1057,8 +1059,9 @@ fn move_down_in_rub_mode_skips_unavailable_targets() {
10571059
}),
10581060
];
10591061
let mode = Mode::Rub(RubMode {
1060-
source: unassigned("source"),
1062+
source: RubSource::CliId(unassigned("source")),
10611063
available_targets: vec![allowed],
1064+
_unlock_details: None,
10621065
});
10631066

10641067
let mut cursor = Cursor(0);
@@ -1101,8 +1104,9 @@ fn movement_in_rub_mode_handles_starting_on_unavailable_line() {
11011104
}),
11021105
];
11031106
let mode = Mode::Rub(RubMode {
1104-
source: unassigned("source"),
1107+
source: RubSource::CliId(unassigned("source")),
11051108
available_targets: vec![allowed_a, allowed_b],
1109+
_unlock_details: None,
11061110
});
11071111

11081112
let mut cursor = Cursor(2);
@@ -1230,8 +1234,9 @@ fn move_next_section_in_rub_mode_skips_unavailable_sections() {
12301234
}),
12311235
];
12321236
let mode = Mode::Rub(RubMode {
1233-
source: unassigned("source"),
1237+
source: RubSource::CliId(unassigned("source")),
12341238
available_targets: vec![allowed],
1239+
_unlock_details: None,
12351240
});
12361241

12371242
let mut cursor = Cursor(0);
@@ -1267,8 +1272,9 @@ fn move_previous_section_in_rub_mode_moves_to_current_available_section_header()
12671272
}),
12681273
];
12691274
let mode = Mode::Rub(RubMode {
1270-
source: unassigned("source"),
1275+
source: RubSource::CliId(unassigned("source")),
12711276
available_targets: vec![allowed],
1277+
_unlock_details: None,
12721278
});
12731279

12741280
let mut cursor = Cursor(3);
@@ -1307,8 +1313,9 @@ fn move_previous_section_in_rub_mode_from_unavailable_section_header_goes_to_pre
13071313
line(StatusOutputLineData::UnassignedChanges { cli_id: blocked }),
13081314
];
13091315
let mode = Mode::Rub(RubMode {
1310-
source: unassigned("source"),
1316+
source: RubSource::CliId(unassigned("source")),
13111317
available_targets: vec![allowed_a, allowed_b],
1318+
_unlock_details: None,
13121319
});
13131320

13141321
let mut cursor = Cursor(2);
@@ -1376,8 +1383,9 @@ fn is_selectable_in_rub_mode_requires_available_target() {
13761383
let not_selectable_line = line(StatusOutputLineData::Hint);
13771384

13781385
let mode = Mode::Rub(RubMode {
1379-
source: unassigned("source"),
1386+
source: RubSource::CliId(unassigned("source")),
13801387
available_targets: vec![allowed],
1388+
_unlock_details: None,
13811389
});
13821390

13831391
assert!(is_selectable_in_mode(
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::command::legacy::status::tui::details::{PartiallyRenderedDiffSection, SectionId};
2+
3+
#[derive(Default, Debug)]
4+
pub(super) struct DetailsCursor {
5+
selection_section: Option<SectionId>,
6+
}
7+
8+
impl DetailsCursor {
9+
pub(super) fn move_selection_by<F>(&mut self, sections: &[PartiallyRenderedDiffSection], f: F)
10+
where
11+
F: FnOnce(usize) -> usize,
12+
{
13+
let Some(selection) = self.selection() else {
14+
return;
15+
};
16+
let Some(current_selection_idx) =
17+
sections.iter().position(|section| &section.id == selection)
18+
else {
19+
return;
20+
};
21+
let Some(next) = sections.get(f(current_selection_idx)) else {
22+
return;
23+
};
24+
self.select_section(next.id.clone());
25+
}
26+
27+
pub(super) fn select_section(&mut self, id: SectionId) {
28+
self.selection_section = Some(id);
29+
}
30+
31+
pub(super) fn deselect(&mut self) {
32+
self.selection_section = None;
33+
}
34+
35+
pub(super) fn selection(&self) -> Option<&SectionId> {
36+
self.selection_section.as_ref()
37+
}
38+
}

0 commit comments

Comments
 (0)