summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2020-07-15 20:46:25 +0200
committerCanop <cano.petrole@gmail.com>2020-07-15 20:46:25 +0200
commit727ed77ff18b6771ec50a2dd7bb81abf7477342a (patch)
tree75b4bf05a2f8584228b0f7c9f24254b61fe49ecf /src
parent96497a8f3e248aaf493114bb446f9da5760b87c4 (diff)
:open_preview, :close_preview, and :toggle_preview verbs
Diffstat (limited to 'src')
-rw-r--r--src/app/app.rs9
-rw-r--r--src/app/state.rs117
-rw-r--r--src/browser/browser_state.rs30
-rw-r--r--src/help/help_state.rs68
-rw-r--r--src/preview/preview_state.rs104
-rw-r--r--src/verb/builtin.rs3
-rw-r--r--src/verb/internal.rs3
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",