summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-01-07 20:31:08 +0100
committerCanop <cano.petrole@gmail.com>2019-01-07 20:31:08 +0100
commitdbfe0bc826a52af41c5957a7af5b596017f6ae45 (patch)
tree3dc66f5a3655003ef37bd8fc4dec799bbed4f46d
parent7c6a719ae2b37becad912c977abc4aaaa5f682f4 (diff)
filtering pattern kept after verb executionv0.4.2
(when the verb doesn't quit broot)
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/app.rs2
-rw-r--r--src/browser_states.rs9
-rw-r--r--src/commands.rs88
-rw-r--r--src/conf.rs12
-rw-r--r--src/flat_tree.rs8
-rw-r--r--src/main.rs2
-rw-r--r--src/tree_options.rs2
-rw-r--r--src/tree_views.rs66
-rw-r--r--src/verbs.rs14
11 files changed, 139 insertions, 68 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f439b6f..58690cd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -31,7 +31,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "broot"
-version = "0.4.1"
+version = "0.4.2"
dependencies = [
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"custom_error 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 8724cbd..0447b4c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "broot"
-version = "0.4.1"
+version = "0.4.2"
authors = ["dystroy <denys.seguret@gmail.com>"]
repository = "https://github.com/Canop/broot"
edition = "2018"
diff --git a/src/app.rs b/src/app.rs
index d07197f..2b926ab 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -152,7 +152,7 @@ impl App {
}
AppStateCmdResult::NewState(boxed_state) => {
self.push(boxed_state);
- cmd = Command::new();
+ cmd = cmd.pop_verb();
self.state().write_status(&mut screen, &cmd, con)?;
}
AppStateCmdResult::PopState => {
diff --git a/src/browser_states.rs b/src/browser_states.rs
index 3185e64..00d81f7 100644
--- a/src/browser_states.rs
+++ b/src/browser_states.rs
@@ -27,13 +27,15 @@ pub struct BrowserState {
}
impl BrowserState {
- pub fn new(path: PathBuf, options: TreeOptions, tl: &TaskLifetime) -> Option<BrowserState> {
- let builder = TreeBuilder::from(path, options.clone());
+ pub fn new(path: PathBuf, mut options: TreeOptions, tl: &TaskLifetime) -> Option<BrowserState> {
+ let pending_pattern = options.pattern;
+ options.pattern = None;
+ let builder = TreeBuilder::from(path, options);
match builder.build(screens::max_tree_height() as usize, tl) {
Some(tree) => Some(BrowserState {
tree,
filtered_tree: None,
- pending_pattern: None,
+ pending_pattern,
}),
None => None, // interrupted
}
@@ -101,6 +103,7 @@ impl AppState for BrowserState {
let tl = TaskLifetime::unlimited();
AppStateCmdResult::from_optional_state(BrowserState::new(
tree.selected_line().path.clone(),
+ // tree.options.clone(),
tree.options.without_pattern(),
&tl,
))
diff --git a/src/commands.rs b/src/commands.rs
index 7907e2c..5ad96f1 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -4,50 +4,73 @@ use termion::event::Key;
/// A command is the parsed representation of what the user types
/// in the input. It's independant of the state of the application
/// (verbs arent checked at this point)
-#[derive(Debug)]
-pub enum Action {
- MoveSelection(i32), // up (neg) or down (positive) in the list
- ScrollPage(i32), // in number of pages, not lines
- OpenSelection, // open the selected line (which can't be the root by construct)
- VerbEdit(String), // verb, unfinished
- Verb(String), // verb
- PatternEdit(String), // a pattern being edited
- Back, // back to last app state, or clear pattern
- Next,
- Help(String),
- Unparsed, // or unparsable
+
+struct CommandParts {
+ pattern: Option<String>,
+ verb: Option<String>,
}
-impl Action {
- pub fn from(raw: &str, finished: bool) -> Action {
+impl CommandParts {
+ fn from(raw: &str) -> CommandParts {
+ let mut cp = CommandParts {
+ pattern: None,
+ verb: None,
+ };
lazy_static! {
static ref RE: Regex = Regex::new(
r"(?x)
^
(?P<pattern>[^\s/:]*)
- (?:[\s:]+(?P<verb>\w*))?
+ (?:[\s:]+(?P<verb>\S*))?
$
"
)
.unwrap();
}
if let Some(c) = RE.captures(raw) {
- if let Some(verb) = c.name("verb") {
- return match finished {
- false => Action::VerbEdit(String::from(verb.as_str())),
- true => Action::Verb(String::from(verb.as_str())),
- };
- }
if let Some(pattern) = c.name("pattern") {
- let pattern = pattern.as_str();
- return match finished {
- false => Action::PatternEdit(String::from(pattern)),
- true => Action::OpenSelection,
- };
+ cp.pattern = Some(String::from(pattern.as_str()));
+ }
+ if let Some(verb) = c.name("verb") {
+ cp.verb = Some(String::from(verb.as_str()));
}
} else {
warn!("unexpected lack of capture");
}
+ cp
+ }
+}
+
+#[derive(Debug)]
+pub enum Action {
+ MoveSelection(i32), // up (neg) or down (positive) in the list
+ ScrollPage(i32), // in number of pages, not lines
+ OpenSelection, // open the selected line (which can't be the root by construct)
+ VerbEdit(String), // verb, unfinished
+ Verb(String), // verb
+ PatternEdit(String), // a pattern being edited
+ Back, // back to last app state, or clear pattern
+ Next,
+ Help(String),
+ Unparsed, // or unparsable
+}
+
+impl Action {
+ pub fn from(raw: &str, finished: bool) -> Action {
+ let cp = CommandParts::from(raw);
+ if let Some(verb) = cp.verb {
+ return match finished {
+ false => Action::VerbEdit(String::from(verb.as_str())),
+ true => Action::Verb(String::from(verb.as_str())),
+ };
+ }
+ if let Some(pattern) = cp.pattern {
+ let pattern = pattern.as_str();
+ return match finished {
+ false => Action::PatternEdit(String::from(pattern)),
+ true => Action::OpenSelection,
+ };
+ }
Action::Unparsed
}
}
@@ -65,6 +88,19 @@ impl Command {
action: Action::Unparsed,
}
}
+ // build a new command, after execution of a verb
+ // (in the future the new action might be built by the state
+ // which would be cleaner)
+ pub fn pop_verb(&self) -> Command {
+ let mut c = Command::new();
+ let cp = CommandParts::from(&self.raw);
+ if cp.verb.is_some() {
+ if let Some(pat) = cp.pattern {
+ c.raw = pat;
+ }
+ }
+ c
+ }
pub fn add_key(&mut self, key: Key) {
match key {
Key::Char('\t') => {
diff --git a/src/conf.rs b/src/conf.rs
index fac9e61..3b9970c 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -4,6 +4,8 @@ use std::path::{Path, PathBuf};
use std::result::Result;
use toml::{self, Value};
+/// manage reading the verb shortcuts from the configuration file,
+/// initializing if if it doesn't yet exist
use custom_error::custom_error;
use directories::ProjectDirs;
@@ -96,7 +98,7 @@ const DEFAULT_CONF_FILE: &str = r#"
# ":back" : reverts to the previous state, or quit the application if it's the first one (mapped to <esc>)
# ":cd" : changes directory (see https://github.com/Canop/broot)
# ":print_path" : outputs the path to stdout or to a file provided with --out
-# ":focus" : displays the tree of that directory (mapped to <enter> on directories)
+# ":focus" : displays the tree of that directory, keeps the current search pattern
# ":open" : tries to open the file according to OS settings (e.g. using xdg-open) (mapped to <enter> on files)
# ":parent" : moves to the parent directory
# ":quit" : quits the application
@@ -113,7 +115,7 @@ execution = ":cd"
[[verbs]]
name = "focus"
-invocation = "f"
+invocation = "g"
execution = ":focus"
[[verbs]]
@@ -142,12 +144,6 @@ invocation = "o"
execution = ":open"
[[verbs]]
-# this is an example of a very specific verb
-name = "geany"
-invocation = "g"
-execution = "/usr/bin/geany {file}"
-
-[[verbs]]
name = "toggle sizes"
invocation = "s"
execution = ":toggle_sizes"
diff --git a/src/flat_tree.rs b/src/flat_tree.rs
index 90b83c4..5914410 100644
--- a/src/flat_tree.rs
+++ b/src/flat_tree.rs
@@ -27,9 +27,9 @@ pub struct TreeLine {
pub unlisted: usize, // number of not listed childs (Dir) or brothers (Pruning)
pub score: i32, // 0 if there's no pattern
pub size: Option<Size>, // None when not measured
- pub mode: u32, // unix file mode
- pub uid: u32, // unix user id
- pub gid: u32, // unix group id
+ pub mode: u32, // unix file mode
+ pub uid: u32, // unix user id
+ pub gid: u32, // unix group id
}
#[derive(Debug)]
@@ -194,7 +194,7 @@ impl Tree {
if dy < 0 && sel < self.scroll + 5 {
self.scroll = (self.scroll + 2 * dy).max(0);
} else if dy > 0 && l > page_height && sel > self.scroll + page_height - 5 {
- self.scroll = self.scroll + 2 * dy;
+ self.scroll += 2 * dy;
}
}
pub fn try_scroll(&mut self, dy: i32, page_height: i32) {
diff --git a/src/main.rs b/src/main.rs
index e74cb42..7b046c8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -47,7 +47,7 @@ use crate::verbs::VerbStore;
fn get_cli_args<'a>() -> clap::ArgMatches<'a> {
clap::App::new("broot")
- .version("0.4.1")
+ .version("0.4.2")
.author("dystroy <denys.seguret@gmail.com>")
.about("Balanced tree view + fuzzy search + BFS + customizable launcher")
.arg(clap::Arg::with_name("root").help("sets the root directory"))
diff --git a/src/tree_options.rs b/src/tree_options.rs
index de71ba2..02736d8 100644
--- a/src/tree_options.rs
+++ b/src/tree_options.rs
@@ -12,7 +12,7 @@ pub enum OptionBool {
impl FromStr for OptionBool {
type Err = ProgramError;
fn from_str(s: &str) -> Result<OptionBool, ProgramError> {
- match s.as_ref() {
+ match s {
"auto" => Ok(OptionBool::Auto),
"yes" => Ok(OptionBool::Yes),
"no" => Ok(OptionBool::No),
diff --git a/src/tree_views.rs b/src/tree_views.rs
index d95a3f8..0b59e48 100644
--- a/src/tree_views.rs
+++ b/src/tree_views.rs
@@ -1,8 +1,8 @@
use std::borrow::Cow;
use std::io::{self, Write};
-use termion::{color, style};
-use users::{Users, Groups, UsersCache};
use std::sync::Mutex;
+use termion::{color, style};
+use users::{Groups, Users, UsersCache};
use crate::flat_tree::{LineType, Tree, TreeLine};
use crate::patterns::Pattern;
@@ -34,7 +34,8 @@ impl TreeView for Screen {
max_user_name_len = max_user_name_len.max(user.name().to_string_lossy().len());
}
if let Some(group) = users_cache.get_group_by_gid(line.uid) {
- max_group_name_len = max_group_name_len.max(group.name().to_string_lossy().len());
+ max_group_name_len =
+ max_group_name_len.max(group.name().to_string_lossy().len());
}
}
}
@@ -111,22 +112,58 @@ impl TreeView for Screen {
self.stdout,
"{} {}{}{}{}{}{}{}{}{}",
color::Fg(color::AnsiValue::grayscale(15)),
- if (line.mode & (1<<8))!=0 { 'r' } else { '-' },
- if (line.mode & (1<<7))!=0 { 'w' } else { '-' },
- if (line.mode & (1<<6))!=0 { 'x' } else { '-' },
- if (line.mode & (1<<5))!=0 { 'r' } else { '-' },
- if (line.mode & (1<<4))!=0 { 'w' } else { '-' },
- if (line.mode & (1<<3))!=0 { 'x' } else { '-' },
- if (line.mode & (1<<2))!=0 { 'r' } else { '-' },
- if (line.mode & (1<<1))!=0 { 'w' } else { '-' },
- if (line.mode & (1<<0))!=0 { 'x' } else { '-' },
+ if (line.mode & (1 << 8)) != 0 {
+ 'r'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 7)) != 0 {
+ 'w'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 6)) != 0 {
+ 'x'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 5)) != 0 {
+ 'r'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 4)) != 0 {
+ 'w'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 3)) != 0 {
+ 'x'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 2)) != 0 {
+ 'r'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 1)) != 0 {
+ 'w'
+ } else {
+ '-'
+ },
+ if (line.mode & (1 << 0)) != 0 {
+ 'x'
+ } else {
+ '-'
+ },
)?;
if let Some(user) = users_cache.get_user_by_uid(line.uid) {
write!(
self.stdout,
" {:w$}",
user.name().to_string_lossy(),
- w=max_user_name_len,
+ w = max_user_name_len,
)?;
}
if let Some(group) = users_cache.get_group_by_gid(line.uid) {
@@ -134,7 +171,7 @@ impl TreeView for Screen {
self.stdout,
" {:w$} ",
group.name().to_string_lossy(),
- w=max_group_name_len,
+ w = max_group_name_len,
)?;
}
} else {
@@ -144,7 +181,6 @@ impl TreeView for Screen {
color::Fg(color::AnsiValue::grayscale(5)),
color::Fg(color::Reset),
)?;
-
}
}
let selected = line_index == tree.selection;
diff --git a/src/verbs.rs b/src/verbs.rs
index abe0605..56d8858 100644
--- a/src/verbs.rs
+++ b/src/verbs.rs
@@ -48,8 +48,8 @@ impl VerbExecutor for BrowserState {
Ok(match verb.exec_pattern.as_ref() {
":back" => AppStateCmdResult::PopState,
":focus" => {
- let path = self.tree.selected_line().path.clone();
- let options = self.tree.options.clone();
+ let path = tree.selected_line().path.clone();
+ let options = tree.options.clone();
AppStateCmdResult::from_optional_state(BrowserState::new(
path,
options,
@@ -57,7 +57,7 @@ impl VerbExecutor for BrowserState {
))
}
":toggle_hidden" => {
- let mut options = self.tree.options.clone();
+ let mut options = tree.options.clone();
options.show_hidden = !options.show_hidden;
AppStateCmdResult::from_optional_state(BrowserState::new(
self.tree.root().clone(),
@@ -66,7 +66,7 @@ impl VerbExecutor for BrowserState {
))
}
":toggle_git_ignore" => {
- let mut options = self.tree.options.clone();
+ let mut options = tree.options.clone();
options.respect_git_ignore = match options.respect_git_ignore {
OptionBool::Auto => {
if tree.nb_gitignored > 0 {
@@ -86,7 +86,7 @@ impl VerbExecutor for BrowserState {
))
}
":toggle_files" => {
- let mut options = self.tree.options.clone();
+ let mut options = tree.options.clone();
options.only_folders = !options.only_folders;
AppStateCmdResult::from_optional_state(BrowserState::new(
self.tree.root().clone(),
@@ -95,7 +95,7 @@ impl VerbExecutor for BrowserState {
))
}
":toggle_perm" => {
- let mut options = self.tree.options.clone();
+ let mut options = tree.options.clone();
options.show_permissions = !options.show_permissions;
AppStateCmdResult::from_optional_state(BrowserState::new(
self.tree.root().clone(),
@@ -104,7 +104,7 @@ impl VerbExecutor for BrowserState {
))
}
":toggle_sizes" => {
- let mut options = self.tree.options.clone();
+ let mut options = tree.options.clone();
options.show_sizes = !options.show_sizes;
AppStateCmdResult::from_optional_state(BrowserState::new(
self.tree.root().clone(),