diff options
author | Canop <cano.petrole@gmail.com> | 2020-06-06 14:51:03 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2020-06-06 14:51:03 +0200 |
commit | 1cd64478226284d4266d441135041b2f710976b8 (patch) | |
tree | 672196300dc7d97d683f1b1b66938809206101dc | |
parent | fe80fc4f9e86f0603ecf39d3a3b7bae828905965 (diff) |
a few minor refactorings and cleanings
31 files changed, 352 insertions, 298 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index bb46023..983fe04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ ### next version +[documentation of this version](https://dystroy.org/broot-master/) #### 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 @@ -93,7 +93,7 @@ dependencies = [ [[package]] name = "broot" -version = "0.14.3-dev" +version = "0.15.0-alpha" dependencies = [ "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1,6 +1,6 @@ [package] name = "broot" -version = "0.14.3-dev" +version = "0.15.0-alpha" authors = ["dystroy <denys.seguret@gmail.com>"] repository = "https://github.com/Canop/broot" documentation = "https://dystroy.org/broot" diff --git a/clippy.sh b/clippy.sh new file mode 100755 index 0000000..7181935 --- /dev/null +++ b/clippy.sh @@ -0,0 +1,26 @@ +# run clippy, with some lints disabled: +# +# clippy_regex_macro +# the regex_macro clippy lint doesn't check *what* macro +# it finds so it produces a lot of false positives. +# +# clippy::collapsible_if +# my experience is that the collapsible_if lint is mostly +# a nuisance which pushes towards hiding intent in code. +# +# clippy::module_inception +# I don't know whether it's bad or not to have sub modules +# named the same as their parent, and I'm willing to discuss +# it if you want, but I don't need clippy to tell me every +# time. +# + +# there's a issue somewhere about clippy unable to run +# its lints twice. This part will disappear when the issue +# is solved +rm -rf target +cargo build + + +# do the clippy +cargo clippy -- -A clippy::regex_macro -A clippy::collapsible_if -A clippy::module_inception diff --git a/src/app/cmd_context.rs b/src/app/cmd_context.rs new file mode 100644 index 0000000..4411cb9 --- /dev/null +++ b/src/app/cmd_context.rs @@ -0,0 +1,21 @@ + +use { + super::*, + crate::{ + command::*, + display::Areas, + skin::PanelSkin, + }, + std::path::PathBuf, +}; + +/// short lived wrapping of a few things which are needed for the handling +/// of a command in a panel and won't be modified during the operation. +pub struct CmdContext<'c> { + pub cmd: &'c Command, + pub other_path: &'c Option<PathBuf>, + pub panel_skin: &'c PanelSkin, + pub con: &'c AppContext, + pub areas: &'c Areas, + pub panel_purpose: PanelPurpose, +} diff --git a/src/app/mod.rs b/src/app/mod.rs index 028c022..1a08687 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,4 +1,5 @@ mod app; +mod cmd_context; mod cmd_result; mod context; mod panel; @@ -10,6 +11,7 @@ mod status; pub use { app::App, cmd_result::*, + cmd_context::CmdContext, context::AppContext, panel::Panel, panel_id::PanelId, diff --git a/src/app/panel.rs b/src/app/panel.rs index 250ba6e..272589f 100644 --- a/src/app/panel.rs +++ b/src/app/panel.rs @@ -55,17 +55,16 @@ impl Panel { panel_skin: &PanelSkin, con: &AppContext, ) -> Result<AppStateCmdResult, ProgramError> { - let purpose = self.purpose; let state_idx = self.states.len()-1; - let result = self.states[state_idx].on_command( + let cc = CmdContext { cmd, other_path, - &self.areas, - screen, panel_skin, con, - purpose, - ); + areas: &self.areas, + panel_purpose: self.purpose, + }; + let result = self.states[state_idx].on_command(&cc, screen); self.status = Some(self.state().get_status(cmd, other_path, con)); debug!("result in panel {:?}: {:?}", &self.id, &result); result @@ -209,7 +208,7 @@ impl Panel { .filter_map(|v| v.keys.first()) .map(|&k| keys::key_event_desc(k)) .next() - .unwrap_or(":start_end_panel".to_string()); + .unwrap_or_else(|| ":start_end_panel".to_string()); let md = format!("hit *{}* to fill arg ", shortcut); // Add verbindex in purpose ? diff --git a/src/app/state.rs b/src/app/state.rs index 9943733..312d4dd 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -2,7 +2,7 @@ use { super::*, crate::{ command::{Command, TriggerType}, - display::{Areas, Screen, W}, + display::{Screen, W}, errors::ProgramError, flag::Flag, pattern::Pattern, @@ -59,26 +59,19 @@ pub trait AppState { internal_exec: &InternalExecution, input_invocation: Option<&VerbInvocation>, trigger_type: TriggerType, - areas: &Areas, + cc: &CmdContext, screen: &mut Screen, - panel_skin: &PanelSkin, - con: &AppContext, - panel_purpose: PanelPurpose, ) -> Result<AppStateCmdResult, ProgramError>; /// change the state, does no rendering fn on_command( &mut self, - cmd: &Command, - other_path: &Option<PathBuf>, - areas: &Areas, + cc: &CmdContext, screen: &mut Screen, - panel_skin: &PanelSkin, - con: &AppContext, - panel_purpose: PanelPurpose, ) -> Result<AppStateCmdResult, ProgramError> { self.clear_pending(); - match cmd { + let con = &cc.con; + match cc.cmd { Command::Click(x, y) => self.on_click(*x, *y, screen, con), Command::DoubleClick(x, y) => self.on_double_click(*x, *y, screen, con), Command::PatternEdit(parts) => { @@ -98,15 +91,12 @@ pub trait AppState { internal_exec, input_invocation.as_ref(), TriggerType::Other, - areas, + cc, screen, - panel_skin, - con, - panel_purpose, ), VerbExecution::External(external) => external.to_cmd_result( self.selected_path(), - other_path, + &cc.other_path, if let Some(inv) = &input_invocation { &inv.args } else { @@ -123,15 +113,12 @@ pub trait AppState { &InternalExecution::from_internal(*internal), input_invocation.as_ref(), TriggerType::Other, - areas, + cc, screen, - panel_skin, - con, - panel_purpose, ), Command::VerbInvocate(invocation) => match con.verb_store.search(&invocation.name) { PrefixSearchResult::Match(_, verb) => { - if let Some(err) = verb.check_args(invocation, other_path) { + if let Some(err) = verb.check_args(invocation, &cc.other_path) { Ok(AppStateCmdResult::DisplayError(err)) } else { match &verb.execution { @@ -139,16 +126,13 @@ pub trait AppState { internal_exec, Some(invocation), TriggerType::Input, - areas, + cc, screen, - panel_skin, - con, - panel_purpose, ), VerbExecution::External(external) => { external.to_cmd_result( self.selected_path(), - other_path, + &cc.other_path, &invocation.args, con, ) diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index b39600f..c49d50e 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -2,7 +2,7 @@ use { crate::{ app::*, command::{Command, TriggerType}, - display::{Areas, DisplayableTree, Screen, W}, + display::{DisplayableTree, Screen, W}, errors::{ProgramError, TreeBuildError}, flag::Flag, git, @@ -359,12 +359,10 @@ impl AppState for BrowserState { internal_exec: &InternalExecution, input_invocation: Option<&VerbInvocation>, trigger_type: TriggerType, - areas: &Areas, + cc: &CmdContext, screen: &mut Screen, - panel_skin: &PanelSkin, - con: &AppContext, - panel_purpose: PanelPurpose, ) -> Result<AppStateCmdResult, ProgramError> { + let con = &cc.con; let page_height = BrowserState::page_height(screen); let bang = input_invocation .map(|inv| inv.bang) @@ -450,7 +448,7 @@ impl AppState for BrowserState { AppStateCmdResult::Keep } Internal::panel_left => { - if areas.is_first() { + if cc.areas.is_first() { // we ask for the creation of a panel to the left internal_focus::new_panel_on_path( self.selected_path().to_path_buf(), @@ -466,7 +464,7 @@ impl AppState for BrowserState { } } Internal::panel_right => { - if areas.is_last() { + if cc.areas.is_last() { // we ask for the creation of a panel to the left internal_focus::new_panel_on_path( self.selected_path().to_path_buf(), @@ -491,7 +489,7 @@ impl AppState for BrowserState { print::print_relative_path(path, con)? } Internal::print_tree => { - print::print_tree(&self.displayed_tree(), screen, panel_skin, con)? + print::print_tree(&self.displayed_tree(), screen, &cc.panel_skin, con)? } Internal::refresh => AppStateCmdResult::RefreshState { clear_cache: true }, Internal::select_first => { @@ -503,7 +501,7 @@ impl AppState for BrowserState { AppStateCmdResult::Keep } Internal::start_end_panel => { - if panel_purpose.is_arg_edition() { + if cc.panel_purpose.is_arg_edition() { debug!("start_end understood as end"); AppStateCmdResult::ClosePanel { validate_purpose: true, @@ -514,8 +512,7 @@ impl AppState for BrowserState { if let Some(input_invocation) = input_invocation { // we'll go for input arg editing let path = if let Some(input_arg) = &input_invocation.args { - let path = path::path_from(self.root(), input_arg); - PathBuf::from(path) + path::path_from(self.root(), input_arg) } else { self.root().to_path_buf() }; @@ -686,7 +683,7 @@ impl AppState for BrowserState { } else { self.filtered_tree.as_ref() .map(|t| t.options.pattern.as_input(&con.search_modes)) - .unwrap_or_else(|| String::new()) + .unwrap_or_else(String::new) } } } @@ -22,6 +22,7 @@ use { env, io::{self, Write}, path::{Path, PathBuf}, + str::FromStr, }, }; @@ -81,9 +82,9 @@ fn get_root_path(cli_args: &ArgMatches<'_>) -> Result<PathBuf, ProgramError> { .value_of("root") .map_or(env::current_dir()?, PathBuf::from); if !root.exists() { - Err(TreeBuildError::FileNotFound { + return Err(TreeBuildError::FileNotFound { path: format!("{:?}", &root), - })?; + }.into()); } if !root.is_dir() { // we try to open the parent directory if the passed file isn't one @@ -92,9 +93,9 @@ fn get_root_path(cli_args: &ArgMatches<'_>) -> Result<PathBuf, ProgramError> { root = parent.to_path_buf(); } else { // let's give up - Err(TreeBuildError::NotADirectory { + return Err(TreeBuildError::NotADirectory { path: format!("{:?}", &root), - })?; + }.into()); } } Ok(canonicalize_root(&root)?) @@ -169,7 +170,7 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> { } // verb store is completed from the config file(s) - let mut verb_store = VerbStore::new(); + let mut verb_store = VerbStore::default(); verb_store.init(&config); // reading the other arguments @@ -214,7 +215,7 @@ pub fn ask_authorization() -> Result<bool, ProgramError> { let mut answer = String::new(); io::stdin().read_line(&mut answer)?; let answer = answer.trim(); - Ok(match answer.as_ref() { + Ok(match answer { "n" | "N" => false, _ => true, }) diff --git a/src/conf.rs b/src/conf/conf.rs index 55db7af..67f21fe 100644 --- a/src/conf.rs +++ b/src/conf/conf.rs @@ -2,6 +2,9 @@ //! initializing if if it doesn't yet exist use { + super::{ + default_conf::DEFAULT_CONF_FILE, + }, crate::{ errors::ConfError, keys, @@ -12,7 +15,6 @@ use { verb::VerbConf, }, crossterm::style::Attribute, - directories::ProjectDirs, std::{ collections::HashMap, fs, io, @@ -53,21 +55,11 @@ fn bool_field(value: &Value, field_name: &str) -> Option<bool> { None } -/// return the instance of ProjectDirs holding broot's specific paths -pub fn app_dirs() -> ProjectDirs { - ProjectDirs::from("org", "dystroy", "broot").expect("Unable to find configuration directories") -} - -/// return the path to the config directory, based on XDG -pub fn dir() -> PathBuf { - app_dirs().config_dir().to_path_buf() -} - impl Conf { pub fn default_location() -> &'static Path { lazy_static! { - static ref CONF_PATH: PathBuf = dir().join("conf.toml"); + static ref CONF_PATH: PathBuf = super::dir().join("conf.toml"); } &*CONF_PATH } @@ -228,192 +220,3 @@ impl Conf { } } -const DEFAULT_CONF_FILE: &str = r#" -############################################################### -# This configuration file lets you -# - define new commands -# - change the shortcut or triggering keys of built-in verbs -# - change the colors -# - set default values for flags -# -# Configuration documentation is available at -# https://dystroy.org/broot -############################################################### - -############################################################### -# Default flags -# You can set up flags you want broot to start with by -# default, for example `default_flags="ihp"` if you usually want -# to see hidden and gitignored files and the permissions (then -# if you don't want the hidden files you can launch `br -H`) -# A popular flag is the `g` one which displays git related info. -# -default_flags = "" - -############################################################### -# Date/Time format -# If you want to change the format for date/time, uncomment the -# following line and change it according to -# https://docs.rs/chrono/0.4.11/chrono/format/strftime/index.html -# -# date_time_format = "%Y/%m/%d %R " - -############################################################### -# Special paths -# If some paths must be handled specially, uncomment (and change -# this section as per the examples -# -# [special-paths] -# "/media/slow-backup-disk" = "no-enter" -# "/home/dys/useless" = "hide" -# "/home/dys/my-link-I-want-to-explore" = "enter" - -############################################################### -# Verbs and shortcuts -# You can define your own commands which would be applied to -# the selection. -# -# Exemple 1: launching `tail -n` on the selected file (leaving broot) -# [[verbs]] -# name = "tail_lines" -# invocation = "tl {lines_count}" -# execution = "tail -f -n {lines_count} {file}" -# -# Exemple 2: creating a new file without leaving broot -# [[verbs]] -# name = "touch" -# invocation = "touch {new_file}" -# execution = "touch {directory}/{new_file}" -# leave_broot = false - -# If $EDITOR isn't set on your computer, you should either set it using -# something similar to -# export EDITOR=/usr/bin/nvim -# or just replace it with your editor of choice in the 'execution' -# pattern. -# Example: -# execution = "/usr/bin/nvim {file}" -[[verbs]] -invocation = "edit" -key = "F2" -shortcut = "e" -execution = "$EDITOR {file}" - -[[verbs]] -invocation = "create {subpath}" -execution = "$EDITOR {directory}/{subpath}" - -[[verbs]] -invocation = "git_diff" -shortcut = "gd" -leave_broot = false -execution = "git diff {file}" - -# If $PAGER isn't set on your computer, you should either set it -# or just replace it with your viewer of choice in the 'execution' -# pattern. -# Example: -# execution = "less {file}" -[[verbs]] -name = "view" -invocation = "view" -execution = "$PAGER {file}" - -# A popular set of shorctuts for going up and down: -# -# [[verbs]] -# key = "ctrl-j" -# execution = ":line_down" -# -# [[verbs]] -# key = "ctrl-k" -# execution = ":line_up" -# -# [[verbs]] -# key = "ctrl-d" -# execution = ":page_down" -# -# [[verbs]] -# key = "ctrl-u" -# execution = ":page_up" - -# If you develop using git, you might like to often switch -# to the "git status" filter: -# [[verbs]] -# key = "ctrl-g" -# execution = ":toggle_git_status" - -# You can reproduce the bindings of Norton Commander -# on copying or moving to the other panel: -# -# [[verbs]] -# key = "F5" -# execution = ":copy_to_panel" -# -# [[verbs]] -# key = "F6" -# execution = ":move_to_panel" - - -############################################################### -# Skin -# If you want to change the colors of broot, -# uncomment the following bloc and start messing -# with the various values. -# -# [skin] -# default = "gray(23) none / gray(20) none" -# tree = "ansi(94) None / gray(3) None" -# file = "gray(18) None / gray(15) None" -# directory = "ansi(208) None Bold / ansi(172) None bold" -# exe = "Cyan None" -# link = "Magenta None" -# pruning = "gray(12) None Italic" -# perm__ = "gray(5) None" -# perm_r = "ansi(94) None" -# perm_w = "ansi(132) None" -# perm_x = "ansi(65) None" -# owner = "ansi(138) None" -# group = "ansi(131) None" -# dates = "ansi(66) None" -# sparse = "ansi(214) None" -# git_branch = "ansi(229) None" -# git_insertions = "ansi(28) None" -# git_deletions = "ansi(160) None" -# git_status_current = "gray(5) None" -# git_status_modified = "ansi(28) None" -# git_status_new = "ansi(94) None Bold" -# git_status_ignored = "gray(17) None" -# git_status_conflicted = "ansi(88) None" -# git_status_other = "ansi(88) None" -# selected_line = "None gray(5) / None gray(4)" -# char_match = "Yellow None" -# file_error = "Red None" -# flag_label = "gray(15) None" -# flag_value = "ansi(208) None Bold" -# input = "White None / gray(15) gray(2)" -# status_error = "gray(22) ansi(124)" -# status_job = "ansi(220) gray(5)" -# status_normal = "gray(20) gray(3) / gray(2) gray(2)" -# status_italic = "ansi(208) gray(3) / gray(2) gray(2)" -# status_bold = "ansi(208) gray(3) Bold / gray(2) gray(2)" -# status_code = "ansi(229) gray(3) / gray(2) gray(2)" -# status_ellipsis = "gray(19) gray(1) / gray(2) gray(2)" -# purpose_normal = "gray(20) gray(2)" -# purpose_italic = "ansi(178) gray(2)" -# purpose_bold = "ansi(178) gray(2) Bold" -# purpose_ellipsis = "gray(20) gray(2)" -# scrollbar_track = "gray(7) None / gray(4) None" -# scrollbar_thumb = "gray(22) None / gray(14) None" -# help_paragraph = "gray(20) None" -# help_bold = "ansi(208) None Bold" -# help_italic = "ansi(166) None" -# help_code = "gray(21) gray(3)" -# help_headers = "ansi(208) None" -# help_table_border = "ansi(239) None" - -# You may find explanations and other skins on -# https://dystroy.org/broot/skins -# for example a skin suitable for white backgrounds - -"#; diff --git a/src/conf/default_conf.rs b/src/conf/default_conf.rs new file mode 100644 index 0000000..b36e878 --- /dev/null +++ b/src/conf/default_conf.rs @@ -0,0 +1,195 @@ + +/// the content a the conf.toml file broot creates +/// when there's none. It features some default +/// configuration and many completable +/// or uncommentable sections to help the user +/// define her own configuration. +pub const DEFAULT_CONF_FILE: &str = r#" +############################################################### +# This configuration file lets you +# - define new commands +# - change the shortcut or triggering keys of built-in verbs +# - change the colors +# - set default values for flags +# +# Configuration documentation is available at +# https://dystroy.org/broot +############################################################### + +############################################################### +# Default flags +# You can set up flags you want broot to start with by +# default, for example `default_flags="ihp"` if you usually want +# to see hidden and gitignored files and the permissions (then +# if you don't want the hidden files you can launch `br -H`) +# A popular flag is the `g` one which displays git related info. +# +default_flags = "" + +############################################################### +# Date/Time format +# If you want to change the format for date/time, uncomment the +# following line and change it according to +# https://docs.rs/chrono/0.4.11/chrono/format/strftime/index.html +# +# date_time_format = "%Y/%m/%d %R " + +############################################################### +# Special paths +# If some paths must be handled specially, uncomment (and change +# this section as per the examples +# +# [special-paths] +# "/media/slow-backup-disk" = "no-enter" +# "/home/dys/useless" = "hide" +# "/home/dys/my-link-I-want-to-explore" = "enter" + +############################################################### +# Verbs and shortcuts +# You can define your own commands which would be applied to +# the selection. +# +# Exemple 1: launching `tail -n` on the selected file (leaving broot) +# [[verbs]] +# name = "tail_lines" +# invocation = "tl {lines_count}" +# execution = "tail -f -n {lines_count} {file}" +# +# Exemple 2: creating a new file without leaving broot +# [[verbs]] +# name = "touch" +# invocation = "touch {new_file}" +# execution = "touch {directory}/{new_file}" +# leave_broot = false + +# If $EDITOR isn't set on your computer, you should either set it using +# something similar to +# export EDITOR=/usr/bin/nvim +# or just replace it with your editor of choice in the 'execution' +# pattern. +# Example: +# execution = "/usr/bin/nvim {file}" +[[verbs]] +invocation = "edit" +key = "F2" +shortcut = "e" +execution = "$EDITOR {file}" + +[[verbs]] +invocation = "create {subpath}" +execution = "$EDITOR {directory}/{subpath}" + +[[verbs]] +invocation = "git_diff" +shortcut = "gd" +leave_broot = false +execution = "git diff {file}" + +# If $PAGER isn't set on your computer, you should either set it +# or just replace it with your viewer of choice in the 'execution' +# pattern. +# Example: +# execution = "less {file}" +[[verbs]] +name = "view" +invocation = "view" +execution = "$PAGER {file}" + +# A popular set of shorctuts for going up and down: +# +# [[verbs]] +# key = "ctrl-j" +# execution = ":line_down" +# +# [[verbs]] +# key = "ctrl-k" +# execution = ":line_up" +# +# [[verbs]] +# key = "ctrl-d" +# execution = ":page_down" +# +# [[verbs]] +# key = "ctrl-u" +# execution = ":page_up" + +# If you develop using git, you might like to often switch +# to the "git status" filter: +# [[verbs]] +# key = "ctrl-g" +# execution = ":toggle_git_status" + +# You can reproduce the bindings of Norton Commander +# on copying or moving to the other panel: +# +# [[verbs]] +# key = "F5" +# execution = ":copy_to_panel" +# +# [[verbs]] +# key = "F6" +# execution = ":move_to_panel" + + +############################################################### +# Skin +# If you want to change the colors of broot, +# uncomment the following bloc and start messing +# with the various values. +# +# [skin] +# default = "gray(23) none / gray(20) none" +# tree = "ansi(94) None / gray(3) None" +# file = "gray(18) None / gray(15) None" +# directory = "ansi(208) None Bold / ansi(172) None bold" +# exe = "Cyan None" +# link = "Magenta None" +# pruning = "gray(12) None Italic" +# perm__ = "gray(5) None" +# perm_r = "ansi(94) None" +# perm_w = "ansi(132) None" +# perm_x = "ansi(65) None" +# owner = "ansi(138) None" +# group = "ansi(131) None" +# dates = "ansi(66) None" +# sparse = "ansi(214) None" +# git_branch = "ansi(229) None" +# git_insertions = "ansi(28) None" +# git_deletions = "ansi(160) None" +# git_status_current = "gray(5) None" +# git_status_modified = "ansi(28) None" +# git_status_new = "ansi(94) None Bold" +# git_status_ignored = "gray(17) None" +# git_status_conflicted = "ansi(88) None" +# git_status_other = "ansi(88) None" +# selected_line = "None gray(5) / None gray(4)" +# char_match = "Yellow None" +# file_error = "Red None" +# flag_label = "gray(15) None" +# flag_value = "ansi(208) None Bold" +# input = "White None / gray(15) gray(2)" +# status_error = "gray(22) ansi(124)" +# status_job = "ansi(220) gray(5)" +# status_normal = "gray(20) gray(3) / gray(2) gray(2)" +# status_italic = "ansi(208) gray(3) / gray(2) gray(2)" +# status_bold = "ansi(208) gray(3) Bold / gray(2) gray(2)" +# status_code = "ansi(229) gray(3) / gray(2) gray(2)" +# status_ellipsis = "gray(19) gray(1) / gray(2) gray(2)" +# purpose_normal = "gray(20) gray(2)" +# purpose_italic = "ansi(178) gray(2)" +# purpose_bold = |