diff options
author | Canop <cano.petrole@gmail.com> | 2020-07-15 20:46:25 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2020-07-15 20:46:25 +0200 |
commit | 727ed77ff18b6771ec50a2dd7bb81abf7477342a (patch) | |
tree | 75b4bf05a2f8584228b0f7c9f24254b61fe49ecf /src | |
parent | 96497a8f3e248aaf493114bb446f9da5760b87c4 (diff) |
:open_preview, :close_preview, and :toggle_preview verbs
Diffstat (limited to 'src')
-rw-r--r-- | src/app/app.rs | 9 | ||||
-rw-r--r-- | src/app/state.rs | 117 | ||||
-rw-r--r-- | src/browser/browser_state.rs | 30 | ||||
-rw-r--r-- | src/help/help_state.rs | 68 | ||||
-rw-r--r-- | src/preview/preview_state.rs | 104 | ||||
-rw-r--r-- | src/verb/builtin.rs | 3 | ||||
-rw-r--r-- | src/verb/internal.rs | 3 |
7 files changed, 183 insertions, 151 deletions
diff --git a/src/app/app.rs b/src/app/app.rs index 1792165..4232414 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -167,6 +167,9 @@ impl App { con, )? { ClosePanel { validate_purpose, id } => { + if is_input_invocation { + self.mut_panel().clear_input_invocation(); + } let close_idx = id .and_then(|id| self.panel_idx(id)) .unwrap_or(self.active_panel_idx); @@ -213,9 +216,11 @@ impl App { direction, } => { if is_input_invocation { - self.mut_panel().clear_input(); + self.mut_panel().clear_input_invocation(); } - let insertion_idx = if direction == HDir::Right { + let insertion_idx = if purpose.is_preview() { + self.panels.len().get() + } else if direction == HDir::Right { self.active_panel_idx + 1 } else { self.active_panel_idx diff --git a/src/app/state.rs b/src/app/state.rs index 690d0a9..894cc4d 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -5,7 +5,10 @@ use { display::{Screen, W}, errors::ProgramError, flag::Flag, + help::HelpState, pattern::*, + preview::PreviewState, + print, selection_type::SelectionType, skin::PanelSkin, task_sync::Dam, @@ -64,6 +67,120 @@ pub trait AppState { screen: &mut Screen, ) -> Result<AppStateCmdResult, ProgramError>; + /// a generic implementation of on_internal which may be + /// called by states when they don't have a specific + /// behavior to execute + fn on_internal_generic( + &mut self, + _w: &mut W, + internal_exec: &InternalExecution, + input_invocation: Option<&VerbInvocation>, + _trigger_type: TriggerType, + cc: &CmdContext, + screen: &mut Screen, + ) -> Result<AppStateCmdResult, ProgramError> { + let con = &cc.con; + Ok(match internal_exec.internal { + Internal::back => AppStateCmdResult::PopState, + Internal::close_panel_ok => AppStateCmdResult::ClosePanel { + validate_purpose: true, + id: None, + }, + Internal::close_panel_cancel => AppStateCmdResult::ClosePanel { + validate_purpose: false, + id: None, + }, + Internal::help => { + let bang = input_invocation + .map(|inv| inv.bang) + .unwrap_or(internal_exec.bang); + if bang && cc.preview.is_none() { + AppStateCmdResult::NewPanel { + state: Box::new(HelpState::new(screen, con)), + purpose: PanelPurpose::None, + direction: HDir::Right, + } + } else { + AppStateCmdResult::NewState(Box::new(HelpState::new(screen, con))) + } + } + Internal::open_preview => { + if cc.preview.is_some() { + AppStateCmdResult::Keep + } else { + let path = self.selected_path(); + if path.is_file() { + AppStateCmdResult::NewPanel { + state: Box::new(PreviewState::new(path.to_path_buf(), con)), + purpose: PanelPurpose::Preview, + direction: HDir::Right, + } + } else { + AppStateCmdResult::DisplayError( + "only regular files can be previewed".to_string() + ) + } + } + } + Internal::close_preview => { + if let Some(id) = cc.preview { + AppStateCmdResult::ClosePanel { + validate_purpose: false, + id: Some(id), + } + } else { + AppStateCmdResult::Keep + } + } + Internal::toggle_preview => { + if let Some(id) = cc.preview { + AppStateCmdResult::ClosePanel { + validate_purpose: false, + id: Some(id), + } + } else { + let path = self.selected_path(); + if path.is_file() { + AppStateCmdResult::NewPanel { + state: Box::new(PreviewState::new(path.to_path_buf(), con)), + purpose: PanelPurpose::Preview, + direction: HDir::Right, + } + } else { + AppStateCmdResult::DisplayError( + "only regular files can be previewed".to_string() + ) + } + } + } + Internal::panel_left => { + if cc.areas.is_first() { + AppStateCmdResult::Keep + } else { + // we ask the app to focus the panel to the left + AppStateCmdResult::Propagate(Internal::panel_left) + } + } + Internal::panel_right => { + if cc.areas.is_last() { + AppStateCmdResult::Keep + } else { + // we ask the app to focus the panel to the left + AppStateCmdResult::Propagate(Internal::panel_right) + } + } + Internal::print_path => { + print::print_path(self.selected_path(), con)? + } + Internal::print_relative_path => { + print::print_relative_path(self.selected_path(), con)? + } + Internal::refresh => AppStateCmdResult::RefreshState { clear_cache: true }, + Internal::quit => AppStateCmdResult::Quit, + _ => AppStateCmdResult::Keep, + }) + } + /// change the state, does no rendering fn on_command( &mut self, diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index 0dcfc16..6c54df8 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -6,7 +6,6 @@ use { errors::{ProgramError, TreeBuildError}, flag::Flag, git, - help::HelpState, launchable::Launchable, pattern::*, path, @@ -387,14 +386,6 @@ impl AppState for BrowserState { AppStateCmdResult::PopState } } - Internal::close_panel_ok => AppStateCmdResult::ClosePanel { - validate_purpose: true, - id: None, // close current panel - }, - Internal::close_panel_cancel => AppStateCmdResult::ClosePanel { - validate_purpose: false, - id: None, // close current panel - }, Internal::focus => internal_focus::on_internal( internal_exec, input_invocation, @@ -414,17 +405,6 @@ impl AppState for BrowserState { ), None => AppStateCmdResult::DisplayError("no parent found".to_string()), }, - Internal::help => { - if bang { - AppStateCmdResult::NewPanel { - state: Box::new(HelpState::new(screen, con)), - purpose: PanelPurpose::None, - direction: HDir::Right, - } - } else { - AppStateCmdResult::NewState(Box::new(HelpState::new(screen, con))) - } - } Internal::open_stay => self.open_selection_stay_in_broot(screen, con, bang, false)?, Internal::open_stay_filter => self.open_selection_stay_in_broot(screen, con, bang, true)?, Internal::open_leave => self.open_selection_quit_broot(w, con)?, @@ -515,7 +495,6 @@ impl AppState for BrowserState { Internal::print_tree => { print::print_tree(&self.displayed_tree(), screen, &cc.panel_skin, con)? } - Internal::refresh => AppStateCmdResult::RefreshState { clear_cache: true }, Internal::select_first => { self.displayed_tree_mut().try_select_first(); AppStateCmdResult::Keep @@ -665,7 +644,14 @@ impl AppState for BrowserState { } } Internal::quit => AppStateCmdResult::Quit, - _ => AppStateCmdResult::Keep, + _ => self.on_internal_generic( + w, + internal_exec, + input_invocation, + trigger_type, + cc, + screen, + )?, }) } diff --git a/src/help/help_state.rs b/src/help/help_state.rs index 8c330fb..277eedf 100644 --- a/src/help/help_state.rs +++ b/src/help/help_state.rs @@ -2,17 +2,13 @@ use { super::help_content, crate::{ app::*, - browser::BrowserState, command::{Command, TriggerType}, - conf::{self, Conf}, + conf::Conf, display::{Screen, W}, errors::ProgramError, launchable::Launchable, - print, selection_type::SelectionType, skin::PanelSkin, - task_sync::Dam, - tree::TreeOptions, verb::*, }, std::path::{Path, PathBuf}, @@ -60,11 +56,15 @@ impl AppState for HelpState { panel_skin: &PanelSkin, con: &AppContext, ) -> Result<(), ProgramError> { + let mut text_area = state_area.clone(); + text_area.pad_for_max_width(120); + if text_area != self.text_area { + self.dirty = true; + self.text_area = text_area; + } if self.dirty { panel_skin.styles.default.queue_bg(w)?; screen.clear_area_to_right(w, &state_area)?; - self.text_area = state_area; - self.text_area.pad_for_max_width(120); self.dirty = false; } let text = help_content::build_text(con); @@ -117,37 +117,15 @@ impl AppState for HelpState { fn on_internal( &mut self, - _w: &mut W, + w: &mut W, internal_exec: &InternalExecution, input_invocation: Option<&VerbInvocation>, - _trigger_type: TriggerType, + trigger_type: TriggerType, cc: &CmdContext, screen: &mut Screen, ) -> Result<AppStateCmdResult, ProgramError> { use Internal::*; - let bang = input_invocation - .map(|inv| inv.bang) - .unwrap_or(internal_exec.bang); Ok(match internal_exec.internal { - back => AppStateCmdResult::PopState, - focus | parent => AppStateCmdResult::from_optional_state( - BrowserState::new( - conf::dir().to_path_buf(), - TreeOptions::default(), - screen, - &cc.con, - &Dam::unlimited(), - ), - bang, - ), - Internal::close_panel_ok => AppStateCmdResult::ClosePanel { - validate_purpose: true, - id: None, - }, - Internal::close_panel_cancel => AppStateCmdResult::ClosePanel { - validate_purpose: false, - id: None, - }, help => AppStateCmdResult::Keep, line_down => { self.scroll += 1; @@ -177,29 +155,17 @@ impl AppState for HelpState { self.scroll -= self.text_area.height as i32; AppStateCmdResult::Keep } - Internal::panel_left => { - if cc.areas.is_first() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::Propagate(Internal::panel_left) - } - } - Internal::panel_right => { - if cc.areas.is_last() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::Propagate(Internal::panel_right) - } - } - print_path => print::print_path(&Conf::default_location(), &cc.con)?, - print_relative_path => print::print_relative_path(&Conf::default_location(), &cc.con)?, - quit => AppStateCmdResult::Quit, toggle_dates | toggle_files | toggle_hidden | toggle_git_ignore | toggle_git_file_info | toggle_git_status | toggle_perm | toggle_sizes | toggle_trim_root => AppStateCmdResult::PopStateAndReapply, - _ => AppStateCmdResult::Keep, + _ => self.on_internal_generic( + w, + internal_exec, + input_invocation, + trigger_type, + cc, + screen, + )?, }) } diff --git a/src/preview/preview_state.rs b/src/preview/preview_state.rs index ace6b87..1704563 100644 --- a/src/preview/preview_state.rs +++ b/src/preview/preview_state.rs @@ -2,18 +2,12 @@ use { super::*, crate::{ app::*, - browser::BrowserState, command::{Command, ScrollCommand, TriggerType}, - conf::{self, Conf}, display::{CropWriter, LONG_SPACE, Screen, W}, errors::ProgramError, flag::Flag, - launchable::Launchable, - print, selection_type::SelectionType, skin::PanelSkin, - task_sync::Dam, - tree::TreeOptions, verb::*, }, crossterm::{ @@ -82,16 +76,20 @@ impl AppState for PreviewState { panel_skin: &PanelSkin, _con: &AppContext, ) -> Result<(), ProgramError> { - if state_area.height < 8 { + if state_area.height < 3 { warn!("area too small for preview"); return Ok(()); } + let mut preview_area = state_area.clone(); + preview_area.height -= 1; + preview_area.top += 1; + if preview_area != self.preview_area { + self.dirty = true; + self.preview_area = preview_area; + } if self.dirty { panel_skin.styles.default.queue_bg(w)?; screen.clear_area_to_right(w, &state_area)?; - self.preview_area = state_area.clone(); - self.preview_area.height -= 1; - self.preview_area.top += 1; self.dirty = false; } let styles = &panel_skin.styles; @@ -141,85 +139,39 @@ impl AppState for PreviewState { fn on_internal( &mut self, - _w: &mut W, + w: &mut W, internal_exec: &InternalExecution, input_invocation: Option<&VerbInvocation>, - _trigger_type: TriggerType, + trigger_type: TriggerType, cc: &CmdContext, screen: &mut Screen, ) -> Result<AppStateCmdResult, ProgramError> { - use Internal::*; - let bang = input_invocation - .map(|inv| inv.bang) - .unwrap_or(internal_exec.bang); - Ok(match internal_exec.internal { - back => AppStateCmdResult::PopState, - focus | parent => AppStateCmdResult::from_optional_state( - BrowserState::new( - conf::dir().to_path_buf(), - TreeOptions::default(), - screen, - &cc.con, - &Dam::unlimited(), - ), - bang, - ), - Internal::close_panel_ok => AppStateCmdResult::ClosePanel { - validate_purpose: true, - id: None, - }, - Internal::close_panel_cancel => AppStateCmdResult::ClosePanel { - validate_purpose: false, - id: None, - }, - help => AppStateCmdResult::Keep, - line_down => { + match internal_exec.internal { + Internal::line_down => { self.preview.try_scroll(ScrollCommand::Lines(1)); - AppStateCmdResult::Keep + Ok(AppStateCmdResult::Keep) } - line_up => { + Internal::line_up => { self.preview.try_scroll(ScrollCommand::Lines(-1)); - AppStateCmdResult::Keep + Ok(AppStateCmdResult::Keep) } - open_stay => match open::that(&Conf::default_location()) { - Ok(exit_status) => { - info!("open returned with exit_status {:?}", exit_status); - AppStateCmdResult::Keep - } - Err(e) => AppStateCmdResult::DisplayError(format!("{:?}", e)), - }, - open_leave => { - AppStateCmdResult::from(Launchable::opener(self.path.clone())) - } - page_down => { + Internal::page_down => { self.preview.try_scroll(ScrollCommand::Pages(1)); - AppStateCmdResult::Keep + Ok(AppStateCmdResult::Keep) } - page_up => { + Internal::page_up => { self.preview.try_scroll(ScrollCommand::Pages(-1)); - AppStateCmdResult::Keep + Ok(AppStateCmdResult::Keep) } - Internal::panel_left => { - if cc.areas.is_first() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::Propagate(Internal::panel_left) - } - } - Internal::panel_right => { - if cc.areas.is_last() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::Propagate(Internal::panel_right) - } - } - print_path => print::print_path(&Conf::default_location(), &cc.con)?, - print_relative_path => print::print_relative_path(&Conf::default_location(), &cc.con)?, - quit => AppStateCmdResult::Quit, - _ => AppStateCmdResult::Keep, - }) + _ => self.on_internal_generic( + w, + internal_exec, + input_invocation, + trigger_type, + cc, + screen, + ), + } } // TODO put the hex/txt view here diff --git a/src/verb/builtin.rs b/src/verb/builtin.rs index bd09ca7..cd92494 100644 --- a/src/verb/builtin.rs +++ b/src/verb/builtin.rs @@ -14,6 +14,9 @@ pub fn builtin_verbs() -> Vec<Verb> { .with_description("change directory and quit (mapped to *alt*-*enter*)"), #[cfg(unix)] Verb::external("chmod {args}", "chmod {args} {file}", StayInBroot).unwrap(), + Verb::internal(open_preview), + Verb::internal(close_preview), + Verb::internal(toggle_preview), Verb::internal(close_panel_ok), Verb::internal(close_panel_cancel) .with_key(BACK_TAB) diff --git a/src/verb/internal.rs b/src/verb/internal.rs index ccf9127..2c91030 100644 --- a/src/verb/internal.rs +++ b/src/verb/internal.rs @@ -81,6 +81,9 @@ Internals! { panel_left: "focus panel on left", panel_right: "focus panel on right", previous_match: "select the previous match", + open_preview: "open the preview panel", + close_preview: "close the preview panel", + toggle_preview: "open/close the preview panel", print_path: "print path and leaves broot", print_relative_path: "print relative path and leaves broot", print_tree: "print tree and leaves broot", |