mirror of
https://github.com/extrawurst/gitui.git
synced 2024-12-27 11:03:03 +03:00
Customize key binds (#234)
* customizable key config * provide example vim key config * automatically show correct key binding in bottom cmd-bar
This commit is contained in:
parent
d8bd4721ef
commit
a95ffd7bcc
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
/.idea/
|
/.idea/
|
||||||
flamegraph.svg
|
flamegraph.svg
|
||||||
|
KEY_CONFIG.md
|
||||||
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -316,6 +316,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot 0.10.2",
|
"parking_lot 0.10.2",
|
||||||
|
"serde",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -21,7 +21,7 @@ keywords = [
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
scopetime = { path = "./scopetime", version = "0.1" }
|
scopetime = { path = "./scopetime", version = "0.1" }
|
||||||
asyncgit = { path = "./asyncgit", version = "0.9" }
|
asyncgit = { path = "./asyncgit", version = "0.9" }
|
||||||
crossterm = "0.17"
|
crossterm = { version = "0.17", features = [ "serde" ] }
|
||||||
clap = { version = "2.33", default-features = false }
|
clap = { version = "2.33", default-features = false }
|
||||||
tui = { version = "0.9", default-features = false, features = ['crossterm'] }
|
tui = { version = "0.9", default-features = false, features = ['crossterm'] }
|
||||||
bytesize = { version = "1.0.1", default-features = false}
|
bytesize = { version = "1.0.1", default-features = false}
|
||||||
|
15
KEY_CONFIG.md
Normal file
15
KEY_CONFIG.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Key Config
|
||||||
|
|
||||||
|
Default using arrow key to navigate the gitui and Ctrl + C to quit the program
|
||||||
|
|
||||||
|
The first time Gitui will create `key_config.ron` file automatically.
|
||||||
|
You can change the every single key bindings of the program as what you like.
|
||||||
|
|
||||||
|
The config file format is [Ron format](https://github.com/ron-rs/ron).
|
||||||
|
And the path differs depending on the operating system:
|
||||||
|
* `$HOME/Library/Preferences/gitui/key_config.ron` (mac)
|
||||||
|
* `$XDG_CONFIG_HOME/gitui/key_config.ron` (linux using XDG)
|
||||||
|
* `$HOME/.config/gitui/key_config.ron` (linux)
|
||||||
|
|
||||||
|
Here is a [vim style key config](assets/vim_style_key_config.ron) with `h`, `j`, `k`, `l` to navigate and `Ctrl + C` to leave.
|
||||||
|
You can use it to replace `key_config.ron` and get a vim style setting.
|
@ -135,3 +135,6 @@ However, you can customize everything to your liking: See [Themes](THEMES.md).
|
|||||||
- [tig](https://github.com/jonas/tig)
|
- [tig](https://github.com/jonas/tig)
|
||||||
- [GitUp](https://github.com/git-up/GitUp)
|
- [GitUp](https://github.com/git-up/GitUp)
|
||||||
- It would be nice to come up with a way to have the map view available in a terminal tool
|
- It would be nice to come up with a way to have the map view available in a terminal tool
|
||||||
|
|
||||||
|
# Key Bindings
|
||||||
|
You can customize every keybing to your liking: See [Key Config](KEY_CONFIG.md).
|
||||||
|
66
assets/vim_style_key_config.ron
Normal file
66
assets/vim_style_key_config.ron
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// bit for modifiers
|
||||||
|
// bits: 0 None
|
||||||
|
// bits: 1 SHIFT
|
||||||
|
// bits: 2 CONTROL
|
||||||
|
(
|
||||||
|
tab_status: ( code: Char('1'), modifiers: ( bits: 0,),),
|
||||||
|
tab_log: ( code: Char('2'), modifiers: ( bits: 0,),),
|
||||||
|
tab_stashing: ( code: Char('3'), modifiers: ( bits: 0,),),
|
||||||
|
tab_stashes: ( code: Char('4'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
tab_toggle: ( code: Tab, modifiers: ( bits: 0,),),
|
||||||
|
tab_toggle_reverse: ( code: BackTab, modifiers: ( bits: 0,),),
|
||||||
|
tab_toggle_reverse_windows: ( code: BackTab, modifiers: ( bits: 1,),),
|
||||||
|
|
||||||
|
focus_workdir: ( code: Char('w'), modifiers: ( bits: 0,),),
|
||||||
|
focus_stage: ( code: Char('s'), modifiers: ( bits: 0,),),
|
||||||
|
focus_right: ( code: Char('l'), modifiers: ( bits: 0,),),
|
||||||
|
focus_left: ( code: Char('h'), modifiers: ( bits: 0,),),
|
||||||
|
focus_above: ( code: Char('k'), modifiers: ( bits: 0,),),
|
||||||
|
focus_below: ( code: Char('j'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
exit: ( code: Char('c'), modifiers: ( bits: 2,),),
|
||||||
|
exit_popup: ( code: Esc, modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
close_msg: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
open_commit: ( code: Char('c'), modifiers: ( bits: 0,),),
|
||||||
|
open_commit_editor: ( code: Char('E'), modifiers: ( bits: 0,),),
|
||||||
|
open_help: ( code: F(1), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
move_left: ( code: Char('h'), modifiers: ( bits: 0,),),
|
||||||
|
move_right: ( code: Char('l'), modifiers: ( bits: 0,),),
|
||||||
|
home: ( code: Home, modifiers: ( bits: 0,),),
|
||||||
|
end: ( code: End, modifiers: ( bits: 0,),),
|
||||||
|
move_up: ( code: Char('k'), modifiers: ( bits: 0,),),
|
||||||
|
move_down: ( code: Char('j'), modifiers: ( bits: 0,),),
|
||||||
|
page_up: ( code: Char('u'), modifiers: ( bits: 2,),),
|
||||||
|
page_down: ( code: Char('d'), modifiers: ( bits: 2,),),
|
||||||
|
|
||||||
|
shift_up: ( code: Char('K'), modifiers: ( bits: 0,),),
|
||||||
|
shift_down: ( code: Char('J'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
enter: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
edit_file: ( code: Char('I'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
status_stage_file: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
status_stage_all: ( code: Char('a'), modifiers: ( bits: 0,),),
|
||||||
|
status_reset_file: ( code: Char('U'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
diff_reset_hunk: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
status_ignore_file: ( code: Char('i'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
stashing_save: ( code: Char('w'), modifiers: ( bits: 0,),),
|
||||||
|
stashing_toggle_untracked: ( code: Char('u'), modifiers: ( bits: 0,),),
|
||||||
|
stashing_toggle_index: ( code: Char('m'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
stash_apply: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
stash_open: ( code: Char('l'), modifiers: ( bits: 0,),),
|
||||||
|
stash_drop: ( code: Char('D'), modifiers: ( bits: 0,),),
|
||||||
|
|
||||||
|
cmd_bar_toggle: ( code: Char('.'), modifiers: ( bits: 0,),),
|
||||||
|
log_commit_details: ( code: Enter, modifiers: ( bits: 0,),),
|
||||||
|
log_tag_commit: ( code: Char('t'), modifiers: ( bits: 0,),),
|
||||||
|
commit_amend: ( code: Char('A'), modifiers: ( bits: 0,),),
|
||||||
|
copy: ( code: Char('y'), modifiers: ( bits: 0,),),
|
||||||
|
)
|
129
src/app.rs
129
src/app.rs
@ -8,9 +8,9 @@ use crate::{
|
|||||||
ResetComponent, StashMsgComponent, TagCommitComponent,
|
ResetComponent, StashMsgComponent, TagCommitComponent,
|
||||||
},
|
},
|
||||||
input::{Input, InputEvent, InputState},
|
input::{Input, InputEvent, InputState},
|
||||||
keys,
|
keys::{KeyConfig, SharedKeyConfig},
|
||||||
queue::{Action, InternalEvent, NeedsUpdate, Queue},
|
queue::{Action, InternalEvent, NeedsUpdate, Queue},
|
||||||
strings::{self, commands, order},
|
strings::{self, order},
|
||||||
tabs::{Revlog, StashList, Stashing, Status},
|
tabs::{Revlog, StashList, Stashing, Status},
|
||||||
ui::style::{SharedTheme, Theme},
|
ui::style::{SharedTheme, Theme},
|
||||||
};
|
};
|
||||||
@ -49,6 +49,7 @@ pub struct App {
|
|||||||
stashlist_tab: StashList,
|
stashlist_tab: StashList,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
input: Input,
|
input: Input,
|
||||||
|
|
||||||
// "Flags"
|
// "Flags"
|
||||||
@ -66,45 +67,77 @@ impl App {
|
|||||||
let queue = Queue::default();
|
let queue = Queue::default();
|
||||||
|
|
||||||
let theme = Rc::new(Theme::init());
|
let theme = Rc::new(Theme::init());
|
||||||
|
let key_config = Rc::new(KeyConfig::init());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
input,
|
input,
|
||||||
reset: ResetComponent::new(queue.clone(), theme.clone()),
|
reset: ResetComponent::new(
|
||||||
|
queue.clone(),
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
commit: CommitComponent::new(
|
commit: CommitComponent::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
stashmsg_popup: StashMsgComponent::new(
|
stashmsg_popup: StashMsgComponent::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
inspect_commit_popup: InspectCommitComponent::new(
|
inspect_commit_popup: InspectCommitComponent::new(
|
||||||
&queue,
|
&queue,
|
||||||
sender,
|
sender,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
external_editor_popup: ExternalEditorComponent::new(
|
external_editor_popup: ExternalEditorComponent::new(
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
tag_commit_popup: TagCommitComponent::new(
|
tag_commit_popup: TagCommitComponent::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
do_quit: false,
|
do_quit: false,
|
||||||
cmdbar: RefCell::new(CommandBar::new(theme.clone())),
|
cmdbar: RefCell::new(CommandBar::new(
|
||||||
help: HelpComponent::new(theme.clone()),
|
theme.clone(),
|
||||||
msg: MsgComponent::new(theme.clone()),
|
key_config.clone(),
|
||||||
|
)),
|
||||||
|
help: HelpComponent::new(
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
msg: MsgComponent::new(theme.clone(), key_config.clone()),
|
||||||
tab: 0,
|
tab: 0,
|
||||||
revlog: Revlog::new(&queue, sender, theme.clone()),
|
revlog: Revlog::new(
|
||||||
status_tab: Status::new(&queue, sender, theme.clone()),
|
&queue,
|
||||||
|
sender,
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
status_tab: Status::new(
|
||||||
|
&queue,
|
||||||
|
sender,
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
stashing_tab: Stashing::new(
|
stashing_tab: Stashing::new(
|
||||||
sender,
|
sender,
|
||||||
&queue,
|
&queue,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
stashlist_tab: StashList::new(
|
||||||
|
&queue,
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
stashlist_tab: StashList::new(&queue, theme.clone()),
|
|
||||||
queue,
|
queue,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
requires_redraw: Cell::new(false),
|
requires_redraw: Cell::new(false),
|
||||||
file_to_open: None,
|
file_to_open: None,
|
||||||
}
|
}
|
||||||
@ -160,30 +193,26 @@ impl App {
|
|||||||
if event_pump(ev, self.components_mut().as_mut_slice())? {
|
if event_pump(ev, self.components_mut().as_mut_slice())? {
|
||||||
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 = match k {
|
let new_flags = if k == self.key_config.tab_toggle {
|
||||||
keys::TAB_TOGGLE => {
|
self.toggle_tabs(false)?;
|
||||||
self.toggle_tabs(false)?;
|
NeedsUpdate::COMMANDS
|
||||||
NeedsUpdate::COMMANDS
|
} else if k == self.key_config.tab_toggle_reverse
|
||||||
}
|
|| k == self.key_config.tab_toggle_reverse_windows
|
||||||
keys::TAB_TOGGLE_REVERSE
|
{
|
||||||
| keys::TAB_TOGGLE_REVERSE_WINDOWS => {
|
self.toggle_tabs(true)?;
|
||||||
self.toggle_tabs(true)?;
|
NeedsUpdate::COMMANDS
|
||||||
NeedsUpdate::COMMANDS
|
} else if k == self.key_config.tab_status
|
||||||
}
|
|| k == self.key_config.tab_log
|
||||||
keys::TAB_1
|
|| k == self.key_config.tab_stashing
|
||||||
| keys::TAB_2
|
|| k == self.key_config.tab_stashes
|
||||||
| keys::TAB_3
|
{
|
||||||
| keys::TAB_4 => {
|
self.switch_tab(k)?;
|
||||||
self.switch_tab(k)?;
|
NeedsUpdate::COMMANDS
|
||||||
NeedsUpdate::COMMANDS
|
} else if k == self.key_config.cmd_bar_toggle {
|
||||||
}
|
self.cmdbar.borrow_mut().toggle_more();
|
||||||
|
NeedsUpdate::empty()
|
||||||
keys::CMD_BAR_TOGGLE => {
|
} else {
|
||||||
self.cmdbar.borrow_mut().toggle_more();
|
NeedsUpdate::empty()
|
||||||
NeedsUpdate::empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => NeedsUpdate::empty(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
flags.insert(new_flags);
|
flags.insert(new_flags);
|
||||||
@ -312,7 +341,7 @@ impl App {
|
|||||||
|
|
||||||
fn check_quit_key(&mut self, ev: Event) -> bool {
|
fn check_quit_key(&mut self, ev: Event) -> bool {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
if let keys::EXIT = e {
|
if e == self.key_config.exit {
|
||||||
self.do_quit = true;
|
self.do_quit = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -341,12 +370,14 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn switch_tab(&mut self, k: KeyEvent) -> Result<()> {
|
fn switch_tab(&mut self, k: KeyEvent) -> Result<()> {
|
||||||
match k {
|
if k == self.key_config.tab_status {
|
||||||
keys::TAB_1 => self.set_tab(0)?,
|
self.set_tab(0)?
|
||||||
keys::TAB_2 => self.set_tab(1)?,
|
} else if k == self.key_config.tab_log {
|
||||||
keys::TAB_3 => self.set_tab(2)?,
|
self.set_tab(1)?
|
||||||
keys::TAB_4 => self.set_tab(3)?,
|
} else if k == self.key_config.tab_stashing {
|
||||||
_ => (),
|
self.set_tab(2)?
|
||||||
|
} else if k == self.key_config.tab_stashes {
|
||||||
|
self.set_tab(3)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -458,7 +489,7 @@ impl App {
|
|||||||
|
|
||||||
res.push(
|
res.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::TOGGLE_TABS,
|
strings::commands::toggle_tabs(&self.key_config),
|
||||||
true,
|
true,
|
||||||
!self.any_popup_visible(),
|
!self.any_popup_visible(),
|
||||||
)
|
)
|
||||||
@ -466,7 +497,9 @@ impl App {
|
|||||||
);
|
);
|
||||||
res.push(
|
res.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::TOGGLE_TABS_DIRECT,
|
strings::commands::toggle_tabs_direct(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
true,
|
true,
|
||||||
!self.any_popup_visible(),
|
!self.any_popup_visible(),
|
||||||
)
|
)
|
||||||
@ -475,7 +508,7 @@ impl App {
|
|||||||
|
|
||||||
res.push(
|
res.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::QUIT,
|
strings::commands::quit(&self.key_config),
|
||||||
true,
|
true,
|
||||||
!self.any_popup_visible(),
|
!self.any_popup_visible(),
|
||||||
)
|
)
|
||||||
@ -531,10 +564,10 @@ impl App {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let tabs = &[
|
let tabs = &[
|
||||||
strings::TAB_STATUS,
|
strings::tab_status(&self.key_config),
|
||||||
strings::TAB_LOG,
|
strings::tab_log(&self.key_config),
|
||||||
strings::TAB_STASHING,
|
strings::tab_stashing(&self.key_config),
|
||||||
strings::TAB_STASHES,
|
strings::tab_stashes(&self.key_config),
|
||||||
];
|
];
|
||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
@ -547,7 +580,7 @@ impl App {
|
|||||||
.titles(tabs)
|
.titles(tabs)
|
||||||
.style(self.theme.tab(false))
|
.style(self.theme.tab(false))
|
||||||
.highlight_style(self.theme.tab(true))
|
.highlight_style(self.theme.tab(true))
|
||||||
.divider(strings::TAB_DIVIDER)
|
.divider(&strings::tab_divider(&self.key_config))
|
||||||
.select(self.tab),
|
.select(self.tab),
|
||||||
r,
|
r,
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::CommandInfo, strings, ui::style::SharedTheme,
|
components::CommandInfo, keys::SharedKeyConfig, strings,
|
||||||
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use tui::{
|
use tui::{
|
||||||
@ -27,6 +28,7 @@ pub struct CommandBar {
|
|||||||
draw_list: Vec<DrawListEntry>,
|
draw_list: Vec<DrawListEntry>,
|
||||||
cmd_infos: Vec<CommandInfo>,
|
cmd_infos: Vec<CommandInfo>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
lines: u16,
|
lines: u16,
|
||||||
width: u16,
|
width: u16,
|
||||||
expandable: bool,
|
expandable: bool,
|
||||||
@ -36,11 +38,15 @@ pub struct CommandBar {
|
|||||||
const MORE_WIDTH: u16 = 11;
|
const MORE_WIDTH: u16 = 11;
|
||||||
|
|
||||||
impl CommandBar {
|
impl CommandBar {
|
||||||
pub const fn new(theme: SharedTheme) -> Self {
|
pub const fn new(
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
draw_list: Vec::new(),
|
draw_list: Vec::new(),
|
||||||
cmd_infos: Vec::new(),
|
cmd_infos: Vec::new(),
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
lines: 0,
|
lines: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
expandable: false,
|
expandable: false,
|
||||||
@ -58,7 +64,8 @@ impl CommandBar {
|
|||||||
fn is_multiline(&self, width: u16) -> bool {
|
fn is_multiline(&self, width: u16) -> bool {
|
||||||
let mut line_width = 0_usize;
|
let mut line_width = 0_usize;
|
||||||
for c in &self.cmd_infos {
|
for c in &self.cmd_infos {
|
||||||
let entry_w = UnicodeWidthStr::width(c.text.name);
|
let entry_w =
|
||||||
|
UnicodeWidthStr::width(c.text.name.as_str());
|
||||||
|
|
||||||
if line_width + entry_w > width as usize {
|
if line_width + entry_w > width as usize {
|
||||||
return true;
|
return true;
|
||||||
@ -83,7 +90,8 @@ impl CommandBar {
|
|||||||
let mut lines = 1_u16;
|
let mut lines = 1_u16;
|
||||||
|
|
||||||
for c in &self.cmd_infos {
|
for c in &self.cmd_infos {
|
||||||
let entry_w = UnicodeWidthStr::width(c.text.name);
|
let entry_w =
|
||||||
|
UnicodeWidthStr::width(c.text.name.as_str());
|
||||||
|
|
||||||
if line_width + entry_w > width as usize {
|
if line_width + entry_w > width as usize {
|
||||||
self.draw_list.push(DrawListEntry::LineBreak);
|
self.draw_list.push(DrawListEntry::LineBreak);
|
||||||
@ -131,7 +139,9 @@ impl CommandBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw<B: Backend>(&self, f: &mut Frame<B>, r: Rect) {
|
pub fn draw<B: Backend>(&self, f: &mut Frame<B>, r: Rect) {
|
||||||
let splitter = Text::Raw(Cow::from(strings::CMD_SPLITTER));
|
let splitter = Text::Raw(Cow::from(strings::cmd_splitter(
|
||||||
|
&self.key_config,
|
||||||
|
)));
|
||||||
|
|
||||||
let texts = self
|
let texts = self
|
||||||
.draw_list
|
.draw_list
|
||||||
|
@ -5,7 +5,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{CommandInfo, Component},
|
components::{CommandInfo, Component},
|
||||||
keys,
|
keys::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,
|
||||||
@ -14,7 +14,6 @@ use anyhow::Result;
|
|||||||
use asyncgit::{cached, sync, StatusItem, StatusItemType, CWD};
|
use asyncgit::{cached, sync, StatusItem, StatusItemType, CWD};
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use strings::commands;
|
|
||||||
use tui::{backend::Backend, layout::Rect, Frame};
|
use tui::{backend::Backend, layout::Rect, Frame};
|
||||||
|
|
||||||
///
|
///
|
||||||
@ -24,9 +23,10 @@ pub struct ChangesComponent {
|
|||||||
is_working_dir: bool,
|
is_working_dir: bool,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
branch_name: cached::BranchName,
|
branch_name: cached::BranchName,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChangesComponent {
|
impl<'a> ChangesComponent {
|
||||||
///
|
///
|
||||||
pub fn new(
|
pub fn new(
|
||||||
title: &str,
|
title: &str,
|
||||||
@ -34,6 +34,7 @@ impl ChangesComponent {
|
|||||||
is_working_dir: bool,
|
is_working_dir: bool,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.into(),
|
title: title.into(),
|
||||||
@ -42,10 +43,12 @@ impl ChangesComponent {
|
|||||||
focus,
|
focus,
|
||||||
Some(queue.clone()),
|
Some(queue.clone()),
|
||||||
theme,
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
is_working_dir,
|
is_working_dir,
|
||||||
queue,
|
queue,
|
||||||
branch_name: cached::BranchName::new(CWD),
|
branch_name: cached::BranchName::new(CWD),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,39 +209,39 @@ impl Component for ChangesComponent {
|
|||||||
|
|
||||||
if self.is_working_dir {
|
if self.is_working_dir {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STAGE_ALL,
|
strings::commands::stage_all(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STAGE_ITEM,
|
strings::commands::stage_item(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::RESET_ITEM,
|
strings::commands::reset_item(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::IGNORE_ITEM,
|
strings::commands::ignore_item(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::UNSTAGE_ITEM,
|
strings::commands::unstage_item(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::UNSTAGE_ALL,
|
strings::commands::unstage_all(&self.key_config),
|
||||||
some_selection,
|
some_selection,
|
||||||
self.focused(),
|
self.focused(),
|
||||||
));
|
));
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::COMMIT_OPEN,
|
strings::commands::commit_open(&self.key_config),
|
||||||
!self.is_empty(),
|
!self.is_empty(),
|
||||||
self.focused() || force_all,
|
self.focused() || force_all,
|
||||||
)
|
)
|
||||||
@ -256,57 +259,49 @@ impl Component for ChangesComponent {
|
|||||||
|
|
||||||
if self.focused() {
|
if self.focused() {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
return match e {
|
return if e == self.key_config.open_commit
|
||||||
keys::OPEN_COMMIT
|
&& !self.is_working_dir
|
||||||
if !self.is_working_dir
|
&& !self.is_empty()
|
||||||
&& !self.is_empty() =>
|
{
|
||||||
{
|
self.queue
|
||||||
self.queue
|
.borrow_mut()
|
||||||
.borrow_mut()
|
.push_back(InternalEvent::OpenCommit);
|
||||||
.push_back(InternalEvent::OpenCommit);
|
Ok(true)
|
||||||
Ok(true)
|
} else if e == self.key_config.status_stage_file {
|
||||||
}
|
try_or_popup!(
|
||||||
keys::STATUS_STAGE_FILE => {
|
self,
|
||||||
|
"staging error:",
|
||||||
|
self.index_add_remove()
|
||||||
|
);
|
||||||
|
|
||||||
|
self.queue.borrow_mut().push_back(
|
||||||
|
InternalEvent::Update(NeedsUpdate::ALL),
|
||||||
|
);
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.status_stage_all
|
||||||
|
&& !self.is_empty()
|
||||||
|
{
|
||||||
|
if self.is_working_dir {
|
||||||
try_or_popup!(
|
try_or_popup!(
|
||||||
self,
|
self,
|
||||||
"staging error:",
|
"staging error:",
|
||||||
self.index_add_remove()
|
self.index_add_all()
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
self.queue.borrow_mut().push_back(
|
self.stage_remove_all()?;
|
||||||
InternalEvent::Update(NeedsUpdate::ALL),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
}
|
||||||
|
Ok(true)
|
||||||
keys::STATUS_STAGE_ALL if !self.is_empty() => {
|
} else if e == self.key_config.status_reset_file
|
||||||
if self.is_working_dir {
|
&& self.is_working_dir
|
||||||
try_or_popup!(
|
{
|
||||||
self,
|
Ok(self.dispatch_reset_workdir())
|
||||||
"staging error:",
|
} else if e == self.key_config.status_ignore_file
|
||||||
self.index_add_all()
|
&& self.is_working_dir
|
||||||
);
|
&& !self.is_empty()
|
||||||
} else {
|
{
|
||||||
self.stage_remove_all()?;
|
Ok(self.add_to_ignore())
|
||||||
}
|
} else {
|
||||||
|
Ok(false)
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
keys::STATUS_RESET_FILE
|
|
||||||
if self.is_working_dir =>
|
|
||||||
{
|
|
||||||
Ok(self.dispatch_reset_workdir())
|
|
||||||
}
|
|
||||||
|
|
||||||
keys::STATUS_IGNORE_FILE
|
|
||||||
if self.is_working_dir
|
|
||||||
&& !self.is_empty() =>
|
|
||||||
{
|
|
||||||
Ok(self.add_to_ignore())
|
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
///
|
///
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
|
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq)]
|
||||||
pub struct CommandText {
|
pub struct CommandText {
|
||||||
///
|
///
|
||||||
pub name: &'static str,
|
pub name: String,
|
||||||
///
|
///
|
||||||
pub desc: &'static str,
|
pub desc: &'static str,
|
||||||
///
|
///
|
||||||
@ -14,7 +14,7 @@ pub struct CommandText {
|
|||||||
impl CommandText {
|
impl CommandText {
|
||||||
///
|
///
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
name: &'static str,
|
name: String,
|
||||||
desc: &'static str,
|
desc: &'static str,
|
||||||
group: &'static str,
|
group: &'static str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -77,7 +77,7 @@ impl CommandInfo {
|
|||||||
}
|
}
|
||||||
///
|
///
|
||||||
pub fn print(&self, out: &mut String) {
|
pub fn print(&self, out: &mut String) {
|
||||||
out.push_str(self.text.name);
|
out.push_str(&self.text.name);
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
pub fn show_in_quickbar(&self) -> bool {
|
pub fn show_in_quickbar(&self) -> bool {
|
||||||
|
@ -4,9 +4,10 @@ use super::{
|
|||||||
ExternalEditorComponent,
|
ExternalEditorComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
get_app_config_path, keys,
|
get_app_config_path,
|
||||||
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -26,6 +27,7 @@ pub struct CommitComponent {
|
|||||||
input: TextInputComponent,
|
input: TextInputComponent,
|
||||||
amend: Option<CommitId>,
|
amend: Option<CommitId>,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for CommitComponent {
|
impl DrawableComponent for CommitComponent {
|
||||||
@ -50,19 +52,21 @@ impl Component for CommitComponent {
|
|||||||
|
|
||||||
if self.is_visible() || force_all {
|
if self.is_visible() || force_all {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::COMMIT_ENTER,
|
strings::commands::commit_enter(&self.key_config),
|
||||||
self.can_commit(),
|
self.can_commit(),
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::COMMIT_AMEND,
|
strings::commands::commit_amend(&self.key_config),
|
||||||
self.can_amend(),
|
self.can_amend(),
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::COMMIT_OPEN_EDITOR,
|
strings::commands::commit_open_editor(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
@ -78,25 +82,19 @@ impl Component for CommitComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
match e {
|
if e == self.key_config.enter && self.can_commit() {
|
||||||
keys::ENTER if self.can_commit() => {
|
self.commit()?;
|
||||||
self.commit()?;
|
} else if e == self.key_config.commit_amend
|
||||||
}
|
&& self.can_amend()
|
||||||
|
{
|
||||||
keys::COMMIT_AMEND if self.can_amend() => {
|
self.amend()?;
|
||||||
self.amend()?;
|
} else if e == self.key_config.open_commit_editor {
|
||||||
}
|
self.queue.borrow_mut().push_back(
|
||||||
|
InternalEvent::OpenExternalEditor(None),
|
||||||
keys::OPEN_COMMIT_EDITOR => {
|
);
|
||||||
self.queue.borrow_mut().push_back(
|
self.hide();
|
||||||
InternalEvent::OpenExternalEditor(None),
|
} else {
|
||||||
);
|
}
|
||||||
self.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
// stop key event propagation
|
// stop key event propagation
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@ -117,7 +115,8 @@ impl Component for CommitComponent {
|
|||||||
self.amend = None;
|
self.amend = None;
|
||||||
|
|
||||||
self.input.clear();
|
self.input.clear();
|
||||||
self.input.set_title(strings::COMMIT_TITLE.into());
|
self.input
|
||||||
|
.set_title(strings::commit_title(&self.key_config));
|
||||||
self.input.show()?;
|
self.input.show()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -126,15 +125,21 @@ impl Component for CommitComponent {
|
|||||||
|
|
||||||
impl CommitComponent {
|
impl CommitComponent {
|
||||||
///
|
///
|
||||||
pub fn new(queue: Queue, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
queue: Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue,
|
queue,
|
||||||
amend: None,
|
amend: None,
|
||||||
input: TextInputComponent::new(
|
input: TextInputComponent::new(
|
||||||
theme,
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
"",
|
"",
|
||||||
strings::COMMIT_MSG,
|
&strings::commit_msg(&key_config),
|
||||||
),
|
),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +155,10 @@ impl CommitComponent {
|
|||||||
"{}\n",
|
"{}\n",
|
||||||
self.input.get_text()
|
self.input.get_text()
|
||||||
))?;
|
))?;
|
||||||
file.write_all(strings::COMMIT_EDITOR_MSG.as_bytes())?;
|
file.write_all(
|
||||||
|
strings::commit_editor_msg(&self.key_config)
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalEditorComponent::open_file_in_editor(&config_path)?;
|
ExternalEditorComponent::open_file_in_editor(&config_path)?;
|
||||||
@ -251,7 +259,8 @@ impl CommitComponent {
|
|||||||
|
|
||||||
let details = sync::get_commit_details(CWD, id)?;
|
let details = sync::get_commit_details(CWD, id)?;
|
||||||
|
|
||||||
self.input.set_title(strings::COMMIT_TITLE_AMEND.into());
|
self.input
|
||||||
|
.set_title(strings::commit_title_amend(&self.key_config));
|
||||||
|
|
||||||
if let Some(msg) = details.message {
|
if let Some(msg) = details.message {
|
||||||
self.input.set_text(msg.combine());
|
self.input.set_text(msg.combine());
|
||||||
|
@ -3,8 +3,8 @@ use crate::{
|
|||||||
dialog_paragraph, utils::time_to_string, CommandBlocking,
|
dialog_paragraph, utils::time_to_string, CommandBlocking,
|
||||||
CommandInfo, Component, DrawableComponent, ScrollType,
|
CommandInfo, Component, DrawableComponent, ScrollType,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
strings::{self, commands, order},
|
strings::{self, order},
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -24,6 +24,13 @@ use tui::{
|
|||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Detail {
|
||||||
|
Author,
|
||||||
|
Date,
|
||||||
|
Commiter,
|
||||||
|
Sha,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DetailsComponent {
|
pub struct DetailsComponent {
|
||||||
data: Option<CommitDetails>,
|
data: Option<CommitDetails>,
|
||||||
tags: Vec<String>,
|
tags: Vec<String>,
|
||||||
@ -31,6 +38,7 @@ pub struct DetailsComponent {
|
|||||||
focused: bool,
|
focused: bool,
|
||||||
current_size: Cell<(u16, u16)>,
|
current_size: Cell<(u16, u16)>,
|
||||||
scroll_top: Cell<usize>,
|
scroll_top: Cell<usize>,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
type WrappedCommitMessage<'a> =
|
type WrappedCommitMessage<'a> =
|
||||||
@ -38,7 +46,11 @@ type WrappedCommitMessage<'a> =
|
|||||||
|
|
||||||
impl DetailsComponent {
|
impl DetailsComponent {
|
||||||
///
|
///
|
||||||
pub const fn new(theme: SharedTheme, focused: bool) -> Self {
|
pub const fn new(
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
focused: bool,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: None,
|
data: None,
|
||||||
tags: Vec::new(),
|
tags: Vec::new(),
|
||||||
@ -46,6 +58,7 @@ impl DetailsComponent {
|
|||||||
focused,
|
focused,
|
||||||
current_size: Cell::new((0, 0)),
|
current_size: Cell::new((0, 0)),
|
||||||
scroll_top: Cell::new(0),
|
scroll_top: Cell::new(0),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,15 +160,41 @@ impl DetailsComponent {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn style_detail(&self, field: &Detail) -> Text {
|
||||||
|
match field {
|
||||||
|
Detail::Author => Text::Styled(
|
||||||
|
Cow::from(strings::commit::details_author(
|
||||||
|
&self.key_config,
|
||||||
|
)),
|
||||||
|
self.theme.text(false, false),
|
||||||
|
),
|
||||||
|
Detail::Date => Text::Styled(
|
||||||
|
Cow::from(strings::commit::details_date(
|
||||||
|
&self.key_config,
|
||||||
|
)),
|
||||||
|
self.theme.text(false, false),
|
||||||
|
),
|
||||||
|
Detail::Commiter => Text::Styled(
|
||||||
|
Cow::from(strings::commit::details_committer(
|
||||||
|
&self.key_config,
|
||||||
|
)),
|
||||||
|
self.theme.text(false, false),
|
||||||
|
),
|
||||||
|
Detail::Sha => Text::Styled(
|
||||||
|
Cow::from(strings::commit::details_tags(
|
||||||
|
&self.key_config,
|
||||||
|
)),
|
||||||
|
self.theme.text(false, false),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_text_info(&self) -> Vec<Text> {
|
fn get_text_info(&self) -> Vec<Text> {
|
||||||
let new_line = Text::Raw(Cow::from("\n"));
|
let new_line = Text::Raw(Cow::from("\n"));
|
||||||
|
|
||||||
if let Some(ref data) = self.data {
|
if let Some(ref data) = self.data {
|
||||||
let mut res = vec![
|
let mut res = vec![
|
||||||
Text::Styled(
|
self.style_detail(&Detail::Author),
|
||||||
Cow::from(strings::commit::DETAILS_AUTHOR),
|
|
||||||
self.theme.text(false, false),
|
|
||||||
),
|
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
Cow::from(format!(
|
Cow::from(format!(
|
||||||
"{} <{}>",
|
"{} <{}>",
|
||||||
@ -164,10 +203,7 @@ impl DetailsComponent {
|
|||||||
self.theme.text(true, false),
|
self.theme.text(true, false),
|
||||||
),
|
),
|
||||||
new_line.clone(),
|
new_line.clone(),
|
||||||
Text::Styled(
|
self.style_detail(&Detail::Date),
|
||||||
Cow::from(strings::commit::DETAILS_DATE),
|
|
||||||
self.theme.text(false, false),
|
|
||||||
),
|
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
Cow::from(time_to_string(
|
Cow::from(time_to_string(
|
||||||
data.author.time,
|
data.author.time,
|
||||||
@ -180,10 +216,7 @@ impl DetailsComponent {
|
|||||||
|
|
||||||
if let Some(ref committer) = data.committer {
|
if let Some(ref committer) = data.committer {
|
||||||
res.extend(vec![
|
res.extend(vec![
|
||||||
Text::Styled(
|
self.style_detail(&Detail::Commiter),
|
||||||
Cow::from(strings::commit::DETAILS_COMMITTER),
|
|
||||||
self.theme.text(false, false),
|
|
||||||
),
|
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
Cow::from(format!(
|
Cow::from(format!(
|
||||||
"{} <{}>",
|
"{} <{}>",
|
||||||
@ -192,10 +225,7 @@ impl DetailsComponent {
|
|||||||
self.theme.text(true, false),
|
self.theme.text(true, false),
|
||||||
),
|
),
|
||||||
new_line.clone(),
|
new_line.clone(),
|
||||||
Text::Styled(
|
self.style_detail(&Detail::Date),
|
||||||
Cow::from(strings::commit::DETAILS_DATE),
|
|
||||||
self.theme.text(false, false),
|
|
||||||
),
|
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
Cow::from(time_to_string(
|
Cow::from(time_to_string(
|
||||||
committer.time,
|
committer.time,
|
||||||
@ -209,7 +239,9 @@ impl DetailsComponent {
|
|||||||
|
|
||||||
res.extend(vec![
|
res.extend(vec![
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
Cow::from(strings::commit::DETAILS_SHA),
|
Cow::from(strings::commit::details_sha(
|
||||||
|
&self.key_config,
|
||||||
|
)),
|
||||||
self.theme.text(false, false),
|
self.theme.text(false, false),
|
||||||
),
|
),
|
||||||
Text::Styled(
|
Text::Styled(
|
||||||
@ -220,11 +252,7 @@ impl DetailsComponent {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if !self.tags.is_empty() {
|
if !self.tags.is_empty() {
|
||||||
res.push(Text::Styled(
|
res.push(self.style_detail(&Detail::Sha));
|
||||||
Cow::from(strings::commit::DETAILS_TAGS),
|
|
||||||
self.theme.text(false, false),
|
|
||||||
));
|
|
||||||
|
|
||||||
res.extend(
|
res.extend(
|
||||||
self.tags
|
self.tags
|
||||||
.iter()
|
.iter()
|
||||||
@ -295,7 +323,9 @@ impl DrawableComponent for DetailsComponent {
|
|||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
dialog_paragraph(
|
dialog_paragraph(
|
||||||
strings::commit::DETAILS_INFO_TITLE,
|
&strings::commit::details_info_title(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
self.get_text_info().iter(),
|
self.get_text_info().iter(),
|
||||||
&self.theme,
|
&self.theme,
|
||||||
false,
|
false,
|
||||||
@ -319,7 +349,9 @@ impl DrawableComponent for DetailsComponent {
|
|||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
dialog_paragraph(
|
dialog_paragraph(
|
||||||
strings::commit::DETAILS_MESSAGE_TITLE,
|
&strings::commit::details_message_title(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
wrapped_lines.iter(),
|
wrapped_lines.iter(),
|
||||||
&self.theme,
|
&self.theme,
|
||||||
self.focused,
|
self.focused,
|
||||||
@ -344,7 +376,9 @@ impl Component for DetailsComponent {
|
|||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::NAVIGATE_COMMIT_MESSAGE,
|
strings::commands::navigate_commit_message(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
number_of_lines > 0,
|
number_of_lines > 0,
|
||||||
self.focused || force_all,
|
self.focused || force_all,
|
||||||
)
|
)
|
||||||
@ -357,20 +391,20 @@ impl Component for DetailsComponent {
|
|||||||
fn event(&mut self, event: Event) -> Result<bool> {
|
fn event(&mut self, event: Event) -> Result<bool> {
|
||||||
if self.focused {
|
if self.focused {
|
||||||
if let Event::Key(e) = event {
|
if let Event::Key(e) = event {
|
||||||
return match e {
|
return if e == self.key_config.move_up {
|
||||||
keys::MOVE_UP => {
|
self.move_scroll_top(ScrollType::Up)
|
||||||
self.move_scroll_top(ScrollType::Up)
|
} else if e == self.key_config.move_down {
|
||||||
}
|
self.move_scroll_top(ScrollType::Down)
|
||||||
keys::MOVE_DOWN => {
|
} else if e == self.key_config.home
|
||||||
self.move_scroll_top(ScrollType::Down)
|
|| e == self.key_config.shift_up
|
||||||
}
|
{
|
||||||
keys::HOME | keys::SHIFT_UP => {
|
self.move_scroll_top(ScrollType::Home)
|
||||||
self.move_scroll_top(ScrollType::Home)
|
} else if e == self.key_config.end
|
||||||
}
|
|| e == self.key_config.shift_down
|
||||||
keys::END | keys::SHIFT_DOWN => {
|
{
|
||||||
self.move_scroll_top(ScrollType::End)
|
self.move_scroll_top(ScrollType::End)
|
||||||
}
|
} else {
|
||||||
_ => Ok(false),
|
Ok(false)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ use super::{
|
|||||||
Component, DrawableComponent, FileTreeComponent,
|
Component, DrawableComponent, FileTreeComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
accessors, keys, queue::Queue, strings, ui::style::SharedTheme,
|
accessors, keys::SharedKeyConfig, queue::Queue, strings,
|
||||||
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use asyncgit::{
|
use asyncgit::{
|
||||||
@ -26,6 +27,7 @@ pub struct CommitDetailsComponent {
|
|||||||
file_tree: FileTreeComponent,
|
file_tree: FileTreeComponent,
|
||||||
git_commit_files: AsyncCommitFiles,
|
git_commit_files: AsyncCommitFiles,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitDetailsComponent {
|
impl CommitDetailsComponent {
|
||||||
@ -36,17 +38,24 @@ impl CommitDetailsComponent {
|
|||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
details: DetailsComponent::new(theme.clone(), false),
|
details: DetailsComponent::new(
|
||||||
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
false,
|
||||||
|
),
|
||||||
git_commit_files: AsyncCommitFiles::new(sender),
|
git_commit_files: AsyncCommitFiles::new(sender),
|
||||||
file_tree: FileTreeComponent::new(
|
file_tree: FileTreeComponent::new(
|
||||||
"",
|
"",
|
||||||
false,
|
false,
|
||||||
Some(queue.clone()),
|
Some(queue.clone()),
|
||||||
theme,
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
visible: false,
|
visible: false,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +64,7 @@ impl CommitDetailsComponent {
|
|||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
strings::commit::DETAILS_FILES_TITLE,
|
strings::commit::details_files_title(&self.key_config),
|
||||||
files_count
|
files_count
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -148,22 +157,20 @@ impl Component for CommitDetailsComponent {
|
|||||||
|
|
||||||
if self.focused() {
|
if self.focused() {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
return match e {
|
return if e == self.key_config.focus_below
|
||||||
keys::FOCUS_BELOW if (self.details.focused()) => {
|
&& self.details.focused()
|
||||||
self.details.focus(false);
|
{
|
||||||
self.file_tree.focus(true);
|
self.details.focus(false);
|
||||||
|
self.file_tree.focus(true);
|
||||||
return Ok(true);
|
Ok(true)
|
||||||
}
|
} else if e == self.key_config.focus_above
|
||||||
keys::FOCUS_ABOVE
|
&& self.file_tree.focused()
|
||||||
if (self.file_tree.focused()) =>
|
{
|
||||||
{
|
self.file_tree.focus(false);
|
||||||
self.file_tree.focus(false);
|
self.details.focus(true);
|
||||||
self.details.focus(true);
|
Ok(true)
|
||||||
|
} else {
|
||||||
return Ok(true);
|
Ok(false)
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ use crate::{
|
|||||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||||
ScrollType,
|
ScrollType,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
strings::commands,
|
strings,
|
||||||
ui::calc_scroll_top,
|
ui::calc_scroll_top,
|
||||||
ui::style::{SharedTheme, Theme},
|
ui::style::{SharedTheme, Theme},
|
||||||
};
|
};
|
||||||
@ -37,11 +37,16 @@ pub struct CommitList {
|
|||||||
current_size: Cell<(u16, u16)>,
|
current_size: Cell<(u16, u16)>,
|
||||||
scroll_top: Cell<usize>,
|
scroll_top: Cell<usize>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitList {
|
impl CommitList {
|
||||||
///
|
///
|
||||||
pub fn new(title: &str, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
title: &str,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
items: ItemBatch::default(),
|
items: ItemBatch::default(),
|
||||||
selection: 0,
|
selection: 0,
|
||||||
@ -52,6 +57,7 @@ impl CommitList {
|
|||||||
current_size: Cell::new((0, 0)),
|
current_size: Cell::new((0, 0)),
|
||||||
scroll_top: Cell::new(0),
|
scroll_top: Cell::new(0),
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
title: String::from(title),
|
title: String::from(title),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,10 +178,10 @@ impl CommitList {
|
|||||||
self.scroll_state.1 = speed.min(SCROLL_SPEED_MAX);
|
self.scroll_state.1 = speed.min(SCROLL_SPEED_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_entry<'a>(
|
fn add_entry<'b>(
|
||||||
e: &'a LogEntry,
|
e: &'b LogEntry,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
txt: &mut Vec<Text<'a>>,
|
txt: &mut Vec<Text<'b>>,
|
||||||
tags: Option<String>,
|
tags: Option<String>,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
width: usize,
|
width: usize,
|
||||||
@ -331,28 +337,25 @@ impl DrawableComponent for CommitList {
|
|||||||
impl Component for CommitList {
|
impl Component for CommitList {
|
||||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||||
if let Event::Key(k) = ev {
|
if let Event::Key(k) = ev {
|
||||||
let selection_changed = match k {
|
let selection_changed = if k == self.key_config.move_up {
|
||||||
keys::MOVE_UP => {
|
self.move_selection(ScrollType::Up)?
|
||||||
self.move_selection(ScrollType::Up)?
|
} else if k == self.key_config.move_down {
|
||||||
}
|
self.move_selection(ScrollType::Down)?
|
||||||
keys::MOVE_DOWN => {
|
} else if k == self.key_config.shift_up
|
||||||
self.move_selection(ScrollType::Down)?
|
|| k == self.key_config.home
|
||||||
}
|
{
|
||||||
keys::SHIFT_UP | keys::HOME => {
|
self.move_selection(ScrollType::Home)?
|
||||||
self.move_selection(ScrollType::Home)?
|
} else if k == self.key_config.shift_down
|
||||||
}
|
|| k == self.key_config.end
|
||||||
keys::SHIFT_DOWN | keys::END => {
|
{
|
||||||
self.move_selection(ScrollType::End)?
|
self.move_selection(ScrollType::End)?
|
||||||
}
|
} else if k == self.key_config.page_up {
|
||||||
keys::PAGE_UP => {
|
self.move_selection(ScrollType::PageUp)?
|
||||||
self.move_selection(ScrollType::PageUp)?
|
} else if k == self.key_config.page_down {
|
||||||
}
|
self.move_selection(ScrollType::PageDown)?
|
||||||
keys::PAGE_DOWN => {
|
} else {
|
||||||
self.move_selection(ScrollType::PageDown)?
|
false
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(selection_changed);
|
return Ok(selection_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,7 +368,7 @@ impl Component for CommitList {
|
|||||||
_force_all: bool,
|
_force_all: bool,
|
||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::SCROLL,
|
strings::commands::scroll(&self.key_config),
|
||||||
self.selected_entry().is_some(),
|
self.selected_entry().is_some(),
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
|
@ -3,10 +3,9 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{CommandInfo, Component},
|
components::{CommandInfo, Component},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
|
||||||
strings::{self, commands},
|
strings, try_or_popup,
|
||||||
try_or_popup,
|
|
||||||
ui::{calc_scroll_top, style::SharedTheme},
|
ui::{calc_scroll_top, style::SharedTheme},
|
||||||
};
|
};
|
||||||
use asyncgit::{hash, sync, DiffLine, DiffLineType, FileDiff, CWD};
|
use asyncgit::{hash, sync, DiffLine, DiffLineType, FileDiff, CWD};
|
||||||
@ -106,6 +105,7 @@ pub struct DiffComponent {
|
|||||||
scroll_top: Cell<usize>,
|
scroll_top: Cell<usize>,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
is_immutable: bool,
|
is_immutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +114,7 @@ impl DiffComponent {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
is_immutable: bool,
|
is_immutable: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -127,6 +128,7 @@ impl DiffComponent {
|
|||||||
selection: Selection::Single(0),
|
selection: Selection::Single(0),
|
||||||
scroll_top: Cell::new(0),
|
scroll_top: Cell::new(0),
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
is_immutable,
|
is_immutable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,12 +558,15 @@ impl DrawableComponent for DiffComponent {
|
|||||||
self.selection.get_end(),
|
self.selection.get_end(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let title =
|
let title = format!(
|
||||||
format!("{}{}", strings::TITLE_DIFF, self.current.path);
|
"{}{}",
|
||||||
|
strings::title_diff(&self.key_config),
|
||||||
|
self.current.path
|
||||||
|
);
|
||||||
|
|
||||||
let txt = if self.pending {
|
let txt = if self.pending {
|
||||||
vec![Text::Styled(
|
vec![Text::Styled(
|
||||||
Cow::from(strings::LOADING_TEXT),
|
Cow::from(strings::loading_text(&self.key_config)),
|
||||||
self.theme.text(false, false),
|
self.theme.text(false, false),
|
||||||
)]
|
)]
|
||||||
} else {
|
} else {
|
||||||
@ -590,20 +595,20 @@ impl Component for DiffComponent {
|
|||||||
_force_all: bool,
|
_force_all: bool,
|
||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::SCROLL,
|
strings::commands::scroll(&self.key_config),
|
||||||
self.can_scroll(),
|
self.can_scroll(),
|
||||||
self.focused,
|
self.focused,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::COPY,
|
strings::commands::copy(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.focused,
|
self.focused,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::DIFF_HOME_END,
|
strings::commands::diff_home_end(&self.key_config),
|
||||||
self.can_scroll(),
|
self.can_scroll(),
|
||||||
self.focused,
|
self.focused,
|
||||||
)
|
)
|
||||||
@ -612,17 +617,17 @@ impl Component for DiffComponent {
|
|||||||
|
|
||||||
if !self.is_immutable {
|
if !self.is_immutable {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_HUNK_REMOVE,
|
strings::commands::diff_hunk_remove(&self.key_config),
|
||||||
self.selected_hunk.is_some(),
|
self.selected_hunk.is_some(),
|
||||||
self.focused && self.is_stage(),
|
self.focused && self.is_stage(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_HUNK_ADD,
|
strings::commands::diff_hunk_add(&self.key_config),
|
||||||
self.selected_hunk.is_some(),
|
self.selected_hunk.is_some(),
|
||||||
self.focused && !self.is_stage(),
|
self.focused && !self.is_stage(),
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_HUNK_REVERT,
|
strings::commands::diff_hunk_revert(&self.key_config),
|
||||||
self.selected_hunk.is_some(),
|
self.selected_hunk.is_some(),
|
||||||
self.focused && !self.is_stage(),
|
self.focused && !self.is_stage(),
|
||||||
));
|
));
|
||||||
@ -634,64 +639,56 @@ impl Component for DiffComponent {
|
|||||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||||
if self.focused {
|
if self.focused {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
return match e {
|
return if e == self.key_config.move_down {
|
||||||
keys::MOVE_DOWN => {
|
self.move_selection(ScrollType::Down)?;
|
||||||
self.move_selection(ScrollType::Down)?;
|
Ok(true)
|
||||||
Ok(true)
|
} else if e == self.key_config.shift_down {
|
||||||
|
self.modify_selection(Direction::Down)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.shift_up {
|
||||||
|
self.modify_selection(Direction::Up)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.end {
|
||||||
|
self.move_selection(ScrollType::End)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.home {
|
||||||
|
self.move_selection(ScrollType::Home)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.move_up {
|
||||||
|
self.move_selection(ScrollType::Up)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.page_up {
|
||||||
|
self.move_selection(ScrollType::PageUp)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.page_down {
|
||||||
|
self.move_selection(ScrollType::PageDown)?;
|
||||||
|
Ok(true)
|
||||||
|
} else if e == self.key_config.enter
|
||||||
|
&& !self.is_immutable
|
||||||
|
{
|
||||||
|
if self.current.is_stage {
|
||||||
|
self.unstage_hunk()?;
|
||||||
|
} else {
|
||||||
|
self.stage_hunk()?;
|
||||||
}
|
}
|
||||||
keys::SHIFT_DOWN => {
|
Ok(true)
|
||||||
self.modify_selection(Direction::Down)?;
|
} else if e == self.key_config.diff_reset_hunk
|
||||||
Ok(true)
|
&& !self.is_immutable
|
||||||
}
|
&& !self.is_stage()
|
||||||
keys::SHIFT_UP => {
|
{
|
||||||
self.modify_selection(Direction::Up)?;
|
if let Some(diff) = &self.diff {
|
||||||
Ok(true)
|
if diff.untracked {
|
||||||
}
|
self.reset_untracked()?;
|
||||||
keys::END => {
|
|
||||||
self.move_selection(ScrollType::End)?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::HOME => {
|
|
||||||
self.move_selection(ScrollType::Home)?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::MOVE_UP => {
|
|
||||||
self.move_selection(ScrollType::Up)?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::PAGE_UP => {
|
|
||||||
self.move_selection(ScrollType::PageUp)?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::PAGE_DOWN => {
|
|
||||||
self.move_selection(ScrollType::PageDown)?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::ENTER if !self.is_immutable => {
|
|
||||||
if self.current.is_stage {
|
|
||||||
self.unstage_hunk()?;
|
|
||||||
} else {
|
} else {
|
||||||
self.stage_hunk()?;
|
self.reset_hunk()?;
|
||||||
}
|
}
|
||||||
Ok(true)
|
|
||||||
}
|
}
|
||||||
keys::DIFF_RESET_HUNK
|
Ok(true)
|
||||||
if !self.is_immutable && !self.is_stage() =>
|
} else if e == self.key_config.copy {
|
||||||
{
|
self.copy_selection()?;
|
||||||
if let Some(diff) = &self.diff {
|
Ok(true)
|
||||||
if diff.untracked {
|
} else {
|
||||||
self.reset_untracked()?;
|
Ok(false)
|
||||||
} else {
|
|
||||||
self.reset_hunk()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
keys::COPY => {
|
|
||||||
self.copy_selection()?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use crate::{
|
|||||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
DrawableComponent,
|
DrawableComponent,
|
||||||
},
|
},
|
||||||
|
keys::SharedKeyConfig,
|
||||||
strings,
|
strings,
|
||||||
ui::{self, style::SharedTheme},
|
ui::{self, style::SharedTheme},
|
||||||
};
|
};
|
||||||
@ -27,14 +28,19 @@ use tui::{
|
|||||||
pub struct ExternalEditorComponent {
|
pub struct ExternalEditorComponent {
|
||||||
visible: bool,
|
visible: bool,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalEditorComponent {
|
impl ExternalEditorComponent {
|
||||||
///
|
///
|
||||||
pub fn new(theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
visible: false,
|
visible: false,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +99,9 @@ impl DrawableComponent for ExternalEditorComponent {
|
|||||||
_rect: Rect,
|
_rect: Rect,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if self.visible {
|
if self.visible {
|
||||||
let txt =
|
let txt = vec![Text::Raw(
|
||||||
vec![Text::Raw(strings::MSG_OPENING_EDITOR.into())];
|
strings::msg_opening_editor(&self.key_config).into(),
|
||||||
|
)];
|
||||||
|
|
||||||
let area = ui::centered_rect_absolute(25, 3, f.size());
|
let area = ui::centered_rect_absolute(25, 3, f.size());
|
||||||
f.render_widget(Clear, area);
|
f.render_widget(Clear, area);
|
||||||
|
@ -7,9 +7,9 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{CommandInfo, Component},
|
components::{CommandInfo, Component},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||||
strings::{self, commands, order},
|
strings::{self, order},
|
||||||
ui,
|
ui,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
@ -29,6 +29,7 @@ pub struct FileTreeComponent {
|
|||||||
show_selection: bool,
|
show_selection: bool,
|
||||||
queue: Option<Queue>,
|
queue: Option<Queue>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
scroll_top: Cell<usize>,
|
scroll_top: Cell<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ impl FileTreeComponent {
|
|||||||
focus: bool,
|
focus: bool,
|
||||||
queue: Option<Queue>,
|
queue: Option<Queue>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
@ -48,6 +50,7 @@ impl FileTreeComponent {
|
|||||||
show_selection: focus,
|
show_selection: focus,
|
||||||
queue,
|
queue,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
scroll_top: Cell::new(0),
|
scroll_top: Cell::new(0),
|
||||||
pending: true,
|
pending: true,
|
||||||
}
|
}
|
||||||
@ -134,12 +137,12 @@ impl FileTreeComponent {
|
|||||||
changed
|
changed
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_to_text<'a>(
|
fn item_to_text<'b>(
|
||||||
item: &FileTreeItem,
|
item: &FileTreeItem,
|
||||||
width: u16,
|
width: u16,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
theme: &'a SharedTheme,
|
theme: &'b SharedTheme,
|
||||||
) -> Option<Text<'a>> {
|
) -> Option<Text<'b>> {
|
||||||
let indent_str = if item.info.indent == 0 {
|
let indent_str = if item.info.indent == 0 {
|
||||||
String::from("")
|
String::from("")
|
||||||
} else {
|
} else {
|
||||||
@ -223,7 +226,7 @@ impl DrawableComponent for FileTreeComponent {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if self.pending {
|
if self.pending {
|
||||||
let items = vec![Text::Styled(
|
let items = vec![Text::Styled(
|
||||||
Cow::from(strings::LOADING_TEXT),
|
Cow::from(strings::loading_text(&self.key_config)),
|
||||||
self.theme.text(false, false),
|
self.theme.text(false, false),
|
||||||
)];
|
)];
|
||||||
|
|
||||||
@ -309,7 +312,7 @@ impl Component for FileTreeComponent {
|
|||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::NAVIGATE_TREE,
|
strings::commands::navigate_tree(&self.key_config),
|
||||||
!self.is_empty(),
|
!self.is_empty(),
|
||||||
self.focused || force_all,
|
self.focused || force_all,
|
||||||
)
|
)
|
||||||
@ -322,26 +325,24 @@ impl Component for FileTreeComponent {
|
|||||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||||
if self.focused {
|
if self.focused {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
return match e {
|
return if e == self.key_config.move_down {
|
||||||
keys::MOVE_DOWN => {
|
Ok(self.move_selection(MoveSelection::Down))
|
||||||
Ok(self.move_selection(MoveSelection::Down))
|
} else if e == self.key_config.move_up {
|
||||||
}
|
Ok(self.move_selection(MoveSelection::Up))
|
||||||
keys::MOVE_UP => {
|
} else if e == self.key_config.home
|
||||||
Ok(self.move_selection(MoveSelection::Up))
|
|| e == self.key_config.shift_up
|
||||||
}
|
{
|
||||||
keys::HOME | keys::SHIFT_UP => {
|
Ok(self.move_selection(MoveSelection::Home))
|
||||||
Ok(self.move_selection(MoveSelection::Home))
|
} else if e == self.key_config.end
|
||||||
}
|
|| e == self.key_config.shift_down
|
||||||
keys::END | keys::SHIFT_DOWN => {
|
{
|
||||||
Ok(self.move_selection(MoveSelection::End))
|
Ok(self.move_selection(MoveSelection::End))
|
||||||
}
|
} else if e == self.key_config.move_left {
|
||||||
keys::MOVE_LEFT => {
|
Ok(self.move_selection(MoveSelection::Left))
|
||||||
Ok(self.move_selection(MoveSelection::Left))
|
} else if e == self.key_config.move_right {
|
||||||
}
|
Ok(self.move_selection(MoveSelection::Right))
|
||||||
keys::MOVE_RIGHT => {
|
} else {
|
||||||
Ok(self.move_selection(MoveSelection::Right))
|
Ok(false)
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,7 @@ use super::{
|
|||||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
DrawableComponent,
|
DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{keys::SharedKeyConfig, strings, ui, version::Version};
|
||||||
keys,
|
|
||||||
strings::{self, commands},
|
|
||||||
ui,
|
|
||||||
version::Version,
|
|
||||||
};
|
|
||||||
use asyncgit::hash;
|
use asyncgit::hash;
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -29,6 +24,7 @@ pub struct HelpComponent {
|
|||||||
visible: bool,
|
visible: bool,
|
||||||
selection: u16,
|
selection: u16,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for HelpComponent {
|
impl DrawableComponent for HelpComponent {
|
||||||
@ -49,7 +45,7 @@ impl DrawableComponent for HelpComponent {
|
|||||||
f.render_widget(Clear, area);
|
f.render_widget(Clear, area);
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title(strings::HELP_TITLE)
|
.title(&strings::help_title(&self.key_config))
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Thick),
|
.border_type(BorderType::Thick),
|
||||||
area,
|
area,
|
||||||
@ -104,10 +100,14 @@ impl Component for HelpComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.visible {
|
if self.visible {
|
||||||
out.push(CommandInfo::new(commands::SCROLL, true, true));
|
out.push(CommandInfo::new(
|
||||||
|
strings::commands::scroll(&self.key_config),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::CLOSE_POPUP,
|
strings::commands::close_popup(&self.key_config),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
@ -115,8 +115,12 @@ impl Component for HelpComponent {
|
|||||||
|
|
||||||
if !self.visible || force_all {
|
if !self.visible || force_all {
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(commands::HELP_OPEN, true, true)
|
CommandInfo::new(
|
||||||
.order(99),
|
strings::commands::help_open(&self.key_config),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.order(99),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,18 +130,24 @@ impl Component for HelpComponent {
|
|||||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||||
if self.visible {
|
if self.visible {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
match e {
|
if e == self.key_config.exit_popup {
|
||||||
keys::EXIT_POPUP => self.hide(),
|
self.hide()
|
||||||
keys::MOVE_DOWN => self.move_selection(true),
|
} else if e == self.key_config.move_down {
|
||||||
keys::MOVE_UP => self.move_selection(false),
|
self.move_selection(true)
|
||||||
_ => (),
|
} else if e == self.key_config.move_up {
|
||||||
|
self.move_selection(false)
|
||||||
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else if let Event::Key(keys::OPEN_HELP) = ev {
|
} else if let Event::Key(k) = ev {
|
||||||
self.show()?;
|
if k == self.key_config.open_help {
|
||||||
Ok(true)
|
self.show()?;
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
@ -159,12 +169,16 @@ impl Component for HelpComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HelpComponent {
|
impl HelpComponent {
|
||||||
pub const fn new(theme: SharedTheme) -> Self {
|
pub const fn new(
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cmds: vec![],
|
cmds: vec![],
|
||||||
visible: false,
|
visible: false,
|
||||||
selection: 0,
|
selection: 0,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@ -173,8 +187,8 @@ impl HelpComponent {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|e| !e.text.hide_help)
|
.filter(|e| !e.text.hide_help)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
self.cmds.sort_by_key(|e| e.text);
|
self.cmds.sort_by_key(|e| e.text.clone());
|
||||||
self.cmds.dedup_by_key(|e| e.text);
|
self.cmds.dedup_by_key(|e| e.text.clone());
|
||||||
self.cmds.sort_by_key(|e| hash(&e.text.group));
|
self.cmds.sort_by_key(|e| hash(&e.text.group));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use super::{
|
|||||||
DrawableComponent,
|
DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
accessors, keys, queue::Queue, strings::commands,
|
accessors, keys::SharedKeyConfig, queue::Queue, strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -28,6 +28,7 @@ pub struct InspectCommitComponent {
|
|||||||
details: CommitDetailsComponent,
|
details: CommitDetailsComponent,
|
||||||
git_diff: AsyncDiff,
|
git_diff: AsyncDiff,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for InspectCommitComponent {
|
impl DrawableComponent for InspectCommitComponent {
|
||||||
@ -78,18 +79,22 @@ impl Component for InspectCommitComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(commands::CLOSE_POPUP, true, true)
|
CommandInfo::new(
|
||||||
.order(1),
|
strings::commands::close_popup(&self.key_config),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.order(1),
|
||||||
);
|
);
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_FOCUS_RIGHT,
|
strings::commands::diff_focus_right(&self.key_config),
|
||||||
self.can_focus_diff(),
|
self.can_focus_diff(),
|
||||||
!self.diff.focused() || force_all,
|
!self.diff.focused() || force_all,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_FOCUS_LEFT,
|
strings::commands::diff_focus_left(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.diff.focused() || force_all,
|
self.diff.focused() || force_all,
|
||||||
));
|
));
|
||||||
@ -105,19 +110,19 @@ impl Component for InspectCommitComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
match e {
|
if e == self.key_config.exit_popup {
|
||||||
keys::EXIT_POPUP => {
|
self.hide();
|
||||||
self.hide();
|
} else if e == self.key_config.focus_right
|
||||||
}
|
&& self.can_focus_diff()
|
||||||
keys::FOCUS_RIGHT if 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.focus_left
|
||||||
keys::FOCUS_LEFT if self.diff.focused() => {
|
&& self.diff.focused()
|
||||||
self.details.focus(true);
|
{
|
||||||
self.diff.focus(false);
|
self.details.focus(true);
|
||||||
}
|
self.diff.focus(false);
|
||||||
_ => (),
|
} else {
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop key event propagation
|
// stop key event propagation
|
||||||
@ -152,18 +157,26 @@ impl InspectCommitComponent {
|
|||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
details: CommitDetailsComponent::new(
|
details: CommitDetailsComponent::new(
|
||||||
queue,
|
queue,
|
||||||
sender,
|
sender,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
diff: DiffComponent::new(
|
||||||
|
queue.clone(),
|
||||||
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
diff: DiffComponent::new(queue.clone(), theme, true),
|
|
||||||
commit_id: None,
|
commit_id: None,
|
||||||
tags: None,
|
tags: None,
|
||||||
git_diff: AsyncDiff::new(sender.clone()),
|
git_diff: AsyncDiff::new(sender.clone()),
|
||||||
visible: false,
|
visible: false,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,7 @@ use super::{
|
|||||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||||
DrawableComponent,
|
DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{keys::SharedKeyConfig, strings, ui};
|
||||||
keys,
|
|
||||||
strings::{self, commands},
|
|
||||||
ui,
|
|
||||||
};
|
|
||||||
use crossterm::event::Event;
|
use crossterm::event::Event;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use tui::{
|
use tui::{
|
||||||
@ -21,6 +17,7 @@ pub struct MsgComponent {
|
|||||||
msg: String,
|
msg: String,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -42,7 +39,9 @@ impl DrawableComponent for MsgComponent {
|
|||||||
Paragraph::new(txt.iter())
|
Paragraph::new(txt.iter())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.title(strings::MSG_TITLE_ERROR)
|
.title(&strings::msg_title_error(
|
||||||
|
&self.key_config,
|
||||||
|
))
|
||||||
.title_style(self.theme.text_danger())
|
.title_style(self.theme.text_danger())
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Thick),
|
.border_type(BorderType::Thick),
|
||||||
@ -63,7 +62,7 @@ impl Component for MsgComponent {
|
|||||||
_force_all: bool,
|
_force_all: bool,
|
||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::CLOSE_MSG,
|
strings::commands::close_msg(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible,
|
self.visible,
|
||||||
));
|
));
|
||||||
@ -74,7 +73,7 @@ impl Component for MsgComponent {
|
|||||||
fn event(&mut self, ev: Event) -> Result<bool> {
|
fn event(&mut self, ev: Event) -> Result<bool> {
|
||||||
if self.visible {
|
if self.visible {
|
||||||
if let Event::Key(e) = ev {
|
if let Event::Key(e) = ev {
|
||||||
if let keys::CLOSE_MSG = e {
|
if e == self.key_config.close_msg {
|
||||||
self.hide();
|
self.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,11 +99,15 @@ impl Component for MsgComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MsgComponent {
|
impl MsgComponent {
|
||||||
pub const fn new(theme: SharedTheme) -> Self {
|
pub const fn new(
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
msg: String::new(),
|
msg: String::new(),
|
||||||
visible: false,
|
visible: false,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
|
@ -3,9 +3,9 @@ use crate::{
|
|||||||
popup_paragraph, visibility_blocking, CommandBlocking,
|
popup_paragraph, visibility_blocking, CommandBlocking,
|
||||||
CommandInfo, Component, DrawableComponent,
|
CommandInfo, Component, DrawableComponent,
|
||||||
},
|
},
|
||||||
|
keys::SharedKeyConfig,
|
||||||
queue::{Action, InternalEvent, Queue},
|
queue::{Action, InternalEvent, Queue},
|
||||||
strings::{self, commands},
|
strings, ui,
|
||||||
ui,
|
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::event::{Event, KeyCode};
|
use crossterm::event::{Event, KeyCode};
|
||||||
@ -24,6 +24,7 @@ pub struct ResetComponent {
|
|||||||
visible: bool,
|
visible: bool,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for ResetComponent {
|
impl DrawableComponent for ResetComponent {
|
||||||
@ -43,7 +44,12 @@ impl DrawableComponent for ResetComponent {
|
|||||||
let area = ui::centered_rect(30, 20, f.size());
|
let area = ui::centered_rect(30, 20, f.size());
|
||||||
f.render_widget(Clear, area);
|
f.render_widget(Clear, area);
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
popup_paragraph(title, txt.iter(), &self.theme, true),
|
popup_paragraph(
|
||||||
|
&title,
|
||||||
|
txt.iter(),
|
||||||
|
&self.theme,
|
||||||
|
true,
|
||||||
|
),
|
||||||
area,
|
area,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -59,12 +65,12 @@ impl Component for ResetComponent {
|
|||||||
_force_all: bool,
|
_force_all: bool,
|
||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::RESET_CONFIRM,
|
strings::commands::reset_confirm(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible,
|
self.visible,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::CLOSE_POPUP,
|
strings::commands::close_popup(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible,
|
self.visible,
|
||||||
));
|
));
|
||||||
@ -111,12 +117,17 @@ impl Component for ResetComponent {
|
|||||||
|
|
||||||
impl ResetComponent {
|
impl ResetComponent {
|
||||||
///
|
///
|
||||||
pub fn new(queue: Queue, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
queue: Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
target: None,
|
target: None,
|
||||||
visible: false,
|
visible: false,
|
||||||
queue,
|
queue,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
@ -137,24 +148,26 @@ impl ResetComponent {
|
|||||||
self.hide();
|
self.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_text(&self) -> (&str, &str) {
|
fn get_text(&self) -> (String, String) {
|
||||||
if let Some(ref a) = self.target {
|
if let Some(ref a) = self.target {
|
||||||
return match a {
|
return match a {
|
||||||
Action::Reset(_) => (
|
Action::Reset(_) => (
|
||||||
strings::CONFIRM_TITLE_RESET,
|
strings::confirm_title_reset(&self.key_config),
|
||||||
strings::CONFIRM_MSG_RESET,
|
strings::confirm_msg_reset(&self.key_config),
|
||||||
),
|
),
|
||||||
Action::StashDrop(_) => (
|
Action::StashDrop(_) => (
|
||||||
strings::CONFIRM_TITLE_STASHDROP,
|
strings::confirm_title_stashdrop(
|
||||||
strings::CONFIRM_MSG_STASHDROP,
|
&self.key_config,
|
||||||
|
),
|
||||||
|
strings::confirm_msg_stashdrop(&self.key_config),
|
||||||
),
|
),
|
||||||
Action::ResetHunk(_, _) => (
|
Action::ResetHunk(_, _) => (
|
||||||
strings::CONFIRM_TITLE_RESET,
|
strings::confirm_title_reset(&self.key_config),
|
||||||
strings::CONFIRM_MSG_RESETHUNK,
|
strings::confirm_msg_resethunk(&self.key_config),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
("", "")
|
("".to_string(), "".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ use super::{
|
|||||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
tabs::StashingOptions,
|
tabs::StashingOptions,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
@ -17,6 +18,7 @@ pub struct StashMsgComponent {
|
|||||||
options: StashingOptions,
|
options: StashingOptions,
|
||||||
input: TextInputComponent,
|
input: TextInputComponent,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for StashMsgComponent {
|
impl DrawableComponent for StashMsgComponent {
|
||||||
@ -41,7 +43,9 @@ impl Component for StashMsgComponent {
|
|||||||
self.input.commands(out, force_all);
|
self.input.commands(out, force_all);
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHING_CONFIRM_MSG,
|
strings::commands::stashing_confirm_msg(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
@ -119,15 +123,21 @@ impl Component for StashMsgComponent {
|
|||||||
|
|
||||||
impl StashMsgComponent {
|
impl StashMsgComponent {
|
||||||
///
|
///
|
||||||
pub fn new(queue: Queue, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
queue: Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
options: StashingOptions::default(),
|
options: StashingOptions::default(),
|
||||||
queue,
|
queue,
|
||||||
input: TextInputComponent::new(
|
input: TextInputComponent::new(
|
||||||
theme,
|
theme,
|
||||||
strings::STASH_POPUP_TITLE,
|
key_config.clone(),
|
||||||
strings::STASH_POPUP_MSG,
|
&strings::stash_popup_title(&key_config),
|
||||||
|
&strings::stash_popup_msg(&key_config),
|
||||||
),
|
),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,9 @@ use super::{
|
|||||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, NeedsUpdate, Queue},
|
queue::{InternalEvent, NeedsUpdate, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -19,6 +20,7 @@ pub struct TagCommitComponent {
|
|||||||
input: TextInputComponent,
|
input: TextInputComponent,
|
||||||
commit_id: Option<CommitId>,
|
commit_id: Option<CommitId>,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for TagCommitComponent {
|
impl DrawableComponent for TagCommitComponent {
|
||||||
@ -43,7 +45,9 @@ impl Component for TagCommitComponent {
|
|||||||
self.input.commands(out, force_all);
|
self.input.commands(out, force_all);
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::TAG_COMMIT_CONFIRM_MSG,
|
strings::commands::tag_commit_confirm_msg(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
@ -86,15 +90,21 @@ impl Component for TagCommitComponent {
|
|||||||
|
|
||||||
impl TagCommitComponent {
|
impl TagCommitComponent {
|
||||||
///
|
///
|
||||||
pub fn new(queue: Queue, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
queue: Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue,
|
queue,
|
||||||
input: TextInputComponent::new(
|
input: TextInputComponent::new(
|
||||||
theme,
|
theme,
|
||||||
strings::TAG_COMMIT_POPUP_TITLE,
|
key_config.clone(),
|
||||||
strings::TAG_COMMIT_POPUP_MSG,
|
&strings::tag_commit_popup_title(&key_config),
|
||||||
|
&strings::tag_commit_popup_msg(&key_config),
|
||||||
),
|
),
|
||||||
commit_id: None,
|
commit_id: None,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@ use crate::{
|
|||||||
popup_paragraph, visibility_blocking, CommandBlocking,
|
popup_paragraph, visibility_blocking, CommandBlocking,
|
||||||
CommandInfo, Component, DrawableComponent,
|
CommandInfo, Component, DrawableComponent,
|
||||||
},
|
},
|
||||||
strings::commands,
|
keys::SharedKeyConfig,
|
||||||
|
strings,
|
||||||
ui::{self, style::SharedTheme},
|
ui::{self, style::SharedTheme},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -23,6 +24,7 @@ pub struct TextInputComponent {
|
|||||||
msg: String,
|
msg: String,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
cursor_position: usize,
|
cursor_position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ impl TextInputComponent {
|
|||||||
///
|
///
|
||||||
pub fn new(
|
pub fn new(
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
title: &str,
|
title: &str,
|
||||||
default_msg: &str,
|
default_msg: &str,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -37,6 +40,7 @@ impl TextInputComponent {
|
|||||||
msg: String::default(),
|
msg: String::default(),
|
||||||
visible: false,
|
visible: false,
|
||||||
theme,
|
theme,
|
||||||
|
key_config,
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
default_msg: default_msg.to_string(),
|
default_msg: default_msg.to_string(),
|
||||||
cursor_position: 0,
|
cursor_position: 0,
|
||||||
@ -196,7 +200,7 @@ impl Component for TextInputComponent {
|
|||||||
) -> CommandBlocking {
|
) -> CommandBlocking {
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::CLOSE_POPUP,
|
strings::commands::close_popup(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible,
|
self.visible,
|
||||||
)
|
)
|
||||||
@ -274,8 +278,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_smoke() {
|
fn test_smoke() {
|
||||||
let mut comp =
|
let mut comp = TextInputComponent::new(
|
||||||
TextInputComponent::new(SharedTheme::default(), "", "");
|
SharedTheme::default(),
|
||||||
|
SharedKeyConfig::default(),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
comp.set_text(String::from("a\nb"));
|
comp.set_text(String::from("a\nb"));
|
||||||
|
|
||||||
@ -298,8 +306,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_visualize_newline() {
|
fn test_visualize_newline() {
|
||||||
let mut comp =
|
let mut comp = TextInputComponent::new(
|
||||||
TextInputComponent::new(SharedTheme::default(), "", "");
|
SharedTheme::default(),
|
||||||
|
SharedKeyConfig::default(),
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
comp.set_text(String::from("a\nb"));
|
comp.set_text(String::from("a\nb"));
|
||||||
|
|
||||||
|
320
src/keys.rs
320
src/keys.rs
@ -1,74 +1,260 @@
|
|||||||
|
use crate::get_app_config_path;
|
||||||
|
use anyhow::Result;
|
||||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
|
use ron::{
|
||||||
|
de::from_bytes,
|
||||||
|
ser::{to_string_pretty, PrettyConfig},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
const fn no_mod(code: KeyCode) -> KeyEvent {
|
pub type SharedKeyConfig = Rc<KeyConfig>;
|
||||||
KeyEvent {
|
|
||||||
code,
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
modifiers: KeyModifiers::empty(),
|
pub struct KeyConfig {
|
||||||
|
pub tab_status: KeyEvent,
|
||||||
|
pub tab_log: KeyEvent,
|
||||||
|
pub tab_stashing: KeyEvent,
|
||||||
|
pub tab_stashes: KeyEvent,
|
||||||
|
pub tab_toggle: KeyEvent,
|
||||||
|
pub tab_toggle_reverse: KeyEvent,
|
||||||
|
pub tab_toggle_reverse_windows: KeyEvent,
|
||||||
|
pub focus_workdir: KeyEvent,
|
||||||
|
pub focus_stage: KeyEvent,
|
||||||
|
pub focus_right: KeyEvent,
|
||||||
|
pub focus_left: KeyEvent,
|
||||||
|
pub focus_above: KeyEvent,
|
||||||
|
pub focus_below: KeyEvent,
|
||||||
|
pub exit: KeyEvent,
|
||||||
|
pub exit_popup: KeyEvent,
|
||||||
|
pub close_msg: KeyEvent,
|
||||||
|
pub open_commit: KeyEvent,
|
||||||
|
pub open_commit_editor: KeyEvent,
|
||||||
|
pub open_help: KeyEvent,
|
||||||
|
pub move_left: KeyEvent,
|
||||||
|
pub move_right: KeyEvent,
|
||||||
|
pub home: KeyEvent,
|
||||||
|
pub end: KeyEvent,
|
||||||
|
pub move_up: KeyEvent,
|
||||||
|
pub move_down: KeyEvent,
|
||||||
|
pub page_down: KeyEvent,
|
||||||
|
pub page_up: KeyEvent,
|
||||||
|
pub shift_up: KeyEvent,
|
||||||
|
pub shift_down: KeyEvent,
|
||||||
|
pub enter: KeyEvent,
|
||||||
|
pub edit_file: KeyEvent,
|
||||||
|
pub status_stage_file: KeyEvent,
|
||||||
|
pub status_stage_all: KeyEvent,
|
||||||
|
pub status_reset_file: KeyEvent,
|
||||||
|
pub diff_reset_hunk: KeyEvent,
|
||||||
|
pub status_ignore_file: KeyEvent,
|
||||||
|
pub stashing_save: KeyEvent,
|
||||||
|
pub stashing_toggle_untracked: KeyEvent,
|
||||||
|
pub stashing_toggle_index: KeyEvent,
|
||||||
|
pub stash_apply: KeyEvent,
|
||||||
|
pub stash_open: KeyEvent,
|
||||||
|
pub stash_drop: KeyEvent,
|
||||||
|
pub cmd_bar_toggle: KeyEvent,
|
||||||
|
pub log_commit_details: KeyEvent,
|
||||||
|
pub log_tag_commit: KeyEvent,
|
||||||
|
pub commit_amend: KeyEvent,
|
||||||
|
pub copy: KeyEvent,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
impl Default for KeyConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
tab_status: KeyEvent { code: KeyCode::Char('1'), modifiers: KeyModifiers::empty()},
|
||||||
|
tab_log: KeyEvent { code: KeyCode::Char('2'), modifiers: KeyModifiers::empty()},
|
||||||
|
tab_stashing: KeyEvent { code: KeyCode::Char('3'), modifiers: KeyModifiers::empty()},
|
||||||
|
tab_stashes: KeyEvent { code: KeyCode::Char('4'), modifiers: KeyModifiers::empty()},
|
||||||
|
tab_toggle: KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::empty()},
|
||||||
|
tab_toggle_reverse: KeyEvent { code: KeyCode::BackTab, modifiers: KeyModifiers::empty()},
|
||||||
|
tab_toggle_reverse_windows: KeyEvent { code: KeyCode::BackTab, modifiers: KeyModifiers::SHIFT},
|
||||||
|
focus_workdir: KeyEvent { code: KeyCode::Char('w'), modifiers: KeyModifiers::empty()},
|
||||||
|
focus_stage: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()},
|
||||||
|
focus_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()},
|
||||||
|
focus_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()},
|
||||||
|
focus_above: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::empty()},
|
||||||
|
focus_below: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::empty()},
|
||||||
|
exit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL},
|
||||||
|
exit_popup: KeyEvent { code: KeyCode::Esc, modifiers: KeyModifiers::empty()},
|
||||||
|
close_msg: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
open_commit: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()},
|
||||||
|
open_commit_editor: KeyEvent { code: KeyCode::Char('e'), modifiers:KeyModifiers::CONTROL},
|
||||||
|
open_help: KeyEvent { code: KeyCode::Char('h'), modifiers: KeyModifiers::empty()},
|
||||||
|
move_left: KeyEvent { code: KeyCode::Left, modifiers: KeyModifiers::empty()},
|
||||||
|
move_right: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()},
|
||||||
|
home: KeyEvent { code: KeyCode::Home, modifiers: KeyModifiers::empty()},
|
||||||
|
end: KeyEvent { code: KeyCode::End, modifiers: KeyModifiers::empty()},
|
||||||
|
move_up: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::empty()},
|
||||||
|
move_down: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::empty()},
|
||||||
|
page_down: KeyEvent { code: KeyCode::PageDown, modifiers: KeyModifiers::empty()},
|
||||||
|
page_up: KeyEvent { code: KeyCode::PageUp, modifiers: KeyModifiers::empty()},
|
||||||
|
shift_up: KeyEvent { code: KeyCode::Up, modifiers: KeyModifiers::SHIFT},
|
||||||
|
shift_down: KeyEvent { code: KeyCode::Down, modifiers: KeyModifiers::SHIFT},
|
||||||
|
enter: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
edit_file: KeyEvent { code: KeyCode::Char('e'), modifiers: KeyModifiers::empty()},
|
||||||
|
status_stage_file: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
status_stage_all: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::empty()},
|
||||||
|
status_reset_file: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT,},
|
||||||
|
diff_reset_hunk: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
status_ignore_file: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()},
|
||||||
|
stashing_save: KeyEvent { code: KeyCode::Char('s'), modifiers: KeyModifiers::empty()},
|
||||||
|
stashing_toggle_untracked: KeyEvent { code: KeyCode::Char('u'), modifiers: KeyModifiers::empty()},
|
||||||
|
stashing_toggle_index: KeyEvent { code: KeyCode::Char('i'), modifiers: KeyModifiers::empty()},
|
||||||
|
stash_apply: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
stash_open: KeyEvent { code: KeyCode::Right, modifiers: KeyModifiers::empty()},
|
||||||
|
stash_drop: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
|
||||||
|
cmd_bar_toggle: KeyEvent { code: KeyCode::Char('.'), modifiers: KeyModifiers::empty()},
|
||||||
|
log_commit_details: KeyEvent { code: KeyCode::Enter, modifiers: KeyModifiers::empty()},
|
||||||
|
log_tag_commit: KeyEvent { code: KeyCode::Char('t'), modifiers: KeyModifiers::empty()},
|
||||||
|
commit_amend: KeyEvent { code: KeyCode::Char('a'), modifiers: KeyModifiers::CONTROL},
|
||||||
|
copy: KeyEvent { code: KeyCode::Char('y'), modifiers: KeyModifiers::empty()},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl KeyConfig {
|
||||||
|
fn save(&self) -> Result<()> {
|
||||||
|
let config_file = Self::get_config_file()?;
|
||||||
|
let mut file = File::create(config_file)?;
|
||||||
|
let data = to_string_pretty(self, PrettyConfig::default())?;
|
||||||
|
file.write_all(data.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_config_file() -> Result<PathBuf> {
|
||||||
|
let app_home = get_app_config_path()?;
|
||||||
|
Ok(app_home.join("key_config.ron"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_file(config_file: PathBuf) -> Result<Self> {
|
||||||
|
let mut f = File::open(config_file)?;
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
f.read_to_end(&mut buffer)?;
|
||||||
|
Ok(from_bytes(&buffer)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_internal() -> Result<Self> {
|
||||||
|
let file = Self::get_config_file()?;
|
||||||
|
if file.exists() {
|
||||||
|
Ok(Self::read_file(file)?)
|
||||||
|
} else {
|
||||||
|
let def = Self::default();
|
||||||
|
if def.save().is_err() {
|
||||||
|
log::warn!(
|
||||||
|
"failed to store default key config to disk."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(def)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init() -> Self {
|
||||||
|
Self::init_internal().unwrap_or_default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn with_mod(
|
// The hint follows apple design
|
||||||
code: KeyCode,
|
// http://xahlee.info/comp/unicode_computing_symbols.html
|
||||||
modifiers: KeyModifiers,
|
pub fn get_hint(ev: KeyEvent) -> String {
|
||||||
) -> KeyEvent {
|
match ev.code {
|
||||||
KeyEvent { code, modifiers }
|
KeyCode::Char(c) => {
|
||||||
|
format!("{}{}", get_modifier_hint(ev.modifiers), c)
|
||||||
|
}
|
||||||
|
KeyCode::Enter => {
|
||||||
|
format!("{}\u{23ce}", get_modifier_hint(ev.modifiers)) //⏎
|
||||||
|
}
|
||||||
|
KeyCode::Left => {
|
||||||
|
format!("{}\u{2190}", get_modifier_hint(ev.modifiers)) //←
|
||||||
|
}
|
||||||
|
KeyCode::Right => {
|
||||||
|
format!("{}\u{2192}", get_modifier_hint(ev.modifiers)) //→
|
||||||
|
}
|
||||||
|
KeyCode::Up => {
|
||||||
|
format!("{}\u{2191}", get_modifier_hint(ev.modifiers)) //↑
|
||||||
|
}
|
||||||
|
KeyCode::Down => {
|
||||||
|
format!("{}\u{2193}", get_modifier_hint(ev.modifiers)) //↓
|
||||||
|
}
|
||||||
|
KeyCode::Backspace => {
|
||||||
|
format!("{}\u{232b}", get_modifier_hint(ev.modifiers)) //⌫
|
||||||
|
}
|
||||||
|
KeyCode::Home => {
|
||||||
|
format!("{}\u{2912}", get_modifier_hint(ev.modifiers)) //⤒
|
||||||
|
}
|
||||||
|
KeyCode::End => {
|
||||||
|
format!("{}\u{2913}", get_modifier_hint(ev.modifiers)) //⤓
|
||||||
|
}
|
||||||
|
KeyCode::PageUp => {
|
||||||
|
format!("{}\u{21de}", get_modifier_hint(ev.modifiers)) //⇞
|
||||||
|
}
|
||||||
|
KeyCode::PageDown => {
|
||||||
|
format!("{}\u{21df}", get_modifier_hint(ev.modifiers)) //⇟
|
||||||
|
}
|
||||||
|
KeyCode::Tab => {
|
||||||
|
format!("{}\u{21e5}", get_modifier_hint(ev.modifiers)) //⇥
|
||||||
|
}
|
||||||
|
KeyCode::BackTab => {
|
||||||
|
format!("{}\u{21e4}", get_modifier_hint(ev.modifiers)) //⇤
|
||||||
|
}
|
||||||
|
KeyCode::Delete => {
|
||||||
|
format!("{}\u{2326}", get_modifier_hint(ev.modifiers)) //⌦
|
||||||
|
}
|
||||||
|
KeyCode::Insert => {
|
||||||
|
format!("{}\u{2380}", get_modifier_hint(ev.modifiers)) //⎀
|
||||||
|
}
|
||||||
|
KeyCode::Esc => {
|
||||||
|
format!("{}\u{238b}", get_modifier_hint(ev.modifiers)) //⎋
|
||||||
|
}
|
||||||
|
KeyCode::F(u) => {
|
||||||
|
format!("{}F{}", get_modifier_hint(ev.modifiers), u)
|
||||||
|
}
|
||||||
|
KeyCode::Null => get_modifier_hint(ev.modifiers).to_string(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TAB_1: KeyEvent = no_mod(KeyCode::Char('1'));
|
fn get_modifier_hint(modifier: KeyModifiers) -> String {
|
||||||
pub const TAB_2: KeyEvent = no_mod(KeyCode::Char('2'));
|
match modifier {
|
||||||
pub const TAB_3: KeyEvent = no_mod(KeyCode::Char('3'));
|
KeyModifiers::CONTROL => "^".to_string(),
|
||||||
pub const TAB_4: KeyEvent = no_mod(KeyCode::Char('4'));
|
KeyModifiers::SHIFT => {
|
||||||
pub const TAB_TOGGLE: KeyEvent = no_mod(KeyCode::Tab);
|
"\u{21e7}".to_string() //⇧
|
||||||
pub const TAB_TOGGLE_REVERSE: KeyEvent = no_mod(KeyCode::BackTab);
|
}
|
||||||
//TODO: https://github.com/extrawurst/gitui/issues/112
|
KeyModifiers::ALT => {
|
||||||
pub const TAB_TOGGLE_REVERSE_WINDOWS: KeyEvent =
|
"\u{2325}".to_string() //⌥
|
||||||
with_mod(KeyCode::BackTab, KeyModifiers::SHIFT);
|
}
|
||||||
pub const FOCUS_WORKDIR: KeyEvent = no_mod(KeyCode::Char('w'));
|
_ => "".to_string(),
|
||||||
pub const FOCUS_STAGE: KeyEvent = no_mod(KeyCode::Char('s'));
|
}
|
||||||
pub const FOCUS_RIGHT: KeyEvent = no_mod(KeyCode::Right);
|
}
|
||||||
pub const FOCUS_LEFT: KeyEvent = no_mod(KeyCode::Left);
|
|
||||||
pub const FOCUS_ABOVE: KeyEvent = no_mod(KeyCode::Up);
|
#[cfg(test)]
|
||||||
pub const FOCUS_BELOW: KeyEvent = no_mod(KeyCode::Down);
|
mod tests {
|
||||||
pub const EXIT: KeyEvent =
|
use super::{get_hint, KeyConfig};
|
||||||
with_mod(KeyCode::Char('c'), KeyModifiers::CONTROL);
|
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
pub const EXIT_POPUP: KeyEvent = no_mod(KeyCode::Esc);
|
|
||||||
pub const CLOSE_MSG: KeyEvent = no_mod(KeyCode::Enter);
|
#[test]
|
||||||
pub const OPEN_COMMIT: KeyEvent = no_mod(KeyCode::Char('c'));
|
fn test_get_hint() {
|
||||||
pub const OPEN_COMMIT_EDITOR: KeyEvent =
|
let h = get_hint(KeyEvent {
|
||||||
with_mod(KeyCode::Char('e'), KeyModifiers::CONTROL);
|
code: KeyCode::Char('c'),
|
||||||
pub const OPEN_HELP: KeyEvent = no_mod(KeyCode::Char('h'));
|
modifiers: KeyModifiers::CONTROL,
|
||||||
pub const MOVE_LEFT: KeyEvent = no_mod(KeyCode::Left);
|
});
|
||||||
pub const MOVE_RIGHT: KeyEvent = no_mod(KeyCode::Right);
|
assert_eq!(h, "^c");
|
||||||
pub const HOME: KeyEvent = no_mod(KeyCode::Home);
|
}
|
||||||
pub const END: KeyEvent = no_mod(KeyCode::End);
|
|
||||||
pub const MOVE_UP: KeyEvent = no_mod(KeyCode::Up);
|
#[test]
|
||||||
pub const MOVE_DOWN: KeyEvent = no_mod(KeyCode::Down);
|
fn test_load_vim_style_example() {
|
||||||
pub const PAGE_DOWN: KeyEvent = no_mod(KeyCode::PageDown);
|
assert_eq!(
|
||||||
pub const PAGE_UP: KeyEvent = no_mod(KeyCode::PageUp);
|
KeyConfig::read_file(
|
||||||
pub const SHIFT_UP: KeyEvent =
|
"assets/vim_style_key_config.ron".into()
|
||||||
with_mod(KeyCode::Up, KeyModifiers::SHIFT);
|
)
|
||||||
pub const SHIFT_DOWN: KeyEvent =
|
.is_ok(),
|
||||||
with_mod(KeyCode::Down, KeyModifiers::SHIFT);
|
true
|
||||||
pub const ENTER: KeyEvent = no_mod(KeyCode::Enter);
|
);
|
||||||
pub const COPY: KeyEvent = no_mod(KeyCode::Char('y'));
|
}
|
||||||
pub const EDIT_FILE: KeyEvent = no_mod(KeyCode::Char('e'));
|
}
|
||||||
pub const STATUS_STAGE_FILE: KeyEvent = no_mod(KeyCode::Enter);
|
|
||||||
pub const STATUS_STAGE_ALL: KeyEvent = no_mod(KeyCode::Char('a'));
|
|
||||||
pub const STATUS_RESET_FILE: KeyEvent =
|
|
||||||
with_mod(KeyCode::Char('D'), KeyModifiers::SHIFT);
|
|
||||||
pub const DIFF_RESET_HUNK: KeyEvent = STATUS_RESET_FILE;
|
|
||||||
pub const STATUS_IGNORE_FILE: KeyEvent = no_mod(KeyCode::Char('i'));
|
|
||||||
pub const STASHING_SAVE: KeyEvent = no_mod(KeyCode::Char('s'));
|
|
||||||
pub const STASHING_TOGGLE_UNTRACKED: KeyEvent =
|
|
||||||
no_mod(KeyCode::Char('u'));
|
|
||||||
pub const STASHING_TOGGLE_INDEX: KeyEvent =
|
|
||||||
no_mod(KeyCode::Char('i'));
|
|
||||||
pub const STASH_APPLY: KeyEvent = no_mod(KeyCode::Enter);
|
|
||||||
pub const STASH_OPEN: KeyEvent = no_mod(KeyCode::Right);
|
|
||||||
pub const STASH_DROP: KeyEvent =
|
|
||||||
with_mod(KeyCode::Char('D'), KeyModifiers::SHIFT);
|
|
||||||
pub const CMD_BAR_TOGGLE: KeyEvent = no_mod(KeyCode::Char('.'));
|
|
||||||
pub const LOG_COMMIT_DETAILS: KeyEvent = no_mod(KeyCode::Enter);
|
|
||||||
pub const LOG_TAG_COMMIT: KeyEvent = no_mod(KeyCode::Char('t'));
|
|
||||||
pub const COMMIT_AMEND: KeyEvent =
|
|
||||||
with_mod(KeyCode::Char('a'), KeyModifiers::CONTROL);
|
|
||||||
|
853
src/strings.rs
853
src/strings.rs
@ -1,63 +1,155 @@
|
|||||||
pub static TITLE_STATUS: &str = "Unstaged Changes [w]";
|
use crate::keys::{get_hint, SharedKeyConfig};
|
||||||
pub static TITLE_DIFF: &str = "Diff: ";
|
|
||||||
pub static TITLE_INDEX: &str = "Staged Changes [s]";
|
|
||||||
|
|
||||||
pub static TAB_STATUS: &str = "Status [1]";
|
|
||||||
pub static TAB_LOG: &str = "Log [2]";
|
|
||||||
pub static TAB_STASHING: &str = "Stashing [3]";
|
|
||||||
pub static TAB_STASHES: &str = "Stashes [4]";
|
|
||||||
pub static TAB_DIVIDER: &str = " | ";
|
|
||||||
|
|
||||||
pub static CMD_SPLITTER: &str = " ";
|
|
||||||
|
|
||||||
pub static MSG_OPENING_EDITOR: &str = "opening editor...";
|
|
||||||
pub static MSG_TITLE_ERROR: &str = "Error";
|
|
||||||
pub static COMMIT_TITLE: &str = "Commit";
|
|
||||||
pub static COMMIT_TITLE_AMEND: &str = "Commit (Amend)";
|
|
||||||
pub static COMMIT_MSG: &str = "type commit message..";
|
|
||||||
pub static COMMIT_EDITOR_MSG: &str = r##"
|
|
||||||
# Edit your commit message
|
|
||||||
# Lines starting with '#' will be ignored"##;
|
|
||||||
pub static STASH_POPUP_TITLE: &str = "Stash";
|
|
||||||
pub static STASH_POPUP_MSG: &str = "type name (optional)";
|
|
||||||
pub static CONFIRM_TITLE_RESET: &str = "Reset";
|
|
||||||
pub static CONFIRM_TITLE_STASHDROP: &str = "Drop";
|
|
||||||
pub static CONFIRM_MSG_RESET: &str = "confirm file reset?";
|
|
||||||
pub static CONFIRM_MSG_STASHDROP: &str = "confirm stash drop?";
|
|
||||||
pub static CONFIRM_MSG_RESETHUNK: &str = "confirm reset hunk?";
|
|
||||||
|
|
||||||
pub static LOG_TITLE: &str = "Commit";
|
|
||||||
|
|
||||||
pub static TAG_COMMIT_POPUP_TITLE: &str = "Tag";
|
|
||||||
pub static TAG_COMMIT_POPUP_MSG: &str = "type tag";
|
|
||||||
|
|
||||||
pub static STASHLIST_TITLE: &str = "Stashes";
|
|
||||||
|
|
||||||
pub static HELP_TITLE: &str = "Help: all commands";
|
|
||||||
|
|
||||||
pub static STASHING_FILES_TITLE: &str = "Files to Stash";
|
|
||||||
pub static STASHING_OPTIONS_TITLE: &str = "Options";
|
|
||||||
|
|
||||||
pub static LOADING_TEXT: &str = "Loading ...";
|
|
||||||
|
|
||||||
pub mod commit {
|
|
||||||
pub static DETAILS_AUTHOR: &str = "Author: ";
|
|
||||||
pub static DETAILS_COMMITTER: &str = "Committer: ";
|
|
||||||
pub static DETAILS_SHA: &str = "SHA: ";
|
|
||||||
pub static DETAILS_DATE: &str = "Date: ";
|
|
||||||
pub static DETAILS_TAGS: &str = "Tags: ";
|
|
||||||
|
|
||||||
pub static DETAILS_INFO_TITLE: &str = "Info";
|
|
||||||
pub static DETAILS_MESSAGE_TITLE: &str = "Message";
|
|
||||||
pub static DETAILS_FILES_TITLE: &str = "Files:";
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod order {
|
pub mod order {
|
||||||
pub static NAV: i8 = 1;
|
pub static NAV: i8 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn title_status(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!(
|
||||||
|
"Unstaged Changes [{}]",
|
||||||
|
get_hint(key_config.focus_workdir)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn title_diff(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Diff: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn title_index(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!("Staged Changes [{}]", get_hint(key_config.focus_stage))
|
||||||
|
}
|
||||||
|
pub fn tab_status(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!("Status [{}]", get_hint(key_config.tab_status))
|
||||||
|
}
|
||||||
|
pub fn tab_log(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!("Log [{}]", get_hint(key_config.tab_log))
|
||||||
|
}
|
||||||
|
pub fn tab_stashing(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!("Stashing [{}]", get_hint(key_config.tab_stashing))
|
||||||
|
}
|
||||||
|
pub fn tab_stashes(key_config: &SharedKeyConfig) -> String {
|
||||||
|
format!("Stashes [{}]", get_hint(key_config.tab_stashes))
|
||||||
|
}
|
||||||
|
pub fn tab_divider(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
" | ".to_string()
|
||||||
|
}
|
||||||
|
pub fn cmd_splitter(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
" ".to_string()
|
||||||
|
}
|
||||||
|
pub fn msg_opening_editor(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"opening editor...".to_string()
|
||||||
|
}
|
||||||
|
pub fn msg_title_error(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Error".to_string()
|
||||||
|
}
|
||||||
|
pub fn commit_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Commit".to_string()
|
||||||
|
}
|
||||||
|
pub fn commit_title_amend(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Commit (Amend)".to_string()
|
||||||
|
}
|
||||||
|
pub fn commit_msg(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"type commit message..".to_string()
|
||||||
|
}
|
||||||
|
pub fn commit_editor_msg(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
r##"
|
||||||
|
# Edit your commit message
|
||||||
|
# Lines starting with '#' will be ignored"##
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
pub fn stash_popup_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Stash".to_string()
|
||||||
|
}
|
||||||
|
pub fn stash_popup_msg(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"type name (optional)".to_string()
|
||||||
|
}
|
||||||
|
pub fn confirm_title_reset(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Reset".to_string()
|
||||||
|
}
|
||||||
|
pub fn confirm_title_stashdrop(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Drop".to_string()
|
||||||
|
}
|
||||||
|
pub fn confirm_msg_reset(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"confirm file reset?".to_string()
|
||||||
|
}
|
||||||
|
pub fn confirm_msg_stashdrop(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"confirm stash drop?".to_string()
|
||||||
|
}
|
||||||
|
pub fn confirm_msg_resethunk(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"confirm reset hunk?".to_string()
|
||||||
|
}
|
||||||
|
pub fn log_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Commit".to_string()
|
||||||
|
}
|
||||||
|
pub fn tag_commit_popup_title(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Tag".to_string()
|
||||||
|
}
|
||||||
|
pub fn tag_commit_popup_msg(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"type tag".to_string()
|
||||||
|
}
|
||||||
|
pub fn stashlist_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Stashes".to_string()
|
||||||
|
}
|
||||||
|
pub fn help_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Help: all commands".to_string()
|
||||||
|
}
|
||||||
|
pub fn stashing_files_title(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Files to Stash".to_string()
|
||||||
|
}
|
||||||
|
pub fn stashing_options_title(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Options".to_string()
|
||||||
|
}
|
||||||
|
pub fn loading_text(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Loading ...".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod commit {
|
||||||
|
use crate::keys::SharedKeyConfig;
|
||||||
|
pub fn details_author(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Author: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_committer(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Committer: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_sha(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Sha: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_date(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Date: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_tags(_key_config: &SharedKeyConfig) -> String {
|
||||||
|
"Tags: ".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_info_title(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Info".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_message_title(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Message".to_string()
|
||||||
|
}
|
||||||
|
pub fn details_files_title(
|
||||||
|
_key_config: &SharedKeyConfig,
|
||||||
|
) -> String {
|
||||||
|
"Files:".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod commands {
|
pub mod commands {
|
||||||
use crate::components::CommandText;
|
use crate::components::CommandText;
|
||||||
|
use crate::keys::{get_hint, SharedKeyConfig};
|
||||||
|
|
||||||
static CMD_GROUP_GENERAL: &str = "-- General --";
|
static CMD_GROUP_GENERAL: &str = "-- General --";
|
||||||
static CMD_GROUP_DIFF: &str = "-- Diff --";
|
static CMD_GROUP_DIFF: &str = "-- Diff --";
|
||||||
@ -67,256 +159,425 @@ pub mod commands {
|
|||||||
static CMD_GROUP_STASHES: &str = "-- Stashes --";
|
static CMD_GROUP_STASHES: &str = "-- Stashes --";
|
||||||
static CMD_GROUP_LOG: &str = "-- Log --";
|
static CMD_GROUP_LOG: &str = "-- Log --";
|
||||||
|
|
||||||
///
|
pub fn toggle_tabs(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
pub static TOGGLE_TABS: CommandText = CommandText::new(
|
|
||||||
"Next [tab]",
|
|
||||||
"switch to next tab",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static TOGGLE_TABS_DIRECT: CommandText = CommandText::new(
|
|
||||||
"Tab [1234]",
|
|
||||||
"switch top level tabs directly",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static HELP_OPEN: CommandText = CommandText::new(
|
|
||||||
"Help [h]",
|
|
||||||
"open this help screen",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static NAVIGATE_COMMIT_MESSAGE: CommandText =
|
|
||||||
CommandText::new(
|
CommandText::new(
|
||||||
"Nav [\u{2191}\u{2193}]",
|
format!("Next [{}]", get_hint(key_config.tab_toggle)),
|
||||||
|
"switch to next tab",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn toggle_tabs_direct(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Tab [{}{}{}{}]",
|
||||||
|
get_hint(key_config.tab_status),
|
||||||
|
get_hint(key_config.tab_log),
|
||||||
|
get_hint(key_config.tab_stashing),
|
||||||
|
get_hint(key_config.tab_stashes),
|
||||||
|
),
|
||||||
|
"switch top level tabs directly",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn help_open(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Help [{}]", get_hint(key_config.open_help)),
|
||||||
|
"open this help screen",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn navigate_commit_message(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Nav [{}{}]",
|
||||||
|
get_hint(key_config.move_up),
|
||||||
|
get_hint(key_config.move_down)
|
||||||
|
),
|
||||||
"navigate commit message",
|
"navigate commit message",
|
||||||
CMD_GROUP_GENERAL,
|
CMD_GROUP_GENERAL,
|
||||||
);
|
)
|
||||||
///
|
}
|
||||||
pub static NAVIGATE_TREE: CommandText = CommandText::new(
|
pub fn navigate_tree(
|
||||||
"Nav [\u{2190}\u{2191}\u{2192}\u{2193}]",
|
key_config: &SharedKeyConfig,
|
||||||
"navigate tree view",
|
) -> CommandText {
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static SCROLL: CommandText = CommandText::new(
|
|
||||||
"Scroll [\u{2191}\u{2193}]",
|
|
||||||
"scroll up or down in focused view",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static COPY: CommandText = CommandText::new(
|
|
||||||
"Copy [y]",
|
|
||||||
"copy selected lines to clipboard",
|
|
||||||
CMD_GROUP_DIFF,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_HOME_END: CommandText = CommandText::new(
|
|
||||||
"Jump up/down [home,end,\u{2191} up,\u{2193} down]",
|
|
||||||
"scroll to top or bottom of diff",
|
|
||||||
CMD_GROUP_DIFF,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_HUNK_ADD: CommandText = CommandText::new(
|
|
||||||
"Add hunk [enter]",
|
|
||||||
"adds selected hunk to stage",
|
|
||||||
CMD_GROUP_DIFF,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_HUNK_REVERT: CommandText = CommandText::new(
|
|
||||||
"Revert hunk [D]",
|
|
||||||
"reverts selected hunk",
|
|
||||||
CMD_GROUP_DIFF,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_HUNK_REMOVE: CommandText = CommandText::new(
|
|
||||||
"Remove hunk [enter]",
|
|
||||||
"removes selected hunk from stage",
|
|
||||||
CMD_GROUP_DIFF,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static CLOSE_POPUP: CommandText = CommandText::new(
|
|
||||||
"Close [esc]",
|
|
||||||
"close overlay (e.g commit, help)",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static CLOSE_MSG: CommandText = CommandText::new(
|
|
||||||
"Close [enter]",
|
|
||||||
"close msg popup (e.g msg)",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
)
|
|
||||||
.hide_help();
|
|
||||||
///
|
|
||||||
pub static SELECT_STAGING: CommandText = CommandText::new(
|
|
||||||
"To stage [s]",
|
|
||||||
"focus/select staging area",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static SELECT_STATUS: CommandText = CommandText::new(
|
|
||||||
"To files [1,2]",
|
|
||||||
"focus/select file tree of staged or unstaged files",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static SELECT_UNSTAGED: CommandText = CommandText::new(
|
|
||||||
"To unstaged [w]",
|
|
||||||
"focus/select unstaged area",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static COMMIT_OPEN: CommandText = CommandText::new(
|
|
||||||
"Commit [c]",
|
|
||||||
"open commit popup (available in non-empty stage)",
|
|
||||||
CMD_GROUP_COMMIT,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static COMMIT_OPEN_EDITOR: CommandText = CommandText::new(
|
|
||||||
"Open editor [^e]",
|
|
||||||
"open commit editor (available in non-empty stage)",
|
|
||||||
CMD_GROUP_COMMIT,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static COMMIT_ENTER: CommandText = CommandText::new(
|
|
||||||
"Commit [enter]",
|
|
||||||
"commit (available when commit message is non-empty)",
|
|
||||||
CMD_GROUP_COMMIT,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static COMMIT_AMEND: CommandText = CommandText::new(
|
|
||||||
"Amend [^a]",
|
|
||||||
"amend last commit",
|
|
||||||
CMD_GROUP_COMMIT,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static EDIT_ITEM: CommandText = CommandText::new(
|
|
||||||
"Edit Item [e]",
|
|
||||||
"edit the currently selected file in an external editor",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static STAGE_ITEM: CommandText = CommandText::new(
|
|
||||||
"Stage Item [enter]",
|
|
||||||
"stage currently selected file or entire path",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static STAGE_ALL: CommandText = CommandText::new(
|
|
||||||
"Stage All [a]",
|
|
||||||
"stage all changes (in unstaged files)",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static UNSTAGE_ITEM: CommandText = CommandText::new(
|
|
||||||
"Unstage Item [enter]",
|
|
||||||
"unstage currently selected file or entire path",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static UNSTAGE_ALL: CommandText = CommandText::new(
|
|
||||||
"Unstage all [a]",
|
|
||||||
"unstage all files (in staged files)",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static RESET_ITEM: CommandText = CommandText::new(
|
|
||||||
"Reset Item [D]",
|
|
||||||
"revert changes in selected file or entire path",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static IGNORE_ITEM: CommandText = CommandText::new(
|
|
||||||
"Ignore [i]",
|
|
||||||
"Add file or path to .gitignore",
|
|
||||||
CMD_GROUP_CHANGES,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_FOCUS_LEFT: CommandText = CommandText::new(
|
|
||||||
"Back [\u{2190}]", //←
|
|
||||||
"view and select changed files",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static DIFF_FOCUS_RIGHT: CommandText = CommandText::new(
|
|
||||||
"Diff [\u{2192}]", //→
|
|
||||||
"inspect file diff",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static QUIT: CommandText = CommandText::new(
|
|
||||||
"Quit [^c]",
|
|
||||||
"quit gitui application",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static RESET_CONFIRM: CommandText = CommandText::new(
|
|
||||||
"Confirm [enter]",
|
|
||||||
"resets the file in question",
|
|
||||||
CMD_GROUP_GENERAL,
|
|
||||||
);
|
|
||||||
|
|
||||||
///
|
|
||||||
pub static STASHING_SAVE: CommandText = CommandText::new(
|
|
||||||
"Save [s]",
|
|
||||||
"opens stash name input popup",
|
|
||||||
CMD_GROUP_STASHING,
|
|
||||||
);
|
|
||||||
///
|
|
||||||
pub static STASHING_TOGGLE_INDEXED: CommandText =
|
|
||||||
CommandText::new(
|
CommandText::new(
|
||||||
"Toggle Staged [i]",
|
format!(
|
||||||
|
"Nav [{}{}{}{}]",
|
||||||
|
get_hint(key_config.move_up),
|
||||||
|
get_hint(key_config.move_down),
|
||||||
|
get_hint(key_config.move_right),
|
||||||
|
get_hint(key_config.move_left)
|
||||||
|
),
|
||||||
|
"navigate tree view",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn scroll(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Scroll [{}{}]",
|
||||||
|
get_hint(key_config.focus_above),
|
||||||
|
get_hint(key_config.focus_below)
|
||||||
|
),
|
||||||
|
"scroll up or down in focused view",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn copy(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Copy [{}]", get_hint(key_config.copy),),
|
||||||
|
"copy selected lines to clipboard",
|
||||||
|
CMD_GROUP_DIFF,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn diff_home_end(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Jump up/down [{},{},{},{}]",
|
||||||
|
get_hint(key_config.home),
|
||||||
|
get_hint(key_config.end),
|
||||||
|
get_hint(key_config.move_up),
|
||||||
|
get_hint(key_config.move_down)
|
||||||
|
),
|
||||||
|
"scroll to top or bottom of diff",
|
||||||
|
CMD_GROUP_DIFF,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn diff_hunk_add(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Add hunk [{}]",
|
||||||
|
get_hint(key_config.diff_reset_hunk),
|
||||||
|
),
|
||||||
|
"adds selected hunk to stage",
|
||||||
|
CMD_GROUP_DIFF,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn diff_hunk_revert(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Revert hunk [{}]",
|
||||||
|
get_hint(key_config.status_reset_file),
|
||||||
|
),
|
||||||
|
"reverts selected hunk",
|
||||||
|
CMD_GROUP_DIFF,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn diff_hunk_remove(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Remove hunk [{}]",
|
||||||
|
get_hint(key_config.close_msg),
|
||||||
|
),
|
||||||
|
"removes selected hunk from stage",
|
||||||
|
CMD_GROUP_DIFF,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn close_popup(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Close [{}]", get_hint(key_config.exit_popup),),
|
||||||
|
"close overlay (e.g commit, help)",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn close_msg(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Close [{}]", get_hint(key_config.close_msg),),
|
||||||
|
"close msg popup (e.g msg)",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
.hide_help()
|
||||||
|
}
|
||||||
|
pub fn select_staging(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"To stage [{}]",
|
||||||
|
get_hint(key_config.focus_stage),
|
||||||
|
),
|
||||||
|
"focus/select staging area",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn select_status(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"To files [{},{}]",
|
||||||
|
get_hint(key_config.tab_status),
|
||||||
|
get_hint(key_config.tab_log),
|
||||||
|
),
|
||||||
|
"focus/select file tree of staged or unstaged files",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn select_unstaged(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"To unstaged [{}]",
|
||||||
|
get_hint(key_config.focus_workdir),
|
||||||
|
),
|
||||||
|
"focus/select unstaged area",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn commit_open(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Commit [{}]", get_hint(key_config.open_commit),),
|
||||||
|
"open commit popup (available in non-empty stage)",
|
||||||
|
CMD_GROUP_COMMIT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn commit_open_editor(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Open editor [{}]",
|
||||||
|
get_hint(key_config.open_commit_editor),
|
||||||
|
),
|
||||||
|
"open commit editor (available in non-empty stage)",
|
||||||
|
CMD_GROUP_COMMIT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn commit_enter(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Commit [{}]", get_hint(key_config.enter),),
|
||||||
|
"commit (available when commit message is non-empty)",
|
||||||
|
CMD_GROUP_COMMIT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn commit_amend(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Amend [{}]", get_hint(key_config.commit_amend),),
|
||||||
|
"amend last commit",
|
||||||
|
CMD_GROUP_COMMIT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn edit_item(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Edit Item [{}]", get_hint(key_config.edit_file),),
|
||||||
|
"edit the currently selected file in an external editor",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn stage_item(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Stage Item [{}]",
|
||||||
|
get_hint(key_config.stash_apply),
|
||||||
|
),
|
||||||
|
"stage currently selected file or entire path",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn stage_all(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Stage All [{}]",
|
||||||
|
get_hint(key_config.status_stage_all),
|
||||||
|
),
|
||||||
|
"stage all changes (in unstaged files)",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn unstage_item(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Unstage Item [{}]",
|
||||||
|
get_hint(key_config.stash_apply),
|
||||||
|
),
|
||||||
|
"unstage currently selected file or entire path",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn unstage_all(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Unstage all [{}]",
|
||||||
|
get_hint(key_config.status_stage_all),
|
||||||
|
),
|
||||||
|
"unstage all files (in staged files)",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn reset_item(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Reset Item [{}]",
|
||||||
|
get_hint(key_config.stash_drop),
|
||||||
|
),
|
||||||
|
"revert changes in selected file or entire path",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn ignore_item(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Ignore [{}]",
|
||||||
|
get_hint(key_config.status_ignore_file),
|
||||||
|
),
|
||||||
|
"Add file or path to .gitignore",
|
||||||
|
CMD_GROUP_CHANGES,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn diff_focus_left(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Back [{}]", get_hint(key_config.focus_left),),
|
||||||
|
"view and select changed files",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn diff_focus_right(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Diff [{}]", get_hint(key_config.focus_right),),
|
||||||
|
"inspect file diff",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn quit(key_config: &SharedKeyConfig) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Quit [{}]", get_hint(key_config.exit),),
|
||||||
|
"quit gitui application",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn reset_confirm(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Confirm [{}]", get_hint(key_config.close_msg),),
|
||||||
|
"resets the file in question",
|
||||||
|
CMD_GROUP_GENERAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn stashing_save(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Save [{}]", get_hint(key_config.stashing_save),),
|
||||||
|
"opens stash name input popup",
|
||||||
|
CMD_GROUP_STASHING,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn stashing_toggle_indexed(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!(
|
||||||
|
"Toggle Staged [{}]",
|
||||||
|
get_hint(key_config.stashing_toggle_index),
|
||||||
|
),
|
||||||
"toggle including staged files into stash",
|
"toggle including staged files into stash",
|
||||||
CMD_GROUP_STASHING,
|
CMD_GROUP_STASHING,
|
||||||
);
|
)
|
||||||
///
|
}
|
||||||
pub static STASHING_TOGGLE_UNTRACKED: CommandText =
|
pub fn stashing_toggle_untracked(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
CommandText::new(
|
CommandText::new(
|
||||||
"Toggle Untracked [u]",
|
format!(
|
||||||
|
"Toggle Untracked [{}]",
|
||||||
|
get_hint(key_config.stashing_toggle_untracked),
|
||||||
|
),
|
||||||
"toggle including untracked files into stash",
|
"toggle including untracked files into stash",
|
||||||
CMD_GROUP_STASHING,
|
CMD_GROUP_STASHING,
|
||||||
);
|
)
|
||||||
///
|
}
|
||||||
pub static STASHING_CONFIRM_MSG: CommandText = CommandText::new(
|
pub fn stashing_confirm_msg(
|
||||||
"Stash [enter]",
|
key_config: &SharedKeyConfig,
|
||||||
"save files to stash",
|
) -> CommandText {
|
||||||
CMD_GROUP_STASHING,
|
CommandText::new(
|
||||||
);
|
format!("Stash [{}]", get_hint(key_config.close_msg),),
|
||||||
///
|
"save files to stash",
|
||||||
pub static STASHLIST_APPLY: CommandText = CommandText::new(
|
CMD_GROUP_STASHING,
|
||||||
"Apply [enter]",
|
)
|
||||||
"apply selected stash",
|
}
|
||||||
CMD_GROUP_STASHES,
|
pub fn stashlist_apply(
|
||||||
);
|
key_config: &SharedKeyConfig,
|
||||||
///
|
) -> CommandText {
|
||||||
pub static STASHLIST_DROP: CommandText = CommandText::new(
|
CommandText::new(
|
||||||
"Drop [D]",
|
format!("Apply [{}]", get_hint(key_config.stash_apply),),
|
||||||
"drop selected stash",
|
"apply selected stash",
|
||||||
CMD_GROUP_STASHES,
|
CMD_GROUP_STASHES,
|
||||||
);
|
)
|
||||||
///
|
}
|
||||||
pub static STASHLIST_INSPECT: CommandText = CommandText::new(
|
pub fn stashlist_drop(
|
||||||
"Inspect [\u{2192}]", //→
|
key_config: &SharedKeyConfig,
|
||||||
"open stash commit details (allows to diff files)",
|
) -> CommandText {
|
||||||
CMD_GROUP_STASHES,
|
CommandText::new(
|
||||||
);
|
format!("Drop [{}]", get_hint(key_config.stash_drop),),
|
||||||
|
"drop selected stash",
|
||||||
///
|
CMD_GROUP_STASHES,
|
||||||
pub static LOG_DETAILS_TOGGLE: CommandText = CommandText::new(
|
)
|
||||||
"Details [enter]",
|
}
|
||||||
"open details of selected commit",
|
pub fn stashlist_inspect(
|
||||||
CMD_GROUP_LOG,
|
key_config: &SharedKeyConfig,
|
||||||
);
|
) -> CommandText {
|
||||||
///
|
CommandText::new(
|
||||||
pub static LOG_DETAILS_OPEN: CommandText = CommandText::new(
|
format!("Inspect [{}]", get_hint(key_config.focus_right),),
|
||||||
"Inspect [\u{2192}]", //→
|
"open stash commit details (allows to diff files)",
|
||||||
"inspect selected commit in detail",
|
CMD_GROUP_STASHES,
|
||||||
CMD_GROUP_LOG,
|
)
|
||||||
);
|
}
|
||||||
///
|
pub fn log_details_toggle(
|
||||||
pub static LOG_TAG_COMMIT: CommandText =
|
key_config: &SharedKeyConfig,
|
||||||
CommandText::new("Tag [t]", "tag commit", CMD_GROUP_LOG);
|
) -> CommandText {
|
||||||
///
|
CommandText::new(
|
||||||
pub static TAG_COMMIT_CONFIRM_MSG: CommandText =
|
format!(
|
||||||
CommandText::new("Tag [enter]", "tag commit", CMD_GROUP_LOG);
|
"Details Inspect [{}]",
|
||||||
|
get_hint(key_config.log_commit_details),
|
||||||
|
),
|
||||||
|
"open details of selected commit",
|
||||||
|
CMD_GROUP_LOG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn log_details_open(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Inspect [{}]", get_hint(key_config.focus_right),),
|
||||||
|
"inspect selected commit in detail",
|
||||||
|
CMD_GROUP_LOG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn log_tag_commit(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Tag [{}]", get_hint(key_config.log_tag_commit),),
|
||||||
|
"tag commit",
|
||||||
|
CMD_GROUP_LOG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pub fn tag_commit_confirm_msg(
|
||||||
|
key_config: &SharedKeyConfig,
|
||||||
|
) -> CommandText {
|
||||||
|
CommandText::new(
|
||||||
|
format!("Tag [{}]", get_hint(key_config.close_msg),),
|
||||||
|
"tag commit",
|
||||||
|
CMD_GROUP_LOG,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,9 @@ use crate::{
|
|||||||
CommitDetailsComponent, CommitList, Component,
|
CommitDetailsComponent, CommitList, Component,
|
||||||
DrawableComponent,
|
DrawableComponent,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, Queue},
|
queue::{InternalEvent, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -36,6 +36,7 @@ pub struct Revlog {
|
|||||||
queue: Queue,
|
queue: Queue,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
branch_name: cached::BranchName,
|
branch_name: cached::BranchName,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Revlog {
|
impl Revlog {
|
||||||
@ -44,6 +45,7 @@ impl Revlog {
|
|||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
@ -51,12 +53,18 @@ impl Revlog {
|
|||||||
queue,
|
queue,
|
||||||
sender,
|
sender,
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
list: CommitList::new(
|
||||||
|
&strings::log_title(&key_config),
|
||||||
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
list: CommitList::new(strings::LOG_TITLE, theme),
|
|
||||||
git_log: AsyncLog::new(sender),
|
git_log: AsyncLog::new(sender),
|
||||||
git_tags: AsyncTags::new(sender),
|
git_tags: AsyncTags::new(sender),
|
||||||
visible: false,
|
visible: false,
|
||||||
branch_name: cached::BranchName::new(CWD),
|
branch_name: cached::BranchName::new(CWD),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,48 +207,35 @@ impl Component for Revlog {
|
|||||||
if event_used {
|
if event_used {
|
||||||
self.update()?;
|
self.update()?;
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else {
|
} else if let Event::Key(k) = ev {
|
||||||
match ev {
|
if k == self.key_config.log_commit_details {
|
||||||
Event::Key(keys::LOG_COMMIT_DETAILS) => {
|
self.commit_details.toggle_visible()?;
|
||||||
self.commit_details.toggle_visible()?;
|
self.update()?;
|
||||||
self.update()?;
|
return Ok(true);
|
||||||
return Ok(true);
|
} else if k == self.key_config.log_tag_commit {
|
||||||
}
|
return if let Some(id) = self.selected_commit() {
|
||||||
|
self.queue
|
||||||
Event::Key(keys::LOG_TAG_COMMIT) => {
|
.borrow_mut()
|
||||||
return if let Some(id) =
|
.push_back(InternalEvent::TagCommit(id));
|
||||||
self.selected_commit()
|
Ok(true)
|
||||||
{
|
} else {
|
||||||
self.queue.borrow_mut().push_back(
|
Ok(false)
|
||||||
InternalEvent::TagCommit(id),
|
};
|
||||||
);
|
} else if k == self.key_config.focus_right
|
||||||
Ok(true)
|
&& self.commit_details.is_visible()
|
||||||
} else {
|
{
|
||||||
Ok(false)
|
return if let Some(id) = self.selected_commit() {
|
||||||
};
|
self.queue.borrow_mut().push_back(
|
||||||
}
|
InternalEvent::InspectCommit(
|
||||||
|
id,
|
||||||
Event::Key(keys::FOCUS_RIGHT)
|
self.selected_commit_tags(&Some(id)),
|
||||||
if self.commit_details.is_visible() =>
|
),
|
||||||
{
|
);
|
||||||
return if let Some(id) =
|
Ok(true)
|
||||||
self.selected_commit()
|
} else {
|
||||||
{
|
Ok(false)
|
||||||
self.queue.borrow_mut().push_back(
|
};
|
||||||
InternalEvent::InspectCommit(
|
} else {
|
||||||
id,
|
|
||||||
self.selected_commit_tags(&Some(
|
|
||||||
id,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
Ok(true)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,20 +253,20 @@ impl Component for Revlog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::LOG_DETAILS_TOGGLE,
|
strings::commands::log_details_toggle(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible,
|
self.visible,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::LOG_DETAILS_OPEN,
|
strings::commands::log_details_open(&self.key_config),
|
||||||
true,
|
true,
|
||||||
(self.visible && self.commit_details.is_visible())
|
(self.visible && self.commit_details.is_visible())
|
||||||
|| force_all,
|
|| force_all,
|
||||||
));
|
));
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::LOG_TAG_COMMIT,
|
strings::commands::log_tag_commit(&self.key_config),
|
||||||
true,
|
true,
|
||||||
self.visible || force_all,
|
self.visible || force_all,
|
||||||
));
|
));
|
||||||
|
@ -5,9 +5,9 @@ use crate::{
|
|||||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||||
FileTreeComponent,
|
FileTreeComponent,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, Queue},
|
queue::{InternalEvent, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -36,6 +36,7 @@ pub struct Stashing {
|
|||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
git_status: AsyncStatus,
|
git_status: AsyncStatus,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stashing {
|
impl Stashing {
|
||||||
@ -46,13 +47,15 @@ impl Stashing {
|
|||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
index: FileTreeComponent::new(
|
index: FileTreeComponent::new(
|
||||||
strings::STASHING_FILES_TITLE,
|
&strings::stashing_files_title(&key_config),
|
||||||
true,
|
true,
|
||||||
Some(queue.clone()),
|
Some(queue.clone()),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
visible: false,
|
visible: false,
|
||||||
options: StashingOptions {
|
options: StashingOptions {
|
||||||
@ -62,6 +65,7 @@ impl Stashing {
|
|||||||
theme,
|
theme,
|
||||||
git_status: AsyncStatus::new(sender.clone()),
|
git_status: AsyncStatus::new(sender.clone()),
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,11 +153,11 @@ impl DrawableComponent for Stashing {
|
|||||||
|
|
||||||
f.render_widget(
|
f.render_widget(
|
||||||
Paragraph::new(self.get_option_text().iter())
|
Paragraph::new(self.get_option_text().iter())
|
||||||
.block(
|
.block(Block::default().borders(Borders::ALL).title(
|
||||||
Block::default()
|
&strings::stashing_options_title(
|
||||||
.borders(Borders::ALL)
|
&self.key_config,
|
||||||
.title(strings::STASHING_OPTIONS_TITLE),
|
),
|
||||||
)
|
))
|
||||||
.alignment(Alignment::Left),
|
.alignment(Alignment::Left),
|
||||||
right_chunks[0],
|
right_chunks[0],
|
||||||
);
|
);
|
||||||
@ -178,17 +182,21 @@ impl Component for Stashing {
|
|||||||
);
|
);
|
||||||
|
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHING_SAVE,
|
strings::commands::stashing_save(&self.key_config),
|
||||||
self.visible && !self.index.is_empty(),
|
self.visible && !self.index.is_empty(),
|
||||||
self.visible || force_all,
|
self.visible || force_all,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHING_TOGGLE_INDEXED,
|
strings::commands::stashing_toggle_indexed(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
self.visible,
|
self.visible,
|
||||||
self.visible || force_all,
|
self.visible || force_all,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHING_TOGGLE_UNTRACKED,
|
strings::commands::stashing_toggle_untracked(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
self.visible,
|
self.visible,
|
||||||
self.visible || force_all,
|
self.visible || force_all,
|
||||||
));
|
));
|
||||||
@ -204,31 +212,30 @@ impl Component for Stashing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Event::Key(k) = ev {
|
if let Event::Key(k) = ev {
|
||||||
return match k {
|
return if k == self.key_config.stashing_save
|
||||||
keys::STASHING_SAVE if !self.index.is_empty() => {
|
&& !self.index.is_empty()
|
||||||
self.queue.borrow_mut().push_back(
|
{
|
||||||
InternalEvent::PopupStashing(
|
self.queue.borrow_mut().push_back(
|
||||||
self.options,
|
InternalEvent::PopupStashing(self.options),
|
||||||
),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
} else if k == self.key_config.stashing_toggle_index {
|
||||||
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(true)
|
||||||
Ok(true)
|
} else if k
|
||||||
}
|
== self.key_config.stashing_toggle_untracked
|
||||||
keys::STASHING_TOGGLE_UNTRACKED => {
|
{
|
||||||
self.options.stash_untracked =
|
self.options.stash_untracked =
|
||||||
!self.options.stash_untracked;
|
!self.options.stash_untracked;
|
||||||
self.update()?;
|
self.update()?;
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
} else {
|
||||||
_ => Ok(false),
|
Ok(false)
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
|
@ -3,9 +3,9 @@ use crate::{
|
|||||||
visibility_blocking, CommandBlocking, CommandInfo,
|
visibility_blocking, CommandBlocking, CommandInfo,
|
||||||
CommitList, Component, DrawableComponent,
|
CommitList, Component, DrawableComponent,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{Action, InternalEvent, Queue},
|
queue::{Action, InternalEvent, Queue},
|
||||||
strings::{self, commands},
|
strings,
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -19,15 +19,25 @@ pub struct StashList {
|
|||||||
list: CommitList,
|
list: CommitList,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StashList {
|
impl StashList {
|
||||||
///
|
///
|
||||||
pub fn new(queue: &Queue, theme: SharedTheme) -> Self {
|
pub fn new(
|
||||||
|
queue: &Queue,
|
||||||
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
visible: false,
|
visible: false,
|
||||||
list: CommitList::new(strings::STASHLIST_TITLE, theme),
|
list: CommitList::new(
|
||||||
|
&strings::stashlist_title(&key_config),
|
||||||
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,17 +121,19 @@ impl Component for StashList {
|
|||||||
let selection_valid =
|
let selection_valid =
|
||||||
self.list.selected_entry().is_some();
|
self.list.selected_entry().is_some();
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHLIST_APPLY,
|
strings::commands::stashlist_apply(&self.key_config),
|
||||||
selection_valid,
|
selection_valid,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHLIST_DROP,
|
strings::commands::stashlist_drop(&self.key_config),
|
||||||
selection_valid,
|
selection_valid,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::STASHLIST_INSPECT,
|
strings::commands::stashlist_inspect(
|
||||||
|
&self.key_config,
|
||||||
|
),
|
||||||
selection_valid,
|
selection_valid,
|
||||||
true,
|
true,
|
||||||
));
|
));
|
||||||
@ -137,13 +149,14 @@ impl Component for StashList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Event::Key(k) = ev {
|
if let Event::Key(k) = ev {
|
||||||
match k {
|
if k == self.key_config.stash_apply {
|
||||||
keys::STASH_APPLY => self.apply_stash(),
|
self.apply_stash()
|
||||||
keys::STASH_DROP => self.drop_stash(),
|
} else if k == self.key_config.stash_drop {
|
||||||
keys::STASH_OPEN => self.inspect(),
|
self.drop_stash()
|
||||||
|
} else if k == self.key_config.stash_open {
|
||||||
_ => (),
|
self.inspect()
|
||||||
};
|
} else {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ use crate::{
|
|||||||
ChangesComponent, CommandBlocking, CommandInfo, Component,
|
ChangesComponent, CommandBlocking, CommandInfo, Component,
|
||||||
DiffComponent, DrawableComponent, FileTreeItemKind,
|
DiffComponent, DrawableComponent, FileTreeItemKind,
|
||||||
},
|
},
|
||||||
keys,
|
keys::SharedKeyConfig,
|
||||||
queue::{InternalEvent, Queue, ResetItem},
|
queue::{InternalEvent, Queue, ResetItem},
|
||||||
strings::{self, commands, order},
|
strings::{self, order},
|
||||||
ui::style::SharedTheme,
|
ui::style::SharedTheme,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -47,6 +47,7 @@ pub struct Status {
|
|||||||
git_status_stage: AsyncStatus,
|
git_status_stage: AsyncStatus,
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
git_action_executed: bool,
|
git_action_executed: bool,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DrawableComponent for Status {
|
impl DrawableComponent for Status {
|
||||||
@ -107,6 +108,7 @@ impl Status {
|
|||||||
queue: &Queue,
|
queue: &Queue,
|
||||||
sender: &Sender<AsyncNotification>,
|
sender: &Sender<AsyncNotification>,
|
||||||
theme: SharedTheme,
|
theme: SharedTheme,
|
||||||
|
key_config: SharedKeyConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queue: queue.clone(),
|
queue: queue.clone(),
|
||||||
@ -114,24 +116,32 @@ impl Status {
|
|||||||
focus: Focus::WorkDir,
|
focus: Focus::WorkDir,
|
||||||
diff_target: DiffTarget::WorkingDir,
|
diff_target: DiffTarget::WorkingDir,
|
||||||
index_wd: ChangesComponent::new(
|
index_wd: ChangesComponent::new(
|
||||||
strings::TITLE_STATUS,
|
&strings::title_status(&key_config),
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
),
|
),
|
||||||
index: ChangesComponent::new(
|
index: ChangesComponent::new(
|
||||||
strings::TITLE_INDEX,
|
&strings::title_index(&key_config),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
theme.clone(),
|
theme.clone(),
|
||||||
|
key_config.clone(),
|
||||||
|
),
|
||||||
|
diff: DiffComponent::new(
|
||||||
|
queue.clone(),
|
||||||
|
theme,
|
||||||
|
key_config.clone(),
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
diff: DiffComponent::new(queue.clone(), theme, false),
|
|
||||||
git_diff: AsyncDiff::new(sender.clone()),
|
git_diff: AsyncDiff::new(sender.clone()),
|
||||||
git_status_workdir: AsyncStatus::new(sender.clone()),
|
git_status_workdir: AsyncStatus::new(sender.clone()),
|
||||||
git_status_stage: AsyncStatus::new(sender.clone()),
|
git_status_stage: AsyncStatus::new(sender.clone()),
|
||||||
git_action_executed: false,
|
git_action_executed: false,
|
||||||
|
key_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +342,7 @@ impl Component for Status {
|
|||||||
{
|
{
|
||||||
let focus_on_diff = self.focus == Focus::Diff;
|
let focus_on_diff = self.focus == Focus::Diff;
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::EDIT_ITEM,
|
strings::commands::edit_item(&self.key_config),
|
||||||
if focus_on_diff {
|
if focus_on_diff {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -341,12 +351,12 @@ impl Component for Status {
|
|||||||
self.visible || force_all,
|
self.visible || force_all,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_FOCUS_LEFT,
|
strings::commands::diff_focus_left(&self.key_config),
|
||||||
true,
|
true,
|
||||||
(self.visible && focus_on_diff) || force_all,
|
(self.visible && focus_on_diff) || force_all,
|
||||||
));
|
));
|
||||||
out.push(CommandInfo::new(
|
out.push(CommandInfo::new(
|
||||||
commands::DIFF_FOCUS_RIGHT,
|
strings::commands::diff_focus_right(&self.key_config),
|
||||||
self.can_focus_diff(),
|
self.can_focus_diff(),
|
||||||
(self.visible && !focus_on_diff) || force_all,
|
(self.visible && !focus_on_diff) || force_all,
|
||||||
));
|
));
|
||||||
@ -354,7 +364,7 @@ impl Component for Status {
|
|||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::SELECT_STATUS,
|
strings::commands::select_status(&self.key_config),
|
||||||
true,
|
true,
|
||||||
(self.visible && self.focus == Focus::Diff)
|
(self.visible && self.focus == Focus::Diff)
|
||||||
|| force_all,
|
|| force_all,
|
||||||
@ -364,7 +374,7 @@ impl Component for Status {
|
|||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::SELECT_STAGING,
|
strings::commands::select_staging(&self.key_config),
|
||||||
true,
|
true,
|
||||||
(self.visible && self.focus == Focus::WorkDir)
|
(self.visible && self.focus == Focus::WorkDir)
|
||||||
|| force_all,
|
|| force_all,
|
||||||
@ -374,7 +384,7 @@ impl Component for Status {
|
|||||||
|
|
||||||
out.push(
|
out.push(
|
||||||
CommandInfo::new(
|
CommandInfo::new(
|
||||||
commands::SELECT_UNSTAGED,
|
strings::commands::select_unstaged(&self.key_config),
|
||||||
true,
|
true,
|
||||||
(self.visible && self.focus == Focus::Stage)
|
(self.visible && self.focus == Focus::Stage)
|
||||||
|| force_all,
|
|| force_all,
|
||||||
@ -393,50 +403,43 @@ impl Component for Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Event::Key(k) = ev {
|
if let Event::Key(k) = ev {
|
||||||
return match k {
|
return if k == self.key_config.focus_workdir {
|
||||||
keys::FOCUS_WORKDIR => {
|
self.switch_focus(Focus::WorkDir)
|
||||||
self.switch_focus(Focus::WorkDir)
|
} else if k == self.key_config.focus_stage {
|
||||||
|
self.switch_focus(Focus::Stage)
|
||||||
|
} else if k == self.key_config.edit_file
|
||||||
|
&& (self.can_focus_diff()
|
||||||
|
|| self.focus == Focus::Diff)
|
||||||
|
{
|
||||||
|
if let Some((path, _)) = self.selected_path() {
|
||||||
|
self.queue.borrow_mut().push_back(
|
||||||
|
InternalEvent::OpenExternalEditor(Some(
|
||||||
|
path,
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
keys::FOCUS_STAGE => {
|
Ok(true)
|
||||||
self.switch_focus(Focus::Stage)
|
} else if k == self.key_config.focus_right
|
||||||
}
|
&& self.can_focus_diff()
|
||||||
keys::EDIT_FILE
|
{
|
||||||
if self.can_focus_diff()
|
self.switch_focus(Focus::Diff)
|
||||||
|| self.focus == Focus::Diff =>
|
} else if k == self.key_config.focus_left {
|
||||||
{
|
self.switch_focus(match self.diff_target {
|
||||||
if let Some((path, _)) = self.selected_path()
|
DiffTarget::Stage => Focus::Stage,
|
||||||
{
|
DiffTarget::WorkingDir => Focus::WorkDir,
|
||||||
self.queue.borrow_mut().push_back(
|
})
|
||||||
InternalEvent::OpenExternalEditor(
|
} else if k == self.key_config.move_down
|
||||||
Some(path),
|
&& self.focus == Focus::WorkDir
|
||||||
),
|
&& !self.index.is_empty()
|
||||||
);
|
{
|
||||||
}
|
self.switch_focus(Focus::Stage)
|
||||||
Ok(true)
|
} else if k == self.key_config.move_up
|
||||||
}
|
&& self.focus == Focus::Stage
|
||||||
keys::FOCUS_RIGHT if self.can_focus_diff() => {
|
&& !self.index_wd.is_empty()
|
||||||
self.switch_focus(Focus::Diff)
|
{
|
||||||
}
|
self.switch_focus(Focus::WorkDir)
|
||||||
keys::FOCUS_LEFT => {
|
} else {
|
||||||
self.switch_focus(match self.diff_target {
|
Ok(false)
|
||||||
DiffTarget::Stage => Focus::Stage,
|
|
||||||
DiffTarget::WorkingDir => Focus::WorkDir,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
keys::MOVE_DOWN
|
|
||||||
if self.focus == Focus::WorkDir
|
|
||||||
&& !self.index.is_empty() =>
|
|
||||||
{
|
|
||||||
self.switch_focus(Focus::Stage)
|
|
||||||
}
|
|
||||||
|
|
||||||
keys::MOVE_UP
|
|
||||||
if self.focus == Focus::Stage
|
|
||||||
&& !self.index_wd.is_empty() =>
|
|
||||||
{
|
|
||||||
self.switch_focus(Focus::WorkDir)
|
|
||||||
}
|
|
||||||
_ => Ok(false),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user