From fbca88780ea1c157667ba7ef2cb8f7c5369fdaa5 Mon Sep 17 00:00:00 2001 From: Kyohei Uto Date: Sat, 27 Jan 2024 15:48:30 +0900 Subject: [PATCH] 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 {