From 5f582bc5fff72675fbc96062f5d70930f9be0320 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 20 Jan 2024 06:25:56 +0900 Subject: [PATCH 01/12] Refactor: Use pattern matching for single command --- src/run.rs | 135 ++++++++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 63 deletions(-) diff --git a/src/run.rs b/src/run.rs index f551bb2..3402086 100644 --- a/src/run.rs +++ b/src/run.rs @@ -2062,73 +2062,82 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { let command = commands[0]; if commands.len() == 1 { - if command == "q" { - //quit - break 'main; - } else if command == "cd" || command == "z" { - //go to the home directory - let home_dir = dirs::home_dir() - .ok_or_else(|| { - FxError::Dirs( - "Cannot read home dir." - .to_string(), - ) - })?; - if let Err(e) = - state.chdir(&home_dir, Move::Jump) - { - print_warning(e, state.layout.y); + match command { + "q" => { + //quit + break 'main; } - break 'command; - } else if command == "e" { - //reload current dir - state.keyword = None; - state.layout.nums.reset(); - state.reload(BEGINNING_ROW)?; - break 'command; - } else if command == "h" { - //show help - state.show_help(&screen)?; - state.redraw(state.layout.y); - break 'command; - } else if command == "reg" { - //:reg - Show registers - if state.layout.is_preview() { - state.layout.show_reg(); + "cd" | "z" => { + //go to the home directory + let home_dir = dirs::home_dir() + .ok_or_else(|| { + FxError::Dirs( + "Cannot read home dir." + .to_string(), + ) + })?; + if let Err(e) = + state.chdir(&home_dir, Move::Jump) + { + print_warning(e, state.layout.y); + } + break 'command; + } + "e" => { + //reload current dir + state.keyword = None; + state.layout.nums.reset(); + state.reload(BEGINNING_ROW)?; + break 'command; + } + "h" => { + //show help + state.show_help(&screen)?; state.redraw(state.layout.y); - } else if state.layout.is_reg() { - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); - } else { - state.layout.show_reg(); - let (new_column, new_row) = state - .layout - .update_column_and_row()?; - state.refresh( - new_column, - new_row, - state.layout.y, - )?; - go_to_info_line_and_reset(); - hide_cursor(); - state.move_cursor(state.layout.y); + break 'command; } - break 'command; - } else if command == "trash" { - //move to trash dir - state.layout.nums.reset(); - if let Err(e) = state.chdir( - &(state.trash_dir.clone()), - Move::Jump, - ) { - print_warning(e, state.layout.y); + "reg" => { + //:reg - Show registers + if state.layout.is_preview() { + state.layout.show_reg(); + state.redraw(state.layout.y); + } else if state.layout.is_reg() { + go_to_info_line_and_reset(); + hide_cursor(); + state.move_cursor(state.layout.y); + } else { + state.layout.show_reg(); + let (new_column, new_row) = state + .layout + .update_column_and_row()?; + state.refresh( + new_column, + new_row, + state.layout.y, + )?; + go_to_info_line_and_reset(); + hide_cursor(); + state.move_cursor(state.layout.y); + } + break 'command; } - break 'command; - } else if command == "empty" { - //empty the trash dir - state.empty_trash(&screen)?; - break 'command; + "trash" => { + //move to trash dir + state.layout.nums.reset(); + if let Err(e) = state.chdir( + &(state.trash_dir.clone()), + Move::Jump, + ) { + print_warning(e, state.layout.y); + } + break 'command; + } + "empty" => { + //empty the trash dir + state.empty_trash(&screen)?; + break 'command; + } + _ => {} } } else if commands.len() == 2 && command == "cd" { if let Ok(target) = From 5123d53d14b5d4762d8b4154579d31de9932f955 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 20 Jan 2024 06:28:15 +0900 Subject: [PATCH 02/12] Remove unused method --- src/state.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/state.rs b/src/state.rs index 7cfecf6..3401eca 100644 --- a/src/state.rs +++ b/src/state.rs @@ -40,7 +40,6 @@ use std::os::unix::fs::PermissionsExt; pub const BEGINNING_ROW: u16 = 3; pub const EMPTY_WARNING: &str = "Are you sure to empty the trash directory? (if yes: y)"; -const BASE32: &[u8; 32] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ"; #[derive(Debug)] pub struct State { @@ -1360,33 +1359,6 @@ impl State { } } - /// Creates temp file for directory. Works like touch, but with randomized suffix - #[allow(dead_code)] - pub fn create_temp(&mut self, is_dir: bool) -> Result { - let mut new_name = self.current_dir.join(".tmp"); - if new_name.exists() { - let mut nanos = std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .subsec_nanos(); - let encoded: &mut [u8] = &mut [0, 0, 0, 0, 0]; - for i in 0..5 { - let v = (nanos & 0x1f) as usize; - encoded[4 - i] = BASE32[v]; - nanos >>= 5; - } - new_name = self - .current_dir - .join(format!(".tmp_{}", String::from_utf8(encoded.to_vec())?)) - } - if is_dir { - std::fs::create_dir(new_name.clone())?; - } else { - std::fs::File::create(new_name.clone())?; - } - Ok(new_name) - } - /// Show help pub fn show_help(&self, mut screen: &Stdout) -> Result<(), FxError> { clear_all(); From 7b1d4811e6304f8b0a7e3af3e805fed13c0bb701 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 20 Jan 2024 06:42:04 +0900 Subject: [PATCH 03/12] Add config_path field to State --- src/config.rs | 19 +++++++++++++++---- src/state.rs | 10 ++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/config.rs b/src/config.rs index de8e6d7..df57efe 100644 --- a/src/config.rs +++ b/src/config.rs @@ -54,6 +54,11 @@ const CONFIG_EXAMPLE: &str = r###" # symlink_fg: LightYellow # dirty_fg: Red "###; +#[derive(Debug, Clone)] +pub struct ConfigWithPath { + pub config_path: Option, + pub config: Config, +} #[derive(Deserialize, Debug, Clone)] pub struct Config { @@ -115,13 +120,16 @@ impl Default for Config { } } -fn read_config(p: &Path) -> Result { +fn read_config(p: &Path) -> Result { let s = read_to_string(p)?; let deserialized: Config = serde_yaml::from_str(&s)?; - Ok(deserialized) + Ok(ConfigWithPath { + config_path: Some(p.to_path_buf()), + config: deserialized, + }) } -pub fn read_config_or_default() -> Result { +pub fn read_config_or_default() -> Result { //First, declare default config file path. let (config_file_path1, config_file_path2) = { let mut config_path = { @@ -172,6 +180,9 @@ pub fn read_config_or_default() -> Result { if let Some(config_file) = config_file { read_config(&config_file) } else { - Ok(Config::default()) + Ok(ConfigWithPath { + config_path: None, + config: Config::default(), + }) } } diff --git a/src/state.rs b/src/state.rs index 3401eca..7c14273 100644 --- a/src/state.rs +++ b/src/state.rs @@ -46,6 +46,7 @@ pub struct State { pub list: Vec, pub current_dir: PathBuf, pub trash_dir: PathBuf, + pub config_path: Option, pub lwd_file: Option, pub match_vim_exit_behavior: bool, pub has_zoxide: bool, @@ -234,12 +235,12 @@ impl State { pub fn new(session_path: &std::path::Path) -> Result { //Read config file. //Use default configuration if the file does not exist or cannot be read. - let config = read_config_or_default(); - let config = match config { - Ok(c) => c, + let config_with_path = read_config_or_default(); + let (config_path, config) = match config_with_path { + Ok(c) => (c.config_path, c.config), Err(e) => { eprintln!("Cannot read the config file properly.\nError: {}\nfelix launches with default configuration.", e); - Config::default() + (None, Config::default()) } }; @@ -281,6 +282,7 @@ impl State { }, current_dir: PathBuf::new(), trash_dir: PathBuf::new(), + config_path, lwd_file: None, match_vim_exit_behavior: config.match_vim_exit_behavior.unwrap_or_default(), has_zoxide, From 50df35f0536c2b933a3a4e82c4bc6f46f9a5a58e Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 20 Jan 2024 06:42:10 +0900 Subject: [PATCH 04/12] Remove unused const --- src/config.rs | 45 --------------------------------------------- 1 file changed, 45 deletions(-) diff --git a/src/config.rs b/src/config.rs index df57efe..fffe626 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,51 +9,6 @@ pub const FELIX: &str = "felix"; const CONFIG_FILE: &str = "config.yaml"; const CONFIG_FILE_ANOTHER_EXT: &str = "config.yml"; -#[allow(dead_code)] -const CONFIG_EXAMPLE: &str = r###" -# Default exec command when open files. -# If not set, will default to $EDITOR. -# default: nvim - -# Whether to match the behavior of vim exit keybindings -# i.e. `ZQ` exits without cd to LWD (Last Working Directory) while `ZZ` cd to LWD -# match_vim_exit_behavior: false - -# key (the command you want to use when opening files): [values] (extensions) -# In the key, You can use arguments. -# exec: -# zathura: -# [pdf] -# 'feh -.': -# [jpg, jpeg, png, gif, svg, hdr] - -# The foreground color of directory, file and symlink. -# Pick one of the following: -# Black // 0 -# Red // 1 -# Green // 2 -# Yellow // 3 -# Blue // 4 -# Magenta // 5 -# Cyan // 6 -# White // 7 -# LightBlack // 8 -# LightRed // 9 -# LightGreen // 10 -# LightYellow // 11 -# LightBlue // 12 -# LightMagenta // 13 -# LightCyan // 14 -# LightWhite // 15 -# Rgb(u8, u8, u8) -# AnsiValue(u8) -# Default to LightCyan(dir), LightWhite(file), LightYellow(symlink) and Red(changed/untracked files in git repositories). -# color: -# dir_fg: LightCyan -# file_fg: LightWhite -# symlink_fg: LightYellow -# dirty_fg: Red -"###; #[derive(Debug, Clone)] pub struct ConfigWithPath { pub config_path: Option, From 74d34ae12c8b5fc36714c103b9b04a0a035ccb52 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 20 Jan 2024 06:49:31 +0900 Subject: [PATCH 05/12] Add :config to jump to config file directory --- src/run.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/run.rs b/src/run.rs index 3402086..0362ad0 100644 --- a/src/run.rs +++ b/src/run.rs @@ -2137,6 +2137,33 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { state.empty_trash(&screen)?; break 'command; } + "config" => { + //move to the directory that contains + //config path + state.layout.nums.reset(); + if let Some(ref config_path) = + state.config_path + { + if let Err(e) = state.chdir( + config_path + .clone() + .parent() + .unwrap(), + Move::Jump, + ) { + print_warning( + e, + state.layout.y, + ); + } + } else { + print_warning( + "Cannot find the config path.", + state.layout.y, + ) + } + break 'command; + } _ => {} } } else if commands.len() == 2 && command == "cd" { From 305dca4a3e68668ca1f24657c1251420783293d4 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 15:21:15 +0900 Subject: [PATCH 06/12] Derive default --- src/layout.rs | 8 +++++--- src/nums.rs | 2 +- src/op.rs | 2 +- src/session.rs | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index 40502e7..8583c13 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -16,7 +16,7 @@ pub const PROPER_WIDTH: u16 = 28; pub const TIME_WIDTH: u16 = 16; const EXTRA_SPACES: u16 = 3; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Layout { pub nums: Num, pub y: u16, @@ -46,15 +46,17 @@ pub enum PreviewType { Binary, } -#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)] +#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Default)] pub enum Side { + #[default] Preview, Reg, None, } -#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone, Copy, Default)] pub enum Split { + #[default] Vertical, Horizontal, } diff --git a/src/nums.rs b/src/nums.rs index 4b7720f..3aa05af 100644 --- a/src/nums.rs +++ b/src/nums.rs @@ -1,4 +1,4 @@ -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct Num { pub index: usize, pub skip: u16, diff --git a/src/op.rs b/src/op.rs index d2a54ed..0590a28 100644 --- a/src/op.rs +++ b/src/op.rs @@ -3,7 +3,7 @@ use super::state::ItemBuffer; use log::info; use std::path::PathBuf; -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct Operation { pub pos: usize, pub op_list: Vec, diff --git a/src/session.rs b/src/session.rs index 2b3ad01..f3ac3a6 100644 --- a/src/session.rs +++ b/src/session.rs @@ -18,8 +18,9 @@ pub struct Session { pub split: Option, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Deserialize, Serialize, Debug, Clone, Default)] pub enum SortKey { + #[default] Name, Time, } From 622a6c79ff4558d320fd1392070b91c9b19f7512 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 15:47:29 +0900 Subject: [PATCH 07/12] Add Layout::new --- src/layout.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/layout.rs b/src/layout.rs index 8583c13..20e564b 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -2,10 +2,11 @@ use super::config::*; use super::errors::FxError; use super::functions::*; use super::nums::*; -use super::session::SortKey; +use super::session::{read_session, SortKey}; use super::state::{ItemInfo, BEGINNING_ROW}; use super::term::*; +use log::error; use serde::{Deserialize, Serialize}; pub const MAX_SIZE_TO_PREVIEW: u64 = 1_000_000_000; @@ -62,6 +63,52 @@ pub enum Split { } impl Layout { + pub fn new(session_path: &std::path::Path, config: Config) -> Result { + let (original_column, original_row) = terminal_size()?; + // Return error if terminal size may cause panic + if original_column < 4 { + error!("Too small terminal size (less than 4 columns)."); + return Err(FxError::TooSmallWindowSize); + }; + if original_row < 4 { + error!("Too small terminal size. (less than 4 rows)"); + return Err(FxError::TooSmallWindowSize); + }; + + // Prepare state fields. + let session = read_session(session_path); + let (time_start, name_max) = make_layout(original_column); + let split = session.split.unwrap_or(Split::Vertical); + let has_bat = check_bat(); + let has_chafa = check_chafa(); + let is_kitty = check_kitty_support(); + + let colors = config.color.unwrap_or_default(); + + Ok(Layout { + nums: Num::new(), + y: BEGINNING_ROW, + terminal_row: original_row, + terminal_column: original_column, + name_max_len: name_max, + time_start_pos: time_start, + sort_by: session.sort_by, + show_hidden: session.show_hidden, + side: if session.preview.unwrap_or(false) { + Side::Preview + } else { + Side::None + }, + split, + preview_start: (0, 0), + preview_space: (0, 0), + has_bat, + has_chafa, + is_kitty, + colors, + }) + } + pub fn is_preview(&self) -> bool { self.side == Side::Preview } @@ -366,3 +413,28 @@ pub fn make_layout(column: u16) -> (u16, usize) { (time_start, name_max) } } + +/// Check if bat is installed. +fn check_bat() -> bool { + std::process::Command::new("bat") + .arg("--help") + .output() + .is_ok() +} + +/// Check if chafa is installed. +fn check_chafa() -> bool { + std::process::Command::new("chafa") + .arg("--help") + .output() + .is_ok() +} + +/// Check if the terminal is Kitty or not +fn check_kitty_support() -> bool { + if let Ok(term) = std::env::var("TERM") { + term.contains("kitty") + } else { + false + } +} From fbca88780ea1c157667ba7ef2cb8f7c5369fdaa5 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 15:48:30 +0900 Subject: [PATCH 08/12] Read config inside felix and update it --- src/config.rs | 2 +- src/run.rs | 50 +++++++++++++++++++- src/state.rs | 126 ++++++++------------------------------------------ 3 files changed, 67 insertions(+), 111 deletions(-) diff --git a/src/config.rs b/src/config.rs index fffe626..ca20ffd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -75,7 +75,7 @@ impl Default for Config { } } -fn read_config(p: &Path) -> Result { +pub fn read_config(p: &Path) -> Result { let s = read_to_string(p)?; let deserialized: Config = serde_yaml::from_str(&s)?; Ok(ConfigWithPath { diff --git a/src/run.rs b/src/run.rs index 0362ad0..9e85f54 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,5 +1,4 @@ -#![allow(unreachable_code)] -use super::config::FELIX; +use super::config::{read_config, FELIX}; use super::errors::FxError; use super::functions::*; use super::layout::{PreviewType, Split}; @@ -18,6 +17,8 @@ use std::env; use std::io::{stdout, Write}; use std::panic; use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::thread; use std::time::Instant; const TRASH: &str = "Trash"; @@ -169,7 +170,52 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { } screen.flush()?; + // Spawn another thread to watch the config file. + let mut modified_time = match &state.config_path { + Some(config_path) => config_path.metadata().unwrap().modified().ok(), + None => None, + }; + let config_updated = Arc::new(Mutex::new(false)); + let config_updated_in_another_tread = config_updated.clone(); + let config_path_in_another_thread = state.config_path.clone(); + // if config file does not exist, no watching. + if modified_time.is_some() { + // Every 2 secondes, check if the config file is updated. + thread::spawn(move || loop { + thread::sleep(std::time::Duration::from_secs(2)); + if *config_updated_in_another_tread.lock().unwrap() { + continue; + } + let metadata = config_path_in_another_thread.as_ref().unwrap().metadata(); + if let Ok(metadata) = metadata { + let new_modified = metadata.modified().ok(); + if modified_time != new_modified { + if let Ok(mut updated) = config_updated_in_another_tread.lock() { + *updated = true; + modified_time = new_modified; + } else { + break; + } + } + } + }); + } + 'main: loop { + // Check if config file is updated + if let Ok(mut should_be_updated) = config_updated.lock() { + if *should_be_updated { + if let Ok(c) = read_config(state.config_path.as_ref().unwrap()) { + state.set_config(c.config); + state.redraw(state.layout.y); + print_info("New config set.", state.layout.y); + } else { + print_warning("Something wrong with the config file.", state.layout.y); + } + *should_be_updated = false; + } + } + if state.is_out_of_bounds() { state.layout.nums.reset(); state.redraw(BEGINNING_ROW); diff --git a/src/state.rs b/src/state.rs index 7c14273..78fbaf5 100644 --- a/src/state.rs +++ b/src/state.rs @@ -15,7 +15,7 @@ use chrono::prelude::*; use crossterm::event::KeyEventKind; use crossterm::event::{Event, KeyCode, KeyEvent}; use crossterm::style::Stylize; -use log::{error, info}; +use log::info; use std::collections::VecDeque; use std::collections::{BTreeMap, BTreeSet}; use std::env; @@ -41,7 +41,7 @@ use std::os::unix::fs::PermissionsExt; pub const BEGINNING_ROW: u16 = 3; pub const EMPTY_WARNING: &str = "Are you sure to empty the trash directory? (if yes: y)"; -#[derive(Debug)] +#[derive(Debug, Default)] pub struct State { pub list: Vec, pub current_dir: PathBuf, @@ -63,7 +63,7 @@ pub struct State { pub is_ro: bool, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Registers { pub unnamed: Vec, pub zero: Vec, @@ -243,95 +243,30 @@ impl State { (None, Config::default()) } }; + let mut state = State::default(); + state.set_config(config.clone()); - let session = read_session(session_path); - let (original_column, original_row) = terminal_size()?; - - // Return error if terminal size may cause panic - if original_column < 4 { - error!("Too small terminal size (less than 4 columns)."); - return Err(FxError::TooSmallWindowSize); - }; - if original_row < 4 { - error!("Too small terminal size. (less than 4 rows)"); - return Err(FxError::TooSmallWindowSize); - }; - - let (time_start, name_max) = make_layout(original_column); - - let color = config.color.unwrap_or_default(); - - let split = session.split.unwrap_or(Split::Vertical); - - let has_bat = check_bat(); - let has_chafa = check_chafa(); let has_zoxide = check_zoxide(); - let is_kitty = check_kitty_support(); Ok(State { - list: Vec::new(), - registers: Registers { - unnamed: vec![], - zero: vec![], - numbered: VecDeque::new(), - named: BTreeMap::new(), - }, - operations: Operation { - pos: 0, - op_list: Vec::new(), - }, - current_dir: PathBuf::new(), - trash_dir: PathBuf::new(), config_path, - lwd_file: None, - match_vim_exit_behavior: config.match_vim_exit_behavior.unwrap_or_default(), has_zoxide, - default: config - .default - .unwrap_or_else(|| env::var("EDITOR").unwrap_or_default()), - commands: to_extension_map(&config.exec), - layout: Layout { - nums: Num::new(), - y: BEGINNING_ROW, - terminal_row: original_row, - terminal_column: original_column, - name_max_len: name_max, - time_start_pos: time_start, - colors: ConfigColor { - dir_fg: color.dir_fg, - file_fg: color.file_fg, - symlink_fg: color.symlink_fg, - dirty_fg: color.dirty_fg, - }, - sort_by: session.sort_by, - show_hidden: session.show_hidden, - side: if session.preview.unwrap_or(false) { - Side::Preview - } else { - Side::None - }, - split, - preview_start: match split { - Split::Vertical => (0, 0), - Split::Horizontal => (0, 0), - }, - preview_space: match split { - Split::Vertical => (0, 0), - Split::Horizontal => (0, 0), - }, - has_bat, - has_chafa, - is_kitty, - }, - jumplist: JumpList::default(), - c_memo: Vec::new(), - p_memo: Vec::new(), - keyword: None, - v_start: None, - is_ro: false, + layout: Layout::new(session_path, config)?, + ..state }) } + /// Set configuration from config file. + pub fn set_config(&mut self, config: Config) { + let color = config.color.unwrap_or_default(); + self.match_vim_exit_behavior = config.match_vim_exit_behavior.unwrap_or_default(); + self.default = config + .default + .unwrap_or_else(|| env::var("EDITOR").unwrap_or_default()); + self.commands = to_extension_map(&config.exec); + self.layout.colors = color; + } + /// Select item that the cursor points to. pub fn get_item(&self) -> Result<&ItemInfo, FxError> { self.list @@ -1928,22 +1863,6 @@ fn read_item(entry: fs::DirEntry) -> ItemInfo { // Ok(result) // } -/// Check if bat is installed. -fn check_bat() -> bool { - std::process::Command::new("bat") - .arg("--help") - .output() - .is_ok() -} - -/// Check if chafa is installed. -fn check_chafa() -> bool { - std::process::Command::new("chafa") - .arg("--help") - .output() - .is_ok() -} - /// Check if zoxide is installed. fn check_zoxide() -> bool { std::process::Command::new("zoxide") @@ -1952,15 +1871,6 @@ fn check_zoxide() -> bool { .is_ok() } -/// Check if the terminal is Kitty or not -fn check_kitty_support() -> bool { - if let Ok(term) = std::env::var("TERM") { - term.contains("kitty") - } else { - false - } -} - /// Set content type from ItemInfo. fn set_preview_content_type(item: &mut ItemInfo) { if item.file_size > MAX_SIZE_TO_PREVIEW { From 5a983dbad29d35aaf49ad881d351c11db2a2d9be Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 15:55:14 +0900 Subject: [PATCH 09/12] Fix comment --- src/run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/run.rs b/src/run.rs index 9e85f54..887902d 100644 --- a/src/run.rs +++ b/src/run.rs @@ -109,7 +109,7 @@ pub fn run(arg: PathBuf, log: bool) -> Result<(), FxError> { path }; - //Initialize app state. Inside State::new(), config file is read or created. + //Initialize app state. Inside `State::new()`, config file is read. let mut state = State::new(&session_path)?; state.trash_dir = trash_dir_path; state.lwd_file = lwd_file_path; From 8879cc22d1ef876a3c2ffcc812aff97e206181d8 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 16:05:36 +0900 Subject: [PATCH 10/12] Refactor --- src/layout.rs | 11 +++++------ src/state.rs | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index 20e564b..0cad56c 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -76,9 +76,9 @@ impl Layout { }; // Prepare state fields. - let session = read_session(session_path); let (time_start, name_max) = make_layout(original_column); - let split = session.split.unwrap_or(Split::Vertical); + let session = read_session(session_path); + let split = session.split.unwrap_or_default(); let has_bat = check_bat(); let has_chafa = check_chafa(); let is_kitty = check_kitty_support(); @@ -94,10 +94,9 @@ impl Layout { time_start_pos: time_start, sort_by: session.sort_by, show_hidden: session.show_hidden, - side: if session.preview.unwrap_or(false) { - Side::Preview - } else { - Side::None + side: match session.preview.unwrap_or(false) { + true => Side::Preview, + false => Side::None, }, split, preview_start: (0, 0), diff --git a/src/state.rs b/src/state.rs index 78fbaf5..fa40bed 100644 --- a/src/state.rs +++ b/src/state.rs @@ -258,13 +258,13 @@ impl State { /// Set configuration from config file. pub fn set_config(&mut self, config: Config) { - let color = config.color.unwrap_or_default(); - self.match_vim_exit_behavior = config.match_vim_exit_behavior.unwrap_or_default(); self.default = config .default .unwrap_or_else(|| env::var("EDITOR").unwrap_or_default()); + self.match_vim_exit_behavior = config.match_vim_exit_behavior.unwrap_or_default(); self.commands = to_extension_map(&config.exec); - self.layout.colors = color; + let colors = config.color.unwrap_or_default(); + self.layout.colors = colors; } /// Select item that the cursor points to. From d2b6a98034a22811ca45d5b4e9e6f26df939855c Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 16:08:47 +0900 Subject: [PATCH 11/12] Update CHANGELOG.md --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b75ba..6f5eed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ ## Unreleased +### Added + +- `:config` to point to the config file if exists. +- felix listens to the change of the config file, and re-read the config automatically. +- Refactor around `State::new()`. + - Add `config_path` field to `State`. + ## v2.11.1 (2023-12-10) ### Fixed @@ -34,7 +41,7 @@ - Add `FxError::InvalidPath` to handle invalid unicode in file path. ## v2.9.0 (2023-10-22) - + ### Added - Change color of untracked/changed files or directories containing such files. Default color is Red(1). You can change it in the config file. - Add `git2`. From e95976494b2e8609ade61dbad4db2395fcdbd457 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 16:17:10 +0900 Subject: [PATCH 12/12] Refactor: Better names --- src/run.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/run.rs b/src/run.rs index 887902d..4e49053 100644 --- a/src/run.rs +++ b/src/run.rs @@ -175,22 +175,22 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { Some(config_path) => config_path.metadata().unwrap().modified().ok(), None => None, }; - let config_updated = Arc::new(Mutex::new(false)); - let config_updated_in_another_tread = config_updated.clone(); - let config_path_in_another_thread = state.config_path.clone(); + let wait_update = Arc::new(Mutex::new(false)); + let wait_update_clone = wait_update.clone(); + let config_path_clone = state.config_path.clone(); // if config file does not exist, no watching. if modified_time.is_some() { // Every 2 secondes, check if the config file is updated. thread::spawn(move || loop { thread::sleep(std::time::Duration::from_secs(2)); - if *config_updated_in_another_tread.lock().unwrap() { + if *wait_update_clone.lock().unwrap() { continue; } - let metadata = config_path_in_another_thread.as_ref().unwrap().metadata(); + let metadata = config_path_clone.as_ref().unwrap().metadata(); if let Ok(metadata) = metadata { let new_modified = metadata.modified().ok(); if modified_time != new_modified { - if let Ok(mut updated) = config_updated_in_another_tread.lock() { + if let Ok(mut updated) = wait_update_clone.lock() { *updated = true; modified_time = new_modified; } else { @@ -203,16 +203,19 @@ fn _run(mut state: State, session_path: PathBuf) -> Result<(), FxError> { 'main: loop { // Check if config file is updated - if let Ok(mut should_be_updated) = config_updated.lock() { - if *should_be_updated { - if let Ok(c) = read_config(state.config_path.as_ref().unwrap()) { - state.set_config(c.config); - state.redraw(state.layout.y); - print_info("New config set.", state.layout.y); - } else { - print_warning("Something wrong with the config file.", state.layout.y); + if state.config_path.is_some() { + if let Ok(mut wait_update) = wait_update.lock() { + if *wait_update { + if let Ok(c) = read_config(state.config_path.as_ref().unwrap()) { + state.set_config(c.config); + state.redraw(state.layout.y); + print_info("New config set.", state.layout.y); + } else { + // If reading the config file fails, leave the config as is. + print_warning("Something wrong with the config file.", state.layout.y); + } + *wait_update = false; } - *should_be_updated = false; } }