Skip to content

Commit b1dfdc1

Browse files
authored
Merge pull request #13328 from gitbutlerapp/dp-one-click-amending
Amend selected commit in TUI
2 parents 3a088d8 + 6c38b78 commit b1dfdc1

4 files changed

Lines changed: 109 additions & 1 deletion

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ impl Details {
201201
| Message::ShrinkDetails
202202
| Message::RegisterMessageOnDrop(_)
203203
| Message::WithOneFrameDelay(_)
204+
| Message::Amend
204205
| Message::EnterNormalMode => false,
205206

206207
Message::MoveCursorUp

crates/but/src/command/legacy/status/tui/key_bind.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,15 @@ fn register_normal_mode_key_binds(key_binds: &mut KeyBinds) {
370370
hide_from_hotbar: false,
371371
});
372372

373+
key_binds.register(StaticKeyBind {
374+
short_description: "amend",
375+
chord_display: "a",
376+
key_matcher: press().code(KeyCode::Char('a')),
377+
modes: Vec::from([ModeDiscriminant::Normal]),
378+
message: Message::Amend,
379+
hide_from_hotbar: false,
380+
});
381+
373382
key_binds.register(StaticKeyBind {
374383
short_description: "files",
375384
chord_display: "f",

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ use crate::{
3333
CliId,
3434
command::legacy::{
3535
reword::get_branch_name_from_editor,
36-
rub::RubOperationDiscriminants,
36+
rub::{
37+
RubOperation, RubOperationDiscriminants, StackToCommitOperation,
38+
UnassignedToCommitOperation,
39+
},
3740
status::{
3841
CommitLineContent, FileLineContent, StatusFlags, StatusOutputLine, TuiLaunchOptions,
3942
output::BranchLineContent,
@@ -724,6 +727,9 @@ impl App {
724727
terminal_area,
725728
);
726729
}
730+
Message::Amend => {
731+
self.handle_amend(ctx)?;
732+
}
727733
}
728734

729735
self.ensure_cursor_visible(visible_height);
@@ -2689,6 +2695,57 @@ impl App {
26892695
let details_viewport = self.details_viewport(terminal_area);
26902696
self.details.ensure_selection_visible(details_viewport);
26912697
}
2698+
2699+
fn handle_amend(&mut self, ctx: &mut Context) -> anyhow::Result<()> {
2700+
let Some(selection) = self
2701+
.cursor
2702+
.selected_line(&self.status_lines)
2703+
.and_then(|line| line.data.cli_id())
2704+
else {
2705+
return Ok(());
2706+
};
2707+
2708+
let CliId::Commit { commit_id, .. } = &**selection else {
2709+
return Ok(());
2710+
};
2711+
2712+
let stack_id = {
2713+
let (_guard, _, ws, _) = ctx.workspace_and_db()?;
2714+
ws.find_commit_and_containers(*commit_id)
2715+
.and_then(|(stack, _, _)| stack.id)
2716+
};
2717+
2718+
let (operation, confirm_message) = if let Some(stack_id) = stack_id
2719+
&& operations::stack_has_assigned_changes(ctx, stack_id)?
2720+
{
2721+
(
2722+
RubOperation::StackToCommit(StackToCommitOperation {
2723+
from: stack_id,
2724+
to: *commit_id,
2725+
}),
2726+
format!(
2727+
"Amend changes assigned to stack into {}?",
2728+
commit_id.to_hex_with_len(7)
2729+
),
2730+
)
2731+
} else {
2732+
(
2733+
RubOperation::UnassignedToCommit(UnassignedToCommitOperation { oid: *commit_id }),
2734+
format!("Amend unassigned into {}?", commit_id.to_hex_with_len(7)),
2735+
)
2736+
};
2737+
2738+
self.confirm = Some(Confirm::new(
2739+
confirm_message,
2740+
run_after_confirmation_msg(move |_, ctx, messages| {
2741+
let what_to_select = operations::rub(ctx, &operation)?;
2742+
messages.push(Message::Reload(what_to_select));
2743+
Ok(())
2744+
}),
2745+
));
2746+
2747+
Ok(())
2748+
}
26922749
}
26932750

26942751
fn event_to_messages(ev: Event, key_binds: &KeyBinds, mode: &Mode, messages: &mut Vec<Message>) {
@@ -2775,6 +2832,7 @@ enum Message {
27752832
EnterDetailsMode,
27762833
LeaveDetailsMode,
27772834
NewBranch,
2835+
Amend,
27782836

27792837
// Utilities
27802838
CopySelection,

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,46 @@ fn key_b_creates_new_branch_from_selected_branch() {
564564
.assert_current_line_eq(str!["┊╭┄br [c-branch-1] (no commits)"]);
565565
}
566566

567+
#[test]
568+
fn key_a_amends_selected_commit() {
569+
let env = Sandbox::init_scenario_with_target_and_default_settings("one-stack").unwrap();
570+
env.setup_metadata(&["A"]).unwrap();
571+
572+
let mut tui = test_tui(env);
573+
574+
tui.env().file("test.txt", "content");
575+
576+
tui.input_then_render(None)
577+
.assert_current_line_eq(str!["╭┄zz [unassigned changes]"]);
578+
579+
tui.input_then_render([KeyCode::Down, KeyCode::Down, KeyCode::Down])
580+
.assert_current_line_eq(str!["┊● [..] add A"]);
581+
582+
tui.input_then_render('a')
583+
.assert_current_line_eq(str!["┊● [..] add A"])
584+
.assert_rendered_contains("Amend unassigned into");
585+
586+
tui.input_then_render('y')
587+
.assert_current_line_eq(str!["┊● [..] add A"]);
588+
589+
let status = tui.env().invoke_git("status --porcelain");
590+
assert_eq!(status, "", "expected amend to consume all worktree changes");
591+
}
592+
593+
#[test]
594+
fn key_a_on_non_commit_selection_is_noop() {
595+
let env = Sandbox::init_scenario_with_target_and_default_settings("one-stack").unwrap();
596+
env.setup_metadata(&["A"]).unwrap();
597+
598+
let mut tui = test_tui(env);
599+
600+
tui.input_then_render(None)
601+
.assert_current_line_eq(str!["╭┄zz [unassigned changes] (no changes)"]);
602+
603+
tui.input_then_render('a')
604+
.assert_current_line_eq(str!["╭┄zz [unassigned changes] (no changes)"]);
605+
}
606+
567607
#[test]
568608
fn rubbing() {
569609
let env = Sandbox::init_scenario_with_target_and_default_settings("one-stack").unwrap();

0 commit comments

Comments
 (0)