summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2022-09-24 18:19:07 +0200
committerCanop <cano.petrole@gmail.com>2022-09-24 18:32:33 +0200
commitff7265ca6437b858d9ed8e4472f4b7268a06e949 (patch)
treeddea91278b7a389a56b99f37fc2e1e506aa0d489
parent109c57db154adbb005a5dc76804ee41bb72655ee (diff)
add the :select internal
This internal selects a visible tree line by its path (either absolute or relative)
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/browser/browser_state.rs8
-rw-r--r--src/verb/builtin.rs2
-rw-r--r--src/verb/internal.rs2
-rw-r--r--src/verb/internal_focus.rs2
-rw-r--r--src/verb/internal_select.rs145
-rw-r--r--src/verb/mod.rs1
-rw-r--r--website/docs/conf_verbs.md1
8 files changed, 162 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6ae2c42..c7cf2d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,9 @@
- with `show_matching_characters_on_path_searches: false`, it's possible to show only file names even when searching paths - Fix #490
- `--sort-by-type-dirs-first` and `--sort-by-type-dirs-last` - Fix #602
- modal: in intput mode, uppercase letters don't trigger verbs anymore - Fix #604
-- fix :line_down_no_cycle which was cycling
+- fix :line_down_no_cycle which was cycling - Fix #603
- selecting lines up or down with the mouse wheel now wraps in both direction (ie going up when your on top brings you to the bottom, and vice-versa)
+- :select internal, which can be used to select a visible file when given a path as argument. Experimental
### v1.14.3 - 2022-09-12
<a name="v1.14.3"></a>
diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs
index 744bae8..7c222c6 100644
--- a/src/browser/browser_state.rs
+++ b/src/browser/browser_state.rs
@@ -339,6 +339,14 @@ impl PanelState for BrowserState {
app_state,
cc,
),
+ Internal::select => internal_select::on_internal(
+ internal_exec,
+ input_invocation,
+ trigger_type,
+ self.displayed_tree_mut(),
+ app_state,
+ cc,
+ ),
Internal::up_tree => match self.displayed_tree().root().parent() {
Some(path) => internal_focus::on_path(
path.to_path_buf(),
diff --git a/src/verb/builtin.rs b/src/verb/builtin.rs
index d4869b6..5d7f642 100644
--- a/src/verb/builtin.rs
+++ b/src/verb/builtin.rs
@@ -249,6 +249,7 @@ pub fn builtin_verbs() -> Vec<Verb> {
.with_key(key!(ctrl-down)),
internal(select_first),
internal(select_last),
+ internal(select),
internal(clear_stage).with_shortcut("cls"),
internal(stage)
.with_key(key!('+')),
@@ -292,5 +293,6 @@ pub fn builtin_verbs() -> Vec<Verb> {
internal(toggle_trim_root),
internal(total_search).with_key(key!(ctrl-s)),
internal(up_tree).with_shortcut("up"),
+
]
}
diff --git a/src/verb/internal.rs b/src/verb/internal.rs
index 13559c3..20bf8d8 100644
--- a/src/verb/internal.rs
+++ b/src/verb/internal.rs
@@ -113,6 +113,7 @@ Internals! {
//restore_pattern: "restore a pattern which was just removed" false,
select_first: "select the first item" false,
select_last: "select the last item" false,
+ select: "select a file by path" true,
set_syntax_theme: "set the theme of code preview" false,
sort_by_count: "sort by count" false,
sort_by_date: "sort by date" false,
@@ -149,6 +150,7 @@ impl Internal {
pub fn invocation_pattern(self) -> &'static str {
match self {
Internal::focus => r"focus (?P<path>.*)?",
+ Internal::select => r"select (?P<path>.*)?",
Internal::line_down => r"line_down (?P<count>\d*)?",
Internal::line_up => r"line_up (?P<count>\d*)?",
Internal::line_down_no_cycle => r"line_down_no_cycle (?P<count>\d*)?",
diff --git a/src/verb/internal_focus.rs b/src/verb/internal_focus.rs
index 2399a79..7a13673 100644
--- a/src/verb/internal_focus.rs
+++ b/src/verb/internal_focus.rs
@@ -80,7 +80,7 @@ pub fn new_panel_on_path(
/// Compute the path to go to in case of the internal being triggered from
/// the input.
///
-/// This path depends on the verb (which may hardcore the path of have a
+/// This path depends on the verb (which may hardcore the path or have a
/// pattern), from the selection,
fn path_from_input(
verb: &Verb,
diff --git a/src/verb/internal_select.rs b/src/verb/internal_select.rs
new file mode 100644
index 0000000..ae1b2f7
--- /dev/null
+++ b/src/verb/internal_select.rs
@@ -0,0 +1,145 @@
+//! utility functions to help handle the `:select` internal
+
+use {
+ super::*,
+ crate::{
+ app::*,
+ browser::BrowserState,
+ command::TriggerType,
+ display::Screen,
+ path::{self, PathAnchor},
+ tree::Tree,
+ },
+ std::path::{Path, PathBuf},
+};
+
+
+/// general implementation for verbs based on the :select internal with optionally
+/// a bang or an argument.
+pub fn on_internal(
+ internal_exec: &InternalExecution,
+ input_invocation: Option<&VerbInvocation>,
+ trigger_type: TriggerType,
+ tree: &mut Tree,
+ app_state: & AppState,
+ cc: &CmdContext,
+) -> CmdResult {
+ let screen = cc.app.screen;
+ info!(
+ "internal_select.on_internal internal_exec={:?} input_invocation={:?} trygger_type={:?}",
+ internal_exec,
+ input_invocation,
+ trigger_type,
+ );
+ let bang = input_invocation
+ .map(|inv| inv.bang)
+ .unwrap_or(internal_exec.bang);
+ let input_arg = input_invocation.as_ref()
+ .and_then(|invocation| invocation.args.as_ref());
+ match trigger_type {
+ TriggerType::Input(verb) => {
+ let path = path_from_input(
+ verb,
+ internal_exec,
+ &tree.selected_line().path,
+ input_arg,
+ app_state,
+ );
+ on_path(path, tree, screen, bang)
+ }
+ _ => {
+ // the :select internal was triggered by a key
+ if let Some(arg) = &internal_exec.arg {
+ // the internal_execution specifies the path to use
+ // (it may come from a configured verb whose execution is
+ // `:select some/path`).
+ // The given path may be relative hence the need for the
+ // state's selection
+ let path = path::path_from(
+ &tree.selected_line().path,
+ PathAnchor::Unspecified,
+ arg,
+ );
+ let bang = input_invocation
+ .map(|inv| inv.bang)
+ .unwrap_or(internal_exec.bang);
+ on_path(path, tree, screen, bang)
+ } else {
+ // there's nothing really to do here
+ CmdResult::Keep
+ }
+ }
+ }
+}
+
+
+/// Compute the path to go to in case of the internal being triggered from
+/// the input.
+///
+/// This path depends on the verb (which may hardcore the path or have a
+/// pattern), from the selection,
+fn path_from_input(
+ verb: &Verb,
+ internal_exec: &InternalExecution,
+ base_path: &Path, // either the selected path or the root path
+ input_arg: Option<&String>,
+ app_state: &AppState,
+) -> PathBuf {
+ match (input_arg, internal_exec.arg.as_ref()) {
+ (Some(input_arg), Some(verb_arg)) => {
+ // The verb probably defines some patttern which uses the input.
+ // For example:
+ // {
+ // invocation: "gotar {path}"
+ // execution: ":select {path}/target"
+ // }
+ // (or that input is useless)
+ let path_builder = ExecutionStringBuilder::with_invocation(
+ &verb.invocation_parser,
+ SelInfo::from_path(base_path),
+ app_state,
+ Some(input_arg),
+ );
+ path_builder.path(verb_arg)
+ }
+ (Some(input_arg), None) => {
+ // the verb defines nothing
+ // The :select internal execution was triggered from the
+ // input (which must be a kind of alias for :select)
+ // so we do exactly what the input asks for
+ path::path_from(base_path, PathAnchor::Unspecified, input_arg)
+ }
+ (None, Some(verb_arg)) => {
+ // the verb defines the path where to go..
+ // the internal_execution specifies the path to use
+ // (it may come from a configured verb whose execution is
+ // `:select some/path`).
+ // The given path may be relative hence the need for the
+ // state's selection
+ // (we assume a check before ensured it doesn't need an input)
+ path::path_from(base_path, PathAnchor::Unspecified, verb_arg)
+ }
+ (None, None) => {
+ // This doesn't really make sense: we're selecting the currently
+ // selected path
+ base_path.to_path_buf()
+ }
+ }
+
+}
+
+pub fn on_path(
+ path: PathBuf,
+ tree: &mut Tree,
+ screen: Screen,
+ in_new_panel: bool,
+) -> CmdResult {
+ info!("executing :select on path {:?}", &path);
+ if in_new_panel {
+ warn!("bang in :select isn't supported yet");
+ }
+ if tree.try_select_path(&path) {
+ tree.make_selection_visible(BrowserState::page_height(screen) as usize);
+ }
+ CmdResult::Keep
+}
diff --git a/src/verb/mod.rs b/src/verb/mod.rs
index 3a835de..7ea25ea 100644
--- a/src/verb/mod.rs
+++ b/src/verb/mod.rs
@@ -7,6 +7,7 @@ mod external_execution_mode;
mod internal;
mod internal_execution;
pub mod internal_focus;
+pub mod internal_select;
mod invocation_parser;
mod sequence_execution;
mod verb;
diff --git a/website/docs/conf_verbs.md b/website/docs/conf_verbs.md
index 149313b..92954fa 100644
--- a/website/docs/conf_verbs.md
+++ b/website/docs/conf_verbs.md
@@ -386,6 +386,7 @@ invocation | default key | default shortcut | behavior / details
:rm | - | - | remove the selected file or directory. To stay safe, don't define a keyboard key for this action
:select_first | - | - | select the first line
:select_last | - | - | select the last line
+:select | - | - | select a path given as argument, if it's in the visible tree
:sort_by_count | - | sc | sort by count (only one level of the tree is displayed)
:sort_by_date | - | sd | sort by date
:sort_by_size | - | ss | sort by size