Skip to content

Commit 7f1350e

Browse files
committed
feat: add keybinding to copy commit message
1 parent 1866bf5 commit 7f1350e

File tree

5 files changed

+64
-0
lines changed

5 files changed

+64
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
* use default shell instead of bash on Unix-like OS [[@yerke](https://github.com/yerke)] ([#2343](https://github.com/extrawurst/gitui/pull/2343))
1212

1313
### Fixes
14+
* add keybinding to copy commit message ([#2370](https://github.com/extrawurst/gitui/issues/2370))
1415
* respect env vars like `GIT_CONFIG_GLOBAL` ([#2298](https://github.com/extrawurst/gitui/issues/2298))
1516
* Set `CREATE_NO_WINDOW` flag when executing Git hooks on Windows ([#2371](https://github.com/extrawurst/gitui/pull/2371))
1617

src/components/commitlist.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,33 @@ impl CommitList {
170170
Ok(())
171171
}
172172

173+
///
174+
pub fn selected_commit_message(&self) -> Option<String> {
175+
let commit = self.selected_entry().map(|e| e.id);
176+
let data = commit.and_then(|id| {
177+
sync::get_commit_details(&self.repo.borrow(), id).ok()
178+
});
179+
data.as_ref().and_then(|data| data.message.as_ref()).map(
180+
|message| {
181+
message.body.as_ref().map_or_else(
182+
|| message.subject.clone(),
183+
|body| format!("{}\n{}", message.subject, body),
184+
)
185+
},
186+
)
187+
}
188+
189+
///
190+
pub fn copy_commit_msg(&self) -> Result<()> {
191+
if let Some(yank) = self.selected_commit_message() {
192+
crate::clipboard::copy_string(&yank)?;
193+
self.queue.push(InternalEvent::ShowInfoMsg(
194+
strings::copy_success(&yank),
195+
));
196+
};
197+
Ok(())
198+
}
199+
173200
///
174201
pub fn checkout(&self) {
175202
if let Some(commit_hash) =

src/keys/key_list.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub struct KeysList {
9393
pub toggle_signoff: GituiKeyEvent,
9494
pub toggle_verify: GituiKeyEvent,
9595
pub copy: GituiKeyEvent,
96+
pub copy_commit_msg: GituiKeyEvent,
9697
pub create_branch: GituiKeyEvent,
9798
pub rename_branch: GituiKeyEvent,
9899
pub select_branch: GituiKeyEvent,
@@ -190,6 +191,7 @@ impl Default for KeysList {
190191
toggle_signoff: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::CONTROL),
191192
toggle_verify: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL),
192193
copy: GituiKeyEvent::new(KeyCode::Char('y'), KeyModifiers::empty()),
194+
copy_commit_msg: GituiKeyEvent::new(KeyCode::Char('m'), KeyModifiers::empty()),
193195
create_branch: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()),
194196
rename_branch: GituiKeyEvent::new(KeyCode::Char('r'), KeyModifiers::empty()),
195197
select_branch: GituiKeyEvent::new(KeyCode::Char('b'), KeyModifiers::empty()),

src/strings.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,20 @@ pub mod commands {
636636
CMD_GROUP_LOG,
637637
)
638638
}
639+
640+
pub fn copy_commit_msg(
641+
key_config: &SharedKeyConfig,
642+
) -> CommandText {
643+
CommandText::new(
644+
format!(
645+
"Copy Msg [{}]",
646+
key_config.get_hint(key_config.keys.copy_commit_msg),
647+
),
648+
"copy selected commit msg to clipboard",
649+
CMD_GROUP_LOG,
650+
)
651+
}
652+
639653
pub fn copy_path(key_config: &SharedKeyConfig) -> CommandText {
640654
CommandText::new(
641655
format!(

src/tabs/revlog.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,16 @@ impl Component for Revlog {
478478
self.list.copy_commit_hash()
479479
);
480480
return Ok(EventState::Consumed);
481+
} else if key_match(
482+
k,
483+
self.key_config.keys.copy_commit_msg,
484+
) {
485+
try_or_popup!(
486+
self,
487+
strings::POPUP_FAIL_COPY,
488+
self.list.copy_commit_msg()
489+
);
490+
return Ok(EventState::Consumed);
481491
} else if key_match(k, self.key_config.keys.push) {
482492
self.queue.push(InternalEvent::PushTags);
483493
return Ok(EventState::Consumed);
@@ -611,6 +621,8 @@ impl Component for Revlog {
611621
Ok(EventState::NotConsumed)
612622
}
613623

624+
// TODO: cleanup
625+
#[allow(clippy::too_many_lines)]
614626
fn commands(
615627
&self,
616628
out: &mut Vec<CommandInfo>,
@@ -677,6 +689,12 @@ impl Component for Revlog {
677689
self.visible || force_all,
678690
));
679691

692+
out.push(CommandInfo::new(
693+
strings::commands::copy_commit_msg(&self.key_config),
694+
self.selected_commit().is_some(),
695+
self.visible || force_all,
696+
));
697+
680698
out.push(CommandInfo::new(
681699
strings::commands::log_tag_commit(&self.key_config),
682700
self.selected_commit().is_some(),
@@ -718,11 +736,13 @@ impl Component for Revlog {
718736
self.selected_commit().is_some(),
719737
(self.visible && !self.is_search_pending()) || force_all,
720738
));
739+
721740
out.push(CommandInfo::new(
722741
strings::commands::log_reword_commit(&self.key_config),
723742
self.selected_commit().is_some(),
724743
(self.visible && !self.is_search_pending()) || force_all,
725744
));
745+
726746
out.push(CommandInfo::new(
727747
strings::commands::log_find_commit(&self.key_config),
728748
self.can_start_search(),

0 commit comments

Comments
 (0)