summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md5
-rw-r--r--src/browser/browser_state.rs8
-rw-r--r--src/command/event.rs69
-rw-r--r--src/keys.rs2
-rw-r--r--src/pattern/pattern.rs2
-rw-r--r--src/pattern/search_mode.rs6
-rw-r--r--src/tree/tree.rs1
-rw-r--r--src/tree_build/builder.rs4
-rw-r--r--src/verb/builtin.rs2
-rw-r--r--src/verb/internal.rs2
10 files changed, 59 insertions, 42 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 29fbd9c..d3299f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
### next version
+#### Major feature: new input syntax - Breaking Change
+- new search modes: fuzzy or regex on sub-paths (the path starting from the displayed root)
+- it's possible to configure how search modes are selected in config
+#### Minor changes:
+- tab goes to next direct match when there's no verb in input - Fix #234
<a name="v0.14.2"></a>
### v0.14.2 - 2020-06-01
diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs
index c06ab01..5bbb7c8 100644
--- a/src/browser/browser_state.rs
+++ b/src/browser/browser_state.rs
@@ -427,6 +427,14 @@ impl AppState for BrowserState {
self.displayed_tree_mut().move_selection(-1, page_height);
AppStateCmdResult::Keep
}
+ Internal::previous_match => {
+ self.displayed_tree_mut().try_select_previous_match();
+ AppStateCmdResult::Keep
+ }
+ Internal::next_match => {
+ self.displayed_tree_mut().try_select_next_match();
+ AppStateCmdResult::Keep
+ }
Internal::page_down => {
let tree = self.displayed_tree_mut();
if page_height < tree.lines.len() as i32 {
diff --git a/src/command/event.rs b/src/command/event.rs
index 819760a..7cb9462 100644
--- a/src/command/event.rs
+++ b/src/command/event.rs
@@ -117,41 +117,44 @@ impl PanelInput {
// tab completion
if key == keys::TAB {
- let parts_before_cycle;
- let completable_parts = if let Some(s) = &self.input_before_cycle {
- parts_before_cycle = CommandParts::from(s);
- &parts_before_cycle
- } else {
- &parts
- };
- let completions = Completions::for_input(completable_parts, con, state);
- let added = match completions {
- Completions::None => {
- debug!("nothing to complete!"); // where to tell this ? input field or status ?
- self.tab_cycle_count = 0;
- self.input_before_cycle = None;
- None
- }
- Completions::Common(completion) => {
- self.tab_cycle_count = 0;
- //self.input_before_cycle = Some(raw.to_string());
- Some(completion)
- }
- Completions::List(mut completions) => {
- let idx = self.tab_cycle_count % completions.len();
- if self.tab_cycle_count == 0 {
- self.input_before_cycle = Some(raw.to_string());
+ if parts.verb_invocation.is_some() {
+ let parts_before_cycle;
+ let completable_parts = if let Some(s) = &self.input_before_cycle {
+ parts_before_cycle = CommandParts::from(s);
+ &parts_before_cycle
+ } else {
+ &parts
+ };
+ let completions = Completions::for_input(completable_parts, con, state);
+ let added = match completions {
+ Completions::None => {
+ debug!("nothing to complete!"); // where to tell this ? input field or status ?
+ self.tab_cycle_count = 0;
+ self.input_before_cycle = None;
+ None
+ }
+ Completions::Common(completion) => {
+ self.tab_cycle_count = 0;
+ Some(completion)
}
- self.tab_cycle_count += 1;
- Some(completions.swap_remove(idx))
+ Completions::List(mut completions) => {
+ let idx = self.tab_cycle_count % completions.len();
+ if self.tab_cycle_count == 0 {
+ self.input_before_cycle = Some(raw.to_string());
+ }
+ self.tab_cycle_count += 1;
+ Some(completions.swap_remove(idx))
+ }
+ };
+ if let Some(added) = added {
+ let mut raw = self.input_before_cycle.as_ref().map_or(raw, |s| s.to_string());
+ raw.push_str(&added);
+ self.input_field.set_content(&raw);
+ let parts = CommandParts::from(&raw);
+ return Command::from_parts(&parts, false);
+ } else {
+ return Command::None;
}
- };
- if let Some(added) = added {
- let mut raw = self.input_before_cycle.as_ref().map_or(raw, |s| s.to_string());
- raw.push_str(&added);
- self.input_field.set_content(&raw);
- let parts = CommandParts::from(&raw);
- return Command::from_parts(&parts, false);
}
} else {
self.tab_cycle_count = 0;
diff --git a/src/keys.rs b/src/keys.rs
index 02b503e..59b649d 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -89,7 +89,7 @@ pub fn is_reserved(key: KeyEvent) -> bool {
//RIGHT => true, // needed for the input field
DELETE => true, // needed for the input field
ESC => true, // basic navigation
- TAB => true, // open tab/panel
+ //TAB => true, // completion
//UP => true, // basic navigation
//DOWN => true, // basic navigation
_ => false,
diff --git a/src/pattern/pattern.rs b/src/pattern/pattern.rs
index 4f9f0fe..8744182 100644
--- a/src/pattern/pattern.rs
+++ b/src/pattern/pattern.rs
@@ -6,8 +6,6 @@ use {
SearchMode,
},
crate::{
- app::AppContext,
- command::PatternParts,
errors::PatternError,
},
std::{
diff --git a/src/pattern/search_mode.rs b/src/pattern/search_mode.rs
index 59f1a29..ac0d88c 100644
--- a/src/pattern/search_mode.rs
+++ b/src/pattern/search_mode.rs
@@ -63,8 +63,9 @@ impl SearchModeMapEntry {
(false, true, false, true) => SearchMode::PathRegex,
};
let key = if conf_key.is_empty() || conf_key == "<empty>" {
- // serde toml parser don't handle correctly empty keys so we accept as
+ // serde toml parser doesn't handle correctly empty keys so we accept as
// alternative the `"<empty>" = "fuzzy name"` solution.
+ // TODO look at issues and/or code in serde-toml
None
} else if regex!(r"^\w*/$").is_match(conf_key) {
Some(conf_key[0..conf_key.len()-1].to_string())
@@ -106,14 +107,11 @@ impl SearchModeMap {
self.entries.push(entry);
}
pub fn search_mode(&self, key: &Option<String>) -> Result<SearchMode, PatternError> {
- debug!("searching mode with key {:?}", key);
for entry in self.entries.iter().rev() {
if entry.key == *key {
- debug!("found mode {:?}", entry.mode);
return Ok(entry.mode);
}
}
- debug!("map: {:?}", &self);
Err(PatternError::InvalidMode {
mode: if let Some(key) = key {
format!("{}/", key)
diff --git a/src/tree/tree.rs b/src/tree/tree.rs
index 33c9dd7..6887f7a 100644
--- a/src/tree/tree.rs
+++ b/src/tree/tree.rs
@@ -146,6 +146,7 @@ impl Tree {
loop {
self.selection = (self.selection + ((l as i32) + dy) as usize) % l;
if self.lines[self.selection].is_selectable() {
+ debug!("selected line score: {:?}", self.lines[self.selection].score);
break;
}
}
diff --git a/src/tree_build/builder.rs b/src/tree_build/builder.rs
index 7aa961d..19493ee 100644
--- a/src/tree_build/builder.rs
+++ b/src/tree_build/builder.rs
@@ -134,7 +134,8 @@ impl<'c> TreeBuilder<'c> {
}
}
if let Some(pattern_score) = self.options.pattern.score_of(&name) {
- score += pattern_score;
+ // we dope direct matchs to compensate for depth doping of parent folders
+ score += pattern_score + 10;
} else {
has_match = false;
}
@@ -212,7 +213,6 @@ impl<'c> TreeBuilder<'c> {
match bl {
BLineResult::Some(child_id) => {
if self.blines[child_id].has_match {
- // direct match
self.blines[bid].has_match = true;
has_child_match = true;
}
diff --git a/src/verb/builtin.rs b/src/verb/builtin.rs
index 6b1a9e1..798aa47 100644
--- a/src/verb/builtin.rs
+++ b/src/verb/builtin.rs
@@ -59,6 +59,8 @@ pub fn builtin_verbs() -> Vec<Verb> {
.with_shortcut("mvp"),
Verb::internal_bang(start_end_panel)
.with_control_key('p'),
+ Verb::internal(next_match)
+ .with_key(TAB),
Verb::internal(open_stay)
.with_key(ENTER)
.with_shortcut("os"),
diff --git a/src/verb/internal.rs b/src/verb/internal.rs
index 71941d5..74879f5 100644
--- a/src/verb/internal.rs
+++ b/src/verb/internal.rs
@@ -61,11 +61,13 @@ Internals! {
line_up: "move one line up",
open_stay: "open file or directory according to OS (stay in broot)",
open_leave: "open file or directory according to OS (quit broot)",
+ next_match: "select the next match",
page_down: "scroll one page down",
page_up: "scroll one page up",
parent: "move to the parent directory",
panel_left: "focus panel on left",
panel_right: "focus panel on right",
+ previous_match: "select the previous match",
print_path: "print path and leaves broot",
print_relative_path: "print relative path and leaves broot",
print_tree: "print tree and leaves broot",