Skip to content

Commit

Permalink
Tab goes to next direct match when there's no verb in input
Browse files Browse the repository at this point in the history
Also introduce the :previous_match and :next_match internals.

Fix #234
  • Loading branch information
Canop committed Jun 5, 2020
1 parent 9cec8ab commit f1972b3
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 42 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/browser/browser_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
69 changes: 36 additions & 33 deletions src/command/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions src/pattern/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use {
SearchMode,
},
crate::{
app::AppContext,
command::PatternParts,
errors::PatternError,
},
std::{
Expand Down
6 changes: 2 additions & 4 deletions src/pattern/search_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/tree/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/tree_build/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions src/verb/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
2 changes: 2 additions & 0 deletions src/verb/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit f1972b3

Please sign in to comment.