upgrade crossterm/tui

This commit is contained in:
extrawurst 2022-08-17 21:46:55 +02:00 committed by extrawurst
parent 2eee7e9b0e
commit 8e54bfd364
49 changed files with 860 additions and 574 deletions

8
Cargo.lock generated
View file

@ -317,9 +317,9 @@ dependencies = [
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.23.2" version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crossterm_winapi", "crossterm_winapi",
@ -1638,9 +1638,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tui" name = "tui"
version = "0.18.0" version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96fe69244ec2af261bced1d9046a6fee6c8c2a6b0228e59e5ba39bc8ba4ed729" checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cassowary", "cassowary",

View file

@ -29,7 +29,7 @@ bytesize = { version = "1.1", default-features = false }
chrono = { version = "0.4", default-features = false, features = [ "clock" ] } chrono = { version = "0.4", default-features = false, features = [ "clock" ] }
clap = { version = "3.2", features = [ "env", "cargo" ] } clap = { version = "3.2", features = [ "env", "cargo" ] }
crossbeam-channel = "0.5" crossbeam-channel = "0.5"
crossterm = { version = "0.23", features = [ "serde" ] } crossterm = { version = "0.25", features = [ "serde" ] }
dirs-next = "2.0" dirs-next = "2.0"
easy-cast = "0.4" easy-cast = "0.4"
filetreelist = { path = "./filetreelist", version = "0.5" } filetreelist = { path = "./filetreelist", version = "0.5" }
@ -46,7 +46,7 @@ serde = "1.0"
simplelog = { version = "0.12", default-features = false } simplelog = { version = "0.12", default-features = false }
syntect = { version = "5.0", default-features = false, features = ["parsing", "default-syntaxes", "default-themes", "html", "regex-fancy"] } syntect = { version = "5.0", default-features = false, features = ["parsing", "default-syntaxes", "default-themes", "html", "regex-fancy"] }
textwrap = "0.15" textwrap = "0.15"
tui = { version = "0.18", default-features = false, features = ['crossterm', 'serde'] } tui = { version = "0.19", default-features = false, features = ['crossterm', 'serde'] }
unicode-segmentation = "1.9" unicode-segmentation = "1.9"
unicode-truncate = "0.2" unicode-truncate = "0.2"
unicode-width = "0.1" unicode-width = "0.1"

View file

@ -14,7 +14,7 @@ use crate::{
TagCommitComponent, TagListComponent, TagCommitComponent, TagListComponent,
}, },
input::{Input, InputEvent, InputState}, input::{Input, InputEvent, InputState},
keys::{KeyConfig, SharedKeyConfig}, keys::{key_match, KeyConfig, SharedKeyConfig},
popup_stack::PopupStack, popup_stack::PopupStack,
queue::{ queue::{
Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen, Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen,
@ -345,38 +345,57 @@ impl App {
log::trace!("event: {:?}", ev); log::trace!("event: {:?}", ev);
if let InputEvent::Input(ev) = ev { if let InputEvent::Input(ev) = ev {
if self.check_hard_exit(ev) || self.check_quit(ev) { if self.check_hard_exit(&ev) || self.check_quit(&ev) {
return Ok(()); return Ok(());
} }
let mut flags = NeedsUpdate::empty(); let mut flags = NeedsUpdate::empty();
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(&ev, self.components_mut().as_mut_slice())?
.is_consumed() .is_consumed()
{ {
flags.insert(NeedsUpdate::COMMANDS); flags.insert(NeedsUpdate::COMMANDS);
} else if let Event::Key(k) = ev { } else if let Event::Key(k) = &ev {
let new_flags = if k let new_flags = if key_match(
== self.key_config.keys.tab_toggle k,
{ self.key_config.keys.tab_toggle,
) {
self.toggle_tabs(false)?; self.toggle_tabs(false)?;
NeedsUpdate::COMMANDS NeedsUpdate::COMMANDS
} else if k == self.key_config.keys.tab_toggle_reverse } else if key_match(
{ k,
self.key_config.keys.tab_toggle_reverse,
) {
self.toggle_tabs(true)?; self.toggle_tabs(true)?;
NeedsUpdate::COMMANDS NeedsUpdate::COMMANDS
} else if k == self.key_config.keys.tab_status } else if key_match(
|| k == self.key_config.keys.tab_log k,
|| k == self.key_config.keys.tab_files self.key_config.keys.tab_status,
|| k == self.key_config.keys.tab_stashing ) || key_match(
|| k == self.key_config.keys.tab_stashes k,
{ self.key_config.keys.tab_log,
) || key_match(
k,
self.key_config.keys.tab_files,
) || key_match(
k,
self.key_config.keys.tab_stashing,
) || key_match(
k,
self.key_config.keys.tab_stashes,
) {
self.switch_tab(k)?; self.switch_tab(k)?;
NeedsUpdate::COMMANDS NeedsUpdate::COMMANDS
} else if k == self.key_config.keys.cmd_bar_toggle { } else if key_match(
k,
self.key_config.keys.cmd_bar_toggle,
) {
self.cmdbar.borrow_mut().toggle_more(); self.cmdbar.borrow_mut().toggle_more();
NeedsUpdate::empty() NeedsUpdate::empty()
} else if k == self.key_config.keys.open_options { } else if key_match(
k,
self.key_config.keys.open_options,
) {
self.options_popup.show()?; self.options_popup.show()?;
NeedsUpdate::ALL NeedsUpdate::ALL
} else { } else {
@ -563,12 +582,12 @@ impl App {
] ]
); );
fn check_quit(&mut self, ev: Event) -> bool { fn check_quit(&mut self, ev: &Event) -> bool {
if self.any_popup_visible() { if self.any_popup_visible() {
return false; return false;
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.quit { if key_match(e, self.key_config.keys.quit) {
self.do_quit = true; self.do_quit = true;
return true; return true;
} }
@ -576,9 +595,9 @@ impl App {
false false
} }
fn check_hard_exit(&mut self, ev: Event) -> bool { fn check_hard_exit(&mut self, ev: &Event) -> bool {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit { if key_match(e, self.key_config.keys.exit) {
self.do_quit = true; self.do_quit = true;
return true; return true;
} }
@ -607,16 +626,16 @@ impl App {
self.set_tab(new_tab) self.set_tab(new_tab)
} }
fn switch_tab(&mut self, k: KeyEvent) -> Result<()> { fn switch_tab(&mut self, k: &KeyEvent) -> Result<()> {
if k == self.key_config.keys.tab_status { if key_match(k, self.key_config.keys.tab_status) {
self.set_tab(0)?; self.set_tab(0)?;
} else if k == self.key_config.keys.tab_log { } else if key_match(k, self.key_config.keys.tab_log) {
self.set_tab(1)?; self.set_tab(1)?;
} else if k == self.key_config.keys.tab_files { } else if key_match(k, self.key_config.keys.tab_files) {
self.set_tab(2)?; self.set_tab(2)?;
} else if k == self.key_config.keys.tab_stashing { } else if key_match(k, self.key_config.keys.tab_stashing) {
self.set_tab(3)?; self.set_tab(3)?;
} else if k == self.key_config.keys.tab_stashes { } else if key_match(k, self.key_config.keys.tab_stashes) {
self.set_tab(4)?; self.set_tab(4)?;
} }

View file

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
components::{utils::string_width_align, ScrollType}, components::{utils::string_width_align, ScrollType},
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
string_utils::tabs_to_spaces, string_utils::tabs_to_spaces,
strings, strings,
@ -183,29 +183,48 @@ impl Component for BlameFileComponent {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if let Event::Key(key) = event { if let Event::Key(key) = event {
if key == self.key_config.keys.exit_popup { if key_match(key, self.key_config.keys.exit_popup) {
self.hide_stacked(false); self.hide_stacked(false);
} else if key == self.key_config.keys.move_up { } else if key_match(key, self.key_config.keys.move_up)
{
self.move_selection(ScrollType::Up); self.move_selection(ScrollType::Up);
} else if key == self.key_config.keys.move_down { } else if key_match(
key,
self.key_config.keys.move_down,
) {
self.move_selection(ScrollType::Down); self.move_selection(ScrollType::Down);
} else if key == self.key_config.keys.shift_up } else if key_match(
|| key == self.key_config.keys.home key,
{ self.key_config.keys.shift_up,
) || key_match(
key,
self.key_config.keys.home,
) {
self.move_selection(ScrollType::Home); self.move_selection(ScrollType::Home);
} else if key == self.key_config.keys.shift_down } else if key_match(
|| key == self.key_config.keys.end key,
{ self.key_config.keys.shift_down,
) || key_match(
key,
self.key_config.keys.end,
) {
self.move_selection(ScrollType::End); self.move_selection(ScrollType::End);
} else if key == self.key_config.keys.page_down { } else if key_match(
key,
self.key_config.keys.page_down,
) {
self.move_selection(ScrollType::PageDown); self.move_selection(ScrollType::PageDown);
} else if key == self.key_config.keys.page_up { } else if key_match(key, self.key_config.keys.page_up)
{
self.move_selection(ScrollType::PageUp); self.move_selection(ScrollType::PageUp);
} else if key == self.key_config.keys.focus_right { } else if key_match(
key,
self.key_config.keys.focus_right,
) {
if let Some(commit_id) = self.selected_commit() { if let Some(commit_id) = self.selected_commit() {
self.hide_stacked(true); self.hide_stacked(true);
self.queue.push(InternalEvent::OpenPopup( self.queue.push(InternalEvent::OpenPopup(
@ -214,7 +233,10 @@ impl Component for BlameFileComponent {
), ),
)); ));
} }
} else if key == self.key_config.keys.file_history { } else if key_match(
key,
self.key_config.keys.file_history,
) {
if let Some(filepath) = self if let Some(filepath) = self
.params .params
.as_ref() .as_ref()

View file

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
components::ScrollType, components::ScrollType,
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{ queue::{
Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen, Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen,
}, },
@ -212,62 +212,62 @@ impl Component for BranchListComponent {
//TODO: cleanup //TODO: cleanup
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if !self.visible { if !self.visible {
return Ok(EventState::NotConsumed); return Ok(EventState::NotConsumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
} else if e == self.key_config.keys.move_down { } else if key_match(e, self.key_config.keys.move_down) {
return self return self
.move_selection(ScrollType::Up) .move_selection(ScrollType::Up)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.move_up { } else if key_match(e, self.key_config.keys.move_up) {
return self return self
.move_selection(ScrollType::Down) .move_selection(ScrollType::Down)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.page_down { } else if key_match(e, self.key_config.keys.page_down) {
return self return self
.move_selection(ScrollType::PageDown) .move_selection(ScrollType::PageDown)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.page_up { } else if key_match(e, self.key_config.keys.page_up) {
return self return self
.move_selection(ScrollType::PageUp) .move_selection(ScrollType::PageUp)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.home { } else if key_match(e, self.key_config.keys.home) {
return self return self
.move_selection(ScrollType::Home) .move_selection(ScrollType::Home)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.end { } else if key_match(e, self.key_config.keys.end) {
return self return self
.move_selection(ScrollType::End) .move_selection(ScrollType::End)
.map(Into::into); .map(Into::into);
} else if e == self.key_config.keys.tab_toggle { } else if key_match(e, self.key_config.keys.tab_toggle) {
self.local = !self.local; self.local = !self.local;
self.check_remotes(); self.check_remotes();
self.update_branches()?; self.update_branches()?;
} else if e == self.key_config.keys.enter { } else if key_match(e, self.key_config.keys.enter) {
try_or_popup!( try_or_popup!(
self, self,
"switch branch error:", "switch branch error:",
self.switch_to_selected_branch() self.switch_to_selected_branch()
); );
} else if e == self.key_config.keys.create_branch } else if key_match(e, self.key_config.keys.create_branch)
&& self.local && self.local
{ {
self.queue.push(InternalEvent::CreateBranch); self.queue.push(InternalEvent::CreateBranch);
} else if e == self.key_config.keys.rename_branch } else if key_match(e, self.key_config.keys.rename_branch)
&& self.valid_selection() && self.valid_selection()
{ {
self.rename_branch(); self.rename_branch();
} else if e == self.key_config.keys.delete_branch } else if key_match(e, self.key_config.keys.delete_branch)
&& !self.selection_is_cur_branch() && !self.selection_is_cur_branch()
&& self.valid_selection() && self.valid_selection()
{ {
self.delete_branch(); self.delete_branch();
} else if e == self.key_config.keys.merge_branch } else if key_match(e, self.key_config.keys.merge_branch)
&& !self.selection_is_cur_branch() && !self.selection_is_cur_branch()
&& self.valid_selection() && self.valid_selection()
{ {
@ -276,7 +276,7 @@ impl Component for BranchListComponent {
"merge branch error:", "merge branch error:",
self.merge_branch() self.merge_branch()
); );
} else if e == self.key_config.keys.rebase_branch } else if key_match(e, self.key_config.keys.rebase_branch)
&& !self.selection_is_cur_branch() && !self.selection_is_cur_branch()
&& self.valid_selection() && self.valid_selection()
{ {
@ -285,12 +285,14 @@ impl Component for BranchListComponent {
"rebase error:", "rebase error:",
self.rebase_branch() self.rebase_branch()
); );
} else if e == self.key_config.keys.move_right } else if key_match(e, self.key_config.keys.move_right)
&& self.valid_selection() && self.valid_selection()
{ {
self.inspect_head_of_branch(); self.inspect_head_of_branch();
} else if e == self.key_config.keys.compare_commits } else if key_match(
&& self.valid_selection() e,
self.key_config.keys.compare_commits,
) && self.valid_selection()
{ {
self.hide(); self.hide();
if let Some(commit_id) = self.get_selected() { if let Some(commit_id) = self.get_selected() {
@ -300,11 +302,14 @@ impl Component for BranchListComponent {
), ),
)); ));
} }
} else if e == self.key_config.keys.pull } else if key_match(e, self.key_config.keys.pull)
&& !self.local && self.has_remotes && !self.local && self.has_remotes
{ {
self.queue.push(InternalEvent::FetchRemotes); self.queue.push(InternalEvent::FetchRemotes);
} else if e == self.key_config.keys.cmd_bar_toggle { } else if key_match(
e,
self.key_config.keys.cmd_bar_toggle,
) {
//do not consume if its the more key //do not consume if its the more key
return Ok(EventState::NotConsumed); return Ok(EventState::NotConsumed);
} }

View file

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
components::{CommandInfo, Component, EventState}, components::{CommandInfo, Component, EventState},
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem}, queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
strings, try_or_popup, strings, try_or_popup,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -256,15 +256,17 @@ impl Component for ChangesComponent {
CommandBlocking::PassingOn CommandBlocking::PassingOn
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.files.event(ev)?.is_consumed() { if self.files.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if self.focused() { if self.focused() {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
return if e == self.key_config.keys.stage_unstage_item return if key_match(
{ e,
self.key_config.keys.stage_unstage_item,
) {
try_or_popup!( try_or_popup!(
self, self,
"staging error:", "staging error:",
@ -275,8 +277,10 @@ impl Component for ChangesComponent {
NeedsUpdate::ALL, NeedsUpdate::ALL,
)); ));
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.status_stage_all } else if key_match(
&& !self.is_empty() e,
self.key_config.keys.status_stage_all,
) && !self.is_empty()
{ {
if self.is_working_dir { if self.is_working_dir {
try_or_popup!( try_or_popup!(
@ -290,12 +294,16 @@ impl Component for ChangesComponent {
self.queue self.queue
.push(InternalEvent::StatusLastFileMoved); .push(InternalEvent::StatusLastFileMoved);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.status_reset_item } else if key_match(
&& self.is_working_dir e,
self.key_config.keys.status_reset_item,
) && self.is_working_dir
{ {
Ok(self.dispatch_reset_workdir().into()) Ok(self.dispatch_reset_workdir().into())
} else if e == self.key_config.keys.status_ignore_file } else if key_match(
&& self.is_working_dir e,
self.key_config.keys.status_ignore_file,
) && self.is_working_dir
&& !self.is_empty() && !self.is_empty()
{ {
Ok(self.add_to_ignore().into()) Ok(self.add_to_ignore().into())

View file

@ -4,7 +4,7 @@ use super::{
EventState, ExternalEditorComponent, EventState, ExternalEditorComponent,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, try_or_popup, strings, try_or_popup,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -333,14 +333,14 @@ impl Component for CommitComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.input.event(ev)?.is_consumed() { if self.input.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter if key_match(e, self.key_config.keys.enter)
&& self.can_commit() && self.can_commit()
{ {
try_or_popup!( try_or_popup!(
@ -348,12 +348,16 @@ impl Component for CommitComponent {
"commit error:", "commit error:",
self.commit() self.commit()
); );
} else if e == self.key_config.keys.commit_amend } else if key_match(
&& self.can_amend() e,
self.key_config.keys.commit_amend,
) && self.can_amend()
{ {
self.amend()?; self.amend()?;
} else if e == self.key_config.keys.open_commit_editor } else if key_match(
{ e,
self.key_config.keys.open_commit_editor,
) {
self.queue.push( self.queue.push(
InternalEvent::OpenExternalEditor(None), InternalEvent::OpenExternalEditor(None),
); );

View file

@ -161,7 +161,7 @@ impl Component for CompareDetailsComponent {
CommandBlocking::PassingOn CommandBlocking::PassingOn
} }
fn event(&mut self, _event: Event) -> Result<EventState> { fn event(&mut self, _event: &Event) -> Result<EventState> {
Ok(EventState::NotConsumed) Ok(EventState::NotConsumed)
} }

View file

@ -6,7 +6,7 @@ use crate::{
CommandBlocking, CommandInfo, Component, DrawableComponent, CommandBlocking, CommandInfo, Component, DrawableComponent,
EventState, ScrollType, EventState, ScrollType,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
strings::{self, order}, strings::{self, order},
ui::style::SharedTheme, ui::style::SharedTheme,
}; };
@ -357,24 +357,31 @@ impl Component for DetailsComponent {
CommandBlocking::PassingOn CommandBlocking::PassingOn
} }
fn event(&mut self, event: Event) -> Result<EventState> { fn event(&mut self, event: &Event) -> Result<EventState> {
if self.focused { if self.focused {
if let Event::Key(e) = event { if let Event::Key(e) = event {
return Ok(if e == self.key_config.keys.move_up { return Ok(
self.move_scroll_top(ScrollType::Up).into() if key_match(e, self.key_config.keys.move_up) {
} else if e == self.key_config.keys.move_down { self.move_scroll_top(ScrollType::Up).into()
self.move_scroll_top(ScrollType::Down).into() } else if key_match(
} else if e == self.key_config.keys.home e,
|| e == self.key_config.keys.shift_up self.key_config.keys.move_down,
{ ) {
self.move_scroll_top(ScrollType::Home).into() self.move_scroll_top(ScrollType::Down).into()
} else if e == self.key_config.keys.end } else if key_match(e, self.key_config.keys.home)
|| e == self.key_config.keys.shift_down || key_match(e, self.key_config.keys.shift_up)
{ {
self.move_scroll_top(ScrollType::End).into() self.move_scroll_top(ScrollType::Home).into()
} else { } else if key_match(e, self.key_config.keys.end)
EventState::NotConsumed || key_match(
}); e,
self.key_config.keys.shift_down,
) {
self.move_scroll_top(ScrollType::End).into()
} else {
EventState::NotConsumed
},
);
} }
} }

View file

@ -7,7 +7,10 @@ use super::{
Component, DrawableComponent, EventState, StatusTreeComponent, Component, DrawableComponent, EventState, StatusTreeComponent,
}; };
use crate::{ use crate::{
accessors, keys::SharedKeyConfig, queue::Queue, strings, accessors,
keys::{key_match, SharedKeyConfig},
queue::Queue,
strings,
ui::style::SharedTheme, ui::style::SharedTheme,
}; };
use anyhow::Result; use anyhow::Result;
@ -215,7 +218,7 @@ impl Component for CommitDetailsComponent {
CommandBlocking::PassingOn CommandBlocking::PassingOn
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(ev, self.components_mut().as_mut_slice())?
.is_consumed() .is_consumed()
{ {
@ -228,14 +231,18 @@ impl Component for CommitDetailsComponent {
if self.focused() { if self.focused() {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
return if e == self.key_config.keys.focus_below return if key_match(
&& self.details_focused() e,
self.key_config.keys.focus_below,
) && self.details_focused()
{ {
self.set_details_focus(false); self.set_details_focus(false);
self.file_tree.focus(true); self.file_tree.focus(true);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.focus_above } else if key_match(
&& self.file_tree.focused() e,
self.key_config.keys.focus_above,
) && self.file_tree.focused()
&& !self.is_compare() && !self.is_compare()
{ {
self.file_tree.focus(false); self.file_tree.focus(false);

View file

@ -4,7 +4,7 @@ use crate::{
utils::string_width_align, CommandBlocking, CommandInfo, utils::string_width_align, CommandBlocking, CommandInfo,
Component, DrawableComponent, EventState, ScrollType, Component, DrawableComponent, EventState, ScrollType,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
strings::{self, symbol}, strings::{self, symbol},
ui::style::{SharedTheme, Theme}, ui::style::{SharedTheme, Theme},
ui::{calc_scroll_top, draw_scrollbar}, ui::{calc_scroll_top, draw_scrollbar},
@ -426,26 +426,33 @@ impl DrawableComponent for CommitList {
} }
impl Component for CommitList { impl Component for CommitList {
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if let Event::Key(k) = ev { if let Event::Key(k) = ev {
let selection_changed = let selection_changed =
if k == self.key_config.keys.move_up { if key_match(k, self.key_config.keys.move_up) {
self.move_selection(ScrollType::Up)? self.move_selection(ScrollType::Up)?
} else if k == self.key_config.keys.move_down { } else if key_match(k, self.key_config.keys.move_down)
{
self.move_selection(ScrollType::Down)? self.move_selection(ScrollType::Down)?
} else if k == self.key_config.keys.shift_up } else if key_match(k, self.key_config.keys.shift_up)
|| k == self.key_config.keys.home || key_match(k, self.key_config.keys.home)
{ {
self.move_selection(ScrollType::Home)? self.move_selection(ScrollType::Home)?
} else if k == self.key_config.keys.shift_down } else if key_match(
|| k == self.key_config.keys.end k,
self.key_config.keys.shift_down,
) || key_match(k, self.key_config.keys.end)
{ {
self.move_selection(ScrollType::End)? self.move_selection(ScrollType::End)?
} else if k == self.key_config.keys.page_up { } else if key_match(k, self.key_config.keys.page_up) {
self.move_selection(ScrollType::PageUp)? self.move_selection(ScrollType::PageUp)?
} else if k == self.key_config.keys.page_down { } else if key_match(k, self.key_config.keys.page_down)
{
self.move_selection(ScrollType::PageDown)? self.move_selection(ScrollType::PageDown)?
} else if k == self.key_config.keys.log_mark_commit { } else if key_match(
k,
self.key_config.keys.log_mark_commit,
) {
self.mark(); self.mark();
true true
} else { } else {

View file

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
accessors, accessors,
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -108,7 +108,7 @@ impl Component for CompareCommitsComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(ev, self.components_mut().as_mut_slice())?
.is_consumed() .is_consumed()
@ -120,19 +120,26 @@ impl Component for CompareCommitsComponent {
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide_stacked(false); self.hide_stacked(false);
} else if e == self.key_config.keys.focus_right } else if key_match(
&& self.can_focus_diff() e,
self.key_config.keys.focus_right,
) && self.can_focus_diff()
{ {
self.details.focus(false); self.details.focus(false);
self.diff.focus(true); self.diff.focus(true);
} else if e == self.key_config.keys.focus_left } else if key_match(
&& self.diff.focused() e,
self.key_config.keys.focus_left,
) && self.diff.focused()
{ {
self.details.focus(true); self.details.focus(true);
self.diff.focus(false); self.diff.focus(false);
} else if e == self.key_config.keys.focus_left { } else if key_match(
e,
self.key_config.keys.focus_left,
) {
self.hide_stacked(false); self.hide_stacked(false);
} }

View file

@ -4,7 +4,7 @@ use super::{
EventState, EventState,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -61,14 +61,14 @@ impl Component for CreateBranchComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.input.event(ev)?.is_consumed() { if self.input.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter { if key_match(e, self.key_config.keys.enter) {
self.create_branch(); self.create_branch();
} }

View file

@ -5,6 +5,7 @@ use tui::{backend::Backend, layout::Rect, Frame};
use asyncgit::sync::cred::BasicAuthCredential; use asyncgit::sync::cred::BasicAuthCredential;
use crate::components::{EventState, InputType, TextInputComponent}; use crate::components::{EventState, InputType, TextInputComponent};
use crate::keys::key_match;
use crate::{ use crate::{
components::{ components::{
visibility_blocking, CommandBlocking, CommandInfo, Component, visibility_blocking, CommandBlocking, CommandInfo, Component,
@ -102,10 +103,10 @@ impl Component for CredComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
@ -113,7 +114,7 @@ impl Component for CredComponent {
|| self.input_password.event(ev)?.is_consumed() || self.input_password.event(ev)?.is_consumed()
{ {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if e == self.key_config.keys.enter { } else if key_match(e, self.key_config.keys.enter) {
if self.input_username.is_visible() { if self.input_username.is_visible() {
self.cred = BasicAuthCredential::new( self.cred = BasicAuthCredential::new(
Some( Some(

View file

@ -4,7 +4,7 @@ use super::{
}; };
use crate::{ use crate::{
components::{CommandInfo, Component, EventState}, components::{CommandInfo, Component, EventState},
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem}, queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
string_utils::tabs_to_spaces, string_utils::tabs_to_spaces,
strings, try_or_popup, strings, try_or_popup,
@ -723,35 +723,43 @@ impl Component for DiffComponent {
} }
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.focused() { if self.focused() {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
return if e == self.key_config.keys.move_down { return if key_match(e, self.key_config.keys.move_down)
{
self.move_selection(ScrollType::Down); self.move_selection(ScrollType::Down);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.shift_down { } else if key_match(
e,
self.key_config.keys.shift_down,
) {
self.modify_selection(Direction::Down); self.modify_selection(Direction::Down);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.shift_up { } else if key_match(e, self.key_config.keys.shift_up)
{
self.modify_selection(Direction::Up); self.modify_selection(Direction::Up);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.end { } else if key_match(e, self.key_config.keys.end) {
self.move_selection(ScrollType::End); self.move_selection(ScrollType::End);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.home { } else if key_match(e, self.key_config.keys.home) {
self.move_selection(ScrollType::Home); self.move_selection(ScrollType::Home);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.move_up { } else if key_match(e, self.key_config.keys.move_up) {
self.move_selection(ScrollType::Up); self.move_selection(ScrollType::Up);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.page_up { } else if key_match(e, self.key_config.keys.page_up) {
self.move_selection(ScrollType::PageUp); self.move_selection(ScrollType::PageUp);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.page_down { } else if key_match(e, self.key_config.keys.page_down)
{
self.move_selection(ScrollType::PageDown); self.move_selection(ScrollType::PageDown);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.stage_unstage_item } else if key_match(
&& !self.is_immutable e,
self.key_config.keys.stage_unstage_item,
) && !self.is_immutable
{ {
try_or_popup!( try_or_popup!(
self, self,
@ -760,8 +768,10 @@ impl Component for DiffComponent {
); );
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.status_reset_item } else if key_match(
&& !self.is_immutable e,
self.key_config.keys.status_reset_item,
) && !self.is_immutable
&& !self.is_stage() && !self.is_stage()
{ {
if let Some(diff) = &self.diff { if let Some(diff) = &self.diff {
@ -772,13 +782,17 @@ impl Component for DiffComponent {
} }
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.diff_stage_lines } else if key_match(
&& !self.is_immutable e,
self.key_config.keys.diff_stage_lines,
) && !self.is_immutable
{ {
self.stage_lines(); self.stage_lines();
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.diff_reset_lines } else if key_match(
&& !self.is_immutable e,
self.key_config.keys.diff_reset_lines,
) && !self.is_immutable
&& !self.is_stage() && !self.is_stage()
{ {
if let Some(diff) = &self.diff { if let Some(diff) = &self.diff {
@ -788,7 +802,7 @@ impl Component for DiffComponent {
} }
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.copy { } else if key_match(e, self.key_config.keys.copy) {
self.copy_selection(); self.copy_selection();
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else { } else {

View file

@ -170,7 +170,7 @@ impl Component for ExternalEditorComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, _ev: Event) -> Result<EventState> { fn event(&mut self, _ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }

View file

@ -183,7 +183,7 @@ impl Component for FetchComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(_) = ev { if let Event::Key(_) = ev {
if self.input_cred.is_visible() { if self.input_cred.is_visible() {

View file

@ -3,7 +3,7 @@ use super::{
DrawableComponent, EventState, ScrollType, TextInputComponent, DrawableComponent, EventState, ScrollType, TextInputComponent,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue}, queue::{InternalEvent, Queue},
string_utils::trim_length_left, string_utils::trim_length_left,
strings, strings,
@ -305,17 +305,23 @@ impl Component for FileFindPopup {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if let Event::Key(key) = &event { if let Event::Key(key) = event {
if *key == self.key_config.keys.exit_popup if key_match(key, self.key_config.keys.exit_popup)
|| *key == self.key_config.keys.enter || key_match(key, self.key_config.keys.enter)
{ {
self.hide(); self.hide();
} else if *key == self.key_config.keys.popup_down { } else if key_match(
key,
self.key_config.keys.popup_down,
) {
self.move_selection(ScrollType::Down); self.move_selection(ScrollType::Down);
} else if *key == self.key_config.keys.popup_up { } else if key_match(
key,
self.key_config.keys.popup_up,
) {
self.move_selection(ScrollType::Up); self.move_selection(ScrollType::Up);
} }
} }

View file

@ -1,5 +1,6 @@
use super::{utils::logitems::ItemBatch, SharedOptions}; use super::{utils::logitems::ItemBatch, SharedOptions};
use super::{visibility_blocking, BlameFileOpen, InspectCommitOpen}; use super::{visibility_blocking, BlameFileOpen, InspectCommitOpen};
use crate::keys::key_match;
use crate::queue::StackablePopupOpen; use crate::queue::StackablePopupOpen;
use crate::{ use crate::{
components::{ components::{
@ -470,7 +471,7 @@ impl DrawableComponent for FileRevlogComponent {
} }
impl Component for FileRevlogComponent { impl Component for FileRevlogComponent {
fn event(&mut self, event: Event) -> Result<EventState> { fn event(&mut self, event: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if event_pump( if event_pump(
event, event,
@ -482,17 +483,22 @@ impl Component for FileRevlogComponent {
} }
if let Event::Key(key) = event { if let Event::Key(key) = event {
if key == self.key_config.keys.exit_popup { if key_match(key, self.key_config.keys.exit_popup) {
self.hide_stacked(false); self.hide_stacked(false);
} else if key == self.key_config.keys.focus_right } else if key_match(
&& self.can_focus_diff() key,
self.key_config.keys.focus_right,
) && self.can_focus_diff()
{ {
self.diff.focus(true); self.diff.focus(true);
} else if key == self.key_config.keys.focus_left { } else if key_match(
key,
self.key_config.keys.focus_left,
) {
if self.diff.focused() { if self.diff.focused() {
self.diff.focus(false); self.diff.focus(false);
} }
} else if key == self.key_config.keys.enter { } else if key_match(key, self.key_config.keys.enter) {
if let Some(commit_id) = self.selected_commit() { if let Some(commit_id) = self.selected_commit() {
self.hide_stacked(true); self.hide_stacked(true);
self.queue.push(InternalEvent::OpenPopup( self.queue.push(InternalEvent::OpenPopup(
@ -501,7 +507,7 @@ impl Component for FileRevlogComponent {
), ),
)); ));
}; };
} else if key == self.key_config.keys.blame { } else if key_match(key, self.key_config.keys.blame) {
if let Some(open_request) = if let Some(open_request) =
self.open_request.clone() self.open_request.clone()
{ {
@ -516,21 +522,37 @@ impl Component for FileRevlogComponent {
), ),
)); ));
} }
} else if key == self.key_config.keys.move_up { } else if key_match(key, self.key_config.keys.move_up)
{
self.move_selection(ScrollType::Up); self.move_selection(ScrollType::Up);
} else if key == self.key_config.keys.move_down { } else if key_match(
key,
self.key_config.keys.move_down,
) {
self.move_selection(ScrollType::Down); self.move_selection(ScrollType::Down);
} else if key == self.key_config.keys.shift_up } else if key_match(
|| key == self.key_config.keys.home key,
{ self.key_config.keys.shift_up,
) || key_match(
key,
self.key_config.keys.home,
) {
self.move_selection(ScrollType::Home); self.move_selection(ScrollType::Home);
} else if key == self.key_config.keys.shift_down } else if key_match(
|| key == self.key_config.keys.end key,
{ self.key_config.keys.shift_down,
) || key_match(
key,
self.key_config.keys.end,
) {
self.move_selection(ScrollType::End); self.move_selection(ScrollType::End);
} else if key == self.key_config.keys.page_up { } else if key_match(key, self.key_config.keys.page_up)
{
self.move_selection(ScrollType::PageUp); self.move_selection(ScrollType::PageUp);
} else if key == self.key_config.keys.page_down { } else if key_match(
key,
self.key_config.keys.page_down,
) {
self.move_selection(ScrollType::PageDown); self.move_selection(ScrollType::PageDown);
} }
} }

View file

@ -2,7 +2,11 @@ use super::{
visibility_blocking, CommandBlocking, CommandInfo, Component, visibility_blocking, CommandBlocking, CommandInfo, Component,
DrawableComponent, EventState, DrawableComponent, EventState,
}; };
use crate::{keys::SharedKeyConfig, strings, ui, version::Version}; use crate::{
keys::{key_match, SharedKeyConfig},
strings, ui,
version::Version,
};
use anyhow::Result; use anyhow::Result;
use asyncgit::hash; use asyncgit::hash;
use crossterm::event::Event; use crossterm::event::Event;
@ -121,14 +125,15 @@ impl Component for HelpComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
} else if e == self.key_config.keys.move_down { } else if key_match(e, self.key_config.keys.move_down)
{
self.move_selection(true); self.move_selection(true);
} else if e == self.key_config.keys.move_up { } else if key_match(e, self.key_config.keys.move_up) {
self.move_selection(false); self.move_selection(false);
} else { } else {
} }
@ -136,7 +141,7 @@ impl Component for HelpComponent {
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if let Event::Key(k) = ev { } else if let Event::Key(k) = ev {
if k == self.key_config.keys.open_help { if key_match(k, self.key_config.keys.open_help) {
self.show()?; self.show()?;
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else { } else {

View file

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
accessors, accessors,
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -143,7 +143,7 @@ impl Component for InspectCommitComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(ev, self.components_mut().as_mut_slice())?
.is_consumed() .is_consumed()
@ -156,19 +156,26 @@ impl Component for InspectCommitComponent {
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide_stacked(false); self.hide_stacked(false);
} else if e == self.key_config.keys.focus_right } else if key_match(
&& self.can_focus_diff() e,
self.key_config.keys.focus_right,
) && self.can_focus_diff()
{ {
self.details.focus(false); self.details.focus(false);
self.diff.focus(true); self.diff.focus(true);
} else if e == self.key_config.keys.focus_left } else if key_match(
&& self.diff.focused() e,
self.key_config.keys.focus_left,
) && self.diff.focused()
{ {
self.details.focus(true); self.details.focus(true);
self.diff.focus(false); self.diff.focus(false);
} else if e == self.key_config.keys.open_file_tree { } else if key_match(
e,
self.key_config.keys.open_file_tree,
) {
if let Some(commit) = self if let Some(commit) = self
.open_request .open_request
.as_ref() .as_ref()
@ -181,7 +188,10 @@ impl Component for InspectCommitComponent {
), ),
)); ));
} }
} else if e == self.key_config.keys.focus_left { } else if key_match(
e,
self.key_config.keys.focus_left,
) {
self.hide_stacked(false); self.hide_stacked(false);
} }

View file

@ -146,7 +146,7 @@ macro_rules! setup_popups {
/// returns `true` if event was consumed /// returns `true` if event was consumed
pub fn event_pump( pub fn event_pump(
ev: Event, ev: &Event,
components: &mut [&mut dyn Component], components: &mut [&mut dyn Component],
) -> Result<EventState> { ) -> Result<EventState> {
for c in components { for c in components {
@ -255,7 +255,7 @@ pub trait Component {
) -> CommandBlocking; ) -> CommandBlocking;
/// ///
fn event(&mut self, ev: Event) -> Result<EventState>; fn event(&mut self, ev: &Event) -> Result<EventState>;
/// ///
fn focused(&self) -> bool { fn focused(&self) -> bool {

View file

@ -2,7 +2,10 @@ use super::{
visibility_blocking, CommandBlocking, CommandInfo, Component, visibility_blocking, CommandBlocking, CommandInfo, Component,
DrawableComponent, EventState, DrawableComponent, EventState,
}; };
use crate::{keys::SharedKeyConfig, strings, ui}; use crate::{
keys::{key_match, SharedKeyConfig},
strings, ui,
};
use crossterm::event::Event; use crossterm::event::Event;
use std::convert::TryFrom; use std::convert::TryFrom;
use tui::{ use tui::{
@ -89,10 +92,10 @@ impl Component for MsgComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter { if key_match(e, self.key_config.keys.enter) {
self.hide(); self.hide();
} }
} }

View file

@ -6,7 +6,7 @@ use super::{
}; };
use crate::{ use crate::{
components::utils::string_width_align, components::utils::string_width_align,
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue}, queue::{InternalEvent, Queue},
strings::{self}, strings::{self},
ui::{self, style::SharedTheme}, ui::{self, style::SharedTheme},
@ -340,19 +340,29 @@ impl Component for OptionsPopupComponent {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if let Event::Key(key) = &event { if let Event::Key(key) = &event {
if *key == self.key_config.keys.exit_popup { if key_match(key, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
} else if *key == self.key_config.keys.move_up { } else if key_match(key, self.key_config.keys.move_up)
{
self.move_selection(true); self.move_selection(true);
} else if *key == self.key_config.keys.move_down { } else if key_match(
key,
self.key_config.keys.move_down,
) {
self.move_selection(false); self.move_selection(false);
} else if *key == self.key_config.keys.move_right { } else if key_match(
key,
self.key_config.keys.move_right,
) {
self.switch_option(true); self.switch_option(true);
} else if *key == self.key_config.keys.move_left { } else if key_match(
key,
self.key_config.keys.move_left,
) {
self.switch_option(false); self.switch_option(false);
} }
} }

View file

@ -263,7 +263,7 @@ impl Component for PullComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(_) = ev { if let Event::Key(_) = ev {
if self.input_cred.is_visible() { if self.input_cred.is_visible() {

View file

@ -3,7 +3,7 @@ use crate::{
cred::CredComponent, visibility_blocking, CommandBlocking, cred::CredComponent, visibility_blocking, CommandBlocking,
CommandInfo, Component, DrawableComponent, EventState, CommandInfo, Component, DrawableComponent, EventState,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue}, queue::{InternalEvent, Queue},
strings, strings,
ui::{self, style::SharedTheme}, ui::{self, style::SharedTheme},
@ -297,7 +297,7 @@ impl Component for PushComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if self.input_cred.is_visible() { if self.input_cred.is_visible() {
@ -312,8 +312,10 @@ impl Component for PushComponent {
)?; )?;
self.input_cred.hide(); self.input_cred.hide();
} }
} else if e == self.key_config.keys.exit_popup } else if key_match(
&& !self.pending e,
self.key_config.keys.exit_popup,
) && !self.pending
{ {
self.hide(); self.hide();
} }

View file

@ -3,7 +3,7 @@ use crate::{
cred::CredComponent, visibility_blocking, CommandBlocking, cred::CredComponent, visibility_blocking, CommandBlocking,
CommandInfo, Component, DrawableComponent, EventState, CommandInfo, Component, DrawableComponent, EventState,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue}, queue::{InternalEvent, Queue},
strings::{self}, strings::{self},
ui::{self, style::SharedTheme}, ui::{self, style::SharedTheme},
@ -227,7 +227,7 @@ impl Component for PushTagsComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if self.input_cred.is_visible() { if self.input_cred.is_visible() {
@ -241,8 +241,10 @@ impl Component for PushTagsComponent {
))?; ))?;
self.input_cred.hide(); self.input_cred.hide();
} }
} else if e == self.key_config.keys.exit_popup } else if key_match(
&& !self.pending e,
self.key_config.keys.exit_popup,
) && !self.pending
{ {
self.hide(); self.hide();
} }

View file

@ -4,7 +4,7 @@ use super::{
EventState, EventState,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -55,14 +55,14 @@ impl Component for RenameBranchComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.input.event(ev)?.is_consumed() { if self.input.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter { if key_match(e, self.key_config.keys.enter) {
self.rename_branch(); self.rename_branch();
} }

View file

@ -3,7 +3,7 @@ use crate::{
popup_paragraph, visibility_blocking, CommandBlocking, popup_paragraph, visibility_blocking, CommandBlocking,
CommandInfo, Component, DrawableComponent, EventState, CommandInfo, Component, DrawableComponent, EventState,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, Queue}, queue::{Action, InternalEvent, Queue},
strings, ui, strings, ui,
}; };
@ -70,12 +70,12 @@ impl Component for ConfirmComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
} else if e == self.key_config.keys.enter { } else if key_match(e, self.key_config.keys.enter) {
self.confirm(); self.confirm();
} }

View file

@ -4,7 +4,7 @@ use super::{
EventState, FileRevOpen, SyntaxTextComponent, EventState, FileRevOpen, SyntaxTextComponent,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
strings::{self, order, symbol}, strings::{self, order, symbol},
ui::{self, common_nav, style::SharedTheme}, ui::{self, common_nav, style::SharedTheme},
@ -341,7 +341,7 @@ impl Component for RevisionFilesComponent {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if !self.is_visible() { if !self.is_visible() {
return Ok(EventState::NotConsumed); return Ok(EventState::NotConsumed);
@ -354,36 +354,40 @@ impl Component for RevisionFilesComponent {
{ {
self.selection_changed(); self.selection_changed();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if key == self.key_config.keys.blame { } else if key_match(key, self.key_config.keys.blame) {
if self.blame() { if self.blame() {
self.hide(); self.hide();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
} else if key == self.key_config.keys.file_history { } else if key_match(
key,
self.key_config.keys.file_history,
) {
if self.file_history() { if self.file_history() {
self.hide(); self.hide();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
} else if key == self.key_config.keys.move_right { } else if key_match(key, self.key_config.keys.move_right)
{
if is_tree_focused { if is_tree_focused {
self.focus = Focus::File; self.focus = Focus::File;
self.current_file.focus(true); self.current_file.focus(true);
self.focus(true); self.focus(true);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
} else if key == self.key_config.keys.move_left { } else if key_match(key, self.key_config.keys.move_left) {
if !is_tree_focused { if !is_tree_focused {
self.focus = Focus::Tree; self.focus = Focus::Tree;
self.current_file.focus(false); self.current_file.focus(false);
self.focus(false); self.focus(false);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
} else if key == self.key_config.keys.file_find { } else if key_match(key, self.key_config.keys.file_find) {
if is_tree_focused { if is_tree_focused {
self.open_finder(); self.open_finder();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
} else if key == self.key_config.keys.edit_file { } else if key_match(key, self.key_config.keys.edit_file) {
if let Some(file) = if let Some(file) =
self.selected_file_path_with_prefix() self.selected_file_path_with_prefix()
{ {
@ -437,14 +441,15 @@ fn tree_nav_cmds(
fn tree_nav( fn tree_nav(
tree: &mut FileTree, tree: &mut FileTree,
key_config: &SharedKeyConfig, key_config: &SharedKeyConfig,
key: crossterm::event::KeyEvent, key: &crossterm::event::KeyEvent,
) -> bool { ) -> bool {
if let Some(common_nav) = common_nav(key, key_config) { if let Some(common_nav) = common_nav(key, key_config) {
tree.move_selection(common_nav) tree.move_selection(common_nav)
} else if key == key_config.keys.tree_collapse_recursive { } else if key_match(key, key_config.keys.tree_collapse_recursive)
{
tree.collapse_recursive(); tree.collapse_recursive();
true true
} else if key == key_config.keys.tree_expand_recursive { } else if key_match(key, key_config.keys.tree_expand_recursive) {
tree.expand_recursive(); tree.expand_recursive();
true true
} else { } else {

View file

@ -6,7 +6,7 @@ use super::{
EventState, EventState,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
strings::{self}, strings::{self},
ui::style::SharedTheme, ui::style::SharedTheme,
@ -146,11 +146,11 @@ impl Component for RevisionFilesPopup {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if let Event::Key(key) = &event { if let Event::Key(key) = event {
if *key == self.key_config.keys.exit_popup { if key_match(key, self.key_config.keys.exit_popup) {
self.hide_stacked(false); self.hide_stacked(false);
} }
} }

View file

@ -4,7 +4,7 @@ use super::{
EventState, EventState,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, strings,
tabs::StashingOptions, tabs::StashingOptions,
@ -56,14 +56,14 @@ impl Component for StashMsgComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.input.event(ev)?.is_consumed() { if self.input.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter { if key_match(e, self.key_config.keys.enter) {
let result = sync::stash_save( let result = sync::stash_save(
&self.repo.borrow(), &self.repo.borrow(),
if self.input.get_text().is_empty() { if self.input.get_text().is_empty() {

View file

@ -7,7 +7,7 @@ use super::{
}; };
use crate::{ use crate::{
components::{CommandInfo, Component, EventState}, components::{CommandInfo, Component, EventState},
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue, StackablePopupOpen}, queue::{InternalEvent, NeedsUpdate, Queue, StackablePopupOpen},
strings::{self, order}, strings::{self, order},
ui, ui,
@ -419,10 +419,10 @@ impl Component for StatusTreeComponent {
CommandBlocking::PassingOn CommandBlocking::PassingOn
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.focused { if self.focused {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
return if e == self.key_config.keys.blame { return if key_match(e, self.key_config.keys.blame) {
if let Some(status_item) = self.selection_file() { if let Some(status_item) = self.selection_file() {
self.hide(); self.hide();
if let Some(queue) = &self.queue { if let Some(queue) = &self.queue {
@ -438,7 +438,10 @@ impl Component for StatusTreeComponent {
} }
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.file_history { } else if key_match(
e,
self.key_config.keys.file_history,
) {
if let Some(status_item) = self.selection_file() { if let Some(status_item) = self.selection_file() {
self.hide(); self.hide();
if let Some(queue) = &self.queue { if let Some(queue) = &self.queue {
@ -452,27 +455,32 @@ impl Component for StatusTreeComponent {
} }
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if e == self.key_config.keys.move_down { } else if key_match(e, self.key_config.keys.move_down)
{
Ok(self Ok(self
.move_selection(MoveSelection::Down) .move_selection(MoveSelection::Down)
.into()) .into())
} else if e == self.key_config.keys.move_up { } else if key_match(e, self.key_config.keys.move_up) {
Ok(self.move_selection(MoveSelection::Up).into()) Ok(self.move_selection(MoveSelection::Up).into())
} else if e == self.key_config.keys.home } else if key_match(e, self.key_config.keys.home)
|| e == self.key_config.keys.shift_up || key_match(e, self.key_config.keys.shift_up)
{ {
Ok(self Ok(self
.move_selection(MoveSelection::Home) .move_selection(MoveSelection::Home)
.into()) .into())
} else if e == self.key_config.keys.end } else if key_match(e, self.key_config.keys.end)
|| e == self.key_config.keys.shift_down || key_match(e, self.key_config.keys.shift_down)
{ {
Ok(self.move_selection(MoveSelection::End).into()) Ok(self.move_selection(MoveSelection::End).into())
} else if e == self.key_config.keys.move_left { } else if key_match(e, self.key_config.keys.move_left)
{
Ok(self Ok(self
.move_selection(MoveSelection::Left) .move_selection(MoveSelection::Left)
.into()) .into())
} else if e == self.key_config.keys.move_right { } else if key_match(
e,
self.key_config.keys.move_right,
) {
Ok(self Ok(self
.move_selection(MoveSelection::Right) .move_selection(MoveSelection::Right)
.into()) .into())

View file

@ -267,7 +267,7 @@ impl Component for SyntaxTextComponent {
fn event( fn event(
&mut self, &mut self,
event: crossterm::event::Event, event: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if let Event::Key(key) = event { if let Event::Key(key) = event {
if let Some(nav) = common_nav(key, &self.key_config) { if let Some(nav) = common_nav(key, &self.key_config) {

View file

@ -4,7 +4,7 @@ use super::{
EventState, EventState,
}; };
use crate::{ use crate::{
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, NeedsUpdate, Queue}, queue::{InternalEvent, NeedsUpdate, Queue},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -67,19 +67,21 @@ impl Component for TagCommitComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.input.event(ev)?.is_consumed() { if self.input.event(ev)?.is_consumed() {
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.enter if key_match(e, self.key_config.keys.enter)
&& self.is_valid_tag() && self.is_valid_tag()
{ {
self.tag(); self.tag();
} else if e == self.key_config.keys.tag_annotate } else if key_match(
&& self.is_valid_tag() e,
self.key_config.keys.tag_annotate,
) && self.is_valid_tag()
{ {
let tag_name: String = let tag_name: String =
self.input.get_text().into(); self.input.get_text().into();

View file

@ -4,7 +4,7 @@ use super::{
}; };
use crate::{ use crate::{
components::ScrollType, components::ScrollType,
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, Queue}, queue::{Action, InternalEvent, Queue},
strings, strings,
ui::{self, Size}, ui::{self, Size},
@ -187,32 +187,53 @@ impl Component for TagListComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, event: Event) -> Result<EventState> { fn event(&mut self, event: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(key) = event { if let Event::Key(key) = event {
if key == self.key_config.keys.exit_popup { if key_match(key, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
} else if key == self.key_config.keys.move_up { } else if key_match(key, self.key_config.keys.move_up)
{
self.move_selection(ScrollType::Up); self.move_selection(ScrollType::Up);
} else if key == self.key_config.keys.move_down { } else if key_match(
key,
self.key_config.keys.move_down,
) {
self.move_selection(ScrollType::Down); self.move_selection(ScrollType::Down);
} else if key == self.key_config.keys.shift_up } else if key_match(
|| key == self.key_config.keys.home key,
{ self.key_config.keys.shift_up,
) || key_match(
key,
self.key_config.keys.home,
) {
self.move_selection(ScrollType::Home); self.move_selection(ScrollType::Home);
} else if key == self.key_config.keys.shift_down } else if key_match(
|| key == self.key_config.keys.end key,
{ self.key_config.keys.shift_down,
) || key_match(
key,
self.key_config.keys.end,
) {
self.move_selection(ScrollType::End); self.move_selection(ScrollType::End);
} else if key == self.key_config.keys.page_down { } else if key_match(
key,
self.key_config.keys.page_down,
) {
self.move_selection(ScrollType::PageDown); self.move_selection(ScrollType::PageDown);
} else if key == self.key_config.keys.page_up { } else if key_match(key, self.key_config.keys.page_up)
{
self.move_selection(ScrollType::PageUp); self.move_selection(ScrollType::PageUp);
} else if key == self.key_config.keys.move_right } else if key_match(
&& self.can_show_annotation() key,
self.key_config.keys.move_right,
) && self.can_show_annotation()
{ {
self.show_annotation(); self.show_annotation();
} else if key == self.key_config.keys.delete_tag { } else if key_match(
key,
self.key_config.keys.delete_tag,
) {
return self.selected_tag().map_or( return self.selected_tag().map_or(
Ok(EventState::NotConsumed), Ok(EventState::NotConsumed),
|tag| { |tag| {
@ -226,7 +247,10 @@ impl Component for TagListComponent {
Ok(EventState::Consumed) Ok(EventState::Consumed)
}, },
); );
} else if key == self.key_config.keys.select_tag { } else if key_match(
key,
self.key_config.keys.select_tag,
) {
return self.selected_tag().map_or( return self.selected_tag().map_or(
Ok(EventState::NotConsumed), Ok(EventState::NotConsumed),
|tag| { |tag| {
@ -238,7 +262,7 @@ impl Component for TagListComponent {
Ok(EventState::Consumed) Ok(EventState::Consumed)
}, },
); );
} else if key == self.key_config.keys.push } else if key_match(key, self.key_config.keys.push)
&& self.has_remotes && self.has_remotes
{ {
self.queue.push(InternalEvent::PushTags); self.queue.push(InternalEvent::PushTags);

View file

@ -1,3 +1,4 @@
use crate::keys::key_match;
use crate::strings::symbol; use crate::strings::symbol;
use crate::ui::Size; use crate::ui::Size;
use crate::{ use crate::{
@ -348,10 +349,10 @@ impl Component for TextInputComponent {
visibility_blocking(self) visibility_blocking(self)
} }
fn event(&mut self, ev: Event) -> Result<EventState> { fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
if let Event::Key(e) = ev { if let Event::Key(e) = ev {
if e == self.key_config.keys.exit_popup { if key_match(e, self.key_config.keys.exit_popup) {
self.hide(); self.hide();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} }

View file

@ -21,7 +21,7 @@ pub enum InputState {
} }
/// ///
#[derive(Clone, Copy, Debug)] #[derive(Clone, Debug)]
pub enum InputEvent { pub enum InputEvent {
Input(Event), Input(Event),
State(InputState), State(InputState),

View file

@ -1,10 +1,13 @@
use anyhow::Result; use anyhow::Result;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{KeyCode, KeyModifiers};
use std::{path::PathBuf, rc::Rc}; use std::{path::PathBuf, rc::Rc};
use crate::{args::get_app_config_path, strings::symbol}; use crate::{args::get_app_config_path, strings::symbol};
use super::{key_list::KeysList, symbols::KeySymbols}; use super::{
key_list::{GituiKeyEvent, KeysList},
symbols::KeySymbols,
};
pub type SharedKeyConfig = Rc<KeyConfig>; pub type SharedKeyConfig = Rc<KeyConfig>;
@ -52,7 +55,7 @@ impl KeyConfig {
} }
} }
pub fn get_hint(&self, ev: KeyEvent) -> String { pub fn get_hint(&self, ev: GituiKeyEvent) -> String {
match ev.code { match ev.code {
KeyCode::Down KeyCode::Down
| KeyCode::Up | KeyCode::Up
@ -93,6 +96,7 @@ impl KeyConfig {
KeyCode::Null => { KeyCode::Null => {
self.get_modifier_hint(ev.modifiers).into() self.get_modifier_hint(ev.modifiers).into()
} }
_ => "".into(),
} }
} }
@ -109,15 +113,15 @@ impl KeyConfig {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{KeyCode, KeyModifiers};
#[test] #[test]
fn test_get_hint() { fn test_get_hint() {
let config = KeyConfig::default(); let config = KeyConfig::default();
let h = config.get_hint(KeyEvent { let h = config.get_hint(GituiKeyEvent::new(
code: KeyCode::Char('c'), KeyCode::Char('c'),
modifiers: KeyModifiers::CONTROL, KeyModifiers::CONTROL,
}); ));
assert_eq!(h, "^c"); assert_eq!(h, "^c");
} }
} }

View file

@ -1,159 +1,190 @@
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use super::key_list_file::KeysListFile; use super::key_list_file::KeysListFile;
#[derive(Debug, PartialOrd, Clone, Copy, Serialize, Deserialize)]
pub struct GituiKeyEvent {
pub code: KeyCode,
pub modifiers: KeyModifiers,
}
impl GituiKeyEvent {
pub const fn new(code: KeyCode, modifiers: KeyModifiers) -> Self {
Self { code, modifiers }
}
}
pub fn key_match(ev: &KeyEvent, binding: GituiKeyEvent) -> bool {
ev.code == binding.code && ev.modifiers == binding.modifiers
}
impl PartialEq for GituiKeyEvent {
fn eq(&self, other: &Self) -> bool {
let ev: KeyEvent = self.into();
let other: KeyEvent = other.into();
ev == other
}
}
impl From<&GituiKeyEvent> for KeyEvent {
fn from(other: &GituiKeyEvent) -> Self {
Self::new(other.code, other.modifiers)
}
}
pub struct KeysList { pub struct KeysList {
pub tab_status: KeyEvent, pub tab_status: GituiKeyEvent,
pub tab_log: KeyEvent, pub tab_log: GituiKeyEvent,
pub tab_files: KeyEvent, pub tab_files: GituiKeyEvent,
pub tab_stashing: KeyEvent, pub tab_stashing: GituiKeyEvent,
pub tab_stashes: KeyEvent, pub tab_stashes: GituiKeyEvent,
pub tab_toggle: KeyEvent, pub tab_toggle: GituiKeyEvent,
pub tab_toggle_reverse: KeyEvent, pub tab_toggle_reverse: GituiKeyEvent,
pub toggle_workarea: KeyEvent, pub toggle_workarea: GituiKeyEvent,
pub focus_right: KeyEvent, pub focus_right: GituiKeyEvent,
pub focus_left: KeyEvent, pub focus_left: GituiKeyEvent,
pub focus_above: KeyEvent, pub focus_above: GituiKeyEvent,
pub focus_below: KeyEvent, pub focus_below: GituiKeyEvent,
pub exit: KeyEvent, pub exit: GituiKeyEvent,
pub quit: KeyEvent, pub quit: GituiKeyEvent,
pub exit_popup: KeyEvent, pub exit_popup: GituiKeyEvent,
pub open_commit: KeyEvent, pub open_commit: GituiKeyEvent,
pub open_commit_editor: KeyEvent, pub open_commit_editor: GituiKeyEvent,
pub open_help: KeyEvent, pub open_help: GituiKeyEvent,
pub open_options: KeyEvent, pub open_options: GituiKeyEvent,
pub move_left: KeyEvent, pub move_left: GituiKeyEvent,
pub move_right: KeyEvent, pub move_right: GituiKeyEvent,
pub tree_collapse_recursive: KeyEvent, pub tree_collapse_recursive: GituiKeyEvent,
pub tree_expand_recursive: KeyEvent, pub tree_expand_recursive: GituiKeyEvent,
pub home: KeyEvent, pub home: GituiKeyEvent,
pub end: KeyEvent, pub end: GituiKeyEvent,
pub move_up: KeyEvent, pub move_up: GituiKeyEvent,
pub move_down: KeyEvent, pub move_down: GituiKeyEvent,
pub popup_up: KeyEvent, pub popup_up: GituiKeyEvent,
pub popup_down: KeyEvent, pub popup_down: GituiKeyEvent,
pub page_down: KeyEvent, pub page_down: GituiKeyEvent,
pub page_up: KeyEvent, pub page_up: GituiKeyEvent,
pub shift_up: KeyEvent, pub shift_up: GituiKeyEvent,
pub shift_down: KeyEvent, pub shift_down: GituiKeyEvent,
pub enter: KeyEvent, pub enter: GituiKeyEvent,
pub blame: KeyEvent, pub blame: GituiKeyEvent,
pub file_history: KeyEvent, pub file_history: GituiKeyEvent,
pub edit_file: KeyEvent, pub edit_file: GituiKeyEvent,
pub status_stage_all: KeyEvent, pub status_stage_all: GituiKeyEvent,
pub status_reset_item: KeyEvent, pub status_reset_item: GituiKeyEvent,
pub status_ignore_file: KeyEvent, pub status_ignore_file: GituiKeyEvent,
pub diff_stage_lines: KeyEvent, pub diff_stage_lines: GituiKeyEvent,
pub diff_reset_lines: KeyEvent, pub diff_reset_lines: GituiKeyEvent,
pub stashing_save: KeyEvent, pub stashing_save: GituiKeyEvent,
pub stashing_toggle_untracked: KeyEvent, pub stashing_toggle_untracked: GituiKeyEvent,
pub stashing_toggle_index: KeyEvent, pub stashing_toggle_index: GituiKeyEvent,
pub stash_apply: KeyEvent, pub stash_apply: GituiKeyEvent,
pub stash_open: KeyEvent, pub stash_open: GituiKeyEvent,
pub stash_drop: KeyEvent, pub stash_drop: GituiKeyEvent,
pub cmd_bar_toggle: KeyEvent, pub cmd_bar_toggle: GituiKeyEvent,
pub log_tag_commit: KeyEvent, pub log_tag_commit: GituiKeyEvent,
pub log_mark_commit: KeyEvent, pub log_mark_commit: GituiKeyEvent,
pub commit_amend: KeyEvent, pub commit_amend: GituiKeyEvent,
pub copy: KeyEvent, pub copy: GituiKeyEvent,
pub create_branch: KeyEvent, pub create_branch: GituiKeyEvent,
pub rename_branch: KeyEvent, pub rename_branch: GituiKeyEvent,
pub select_branch: KeyEvent, pub select_branch: GituiKeyEvent,
pub delete_branch: KeyEvent, pub delete_branch: GituiKeyEvent,
pub merge_branch: KeyEvent, pub merge_branch: GituiKeyEvent,
pub rebase_branch: KeyEvent, pub rebase_branch: GituiKeyEvent,
pub compare_commits: KeyEvent, pub compare_commits: GituiKeyEvent,
pub tags: KeyEvent, pub tags: GituiKeyEvent,
pub delete_tag: KeyEvent, pub delete_tag: GituiKeyEvent,
pub select_tag: KeyEvent, pub select_tag: GituiKeyEvent,
pub push: KeyEvent, pub push: GituiKeyEvent,
pub open_file_tree: KeyEvent, pub open_file_tree: GituiKeyEvent,
pub file_find: KeyEvent, pub file_find: GituiKeyEvent,
pub force_push: KeyEvent, pub force_push: GituiKeyEvent,
pub pull: KeyEvent, pub pull: GituiKeyEvent,
pub abort_merge: KeyEvent, pub abort_merge: GituiKeyEvent,
pub undo_commit: KeyEvent, pub undo_commit: GituiKeyEvent,
pub stage_unstage_item: KeyEvent, pub stage_unstage_item: GituiKeyEvent,
pub tag_annotate: KeyEvent, pub tag_annotate: GituiKeyEvent,
} }
#[rustfmt::skip] #[rustfmt::skip]
impl Default for KeysList { impl Default for KeysList {
fn default() -> Self { fn default() -> Self {
Self { Self {
tab_status: KeyEvent { code: KeyCode::Char('1'), modifiers: KeyModifiers::empty()}, tab_status: GituiKeyEvent::new(KeyCode::Char('1'), KeyModifiers::empty()),
tab_log: KeyEvent { code: KeyCode::Char('2'), modifiers: KeyModifiers::empty()}, tab_log: GituiKeyEvent::new(KeyCode::Char('2'), KeyModifiers::empty()),
tab_files: KeyEvent { code: KeyCode::Char('3'), modifiers: KeyModifiers::empty()}, tab_files: GituiKeyEvent::new(KeyCode::Char('3'), KeyModifiers::empty()),
tab_stashing: KeyEvent { code: KeyCode::Char('4'), modifiers: KeyModifiers::empty()}, tab_stashing: GituiKeyEvent::new(KeyCode::Char('4'), KeyModifiers::empty()),
tab_stashes: KeyEvent { code: KeyCode::Char('5'), modifiers: KeyModifiers::empty()}, tab_stashes: GituiKeyEvent::new(KeyCode::Char('5'), KeyModifiers::empty()),
tab_toggle: KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::empty()}, tab_toggle: GituiKeyEvent::new(KeyCode::Tab, KeyModifiers::empty()),
tab_toggle_reverse: KeyEvent { code: KeyCode::BackTab, modifiers: KeyModifiers::SHIFT}, tab_toggle_reverse: GituiKeyEvent::new(KeyCode::BackTab, KeyModifiers::SHIFT),
toggle_workarea: KeyEvent { code: KeyCode::Char('w'), modifiers: KeyModifiers::empty()}, toggle_workarea: GituiKeyEvent::new(KeyCode::Char('w'), KeyModifiers::empty()),
focus_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, focus_right: GituiKeyEvent::new(KeyCode::Right, KeyModifiers::empty()),
focus_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, focus_left: GituiKeyEvent::new(KeyCode::Left, KeyModifiers::empty()),
focus_above: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::empty()}, focus_above: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::empty()),
focus_below: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::empty()}, focus_below: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::empty()),
exit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL}, exit: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL),
quit: KeyEvent { code: KeyCode::Char('q'), modifiers: KeyModifiers::empty()}, quit: GituiKeyEvent::new(KeyCode::Char('q'), KeyModifiers::empty()),
exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()}, exit_popup: GituiKeyEvent::new(KeyCode::Esc, KeyModifiers::empty()),
open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, open_commit: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()),
open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL}, open_commit_editor: GituiKeyEvent::new(KeyCode::Char('e'), KeyModifiers::CONTROL),
open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()}, open_help: GituiKeyEvent::new(KeyCode::Char('h'), KeyModifiers::empty()),
open_options: KeyEvent { code: KeyCode::Char('o'), modifiers: KeyModifiers::empty()}, open_options: GituiKeyEvent::new(KeyCode::Char('o'), KeyModifiers::empty()),
move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()}, move_left: GituiKeyEvent::new(KeyCode::Left, KeyModifiers::empty()),
move_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, move_right: GituiKeyEvent::new(KeyCode::Right, KeyModifiers::empty()),
tree_collapse_recursive: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::SHIFT}, tree_collapse_recursive: GituiKeyEvent::new(KeyCode::Left, KeyModifiers::SHIFT),
tree_expand_recursive: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::SHIFT}, tree_expand_recursive: GituiKeyEvent::new(KeyCode::Right, KeyModifiers::SHIFT),
home: KeyEvent { code: KeyCode::Home, modifiers: KeyModifiers::empty()}, home: GituiKeyEvent::new(KeyCode::Home, KeyModifiers::empty()),
end: KeyEvent { code: KeyCode::End, modifiers: KeyModifiers::empty()}, end: GituiKeyEvent::new(KeyCode::End, KeyModifiers::empty()),
move_up: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::empty()}, move_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::empty()),
move_down: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::empty()}, move_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::empty()),
popup_up: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::empty()}, popup_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::empty()),
popup_down: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::empty()}, popup_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::empty()),
page_down: KeyEvent { code: KeyCode::PageDown, modifiers: KeyModifiers::empty()}, page_down: GituiKeyEvent::new(KeyCode::PageDown, KeyModifiers::empty()),
page_up: KeyEvent { code: KeyCode::PageUp, modifiers: KeyModifiers::empty()}, page_up: GituiKeyEvent::new(KeyCode::PageUp, KeyModifiers::empty()),
shift_up: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::SHIFT}, shift_up: GituiKeyEvent::new(KeyCode::Up, KeyModifiers::SHIFT),
shift_down: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::SHIFT}, shift_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::SHIFT),
enter: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()}, enter: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
blame: KeyEvent { code: KeyCode::Char('B'), modifiers: KeyModifiers::SHIFT}, blame: GituiKeyEvent::new(KeyCode::Char('B'), KeyModifiers::SHIFT),
file_history: KeyEvent { code: KeyCode::Char('H'), modifiers: KeyModifiers::SHIFT}, file_history: GituiKeyEvent::new(KeyCode::Char('H'), KeyModifiers::SHIFT),
edit_file: KeyEvent { code: KeyCode::Char('e'), modifiers: KeyModifiers::empty()}, edit_file: GituiKeyEvent::new(KeyCode::Char('e'), KeyModifiers::empty()),
status_stage_all: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::empty()}, status_stage_all: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::empty()),
status_reset_item: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT}, status_reset_item: GituiKeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT),
diff_reset_lines: KeyEvent { code: KeyCode::Char('d'), modifiers: KeyModifiers::empty()}, diff_reset_lines: GituiKeyEvent::new(KeyCode::Char('d'), KeyModifiers::empty()),
status_ignore_file: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()}, status_ignore_file: GituiKeyEvent::new(KeyCode::Char('i'), KeyModifiers::empty()),
diff_stage_lines: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, diff_stage_lines: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::empty()),
stashing_save: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()}, stashing_save: GituiKeyEvent::new(KeyCode::Char('s'), KeyModifiers::empty()),
stashing_toggle_untracked: KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::empty()}, stashing_toggle_untracked: GituiKeyEvent::new(KeyCode::Char('u'), KeyModifiers::empty()),
stashing_toggle_index: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()}, stashing_toggle_index: GituiKeyEvent::new(KeyCode::Char('i'), KeyModifiers::empty()),
stash_apply: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::empty()}, stash_apply: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::empty()),
stash_open: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()}, stash_open: GituiKeyEvent::new(KeyCode::Right, KeyModifiers::empty()),
stash_drop: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT}, stash_drop: GituiKeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT),
cmd_bar_toggle: KeyEvent { code: KeyCode::Char('.'), modifiers: KeyModifiers::empty()}, cmd_bar_toggle: GituiKeyEvent::new(KeyCode::Char('.'), KeyModifiers::empty()),
log_tag_commit: KeyEvent { code: KeyCode::Char('t'), modifiers: KeyModifiers::empty()}, log_tag_commit: GituiKeyEvent::new(KeyCode::Char('t'), KeyModifiers::empty()),
log_mark_commit: KeyEvent { code: KeyCode::Char(' '), modifiers: KeyModifiers::empty()}, log_mark_commit: GituiKeyEvent::new(KeyCode::Char(' '), KeyModifiers::empty()),
commit_amend: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL}, commit_amend: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
copy: KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::empty()}, copy: GituiKeyEvent::new(KeyCode::Char('y'), KeyModifiers::empty()),
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()}, create_branch: GituiKeyEvent::new(KeyCode::Char('c'), KeyModifiers::empty()),
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty()}, rename_branch: GituiKeyEvent::new(KeyCode::Char('r'), KeyModifiers::empty()),
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::empty()}, select_branch: GituiKeyEvent::new(KeyCode::Char('b'), KeyModifiers::empty()),
delete_branch: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT}, delete_branch: GituiKeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT),
merge_branch: KeyEvent { code: KeyCode::Char('m'), modifiers: KeyModifiers::empty()}, merge_branch: GituiKeyEvent::new(KeyCode::Char('m'), KeyModifiers::empty()),
rebase_branch: KeyEvent { code: KeyCode::Char('R'), modifiers: KeyModifiers::SHIFT}, rebase_branch: GituiKeyEvent::new(KeyCode::Char('R'), KeyModifiers::SHIFT),
compare_commits: KeyEvent { code: KeyCode::Char('C'), modifiers: KeyModifiers::SHIFT}, compare_commits: GituiKeyEvent::new(KeyCode::Char('C'), KeyModifiers::SHIFT),
tags: KeyEvent { code: KeyCode::Char('T'), modifiers: KeyModifiers::SHIFT}, tags: GituiKeyEvent::new(KeyCode::Char('T'), KeyModifiers::SHIFT),
delete_tag: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT}, delete_tag: GituiKeyEvent::new(KeyCode::Char('D'), KeyModifiers::SHIFT),
select_tag: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()}, select_tag: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
push: KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::empty()}, push: GituiKeyEvent::new(KeyCode::Char('p'), KeyModifiers::empty()),
force_push: KeyEvent { code: KeyCode::Char('P'), modifiers: KeyModifiers::SHIFT}, force_push: GituiKeyEvent::new(KeyCode::Char('P'), KeyModifiers::SHIFT),
undo_commit: KeyEvent { code: KeyCode::Char('U'), modifiers: KeyModifiers::SHIFT}, undo_commit: GituiKeyEvent::new(KeyCode::Char('U'), KeyModifiers::SHIFT),
pull: KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty()}, pull: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
abort_merge: KeyEvent { code: KeyCode::Char('A'), modifiers: KeyModifiers::SHIFT}, abort_merge: GituiKeyEvent::new(KeyCode::Char('A'), KeyModifiers::SHIFT),
open_file_tree: KeyEvent { code: KeyCode::Char('F'), modifiers: KeyModifiers::SHIFT}, open_file_tree: GituiKeyEvent::new(KeyCode::Char('F'), KeyModifiers::SHIFT),
file_find: KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty()}, file_find: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
stage_unstage_item: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()}, stage_unstage_item: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
tag_annotate: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL}, tag_annotate: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
} }
} }
} }

View file

@ -1,85 +1,84 @@
use anyhow::Result; use anyhow::Result;
use crossterm::event::KeyEvent;
use ron::{self}; use ron::{self};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fs::File, io::Read, path::PathBuf}; use std::{fs::File, io::Read, path::PathBuf};
use super::key_list::KeysList; use super::key_list::{GituiKeyEvent, KeysList};
#[derive(Serialize, Deserialize, Default)] #[derive(Serialize, Deserialize, Default)]
pub struct KeysListFile { pub struct KeysListFile {
pub tab_status: Option<KeyEvent>, pub tab_status: Option<GituiKeyEvent>,
pub tab_log: Option<KeyEvent>, pub tab_log: Option<GituiKeyEvent>,
pub tab_files: Option<KeyEvent>, pub tab_files: Option<GituiKeyEvent>,
pub tab_stashing: Option<KeyEvent>, pub tab_stashing: Option<GituiKeyEvent>,
pub tab_stashes: Option<KeyEvent>, pub tab_stashes: Option<GituiKeyEvent>,
pub tab_toggle: Option<KeyEvent>, pub tab_toggle: Option<GituiKeyEvent>,
pub tab_toggle_reverse: Option<KeyEvent>, pub tab_toggle_reverse: Option<GituiKeyEvent>,
pub toggle_workarea: Option<KeyEvent>, pub toggle_workarea: Option<GituiKeyEvent>,
pub focus_right: Option<KeyEvent>, pub focus_right: Option<GituiKeyEvent>,
pub focus_left: Option<KeyEvent>, pub focus_left: Option<GituiKeyEvent>,
pub focus_above: Option<KeyEvent>, pub focus_above: Option<GituiKeyEvent>,
pub focus_below: Option<KeyEvent>, pub focus_below: Option<GituiKeyEvent>,
pub exit: Option<KeyEvent>, pub exit: Option<GituiKeyEvent>,
pub quit: Option<KeyEvent>, pub quit: Option<GituiKeyEvent>,
pub exit_popup: Option<KeyEvent>, pub exit_popup: Option<GituiKeyEvent>,
pub open_commit: Option<KeyEvent>, pub open_commit: Option<GituiKeyEvent>,
pub open_commit_editor: Option<KeyEvent>, pub open_commit_editor: Option<GituiKeyEvent>,
pub open_help: Option<KeyEvent>, pub open_help: Option<GituiKeyEvent>,
pub open_options: Option<KeyEvent>, pub open_options: Option<GituiKeyEvent>,
pub move_left: Option<KeyEvent>, pub move_left: Option<GituiKeyEvent>,
pub move_right: Option<KeyEvent>, pub move_right: Option<GituiKeyEvent>,
pub tree_collapse_recursive: Option<KeyEvent>, pub tree_collapse_recursive: Option<GituiKeyEvent>,
pub tree_expand_recursive: Option<KeyEvent>, pub tree_expand_recursive: Option<GituiKeyEvent>,
pub home: Option<KeyEvent>, pub home: Option<GituiKeyEvent>,
pub end: Option<KeyEvent>, pub end: Option<GituiKeyEvent>,
pub move_up: Option<KeyEvent>, pub move_up: Option<GituiKeyEvent>,
pub move_down: Option<KeyEvent>, pub move_down: Option<GituiKeyEvent>,
pub popup_up: Option<KeyEvent>, pub popup_up: Option<GituiKeyEvent>,
pub popup_down: Option<KeyEvent>, pub popup_down: Option<GituiKeyEvent>,
pub page_down: Option<KeyEvent>, pub page_down: Option<GituiKeyEvent>,
pub page_up: Option<KeyEvent>, pub page_up: Option<GituiKeyEvent>,
pub shift_up: Option<KeyEvent>, pub shift_up: Option<GituiKeyEvent>,
pub shift_down: Option<KeyEvent>, pub shift_down: Option<GituiKeyEvent>,
pub enter: Option<KeyEvent>, pub enter: Option<GituiKeyEvent>,
pub blame: Option<KeyEvent>, pub blame: Option<GituiKeyEvent>,
pub edit_file: Option<KeyEvent>, pub edit_file: Option<GituiKeyEvent>,
pub file_history: Option<KeyEvent>, pub file_history: Option<GituiKeyEvent>,
pub status_stage_all: Option<KeyEvent>, pub status_stage_all: Option<GituiKeyEvent>,
pub status_reset_item: Option<KeyEvent>, pub status_reset_item: Option<GituiKeyEvent>,
pub status_ignore_file: Option<KeyEvent>, pub status_ignore_file: Option<GituiKeyEvent>,
pub diff_stage_lines: Option<KeyEvent>, pub diff_stage_lines: Option<GituiKeyEvent>,
pub diff_reset_lines: Option<KeyEvent>, pub diff_reset_lines: Option<GituiKeyEvent>,
pub stashing_save: Option<KeyEvent>, pub stashing_save: Option<GituiKeyEvent>,
pub stashing_toggle_untracked: Option<KeyEvent>, pub stashing_toggle_untracked: Option<GituiKeyEvent>,
pub stashing_toggle_index: Option<KeyEvent>, pub stashing_toggle_index: Option<GituiKeyEvent>,
pub stash_apply: Option<KeyEvent>, pub stash_apply: Option<GituiKeyEvent>,
pub stash_open: Option<KeyEvent>, pub stash_open: Option<GituiKeyEvent>,
pub stash_drop: Option<KeyEvent>, pub stash_drop: Option<GituiKeyEvent>,
pub cmd_bar_toggle: Option<KeyEvent>, pub cmd_bar_toggle: Option<GituiKeyEvent>,
pub log_tag_commit: Option<KeyEvent>, pub log_tag_commit: Option<GituiKeyEvent>,
pub log_mark_commit: Option<KeyEvent>, pub log_mark_commit: Option<GituiKeyEvent>,
pub commit_amend: Option<KeyEvent>, pub commit_amend: Option<GituiKeyEvent>,
pub copy: Option<KeyEvent>, pub copy: Option<GituiKeyEvent>,
pub create_branch: Option<KeyEvent>, pub create_branch: Option<GituiKeyEvent>,
pub rename_branch: Option<KeyEvent>, pub rename_branch: Option<GituiKeyEvent>,
pub select_branch: Option<KeyEvent>, pub select_branch: Option<GituiKeyEvent>,
pub delete_branch: Option<KeyEvent>, pub delete_branch: Option<GituiKeyEvent>,
pub merge_branch: Option<KeyEvent>, pub merge_branch: Option<GituiKeyEvent>,
pub rebase_branch: Option<KeyEvent>, pub rebase_branch: Option<GituiKeyEvent>,
pub compare_commits: Option<KeyEvent>, pub compare_commits: Option<GituiKeyEvent>,
pub tags: Option<KeyEvent>, pub tags: Option<GituiKeyEvent>,
pub delete_tag: Option<KeyEvent>, pub delete_tag: Option<GituiKeyEvent>,
pub select_tag: Option<KeyEvent>, pub select_tag: Option<GituiKeyEvent>,
pub push: Option<KeyEvent>, pub push: Option<GituiKeyEvent>,
pub open_file_tree: Option<KeyEvent>, pub open_file_tree: Option<GituiKeyEvent>,
pub file_find: Option<KeyEvent>, pub file_find: Option<GituiKeyEvent>,
pub force_push: Option<KeyEvent>, pub force_push: Option<GituiKeyEvent>,
pub pull: Option<KeyEvent>, pub pull: Option<GituiKeyEvent>,
pub abort_merge: Option<KeyEvent>, pub abort_merge: Option<GituiKeyEvent>,
pub undo_commit: Option<KeyEvent>, pub undo_commit: Option<GituiKeyEvent>,
pub stage_unstage_item: Option<KeyEvent>, pub stage_unstage_item: Option<GituiKeyEvent>,
pub tag_annotate: Option<KeyEvent>, pub tag_annotate: Option<GituiKeyEvent>,
} }
impl KeysListFile { impl KeysListFile {

View file

@ -4,3 +4,4 @@ mod key_list_file;
mod symbols; mod symbols;
pub use key_config::{KeyConfig, SharedKeyConfig}; pub use key_config::{KeyConfig, SharedKeyConfig};
pub use key_list::key_match;

View file

@ -71,7 +71,7 @@ static TICK_INTERVAL: Duration = Duration::from_secs(5);
static SPINNER_INTERVAL: Duration = Duration::from_millis(80); static SPINNER_INTERVAL: Duration = Duration::from_millis(80);
/// ///
#[derive(Clone, Copy)] #[derive(Clone)]
pub enum QueueEvent { pub enum QueueEvent {
Tick, Tick,
SpinnerUpdate, SpinnerUpdate,

View file

@ -98,7 +98,7 @@ impl Component for FilesTab {
fn event( fn event(
&mut self, &mut self,
ev: crossterm::event::Event, ev: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.visible { if self.visible {
return self.files.event(ev); return self.files.event(ev);

View file

@ -5,7 +5,7 @@ use crate::{
DrawableComponent, EventState, FileTreeOpen, DrawableComponent, EventState, FileTreeOpen,
InspectCommitOpen, InspectCommitOpen,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue, StackablePopupOpen}, queue::{InternalEvent, Queue, StackablePopupOpen},
strings, try_or_popup, strings, try_or_popup,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -242,7 +242,9 @@ impl DrawableComponent for Revlog {
} }
impl Component for Revlog { impl Component for Revlog {
fn event(&mut self, ev: Event) -> Result<EventState> { //TODO: cleanup
#[allow(clippy::too_many_lines)]
fn event(&mut self, ev: &Event) -> Result<EventState> {
if self.visible { if self.visible {
let event_used = self.list.event(ev)?; let event_used = self.list.event(ev)?;
@ -250,17 +252,20 @@ impl Component for Revlog {
self.update()?; self.update()?;
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if let Event::Key(k) = ev { } else if let Event::Key(k) = ev {
if k == self.key_config.keys.enter { if key_match(k, self.key_config.keys.enter) {
self.commit_details.toggle_visible()?; self.commit_details.toggle_visible()?;
self.update()?; self.update()?;
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.copy { } else if key_match(k, self.key_config.keys.copy) {
self.copy_commit_hash()?; self.copy_commit_hash()?;
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.push { } else if key_match(k, self.key_config.keys.push) {
self.queue.push(InternalEvent::PushTags); self.queue.push(InternalEvent::PushTags);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.log_tag_commit { } else if key_match(
k,
self.key_config.keys.log_tag_commit,
) {
return self.selected_commit().map_or( return self.selected_commit().map_or(
Ok(EventState::NotConsumed), Ok(EventState::NotConsumed),
|id| { |id| {
@ -269,16 +274,23 @@ impl Component for Revlog {
Ok(EventState::Consumed) Ok(EventState::Consumed)
}, },
); );
} else if k == self.key_config.keys.focus_right } else if key_match(
&& self.commit_details.is_visible() k,
self.key_config.keys.focus_right,
) && self.commit_details.is_visible()
{ {
self.inspect_commit(); self.inspect_commit();
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.select_branch { } else if key_match(
k,
self.key_config.keys.select_branch,
) {
self.queue.push(InternalEvent::SelectBranch); self.queue.push(InternalEvent::SelectBranch);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.status_reset_item } else if key_match(
{ k,
self.key_config.keys.status_reset_item,
) {
try_or_popup!( try_or_popup!(
self, self,
"revert error:", "revert error:",
@ -286,7 +298,10 @@ impl Component for Revlog {
); );
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.open_file_tree { } else if key_match(
k,
self.key_config.keys.open_file_tree,
) {
return self.selected_commit().map_or( return self.selected_commit().map_or(
Ok(EventState::NotConsumed), Ok(EventState::NotConsumed),
|id| { |id| {
@ -300,11 +315,13 @@ impl Component for Revlog {
Ok(EventState::Consumed) Ok(EventState::Consumed)
}, },
); );
} else if k == self.key_config.keys.tags { } else if key_match(k, self.key_config.keys.tags) {
self.queue.push(InternalEvent::Tags); self.queue.push(InternalEvent::Tags);
return Ok(EventState::Consumed); return Ok(EventState::Consumed);
} else if k == self.key_config.keys.compare_commits } else if key_match(
&& self.list.marked_count() > 0 k,
self.key_config.keys.compare_commits,
) && self.list.marked_count() > 0
{ {
if self.list.marked_count() == 1 { if self.list.marked_count() == 1 {
// compare against head // compare against head

View file

@ -5,7 +5,7 @@ use crate::{
CommandBlocking, CommandInfo, Component, DrawableComponent, CommandBlocking, CommandInfo, Component, DrawableComponent,
EventState, StatusTreeComponent, EventState, StatusTreeComponent,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{InternalEvent, Queue}, queue::{InternalEvent, Queue},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -213,7 +213,7 @@ impl Component for Stashing {
fn event( fn event(
&mut self, &mut self,
ev: crossterm::event::Event, ev: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.visible { if self.visible {
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(ev, self.components_mut().as_mut_slice())?
@ -223,24 +223,28 @@ impl Component for Stashing {
} }
if let Event::Key(k) = ev { if let Event::Key(k) = ev {
return if k == self.key_config.keys.stashing_save return if key_match(
&& !self.index.is_empty() k,
self.key_config.keys.stashing_save,
) && !self.index.is_empty()
{ {
self.queue.push(InternalEvent::PopupStashing( self.queue.push(InternalEvent::PopupStashing(
self.options, self.options,
)); ));
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k } else if key_match(
== self.key_config.keys.stashing_toggle_index k,
{ self.key_config.keys.stashing_toggle_index,
) {
self.options.keep_index = self.options.keep_index =
!self.options.keep_index; !self.options.keep_index;
self.update()?; self.update()?;
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k } else if key_match(
== self.key_config.keys.stashing_toggle_untracked k,
{ self.key_config.keys.stashing_toggle_untracked,
) {
self.options.stash_untracked = self.options.stash_untracked =
!self.options.stash_untracked; !self.options.stash_untracked;
self.update()?; self.update()?;

View file

@ -4,7 +4,7 @@ use crate::{
CommitList, Component, DrawableComponent, EventState, CommitList, Component, DrawableComponent, EventState,
InspectCommitOpen, InspectCommitOpen,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, Queue, StackablePopupOpen}, queue::{Action, InternalEvent, Queue, StackablePopupOpen},
strings, strings,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -200,7 +200,7 @@ impl Component for StashList {
fn event( fn event(
&mut self, &mut self,
ev: crossterm::event::Event, ev: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.is_visible() { if self.is_visible() {
if self.list.event(ev)?.is_consumed() { if self.list.event(ev)?.is_consumed() {
@ -208,13 +208,22 @@ impl Component for StashList {
} }
if let Event::Key(k) = ev { if let Event::Key(k) = ev {
if k == self.key_config.keys.enter { if key_match(k, self.key_config.keys.enter) {
self.pop_stash(); self.pop_stash();
} else if k == self.key_config.keys.stash_apply { } else if key_match(
k,
self.key_config.keys.stash_apply,
) {
self.apply_stash(); self.apply_stash();
} else if k == self.key_config.keys.stash_drop { } else if key_match(
k,
self.key_config.keys.stash_drop,
) {
self.drop_stash(); self.drop_stash();
} else if k == self.key_config.keys.stash_open { } else if key_match(
k,
self.key_config.keys.stash_open,
) {
self.inspect(); self.inspect();
} }
} }

View file

@ -6,7 +6,7 @@ use crate::{
DiffComponent, DrawableComponent, EventState, DiffComponent, DrawableComponent, EventState,
FileTreeItemKind, SharedOptions, FileTreeItemKind, SharedOptions,
}, },
keys::SharedKeyConfig, keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem}, queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
strings, try_or_popup, strings, try_or_popup,
ui::style::SharedTheme, ui::style::SharedTheme,
@ -803,7 +803,7 @@ impl Component for Status {
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)] #[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
fn event( fn event(
&mut self, &mut self,
ev: crossterm::event::Event, ev: &crossterm::event::Event,
) -> Result<EventState> { ) -> Result<EventState> {
if self.visible { if self.visible {
if event_pump(ev, self.components_mut().as_mut_slice())? if event_pump(ev, self.components_mut().as_mut_slice())?
@ -814,7 +814,7 @@ impl Component for Status {
} }
if let Event::Key(k) = ev { if let Event::Key(k) = ev {
return if k == self.key_config.keys.edit_file return if key_match(k, self.key_config.keys.edit_file)
&& (self.can_focus_diff() && (self.can_focus_diff()
|| self.is_focus_on_diff()) || self.is_focus_on_diff())
{ {
@ -826,67 +826,85 @@ impl Component for Status {
); );
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.open_commit } else if key_match(
&& self.can_commit() k,
self.key_config.keys.open_commit,
) && self.can_commit()
{ {
self.queue.push(InternalEvent::OpenCommit); self.queue.push(InternalEvent::OpenCommit);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.toggle_workarea } else if key_match(
&& !self.is_focus_on_diff() k,
self.key_config.keys.toggle_workarea,
) && !self.is_focus_on_diff()
{ {
self.switch_focus(self.focus.toggled_focus()) self.switch_focus(self.focus.toggled_focus())
.map(Into::into) .map(Into::into)
} else if k == self.key_config.keys.focus_right } else if key_match(
&& self.can_focus_diff() k,
self.key_config.keys.focus_right,
) && self.can_focus_diff()
{ {
self.switch_focus(Focus::Diff).map(Into::into) self.switch_focus(Focus::Diff).map(Into::into)
} else if k == self.key_config.keys.focus_left { } else if key_match(
k,
self.key_config.keys.focus_left,
) {
self.switch_focus(match self.diff_target { self.switch_focus(match self.diff_target {
DiffTarget::Stage => Focus::Stage, DiffTarget::Stage => Focus::Stage,
DiffTarget::WorkingDir => Focus::WorkDir, DiffTarget::WorkingDir => Focus::WorkDir,
}) })
.map(Into::into) .map(Into::into)
} else if k == self.key_config.keys.move_down } else if key_match(k, self.key_config.keys.move_down)
&& self.focus == Focus::WorkDir && self.focus == Focus::WorkDir
&& !self.index.is_empty() && !self.index.is_empty()
{ {
self.switch_focus(Focus::Stage).map(Into::into) self.switch_focus(Focus::Stage).map(Into::into)
} else if k == self.key_config.keys.move_up } else if key_match(k, self.key_config.keys.move_up)
&& self.focus == Focus::Stage && self.focus == Focus::Stage
&& !self.index_wd.is_empty() && !self.index_wd.is_empty()
{ {
self.switch_focus(Focus::WorkDir).map(Into::into) self.switch_focus(Focus::WorkDir).map(Into::into)
} else if k == self.key_config.keys.select_branch } else if key_match(
&& !self.is_focus_on_diff() k,
self.key_config.keys.select_branch,
) && !self.is_focus_on_diff()
{ {
self.queue.push(InternalEvent::SelectBranch); self.queue.push(InternalEvent::SelectBranch);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.force_push } else if key_match(
&& !self.is_focus_on_diff() k,
self.key_config.keys.force_push,
) && !self.is_focus_on_diff()
&& self.can_push() && self.can_push()
{ {
self.push(true); self.push(true);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.push } else if key_match(k, self.key_config.keys.push)
&& !self.is_focus_on_diff() && !self.is_focus_on_diff()
{ {
self.push(false); self.push(false);
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.pull } else if key_match(k, self.key_config.keys.pull)
&& !self.is_focus_on_diff() && !self.is_focus_on_diff()
&& self.can_pull() && self.can_pull()
{ {
self.pull(); self.pull();
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.undo_commit } else if key_match(
&& !self.is_focus_on_diff() k,
self.key_config.keys.undo_commit,
) && !self.is_focus_on_diff()
{ {
self.undo_last_commit(); self.undo_last_commit();
self.queue.push(InternalEvent::Update( self.queue.push(InternalEvent::Update(
NeedsUpdate::ALL, NeedsUpdate::ALL,
)); ));
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.abort_merge { } else if key_match(
k,
self.key_config.keys.abort_merge,
) {
if self.can_abort_merge() { if self.can_abort_merge() {
self.queue.push( self.queue.push(
InternalEvent::ConfirmAction( InternalEvent::ConfirmAction(
@ -908,8 +926,10 @@ impl Component for Status {
} }
Ok(EventState::Consumed) Ok(EventState::Consumed)
} else if k == self.key_config.keys.rebase_branch } else if key_match(
&& self.pending_rebase() k,
self.key_config.keys.rebase_branch,
) && self.pending_rebase()
{ {
self.continue_rebase(); self.continue_rebase();
self.queue.push(InternalEvent::Update( self.queue.push(InternalEvent::Update(

View file

@ -14,7 +14,7 @@ pub use stateful_paragraph::{
pub use syntax_text::{AsyncSyntaxJob, SyntaxText}; pub use syntax_text::{AsyncSyntaxJob, SyntaxText};
use tui::layout::{Constraint, Direction, Layout, Rect}; use tui::layout::{Constraint, Direction, Layout, Rect};
use crate::keys::SharedKeyConfig; use crate::keys::{key_match, SharedKeyConfig};
/// return the scroll position (line) necessary to have the `selection` in view if it is not already /// return the scroll position (line) necessary to have the `selection` in view if it is not already
pub const fn calc_scroll_top( pub const fn calc_scroll_top(
@ -115,27 +115,27 @@ pub fn centered_rect_absolute(
/// ///
pub fn common_nav( pub fn common_nav(
key: crossterm::event::KeyEvent, key: &crossterm::event::KeyEvent,
key_config: &SharedKeyConfig, key_config: &SharedKeyConfig,
) -> Option<MoveSelection> { ) -> Option<MoveSelection> {
if key == key_config.keys.move_down { if key_match(key, key_config.keys.move_down) {
Some(MoveSelection::Down) Some(MoveSelection::Down)
} else if key == key_config.keys.move_up { } else if key_match(key, key_config.keys.move_up) {
Some(MoveSelection::Up) Some(MoveSelection::Up)
} else if key == key_config.keys.page_up { } else if key_match(key, key_config.keys.page_up) {
Some(MoveSelection::PageUp) Some(MoveSelection::PageUp)
} else if key == key_config.keys.page_down { } else if key_match(key, key_config.keys.page_down) {
Some(MoveSelection::PageDown) Some(MoveSelection::PageDown)
} else if key == key_config.keys.move_right { } else if key_match(key, key_config.keys.move_right) {
Some(MoveSelection::Right) Some(MoveSelection::Right)
} else if key == key_config.keys.move_left { } else if key_match(key, key_config.keys.move_left) {
Some(MoveSelection::Left) Some(MoveSelection::Left)
} else if key == key_config.keys.home } else if key_match(key, key_config.keys.home)
|| key == key_config.keys.shift_up || key_match(key, key_config.keys.shift_up)
{ {
Some(MoveSelection::Top) Some(MoveSelection::Top)
} else if key == key_config.keys.end } else if key_match(key, key_config.keys.end)
|| key == key_config.keys.shift_down || key_match(key, key_config.keys.shift_down)
{ {
Some(MoveSelection::End) Some(MoveSelection::End)
} else { } else {