From c372aef844ae59e5cb65f0815c2868f19d58aa64 Mon Sep 17 00:00:00 2001 From: Canop Date: Sat, 1 Oct 2022 19:53:46 +0200 Subject: Status message on toggling tree options --- CHANGELOG.md | 3 + src/app/app.rs | 32 +++-- src/app/cmd_result.rs | 16 ++- src/app/panel.rs | 3 + src/app/panel_state.rs | 218 ++++++++++++++++++++++++++++++----- src/browser/browser_state.rs | 36 +++++- src/filesystems/filesystems_state.rs | 3 +- src/help/help_state.rs | 2 +- src/preview/preview_state.rs | 2 +- src/stage/stage_state.rs | 9 +- src/verb/internal_focus.rs | 1 + 11 files changed, 269 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03bd2b..1c9add3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### next +- status messages now displayed on toggling (for example showing hidden files) + ### v1.15.0 - 2022-09-24 - with `show_matching_characters_on_path_searches: false`, it's possible to show only file names even when searching paths - Fix #490 diff --git a/src/app/app.rs b/src/app/app.rs index f9034f9..1533aba 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -266,7 +266,9 @@ impl App { screen: self.screen, // it can't change in this function con, }; - match self.mut_panel().apply_command(w, &cmd, app_state, &app_cmd_context)? { + let cmd_result = self.mut_panel().apply_command(w, &cmd, app_state, &app_cmd_context)?; + debug!("cmd_result: {:?}", &cmd_result); + match cmd_result { ApplyOnPanel { id } => { if let Some(idx) = self.panel_id_to_idx(id) { if let DisplayError(txt) = self.panels[idx].apply_command( @@ -461,10 +463,14 @@ impl App { error = Some(s); } } - NewState(state) => { + NewState { state, message } => { self.mut_panel().clear_input(); self.mut_panel().push_state(state); - self.mut_panel().refresh_input_status(app_state, &app_cmd_context); + if let Some(md) = message { + self.mut_panel().set_message(md); + } else { + self.mut_panel().refresh_input_status(app_state, &app_cmd_context); + } } PopState => { if is_input_invocation { @@ -621,15 +627,17 @@ impl App { self.update_preview(con, false); // the selection may have changed if let Some(error) = &error { self.mut_panel().set_error(error.to_string()); - } else { - let app_cmd_context = AppCmdContext { - panel_skin: &skin.focused, - preview_panel: self.preview_panel, - stage_panel: self.stage_panel, - screen: self.screen, - con, - }; - self.mut_panel().refresh_input_status(app_state, &app_cmd_context); + //} else { + // // the refresh here removes the toggle status message. Not + // // sure there's a case it's useful + // let app_cmd_context = AppCmdContext { + // panel_skin: &skin.focused, + // preview_panel: self.preview_panel, + // stage_panel: self.stage_panel, + // screen: self.screen, + // con, + // }; + // self.mut_panel().refresh_input_status(app_state, &app_cmd_context); } self.display_panels(w, skin, app_state, con)?; if error.is_some() { diff --git a/src/app/cmd_result.rs b/src/app/cmd_result.rs index 465feff..ff7b462 100644 --- a/src/app/cmd_result.rs +++ b/src/app/cmd_result.rs @@ -48,7 +48,10 @@ pub enum CmdResult { purpose: PanelPurpose, direction: HDir, }, - NewState(Box), + NewState { + state: Box, + message: Option<&'static str>, // explaining why there's a new state + }, PopStateAndReapply, // the state asks the command be executed on a previous state PopState, Quit, @@ -63,24 +66,31 @@ impl CmdResult { } pub fn from_optional_state( os: Result, + message: Option<&'static str>, in_new_panel: bool, ) -> CmdResult { match os { Ok(os) => { if in_new_panel { - CmdResult::NewPanel { + CmdResult::NewPanel { // TODO keep the message ? state: Box::new(os), purpose: PanelPurpose::None, direction: HDir::Right, } } else { - CmdResult::NewState(Box::new(os)) + CmdResult::NewState { + state: Box::new(os), + message, + } } } Err(TreeBuildError::Interrupted) => CmdResult::Keep, Err(e) => CmdResult::error(e.to_string()), } } + pub fn new_state(state: Box) -> Self { + Self::NewState { state, message: None } + } pub fn error>(message: S) -> Self { Self::DisplayError(message.into()) } diff --git a/src/app/panel.rs b/src/app/panel.rs index 9a2757d..9577adf 100644 --- a/src/app/panel.rs +++ b/src/app/panel.rs @@ -57,6 +57,9 @@ impl Panel { pub fn set_error(&mut self, text: String) { self.status = Status::from_error(text); } + pub fn set_message>(&mut self, md: S) { + self.status = Status::from_message(md.into()); + } /// apply a command on the current state, with no /// effect on screen diff --git a/src/app/panel_state.rs b/src/app/panel_state.rs index f84f697..0d79d63 100644 --- a/src/app/panel_state.rs +++ b/src/app/panel_state.rs @@ -153,7 +153,7 @@ pub trait PanelState { direction: HDir::Right, } } else { - CmdResult::NewState(Box::new(state)) + CmdResult::new_state(Box::new(state)) } } Err(e) => CmdResult::DisplayError(format!("{}", e)), @@ -170,7 +170,7 @@ pub trait PanelState { direction: HDir::Right, } } else { - CmdResult::NewState(Box::new( + CmdResult::new_state(Box::new( HelpState::new(self.tree_options(), screen, con) )) } @@ -195,9 +195,11 @@ pub trait PanelState { if o.sort == Sort::Count { o.sort = Sort::None; o.show_counts = false; + "*not sorting anymore*" } else { o.sort = Sort::Count; o.show_counts = true; + "*now sorting by file count*" } }, bang, @@ -209,9 +211,11 @@ pub trait PanelState { if o.sort == Sort::Date { o.sort = Sort::None; o.show_dates = false; + "*not sorting anymore*" } else { o.sort = Sort::Date; o.show_dates = true; + "*now sorting by last modified date*" } }, bang, @@ -223,10 +227,12 @@ pub trait PanelState { if o.sort == Sort::Size { o.sort = Sort::None; o.show_sizes = false; + "*not sorting anymore*" } else { o.sort = Sort::Size; o.show_sizes = true; o.show_root_fs = true; + "*now sorting files and directories by total size*" } }, bang, @@ -235,11 +241,20 @@ pub trait PanelState { Internal::sort_by_type => self.with_new_options( screen, &|o| { - o.sort = match o.sort { - Sort::TypeDirsFirst => Sort::TypeDirsLast, - Sort::TypeDirsLast => Sort::None, - _ => Sort::TypeDirsFirst, - }; + match o.sort { + Sort::TypeDirsFirst => { + o.sort = Sort::TypeDirsLast; + "*sorting by type, directories last*" + } + Sort::TypeDirsLast => { + o.sort = Sort::None; + "*not sorting anymore*" + } + _ => { + o.sort = Sort::TypeDirsFirst; + "*sorting by type, directories first*" + } + } }, bang, con, @@ -247,10 +262,13 @@ pub trait PanelState { Internal::sort_by_type_dirs_first => self.with_new_options( screen, &|o| { - o.sort = match o.sort { - Sort::TypeDirsFirst => Sort::None, - _ => Sort::TypeDirsFirst, - }; + if o.sort == Sort::TypeDirsFirst { + o.sort = Sort::None; + "*not sorting anymore*" + } else { + o.sort = Sort::TypeDirsFirst; + "*now sorting by type, directories first*" + } }, bang, con, @@ -258,53 +276,178 @@ pub trait PanelState { Internal::sort_by_type_dirs_last => self.with_new_options( screen, &|o| { - o.sort = match o.sort { - Sort::TypeDirsLast => Sort::None, - _ => Sort::TypeDirsLast, - }; + if o.sort == Sort::TypeDirsLast { + o.sort = Sort::None; + "*not sorting anymore*" + } else { + o.sort = Sort::TypeDirsLast; + "*now sorting by type, directories last*" + } + }, + bang, + con, + ), + Internal::no_sort => self.with_new_options( + screen, + &|o| { + if o.sort == Sort::None { + "*still not searching*" + } else { + o.sort = Sort::None; + "*not sorting anymore*" + } }, bang, con, ), - Internal::no_sort => self.with_new_options(screen, &|o| o.sort = Sort::None, bang, con), Internal::toggle_counts => { - self.with_new_options(screen, &|o| o.show_counts ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_counts ^= true; + if o.show_counts { + "*displaying file counts*" + } else { + "*hiding file counts*" + } + }, + bang, + con, + ) } Internal::toggle_dates => { - self.with_new_options(screen, &|o| o.show_dates ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_dates ^= true; + if o.show_dates { + "*displaying last modified dates*" + } else { + "*hiding last modified dates*" + } + }, + bang, + con, + ) } Internal::toggle_device_id => { - self.with_new_options(screen, &|o| o.show_device_id ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_device_id ^= true; + if o.show_device_id { + "*displaying device id*" + } else { + "*hiding device id*" + } + }, + bang, + con, + ) } Internal::toggle_files => { - self.with_new_options(screen, &|o: &mut TreeOptions| o.only_folders ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.only_folders ^= true; + if o.only_folders { + "*displaying only directories*" + } else { + "*displaying both files and directories*" + } + }, + bang, + con, + ) } Internal::toggle_hidden => { - self.with_new_options(screen, &|o| o.show_hidden ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_hidden ^= true; + if o.show_hidden { + "h:**y** - *Hidden files displayed*" + } else { + "h:**n** - *Hidden files not displayed*" + } + }, + bang, + con, + ) } Internal::toggle_root_fs => { - self.with_new_options(screen, &|o| o.show_root_fs ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_root_fs ^= true; + if o.show_root_fs { + "*displaying filesystem info for the tree's root directory*" + } else { + "*removing filesystem info*" + } + }, + bang, + con, + ) } Internal::toggle_git_ignore => { - self.with_new_options(screen, &|o| o.respect_git_ignore ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.respect_git_ignore ^= true; + if o.respect_git_ignore { + "gi:**y** - *applying gitignore rules*" + } else { + "gi:**n** - *not applying gitignore rules*" + } + }, + bang, + con, + ) } Internal::toggle_git_file_info => { - self.with_new_options(screen, &|o| o.show_git_file_info ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_git_file_info ^= true; + if o.show_git_file_info { + "*displaying git info next to files*" + } else { + "*removing git file info*" + } + }, + bang, + con, + ) } Internal::toggle_git_status => { self.with_new_options( screen, &|o| { if o.filter_by_git_status { o.filter_by_git_status = false; + "*not filtering according to git status anymore*" } else { o.filter_by_git_status = true; o.show_hidden = true; + "*only displaying new or modified files*" } }, bang, con ) } Internal::toggle_perm => { - self.with_new_options(screen, &|o| o.show_permissions ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.show_permissions ^= true; + if o.show_permissions { + "*displaying file permissions*" + } else { + "*removing file permissions*" + } + }, + bang, + con, + ) } Internal::toggle_sizes => self.with_new_options( screen, @@ -312,16 +455,30 @@ pub trait PanelState { if o.show_sizes { o.show_sizes = false; o.show_root_fs = false; + "*removing sizes of files and directories*" } else { o.show_sizes = true; o.show_root_fs = true; + "*now diplaying sizes of files and directories*" } }, bang, con, ), Internal::toggle_trim_root => { - self.with_new_options(screen, &|o| o.trim_root ^= true, bang, con) + self.with_new_options( + screen, + &|o| { + o.trim_root ^= true; + if o.trim_root { + "*now trimming root from excess files*" + } else { + "*not trimming root files anymore*" + } + }, + bang, + con, + ) } Internal::close_preview => { if let Some(id) = cc.app.preview_panel { @@ -709,12 +866,15 @@ pub trait PanelState { fn tree_options(&self) -> TreeOptions; - /// build a cmdResult in response to a command being a change of - /// tree options. This may or not be a new state + /// Build a cmdResult in response to a command being a change of + /// tree options. This may or not be a new state. + /// + /// The provided `change_options` function returns a status message + /// explaining the change fn with_new_options( &mut self, screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, in_new_panel: bool, con: &AppContext, ) -> CmdResult; diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index 7c222c6..5a3c4ef 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -80,6 +80,7 @@ impl BrowserState { screen: Screen, root: PathBuf, options: TreeOptions, + message: Option<&'static str>, in_new_panel: bool, con: &AppContext, ) -> CmdResult { @@ -92,6 +93,7 @@ impl BrowserState { } CmdResult::from_optional_state( new_state, + message, in_new_panel, ) } @@ -147,6 +149,7 @@ impl BrowserState { con, &dam, ), + None, in_new_panel, )) } else { @@ -175,6 +178,7 @@ impl BrowserState { con, &Dam::unlimited(), ), + None, in_new_panel, ), None => CmdResult::error("no parent found"), @@ -238,14 +242,22 @@ impl PanelState for BrowserState { fn with_new_options( &mut self, screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, in_new_panel: bool, con: &AppContext, ) -> CmdResult { let tree = self.displayed_tree(); let mut options = tree.options.clone(); - change_options(&mut options); - self.modified(screen, tree.root().clone(), options, in_new_panel, con) + let message = change_options(&mut options); + let message = Some(message); + self.modified( + screen, + tree.root().clone(), + options, + message, + in_new_panel, + con, + ) } fn clear_pending(&mut self) { @@ -478,7 +490,14 @@ impl PanelState for BrowserState { let tree = self.displayed_tree(); let root = tree.root(); if let Some(new_root) = root.parent() { - self.modified(screen, new_root.to_path_buf(), tree.options.clone(), bang, con) + self.modified( + screen, + new_root.to_path_buf(), + tree.options.clone(), + None, + bang, + con, + ) } else { CmdResult::error(format!("{:?} has no parent", root)) } @@ -491,7 +510,14 @@ impl PanelState for BrowserState { .components() .take(root_len + 1) .collect(); - self.modified(screen, new_root, tree.options.clone(), bang, con) + self.modified( + screen, + new_root, + tree.options.clone(), + None, + bang, + con, + ) } else { CmdResult::error("No selected line") } diff --git a/src/filesystems/filesystems_state.rs b/src/filesystems/filesystems_state.rs index 0465020..e46346a 100644 --- a/src/filesystems/filesystems_state.rs +++ b/src/filesystems/filesystems_state.rs @@ -178,7 +178,7 @@ impl PanelState for FilesystemState { fn with_new_options( &mut self, _screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, _in_new_panel: bool, // TODO open tree if true _con: &AppContext, ) -> CmdResult { @@ -523,6 +523,7 @@ impl PanelState for FilesystemState { con, &dam, ), + None, in_new_panel, ) } diff --git a/src/help/help_state.rs b/src/help/help_state.rs index be309f1..0021ae3 100644 --- a/src/help/help_state.rs +++ b/src/help/help_state.rs @@ -77,7 +77,7 @@ impl PanelState for HelpState { fn with_new_options( &mut self, _screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, _in_new_panel: bool, // TODO open a tree if true _con: &AppContext, ) -> CmdResult { diff --git a/src/preview/preview_state.rs b/src/preview/preview_state.rs index 6cc6eb0..0d9e577 100644 --- a/src/preview/preview_state.rs +++ b/src/preview/preview_state.rs @@ -203,7 +203,7 @@ impl PanelState for PreviewState { fn with_new_options( &mut self, _screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, _in_new_panel: bool, // TODO open tree if true _con: &AppContext, ) -> CmdResult { diff --git a/src/stage/stage_state.rs b/src/stage/stage_state.rs index 997e544..229413c 100644 --- a/src/stage/stage_state.rs +++ b/src/stage/stage_state.rs @@ -240,7 +240,7 @@ impl PanelState for StageState { fn with_new_options( &mut self, _screen: Screen, - change_options: &dyn Fn(&mut TreeOptions), + change_options: &dyn Fn(&mut TreeOptions) -> &'static str, in_new_panel: bool, con: &AppContext, ) -> CmdResult { @@ -248,15 +248,16 @@ impl PanelState for StageState { CmdResult::error("stage can't be displayed in two panels") } else { let mut new_options= self.tree_options(); - change_options(&mut new_options); - CmdResult::NewState(Box::new(StageState { + let message = change_options(&mut new_options); + let state = Box::new(StageState { filtered_stage: self.filtered_stage.clone(), scroll: self.scroll, mode: initial_mode(con), tree_options: new_options, page_height: self.page_height, stage_sum: self.stage_sum, - })) + }); + CmdResult::NewState { state, message: Some(message) } } } diff --git a/src/verb/internal_focus.rs b/src/verb/internal_focus.rs index 7a13673..b883e30 100644 --- a/src/verb/internal_focus.rs +++ b/src/verb/internal_focus.rs @@ -45,6 +45,7 @@ pub fn new_state_on_path( let path = path::closest_dir(&path); CmdResult::from_optional_state( BrowserState::new(path, tree_options, screen, con, &Dam::unlimited()), + None, false, ) } -- cgit v1.2.3