Skip to content

Commit d617ba7

Browse files
author
Stephan Dilly
committed
simplify key bindings file handling (#946)
1 parent f689c42 commit d617ba7

File tree

7 files changed

+244
-165
lines changed

7 files changed

+244
-165
lines changed

CHANGELOG.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## Unreleased
9-
9+
10+
### Breaking Change
11+
Have you used `key_config.ron` for custom key bindings before?
12+
The way this works got changed and simplified ([See docs](https://github.com/extrawurst/gitui/blob/master/KEY_CONFIG.md) for more info):
13+
* You only define the keys that should differ from the default.
14+
* The file is renamed to `key_bindings.ron`
15+
* Future addition of new keys will not break anymore
16+
1017
### Added
1118
- add `trace-libgit` feature to make git tracing optional [[@dm9pZCAq](https://github.com/dm9pZCAq)] ([#902](https://github.com/extrawurst/gitui/issues/902))
1219
- support merging and rebasing remote branches ([#920](https://github.com/extrawurst/gitui/issues/920))
1320
- add highlighting matches in fuzzy finder ([#893](https://github.com/extrawurst/gitui/issues/893))
1421
- support `home` and `end` keys in branchlist ([#957](https://github.com/extrawurst/gitui/issues/957))
1522
- add `ghemoji` feature to make gh-emoji (GitHub emoji) optional ([#954](https://github.com/extrawurst/gitui/pull/954))
1623
- allow customizing key symbols like `` & `` ([see docs](https://github.com/extrawurst/gitui/blob/master/KEY_CONFIG.md#key-symbols)) ([#465](https://github.com/extrawurst/gitui/issues/465))
17-
- fuzzy finder up/down keys compatible with typing search patterns ([#993](https://github.com/extrawurst/gitui/pull/993))
24+
- simplify key overrides ([see docs](https://github.com/extrawurst/gitui/blob/master/KEY_CONFIG.md)) ([#946](https://github.com/extrawurst/gitui/issues/946))
25+
- dedicated fuzzy finder up/down keys to allow vim overrides ([#993](https://github.com/extrawurst/gitui/pull/993))
1826

1927
### Fixed
2028
- honor options (for untracked files) in `stage_all` command ([#933](https://github.com/extrawurst/gitui/issues/933))

KEY_CONFIG.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ The default keys are based on arrow keys to navigate.
44

55
However popular demand lead to fully customizability of the key bindings.
66

7-
On first start `gitui` will create `key_config.ron` file automatically based on the defaults.
7+
On first start `gitui` will create `key_bindings.ron` file automatically based on the defaults.
88
This file allows changing every key binding.
99

1010
The config file format based on the [Ron file format](https://github.com/ron-rs/ron).
1111
The location of the file depends on your OS:
12-
* `$HOME/.config/gitui/key_config.ron` (mac)
13-
* `$XDG_CONFIG_HOME/gitui/key_config.ron` (linux using XDG)
14-
* `$HOME/.config/gitui/key_config.ron` (linux)
15-
* `%APPDATA%/gitui/key_config.ron` (Windows)
12+
* `$HOME/.config/gitui/key_bindings.ron` (mac)
13+
* `$XDG_CONFIG_HOME/gitui/key_bindings.ron` (linux using XDG)
14+
* `$HOME/.config/gitui/key_bindings.ron` (linux)
15+
* `%APPDATA%/gitui/key_bindings.ron` (Windows)
1616

17-
Here is a [vim style key config](vim_style_key_config.ron) with `h`, `j`, `k`, `l` to navigate. Use it to copy the content into `key_config.ron` to get vim style key bindings.
17+
Here is a [vim style key config](vim_style_key_config.ron) with `h`, `j`, `k`, `l` to navigate. Use it to copy the content into `key_bindings.ron` to get vim style key bindings.
1818

1919
# Key Symbols
2020

src/keys/key_config.rs

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anyhow::Result;
22
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
3-
use std::{fs, path::PathBuf, rc::Rc};
3+
use std::{path::PathBuf, rc::Rc};
44

55
use crate::{args::get_app_config_path, strings::symbol};
66

@@ -17,42 +17,16 @@ pub struct KeyConfig {
1717
impl KeyConfig {
1818
fn get_config_file() -> Result<PathBuf> {
1919
let app_home = get_app_config_path()?;
20-
Ok(app_home.join("key_config.ron"))
20+
Ok(app_home.join("key_bindings.ron"))
2121
}
2222

2323
fn get_symbols_file() -> Result<PathBuf> {
2424
let app_home = get_app_config_path()?;
2525
Ok(app_home.join("key_symbols.ron"))
2626
}
2727

28-
fn init_keys() -> Result<KeysList> {
29-
let file = Self::get_config_file()?;
30-
if file.exists() {
31-
match KeysList::read_file(file.clone()) {
32-
Err(e) => {
33-
let config_path = file.clone();
34-
let config_path_old =
35-
format!("{}.old", file.to_string_lossy());
36-
fs::rename(
37-
config_path.clone(),
38-
config_path_old.clone(),
39-
)?;
40-
41-
KeysList::default().save(file)?;
42-
43-
Err(anyhow::anyhow!("{}\n Old file was renamed to {:?}.\n Defaults loaded and saved as {:?}",
44-
e,config_path_old,config_path.to_string_lossy()))
45-
}
46-
Ok(keys) => Ok(keys),
47-
}
48-
} else {
49-
KeysList::default().save(file)?;
50-
Ok(KeysList::default())
51-
}
52-
}
53-
5428
pub fn init() -> Result<Self> {
55-
let keys = Self::init_keys()?;
29+
let keys = KeysList::init(Self::get_config_file()?);
5630
let symbols = KeySymbols::init(Self::get_symbols_file()?);
5731
Ok(Self { keys, symbols })
5832
}

src/keys/key_list.rs

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
1-
use anyhow::Result;
21
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
3-
use ron::{
4-
self,
5-
ser::{to_string_pretty, PrettyConfig},
6-
};
7-
use serde::{Deserialize, Serialize};
8-
use std::{
9-
fs::File,
10-
io::{Read, Write},
11-
path::PathBuf,
12-
};
2+
use std::path::PathBuf;
3+
4+
use super::key_list_file::KeysListFile;
135

14-
#[derive(Serialize, Deserialize, Debug)]
156
pub struct KeysList {
167
pub tab_status: KeyEvent,
178
pub tab_log: KeyEvent,
@@ -164,31 +155,13 @@ impl Default for KeysList {
164155
}
165156

166157
impl KeysList {
167-
pub fn save(&self, file: PathBuf) -> Result<()> {
168-
let mut file = File::create(file)?;
169-
let data = to_string_pretty(self, PrettyConfig::default())?;
170-
file.write_all(data.as_bytes())?;
171-
Ok(())
172-
}
173-
174-
pub fn read_file(config_file: PathBuf) -> Result<Self> {
175-
let mut f = File::open(config_file)?;
176-
let mut buffer = Vec::new();
177-
f.read_to_end(&mut buffer)?;
178-
Ok(ron::de::from_bytes(&buffer)?)
179-
}
180-
}
181-
182-
#[cfg(test)]
183-
mod tests {
184-
use super::*;
185-
186-
#[test]
187-
fn test_load_vim_style_example() {
188-
assert_eq!(
189-
KeysList::read_file("vim_style_key_config.ron".into())
190-
.is_ok(),
191-
true
192-
);
158+
pub fn init(file: PathBuf) -> Self {
159+
if file.exists() {
160+
let file =
161+
KeysListFile::read_file(file).unwrap_or_default();
162+
file.get_list()
163+
} else {
164+
Self::default()
165+
}
193166
}
194167
}

src/keys/key_list_file.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
use anyhow::Result;
2+
use crossterm::event::KeyEvent;
3+
use ron::{self};
4+
use serde::{Deserialize, Serialize};
5+
use std::{fs::File, io::Read, path::PathBuf};
6+
7+
use super::key_list::KeysList;
8+
9+
#[derive(Serialize, Deserialize, Default)]
10+
pub struct KeysListFile {
11+
pub tab_status: Option<KeyEvent>,
12+
pub tab_log: Option<KeyEvent>,
13+
pub tab_files: Option<KeyEvent>,
14+
pub tab_stashing: Option<KeyEvent>,
15+
pub tab_stashes: Option<KeyEvent>,
16+
pub tab_toggle: Option<KeyEvent>,
17+
pub tab_toggle_reverse: Option<KeyEvent>,
18+
pub toggle_workarea: Option<KeyEvent>,
19+
pub focus_right: Option<KeyEvent>,
20+
pub focus_left: Option<KeyEvent>,
21+
pub focus_above: Option<KeyEvent>,
22+
pub focus_below: Option<KeyEvent>,
23+
pub exit: Option<KeyEvent>,
24+
pub quit: Option<KeyEvent>,
25+
pub exit_popup: Option<KeyEvent>,
26+
pub open_commit: Option<KeyEvent>,
27+
pub open_commit_editor: Option<KeyEvent>,
28+
pub open_help: Option<KeyEvent>,
29+
pub open_options: Option<KeyEvent>,
30+
pub move_left: Option<KeyEvent>,
31+
pub move_right: Option<KeyEvent>,
32+
pub tree_collapse_recursive: Option<KeyEvent>,
33+
pub tree_expand_recursive: Option<KeyEvent>,
34+
pub home: Option<KeyEvent>,
35+
pub end: Option<KeyEvent>,
36+
pub move_up: Option<KeyEvent>,
37+
pub move_down: Option<KeyEvent>,
38+
pub popup_up: Option<KeyEvent>,
39+
pub popup_down: Option<KeyEvent>,
40+
pub page_down: Option<KeyEvent>,
41+
pub page_up: Option<KeyEvent>,
42+
pub shift_up: Option<KeyEvent>,
43+
pub shift_down: Option<KeyEvent>,
44+
pub enter: Option<KeyEvent>,
45+
pub blame: Option<KeyEvent>,
46+
pub edit_file: Option<KeyEvent>,
47+
pub status_stage_all: Option<KeyEvent>,
48+
pub status_reset_item: Option<KeyEvent>,
49+
pub status_ignore_file: Option<KeyEvent>,
50+
pub diff_stage_lines: Option<KeyEvent>,
51+
pub diff_reset_lines: Option<KeyEvent>,
52+
pub stashing_save: Option<KeyEvent>,
53+
pub stashing_toggle_untracked: Option<KeyEvent>,
54+
pub stashing_toggle_index: Option<KeyEvent>,
55+
pub stash_apply: Option<KeyEvent>,
56+
pub stash_open: Option<KeyEvent>,
57+
pub stash_drop: Option<KeyEvent>,
58+
pub cmd_bar_toggle: Option<KeyEvent>,
59+
pub log_tag_commit: Option<KeyEvent>,
60+
pub log_mark_commit: Option<KeyEvent>,
61+
pub commit_amend: Option<KeyEvent>,
62+
pub copy: Option<KeyEvent>,
63+
pub create_branch: Option<KeyEvent>,
64+
pub rename_branch: Option<KeyEvent>,
65+
pub select_branch: Option<KeyEvent>,
66+
pub delete_branch: Option<KeyEvent>,
67+
pub merge_branch: Option<KeyEvent>,
68+
pub rebase_branch: Option<KeyEvent>,
69+
pub compare_commits: Option<KeyEvent>,
70+
pub tags: Option<KeyEvent>,
71+
pub delete_tag: Option<KeyEvent>,
72+
pub select_tag: Option<KeyEvent>,
73+
pub push: Option<KeyEvent>,
74+
pub open_file_tree: Option<KeyEvent>,
75+
pub file_find: Option<KeyEvent>,
76+
pub force_push: Option<KeyEvent>,
77+
pub pull: Option<KeyEvent>,
78+
pub abort_merge: Option<KeyEvent>,
79+
pub undo_commit: Option<KeyEvent>,
80+
pub stage_unstage_item: Option<KeyEvent>,
81+
}
82+
83+
impl KeysListFile {
84+
#[allow(dead_code)]
85+
pub fn read_file(config_file: PathBuf) -> Result<Self> {
86+
let mut f = File::open(config_file)?;
87+
let mut buffer = Vec::new();
88+
f.read_to_end(&mut buffer)?;
89+
Ok(ron::de::from_bytes(&buffer)?)
90+
}
91+
92+
#[rustfmt::skip]
93+
pub fn get_list(self) -> KeysList {
94+
let default = KeysList::default();
95+
96+
KeysList {
97+
tab_status: self.tab_status.unwrap_or(default.tab_status),
98+
tab_log: self.tab_log.unwrap_or(default.tab_log),
99+
tab_files: self.tab_files.unwrap_or(default.tab_files),
100+
tab_stashing: self.tab_stashing.unwrap_or(default.tab_stashing),
101+
tab_stashes: self.tab_stashes.unwrap_or(default.tab_stashes),
102+
tab_toggle: self.tab_toggle.unwrap_or(default.tab_toggle),
103+
tab_toggle_reverse: self.tab_toggle_reverse.unwrap_or(default.tab_toggle_reverse),
104+
toggle_workarea: self.toggle_workarea.unwrap_or(default.toggle_workarea),
105+
focus_right: self.focus_right.unwrap_or(default.focus_right),
106+
focus_left: self.focus_left.unwrap_or(default.focus_left),
107+
focus_above: self.focus_above.unwrap_or(default.focus_above),
108+
focus_below: self.focus_below.unwrap_or(default.focus_below),
109+
exit: self.exit.unwrap_or(default.exit),
110+
quit: self.quit.unwrap_or(default.quit),
111+
exit_popup: self.exit_popup.unwrap_or(default.exit_popup),
112+
open_commit: self.open_commit.unwrap_or(default.open_commit),
113+
open_commit_editor: self.open_commit_editor.unwrap_or(default.open_commit_editor),
114+
open_help: self.open_help.unwrap_or(default.open_help),
115+
open_options: self.open_options.unwrap_or(default.open_options),
116+
move_left: self.move_left.unwrap_or(default.move_left),
117+
move_right: self.move_right.unwrap_or(default.move_right),
118+
tree_collapse_recursive: self.tree_collapse_recursive.unwrap_or(default.tree_collapse_recursive),
119+
tree_expand_recursive: self.tree_expand_recursive.unwrap_or(default.tree_expand_recursive),
120+
home: self.home.unwrap_or(default.home),
121+
end: self.end.unwrap_or(default.end),
122+
move_up: self.move_up.unwrap_or(default.move_up),
123+
move_down: self.move_down.unwrap_or(default.move_down),
124+
popup_up: self.popup_up.unwrap_or(default.popup_up),
125+
popup_down: self.popup_down.unwrap_or(default.popup_down),
126+
page_down: self.page_down.unwrap_or(default.page_down),
127+
page_up: self.page_up.unwrap_or(default.page_up),
128+
shift_up: self.shift_up.unwrap_or(default.shift_up),
129+
shift_down: self.shift_down.unwrap_or(default.shift_down),
130+
enter: self.enter.unwrap_or(default.enter),
131+
blame: self.blame.unwrap_or(default.blame),
132+
edit_file: self.edit_file.unwrap_or(default.edit_file),
133+
status_stage_all: self.status_stage_all.unwrap_or(default.status_stage_all),
134+
status_reset_item: self.status_reset_item.unwrap_or(default.status_reset_item),
135+
status_ignore_file: self.status_ignore_file.unwrap_or(default.status_ignore_file),
136+
diff_stage_lines: self.diff_stage_lines.unwrap_or(default.diff_stage_lines),
137+
diff_reset_lines: self.diff_reset_lines.unwrap_or(default.diff_reset_lines),
138+
stashing_save: self.stashing_save.unwrap_or(default.stashing_save),
139+
stashing_toggle_untracked: self.stashing_toggle_untracked.unwrap_or(default.stashing_toggle_untracked),
140+
stashing_toggle_index: self.stashing_toggle_index.unwrap_or(default.stashing_toggle_index),
141+
stash_apply: self.stash_apply.unwrap_or(default.stash_apply),
142+
stash_open: self.stash_open.unwrap_or(default.stash_open),
143+
stash_drop: self.stash_drop.unwrap_or(default.stash_drop),
144+
cmd_bar_toggle: self.cmd_bar_toggle.unwrap_or(default.cmd_bar_toggle),
145+
log_tag_commit: self.log_tag_commit.unwrap_or(default.log_tag_commit),
146+
log_mark_commit: self.log_mark_commit.unwrap_or(default.log_mark_commit),
147+
commit_amend: self.commit_amend.unwrap_or(default.commit_amend),
148+
copy: self.copy.unwrap_or(default.copy),
149+
create_branch: self.create_branch.unwrap_or(default.create_branch),
150+
rename_branch: self.rename_branch.unwrap_or(default.rename_branch),
151+
select_branch: self.select_branch.unwrap_or(default.select_branch),
152+
delete_branch: self.delete_branch.unwrap_or(default.delete_branch),
153+
merge_branch: self.merge_branch.unwrap_or(default.merge_branch),
154+
rebase_branch: self.rebase_branch.unwrap_or(default.rebase_branch),
155+
compare_commits: self.compare_commits.unwrap_or(default.compare_commits),
156+
tags: self.tags.unwrap_or(default.tags),
157+
delete_tag: self.delete_tag.unwrap_or(default.delete_tag),
158+
select_tag: self.select_tag.unwrap_or(default.select_tag),
159+
push: self.push.unwrap_or(default.push),
160+
open_file_tree: self.open_file_tree.unwrap_or(default.open_file_tree),
161+
file_find: self.file_find.unwrap_or(default.file_find),
162+
force_push: self.force_push.unwrap_or(default.force_push),
163+
pull: self.pull.unwrap_or(default.pull),
164+
abort_merge: self.abort_merge.unwrap_or(default.abort_merge),
165+
undo_commit: self.undo_commit.unwrap_or(default.undo_commit),
166+
stage_unstage_item: self.stage_unstage_item.unwrap_or(default.stage_unstage_item),
167+
}
168+
}
169+
}
170+
171+
#[cfg(test)]
172+
mod tests {
173+
use super::*;
174+
175+
#[test]
176+
fn test_load_vim_style_example() {
177+
assert_eq!(
178+
KeysListFile::read_file(
179+
"vim_style_key_config.ron".into()
180+
)
181+
.is_ok(),
182+
true
183+
);
184+
}
185+
}

src/keys/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod key_config;
22
mod key_list;
3+
mod key_list_file;
34
mod symbols;
45

56
pub use key_config::{KeyConfig, SharedKeyConfig};

0 commit comments

Comments
 (0)