mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 08:58:21 +00:00
1751 follow symlink for keybinding config (#1767)
This commit is contained in:
parent
e661ee6e3e
commit
104e5bf62e
2 changed files with 156 additions and 3 deletions
|
|
@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Fixes
|
||||
* fix commit dialog char count for multibyte characters ([#1726](https://github.com/extrawurst/gitui/issues/1726))
|
||||
* fix wrong hit highlighting in fuzzy find popup [[@UUGTech](https://github.com/UUGTech)] ([#1731](https://github.com/extrawurst/gitui/pull/1731))
|
||||
* fix symlink support for configuration files [[@TheBlackSheep3](https://github.com/TheBlackSheep3)] ([#1751](https://github.com/extrawurst/gitui/issues/1751))
|
||||
|
||||
## [0.23.0] - 2022-06-19
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::Result;
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use std::{path::PathBuf, rc::Rc};
|
||||
use std::{fs::canonicalize, path::PathBuf, rc::Rc};
|
||||
|
||||
use crate::{args::get_app_config_path, strings::symbol};
|
||||
|
||||
|
|
@ -10,6 +10,8 @@ use super::{
|
|||
};
|
||||
|
||||
pub type SharedKeyConfig = Rc<KeyConfig>;
|
||||
const KEY_LIST_FILENAME: &str = "key_bindings.ron";
|
||||
const KEY_SYMBOLS_FILENAME: &str = "key_symbols.ron";
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct KeyConfig {
|
||||
|
|
@ -20,12 +22,16 @@ pub struct KeyConfig {
|
|||
impl KeyConfig {
|
||||
fn get_config_file() -> Result<PathBuf> {
|
||||
let app_home = get_app_config_path()?;
|
||||
Ok(app_home.join("key_bindings.ron"))
|
||||
let config_file = app_home.join(KEY_LIST_FILENAME);
|
||||
canonicalize(&config_file)
|
||||
.map_or_else(|_| Ok(config_file), Ok)
|
||||
}
|
||||
|
||||
fn get_symbols_file() -> Result<PathBuf> {
|
||||
let app_home = get_app_config_path()?;
|
||||
Ok(app_home.join("key_symbols.ron"))
|
||||
let symbols_file = app_home.join(KEY_SYMBOLS_FILENAME);
|
||||
canonicalize(&symbols_file)
|
||||
.map_or_else(|_| Ok(symbols_file), Ok)
|
||||
}
|
||||
|
||||
pub fn init() -> Result<Self> {
|
||||
|
|
@ -114,6 +120,9 @@ impl KeyConfig {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn test_get_hint() {
|
||||
|
|
@ -124,4 +133,147 @@ mod tests {
|
|||
));
|
||||
assert_eq!(h, "^c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_symbolic_links() {
|
||||
let app_home = get_app_config_path().unwrap();
|
||||
// save current config
|
||||
let original_key_list_path = app_home.join(KEY_LIST_FILENAME);
|
||||
let renamed_key_list = if original_key_list_path.exists() {
|
||||
let temp = NamedTempFile::new_in(&app_home).unwrap();
|
||||
fs::rename(&original_key_list_path, &temp).unwrap();
|
||||
Some(temp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let original_key_symbols_path =
|
||||
app_home.join(KEY_SYMBOLS_FILENAME);
|
||||
let renamed_key_symbols = if original_key_symbols_path
|
||||
.exists()
|
||||
{
|
||||
let temp = NamedTempFile::new_in(&app_home).unwrap();
|
||||
fs::rename(&original_key_symbols_path, &temp).unwrap();
|
||||
Some(temp)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// create temporary config files
|
||||
let mut temporary_key_list =
|
||||
NamedTempFile::new_in(&app_home).unwrap();
|
||||
writeln!(
|
||||
temporary_key_list,
|
||||
r"
|
||||
(
|
||||
move_down: Some(( code: Char('j'), modifiers: ( bits: 2,),)),
|
||||
)
|
||||
"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut temporary_key_symbols =
|
||||
NamedTempFile::new_in(&app_home).unwrap();
|
||||
writeln!(
|
||||
temporary_key_symbols,
|
||||
"
|
||||
(
|
||||
esc: Some(\"Esc\"),
|
||||
)
|
||||
"
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// testing
|
||||
let result = std::panic::catch_unwind(|| {
|
||||
let loaded_config = KeyConfig::init().unwrap();
|
||||
assert_eq!(
|
||||
loaded_config.keys.move_down,
|
||||
KeysList::default().move_down
|
||||
);
|
||||
assert_eq!(
|
||||
loaded_config.symbols.esc,
|
||||
KeySymbols::default().esc
|
||||
);
|
||||
|
||||
create_symlink(
|
||||
&temporary_key_symbols,
|
||||
&original_key_symbols_path,
|
||||
)
|
||||
.unwrap();
|
||||
let loaded_config = KeyConfig::init().unwrap();
|
||||
assert_eq!(
|
||||
loaded_config.keys.move_down,
|
||||
KeysList::default().move_down
|
||||
);
|
||||
assert_eq!(loaded_config.symbols.esc, "Esc");
|
||||
|
||||
create_symlink(
|
||||
&temporary_key_list,
|
||||
&original_key_list_path,
|
||||
)
|
||||
.unwrap();
|
||||
let loaded_config = KeyConfig::init().unwrap();
|
||||
assert_eq!(
|
||||
loaded_config.keys.move_down,
|
||||
GituiKeyEvent::new(
|
||||
KeyCode::Char('j'),
|
||||
KeyModifiers::CONTROL
|
||||
)
|
||||
);
|
||||
assert_eq!(loaded_config.symbols.esc, "Esc");
|
||||
|
||||
fs::remove_file(&original_key_symbols_path).unwrap();
|
||||
let loaded_config = KeyConfig::init().unwrap();
|
||||
assert_eq!(
|
||||
loaded_config.keys.move_down,
|
||||
GituiKeyEvent::new(
|
||||
KeyCode::Char('j'),
|
||||
KeyModifiers::CONTROL
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
loaded_config.symbols.esc,
|
||||
KeySymbols::default().esc
|
||||
);
|
||||
|
||||
fs::remove_file(&original_key_list_path).unwrap();
|
||||
});
|
||||
|
||||
// remove symlinks from testing if they still exist
|
||||
let _ = fs::remove_file(&original_key_list_path);
|
||||
let _ = fs::remove_file(&original_key_symbols_path);
|
||||
|
||||
// restore original config files
|
||||
if let Some(temp) = renamed_key_list {
|
||||
let _ = fs::rename(&temp, &original_key_list_path);
|
||||
}
|
||||
|
||||
if let Some(temp) = renamed_key_symbols {
|
||||
let _ = fs::rename(&temp, &original_key_symbols_path);
|
||||
}
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn create_symlink<
|
||||
P: AsRef<std::path::Path>,
|
||||
Q: AsRef<std::path::Path>,
|
||||
>(
|
||||
original: P,
|
||||
link: Q,
|
||||
) -> Result<(), std::io::Error> {
|
||||
std::os::unix::fs::symlink(original, link)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn create_symlink<
|
||||
P: AsRef<std::path::Path>,
|
||||
Q: AsRef<std::path::Path>,
|
||||
>(
|
||||
original: P,
|
||||
link: Q,
|
||||
) -> Result<(), std::io::Error> {
|
||||
std::os::windows::fs::symlink_file(original, link)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue