diff options
author | Canop <cano.petrole@gmail.com> | 2020-10-04 11:09:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-04 11:09:17 +0200 |
commit | 409a1020c5acad6ad2920e165107f0a9b12b8463 (patch) | |
tree | f23ebda3a1094bf881f457abf7e371579ec239f7 | |
parent | a2e48f122e94acf45e9c88956f13eed0d5c4d9ed (diff) | |
parent | 607900d9f1a71c37c0ed93f4a3f46829de2af776 (diff) |
Merge pull request #286 from Canop/search-modes-help
Search modes help
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/help/help_content.rs | 112 | ||||
-rw-r--r-- | src/help/help_features.rs | 24 | ||||
-rw-r--r-- | src/help/help_search_modes.rs | 41 | ||||
-rw-r--r-- | src/help/help_state.rs | 11 | ||||
-rw-r--r-- | src/help/help_verbs.rs | 73 | ||||
-rw-r--r-- | src/help/mod.rs | 3 | ||||
-rw-r--r-- | src/pattern/mod.rs | 2 | ||||
-rw-r--r-- | src/pattern/search_mode.rs | 44 |
10 files changed, 206 insertions, 108 deletions
@@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "broot" -version = "1.0.1" +version = "1.0.2-dev" dependencies = [ "ansi_colours", "bet", @@ -1,6 +1,6 @@ [package] name = "broot" -version = "1.0.1" +version = "1.0.2-dev" authors = ["dystroy <denys.seguret@gmail.com>"] repository = "https://github.com/Canop/broot" documentation = "https://dystroy.org/broot" diff --git a/src/help/help_content.rs b/src/help/help_content.rs index 8b7c0e9..a1fba9d 100644 --- a/src/help/help_content.rs +++ b/src/help/help_content.rs @@ -1,9 +1,4 @@ use { - crate::{ - app::AppContext, - pattern::*, - verb::*, - }, minimad::{TextTemplate, TextTemplateExpander}, }; @@ -16,12 +11,13 @@ It's best used when launched as **br**. See **https://dystroy.org/broot** for a complete guide. The *esc* key gets you back to the previous state. -Typing some letters searches the tree and selects the most relevant file. -To use a regular expression, prefix with a slash eg `/j(ava|s)$`. -To search by file content, prefix with `c/` eg `c/TODO`. The *↑* and *↓* arrow keys can be used to change selection. The mouse can be used to select (on click) or open (on double-click). +## Configuration + +Verbs, skin, and more, can be configured in **${config-path}**. + ## Verbs To execute a verb, type a space or `:` then start of its name or shortcut. @@ -33,9 +29,18 @@ ${verb-rows } |-: -## Configuration +## Search Modes -Verbs and skin can be configured in **${config-path}**. +Typing some letters searches the tree and selects the most relevant file. +To use a regular expression, prefix with a slash eg `/j(ava|s)$/i`. +To search by file content, prefix with `c/` eg `c/TODO`. +|:-:|:-: +|**prefix**|**search** +|:-:|:- +${search-mode-rows +|${search-prefix}|${search-type} +} +|-: ## Launch Arguments @@ -60,29 +65,6 @@ ${features } "#; -/// find the list of optional features which are enabled -pub fn determine_features() -> Vec<(&'static str, &'static str)> { - #[allow(unused_mut)] - let mut features: Vec<(&'static str, &'static str)> = Vec::new(); - - #[cfg(not(any(target_family="windows",target_os="android")))] - features.push(("permissions", "allow showing file mode, owner and group")); - - #[cfg(feature="client-server")] - features.push(( - "client-server", - "see https://github.com/Canop/broot/blob/master/client-server.md" - )); - - #[cfg(feature="clipboard")] - features.push(( - "clipboard", - ":copy_path (copying the current path), and :input_paste (pasting into the input)" - )); - - features -} - /// build a markdown expander which will need to be /// completed with data and which then would be used to /// produce the markdown of the help page @@ -93,67 +75,3 @@ pub fn expander() -> TextTemplateExpander<'static, 'static> { } TEMPLATE.expander() } - -/// what should be shown for a verb in the help screen, after -/// filtering -pub struct MatchingVerbRow<'v> { - name: Option<String>, - shortcut: Option<String>, - pub verb: &'v Verb, -} - -impl MatchingVerbRow<'_> { - /// the name in markdown (with matching chars in bold if - /// some filtering occured) - pub fn name(&self) -> &str { - // there should be a better way to write this - self.name.as_deref().unwrap_or_else(|| match self.verb.names.get(0) { - Some(s) => &s.as_str(), - _ => " ", - }) - } - pub fn shortcut(&self) -> &str { - // there should be a better way to write this - self.shortcut.as_deref().unwrap_or_else(|| match self.verb.names.get(1) { - Some(s) => &s.as_str(), - _ => " ", - }) - } -} - -pub fn matching_verb_rows<'v>( - pat: &Pattern, - con: &'v AppContext, -) -> Vec<MatchingVerbRow<'v>> { - let mut rows = Vec::new(); - for verb in &con.verb_store.verbs { - let mut name = None; - let mut shortcut = None; - if pat.is_some() { - let mut ok = false; - name = verb.names.get(0) - .and_then(|s| - pat.search_string(s).map(|nm| { - ok = true; - nm.wrap(s, "**", "**") - }) - ); - shortcut = verb.names.get(1) - .and_then(|s| - pat.search_string(s).map(|nm| { - ok = true; - nm.wrap(s, "**", "**") - }) - ); - if !ok { - continue; - } - } - rows.push(MatchingVerbRow { - name, - shortcut, - verb, - }); - } - rows -} diff --git a/src/help/help_features.rs b/src/help/help_features.rs new file mode 100644 index 0000000..ae07346 --- /dev/null +++ b/src/help/help_features.rs @@ -0,0 +1,24 @@ + + +/// find the list of optional features which are enabled +pub fn list() -> Vec<(&'static str, &'static str)> { + #[allow(unused_mut)] + let mut features: Vec<(&'static str, &'static str)> = Vec::new(); + + #[cfg(not(any(target_family="windows",target_os="android")))] + features.push(("permissions", "allow showing file mode, owner and group")); + + #[cfg(feature="client-server")] + features.push(( + "client-server", + "see https://github.com/Canop/broot/blob/master/client-server.md" + )); + + #[cfg(feature="clipboard")] + features.push(( + "clipboard", + ":copy_path (copying the current path), and :input_paste (pasting into the input)" + )); + + features +} diff --git a/src/help/help_search_modes.rs b/src/help/help_search_modes.rs new file mode 100644 index 0000000..7c795c0 --- /dev/null +++ b/src/help/help_search_modes.rs @@ -0,0 +1,41 @@ +use { + crate::{ + app::AppContext, + pattern::*, + }, +}; + +/// what should be shown for a search_mode in the help screen, after +/// filtering +pub struct MatchingSearchModeRow { + pub prefix: String, + pub description: String, +} + +/// return the rows of the "Search Modes" table in help. +pub fn search_mode_rows( + con: &AppContext, +) -> Vec<MatchingSearchModeRow> { + SEARCH_MODES.iter().map(|mode| { + let prefix = con.search_modes.key(*mode).map_or_else( + || "".to_string(), + |k| format!("{:>3}/", k), + ); + let description = format!( + "{} search on {}", + match mode.kind() { + SearchKind::Exact => "exact string", + SearchKind::Fuzzy => "fuzzy", + SearchKind::Regex => "regex", + _ => "???", // should not happen + }, + match mode.object() { + SearchObject::Name => "file name", + SearchObject::Path => "sub path", + SearchObject::Content => "file content", + }, + ); + MatchingSearchModeRow { prefix, description } + }).collect() +} + diff --git a/src/help/help_state.rs b/src/help/help_state.rs index df31fdd..e0e9ab7 100644 --- a/src/help/help_state.rs +++ b/src/help/help_state.rs @@ -87,7 +87,7 @@ impl AppState for HelpState { expander .set("version", env!("CARGO_PKG_VERSION")) .set("config-path", &con.config_path); - let verb_rows = help_content::matching_verb_rows(&self.pattern, con); + let verb_rows = super::help_verbs::matching_verb_rows(&self.pattern, con); for row in &verb_rows { let sub = expander .sub("verb-rows") @@ -102,7 +102,14 @@ impl AppState for HelpState { sub.set("execution", ""); } } - let features = help_content::determine_features(); + let search_rows = super::help_search_modes::search_mode_rows(con); + for row in &search_rows { + expander + .sub("search-mode-rows") + .set("search-prefix", &row.prefix) + .set("search-type", &row.description); + } + let features = super::help_features::list(); expander.set( "features-text", if features.is_empty() { diff --git a/src/help/help_verbs.rs b/src/help/help_verbs.rs new file mode 100644 index 0000000..383671e --- /dev/null +++ b/src/help/help_verbs.rs @@ -0,0 +1,73 @@ +use { + crate::{ + app::AppContext, + pattern::*, + verb::*, + }, +}; + +/// what should be shown for a verb in the help screen, after +/// filtering +pub struct MatchingVerbRow<'v> { + name: Option<String>, + shortcut: Option<String>, + pub verb: &'v Verb, +} + +impl MatchingVerbRow<'_> { + /// the name in markdown (with matching chars in bold if + /// some filtering occured) + pub fn name(&self) -> &str { + // there should be a better way to write this + self.name.as_deref().unwrap_or_else(|| match self.verb.names.get(0) { + Some(s) => &s.as_str(), + _ => " ", + }) + } + pub fn shortcut(&self) -> &str { + // there should be a better way to write this + self.shortcut.as_deref().unwrap_or_else(|| match self.verb.names.get(1) { + Some(s) => &s.as_str(), + _ => " ", + }) + } +} + +/// return the rows of the verbs table in help, taking the current filter +/// into account +pub fn matching_verb_rows<'v>( + pat: &Pattern, + con: &'v AppContext, +) -> Vec<MatchingVerbRow<'v>> { + let mut rows = Vec::new(); + for verb in &con.verb_store.verbs { + let mut name = None; + let mut shortcut = None; + if pat.is_some() { + let mut ok = false; + name = verb.names.get(0) + .and_then(|s| + pat.search_string(s).map(|nm| { + ok = true; + nm.wrap(s, "**", "**") + }) + ); + shortcut = verb.names.get(1) + .and_then(|s| + pat.search_string(s).map(|nm| { + ok = true; + nm.wrap(s, "**", "**") + }) + ); + if !ok { + continue; + } + } + rows.push(MatchingVerbRow { + name, + shortcut, + verb, + }); + } + rows +} diff --git a/src/help/mod.rs b/src/help/mod.rs index 80a21ed..a737754 100644 --- a/src/help/mod.rs +++ b/src/help/mod.rs @@ -1,4 +1,7 @@ mod help_content; +mod help_features; +mod help_search_modes; mod help_state; +mod help_verbs; pub use help_state::HelpState; diff --git a/src/pattern/mod.rs b/src/pattern/mod.rs index 68ede18..85167b5 100644 --- a/src/pattern/mod.rs +++ b/src/pattern/mod.rs @@ -28,7 +28,7 @@ pub use { pattern_parts::PatternParts, operator::PatternOperator, regex_pattern::RegexPattern, - search_mode::{SearchMode, SearchModeMap, SearchModeMapEntry}, + search_mode::*, }; use crate::errors::PatternError; diff --git a/src/pattern/search_mode.rs b/src/pattern/search_mode.rs index bc2fefa..99faf4d 100644 --- a/src/pattern/search_mode.rs +++ b/src/pattern/search_mode.rs @@ -6,13 +6,15 @@ use { }; /// where to search -enum SearchObject { +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SearchObject { Name, Path, Content, } /// how to search -enum SearchKind { +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum SearchKind { Exact, Fuzzy, Regex, @@ -21,7 +23,7 @@ enum SearchKind { /// a valid combination of SearchObject and SearchKind, /// determine how a pattern will be used -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SearchMode { NameExact, NameFuzzy, @@ -33,6 +35,17 @@ pub enum SearchMode { ContentRegex, } +pub static SEARCH_MODES: &[SearchMode] = &[ + SearchMode::NameFuzzy, + SearchMode::NameRegex, + SearchMode::NameExact, + SearchMode::PathFuzzy, + SearchMode::PathExact, + SearchMode::PathRegex, + SearchMode::ContentExact, + SearchMode::ContentRegex, +]; + impl SearchMode { fn new(search_object: SearchObject, search_kind: SearchKind) -> Option<Self> { use { @@ -56,21 +69,40 @@ impl SearchMode { (Content, Regex) => Some(Self::ContentRegex), } } + pub fn object(&self) -> SearchObject { + match self { + Self::NameExact | Self::NameFuzzy | Self::NameRegex => SearchObject::Name, + Self::PathExact | Self::PathFuzzy | Self::PathRegex => SearchObject::Path, + Self::ContentExact | Self::ContentRegex => SearchObject::Content, + } + } + pub fn kind(&self) -> SearchKind { + match self { + Self::NameExact => SearchKind::Exact, + Self::NameFuzzy => SearchKind::Fuzzy, + Self::NameRegex => SearchKind::Regex, + Self::PathExact => SearchKind::Exact, + Self::PathFuzzy => SearchKind::Fuzzy, + Self::PathRegex => SearchKind::Regex, + Self::ContentExact => SearchKind::Exact, + Self::ContentRegex => SearchKind::Regex, + } + } } /// define a mapping from a search mode which can be typed in /// the input to a SearchMode value #[derive(Debug, Clone)] pub struct SearchModeMapEntry { - key: Option<String>, - mode: SearchMode, + pub key: Option<String>, + pub mode: SearchMode, } /// manage how to find the search mode to apply to a /// pattern taking the config in account. #[derive(Debug, Clone)] pub struct SearchModeMap { - entries: Vec<SearchModeMapEntry>, + pub entries: Vec<SearchModeMapEntry>, } impl SearchModeMapEntry { |