summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-06-08 09:27:21 +0200
committerCanop <cano.petrole@gmail.com>2019-06-08 09:31:39 +0200
commit44d3be5e5aaa5c1cf66e151ebd8a2f7e3c399c16 (patch)
tree385a3eada2e721375cf810c3d875a70797f7b9f4
parenta848be3173a6cfdb9b4af7554180fda13b350dad (diff)
configurable skin supported on help screen and in :print_tree screen outputv0.8.0
also bump version to 0.8, as it's the first deployed version based on crossterm&termimad and having some kind of windows support
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.lock8
-rw-r--r--Cargo.toml4
-rw-r--r--src/app.rs13
-rw-r--r--src/browser_states.rs45
-rw-r--r--src/cli.rs44
-rw-r--r--src/command_parsing.rs34
-rw-r--r--src/commands.rs6
-rw-r--r--src/conf.rs61
-rw-r--r--src/displayable_tree.rs75
-rw-r--r--src/external.rs125
-rw-r--r--src/file_sizes/file_sizes_unix.rs112
-rw-r--r--src/file_sizes/file_sizes_windows.rs101
-rw-r--r--src/file_sizes/mod.rs2
-rw-r--r--src/flat_tree.rs20
-rw-r--r--src/help_content.rs14
-rw-r--r--src/help_states.rs37
-rw-r--r--src/input.rs10
-rw-r--r--src/main.rs4
-rw-r--r--src/patterns.rs38
-rw-r--r--src/permissions/mod.rs1
-rw-r--r--src/permissions/permissions_unix.rs35
-rw-r--r--src/screens.rs12
-rw-r--r--src/shell_bash.rs2
-rw-r--r--src/shell_fish.rs2
-rw-r--r--src/shell_install.rs68
-rw-r--r--src/skin.rs74
-rw-r--r--src/skin_conf.rs36
-rw-r--r--src/spinner.rs10
-rw-r--r--src/status.rs8
-rw-r--r--src/tree_build.rs6
-rw-r--r--src/verb_invocation.rs6
-rw-r--r--src/verb_store.rs138
-rw-r--r--src/verbs.rs122
-rw-r--r--test.txt40
-rw-r--r--website/docs/community.md6
-rw-r--r--website/docs/documentation/configuration.md89
-rw-r--r--website/docs/documentation/installation.md5
-rw-r--r--website/docs/img/20190607-custom-colors-sizes.pngbin0 -> 43007 bytes
-rw-r--r--website/docs/img/20190607-custom-colors-tree.pngbin0 -> 33307 bytes
40 files changed, 732 insertions, 685 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7a084d7..f08a605 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+<a name="v0.8.0"></a>
+### v0.8.0 - 2019-06-07
+Half broot has been rewritten to allow Windows compatibility. Termion has been replaced with crossterm.
+
<a name="v0.7.5"></a>
### v0.7.5 - 2019-04-03
- try to give arguments to verbs executed with --cmd
diff --git a/Cargo.lock b/Cargo.lock
index b32ca4d..f6324fb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -86,7 +86,7 @@ dependencies = [
[[package]]
name = "broot"
-version = "0.7.5"
+version = "0.8.0"
dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -100,7 +100,7 @@ dependencies = [
"opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "termimad 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termimad 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"users 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -617,7 +617,7 @@ dependencies = [
[[package]]
name = "termimad"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossterm 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -795,7 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
-"checksum termimad 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a8326aabc4d9ab6d6410c99fbd1a3bff0f89f2a7d315bbf765e2ea754e41eb45"
+"checksum termimad 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c335380ef344bd1d9f20866ea45ba96319ef3191a43d38210c12a565a547848"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
diff --git a/Cargo.toml b/Cargo.toml
index 0450d31..48036f5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "broot"
-version = "0.7.5"
+version = "0.8.0"
authors = ["dystroy <denys.seguret@gmail.com>"]
repository = "https://github.com/Canop/broot"
description = "Fuzzy Search + tree + cd"
@@ -23,7 +23,7 @@ glob = "0.3"
crossbeam = "0.7"
opener = "0.4"
crossterm = "0.9.5"
-termimad = "0.3.4"
+termimad = "0.3.5"
#termimad = { path = "../termimad" }
[target.'cfg(unix)'.dependencies]
diff --git a/src/app.rs b/src/app.rs
index 69cbd01..f13c699 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -7,17 +7,17 @@
//! - an operation which keeps the state
//! - a request to quit broot
//! - a request to launch an executable (thus leaving broot)
+use crossterm::{InputEvent, TerminalInput};
use std::io::{self, Write};
use std::result::Result;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{mpsc, Arc};
use std::thread;
-use crossterm::{TerminalInput, InputEvent};
use crate::app_context::AppContext;
use crate::browser_states::BrowserState;
-use crate::commands::Command;
use crate::command_parsing::parse_command_sequence;
+use crate::commands::Command;
use crate::errors::ProgramError;
use crate::errors::TreeBuildError;
use crate::external::Launchable;
@@ -65,11 +65,7 @@ pub trait AppState {
screen: &mut Screen,
con: &AppContext,
) -> io::Result<AppStateCmdResult>;
- fn refresh(
- &mut self,
- screen: &Screen,
- con: &AppContext,
- ) -> Command;
+ fn refresh(&mut self, screen: &Screen, con: &AppContext) -> Command;
fn has_pending_tasks(&self) -> bool;
fn do_pending_task(&mut self, screen: &mut Screen, tl: &TaskLifetime);
fn display(&mut self, screen: &mut Screen, con: &AppContext) -> io::Result<()>;
@@ -125,9 +121,9 @@ impl App {
let has_task = self.state().has_pending_tasks();
if has_task {
loop {
+ self.mut_state().display(screen, con)?;
self.state().write_status(screen, &cmd, con)?;
screen.write_spinner(true)?;
- self.mut_state().display(screen, con)?;
if tl.is_expired() {
break;
}
@@ -139,6 +135,7 @@ impl App {
screen.write_spinner(false)?;
}
self.mut_state().display(screen, con)?;
+ self.mut_state().write_status(screen, &cmd, con)?;
Ok(())
}
diff --git a/src/browser_states.rs b/src/browser_states.rs
index 2eb0b29..928be19 100644
--- a/src/browser_states.rs
+++ b/src/browser_states.rs
@@ -1,4 +1,3 @@
-
use std::io;
use std::path::PathBuf;
use std::result::Result;
@@ -18,8 +17,8 @@ use crate::status::Status;
use crate::task_sync::TaskLifetime;
use crate::tree_build::TreeBuilder;
use crate::tree_options::{OptionBool, TreeOptions};
-use crate::verbs::{VerbExecutor};
-use crate::verb_store::{PrefixSearchResult};
+use crate::verb_store::PrefixSearchResult;
+use crate::verbs::VerbExecutor;
/// An application state dedicated to displaying a tree.
/// It's the first and main screen of broot.
@@ -30,7 +29,6 @@ pub struct BrowserState {
}
impl BrowserState {
-
pub fn new(
path: PathBuf,
mut options: TreeOptions,
@@ -82,11 +80,9 @@ impl BrowserState {
None => &self.tree,
}
}
-
}
impl AppState for BrowserState {
-
fn apply(
&mut self,
cmd: &mut Command,
@@ -178,7 +174,9 @@ impl AppState for BrowserState {
con.verb_store.verbs[cd_idx].to_cmd_result(&line.target(), &None, screen, con)?
}
Action::Verb(invocation) => match con.verb_store.search(&invocation.key) {
- PrefixSearchResult::Match(verb) => self.execute_verb(verb, &invocation, screen, con)?,
+ PrefixSearchResult::Match(verb) => {
+ self.execute_verb(verb, &invocation, screen, con)?
+ }
_ => AppStateCmdResult::verb_not_found(&invocation.key),
},
Action::FuzzyPatternEdit(pat) => match pat.len() {
@@ -204,10 +202,7 @@ impl AppState for BrowserState {
}
}
Action::Help => {
- AppStateCmdResult::NewState(
- Box::new(HelpState::new(screen, con)),
- Command::new()
- )
+ AppStateCmdResult::NewState(Box::new(HelpState::new(screen, con)), Command::new())
}
Action::Refresh => AppStateCmdResult::RefreshState,
Action::Quit => AppStateCmdResult::Quit,
@@ -276,7 +271,7 @@ impl AppState for BrowserState {
left: 0,
top: 0,
width: screen.w,
- height: screen.h-2,
+ height: screen.h - 2,
},
in_app: true,
};
@@ -340,11 +335,7 @@ impl AppState for BrowserState {
}
}
- fn refresh(
- &mut self,
- screen: &Screen,
- _con: &AppContext,
- ) -> Command {
+ fn refresh(&mut self, screen: &Screen, _con: &AppContext) -> Command {
let page_height = BrowserState::page_height(screen) as usize;
// refresh the base tree
if let Err(e) = self.tree.refresh(page_height) {
@@ -370,21 +361,23 @@ impl AppState for BrowserState {
screen.goto(screen.w - total_char_size, screen.h);
let terminal = crossterm::Terminal::new();
terminal.clear(crossterm::ClearType::UntilNewLine)?;
- screen.write(&format!(
+ print!(
"{}{} {}{}",
screen.skin.flag_label.apply_to(" h:"),
- screen.skin.flag_value.apply_to(
- if tree.options.show_hidden { 'y' } else { 'n' }
- ),
+ screen
+ .skin
+ .flag_value
+ .apply_to(if tree.options.show_hidden { 'y' } else { 'n' }),
screen.skin.flag_label.apply_to(" gi:"),
- screen.skin.flag_value.apply_to(
- match tree.options.respect_git_ignore {
+ screen
+ .skin
+ .flag_value
+ .apply_to(match tree.options.respect_git_ignore {
OptionBool::Auto => 'a',
OptionBool::Yes => 'y',
OptionBool::No => 'n',
- }
- ),
- ));
+ }),
+ );
Ok(())
}
}
diff --git a/src/cli.rs b/src/cli.rs
index dae85a8..ecf855f 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,6 +1,5 @@
/// this module manages reading and translating
/// the arguments passed on launch of the application.
-
use crate::errors::{ProgramError, TreeBuildError};
use crate::tree_options::TreeOptions;
use clap;
@@ -9,15 +8,18 @@ use std::io;
use std::path::PathBuf;
use std::result::Result;
+use crossterm::Color::*;
+use termimad::{rgb, Alignment, MadSkin};
+
pub struct AppLaunchArgs {
pub root: PathBuf, // what should be the initial root
pub file_export_path: Option<String>, // where to write the produced path (if required with --out)
- pub cmd_export_path: Option<String>, // where to write the produced command (if required with --outcmd, or -oc)
- pub tree_options: TreeOptions, // initial tree options
- pub commands: Option<String>, // commands passed as cli argument, still unparsed
- pub install: bool, // installation is required
- pub height: Option<u16>, // an optional height to replace the screen's one
- pub no_style: bool, // whether to remove all styles (including colors)
+ pub cmd_export_path: Option<String>, // where to write the produced command (if required with --outcmd, or -oc)
+ pub tree_options: TreeOptions, // initial tree options
+ pub commands: Option<String>, // commands passed as cli argument, still unparsed
+ pub install: bool, // installation is required
+ pub height: Option<u16>, // an optional height to replace the screen's one
+ pub no_style: bool, // whether to remove all styles (including colors)
}
/// declare the possible CLI arguments, and gets the values
@@ -64,7 +66,7 @@ fn get_cli_args<'a>() -> clap::ArgMatches<'a> {
clap::Arg::with_name("height")
.long("height")
.help("height (if you don't want to fill the screen or for file export)")
- .takes_value(true)
+ .takes_value(true),
)
.arg(
clap::Arg::with_name("install")
@@ -141,9 +143,7 @@ pub fn read_lauch_args() -> Result<AppLaunchArgs, ProgramError> {
.value_of("commands")
.and_then(|s| Some(s.to_owned()));
let no_style = cli_args.is_present("no-style");
- let height = cli_args
- .value_of("height")
- .and_then(|s| s.parse().ok());
+ let height = cli_args.value_of("height").and_then(|s| s.parse().ok());
Ok(AppLaunchArgs {
root,
file_export_path,
@@ -156,11 +156,27 @@ pub fn read_lauch_args() -> Result<AppLaunchArgs, ProgramError> {
})
}
-pub fn ask_authorization(question: &str) -> io::Result<bool> {
- println!("{}", question);
+/// wait for user input, return `true` if she
+/// didn't answer 'n'
+pub fn ask_authorization() -> io::Result<bool> {
let answer = crossterm::input().read_line()?;
Ok(match answer.as_ref() {
- "n" => false,
+ "n" | "N" => false,
_ => true,
})
}
+
+pub fn mad_skin() -> MadSkin {
+ let mut skin = MadSkin::default();
+ skin.set_headers_fg(rgb!(255, 187, 0));
+ skin.bold.set_fg(Yellow);
+ skin.italic.set_fgbg(Magenta, rgb!(30, 30, 40));
+ skin.scrollbar.set_track_fg(Rgb {
+ r: 30,
+ g: 30,
+ b: 40,
+ });
+ skin.scrollbar.set_thumb_fg(Rgb { r: 67, g: 51, b: 0 });
+ skin.code.align = Alignment::Center;
+ skin
+}
diff --git a/src/command_parsing.rs b/src/command_parsing.rs
index 280442a..8014ee7 100644
--- a/src/command_parsing.rs
+++ b/src/command_parsing.rs
@@ -11,7 +11,7 @@ use crate::verb_store::PrefixSearchResult;
#[derive(Debug)]
enum CommandSequenceToken {
Standard(String), // one or several words, not starting with a ':'. May be a filter or a verb argument
- VerbKey(String), // a verb (the ':' isn't given)
+ VerbKey(String), // a verb (the ':' isn't given)
}
struct CommandSequenceTokenizer {
chars: Vec<char>,
@@ -21,7 +21,7 @@ impl CommandSequenceTokenizer {
pub fn from(sequence: &str) -> CommandSequenceTokenizer {
CommandSequenceTokenizer {
chars: sequence.chars().collect(),
- pos: 0
+ pos: 0,
}
}
}
@@ -49,13 +49,11 @@ impl Iterator for CommandSequenceTokenizer {
}
let token: String = self.chars[self.pos..end].iter().collect();
self.pos = end + 1;
- Some(
- if is_verb {
- CommandSequenceToken::VerbKey(token)
- } else {
- CommandSequenceToken::Standard(token)
- }
- )
+ Some(if is_verb {
+ CommandSequenceToken::VerbKey(token)
+ } else {
+ CommandSequenceToken::Standard(token)
+ })
}
}
@@ -70,7 +68,10 @@ impl Iterator for CommandSequenceTokenizer {
/// The current parsing try to be the least possible flawed by
/// giving verbs the biggest sequence of tokens accepted by their
/// execution pattern.
-pub fn parse_command_sequence(sequence: &str, con: &AppContext) -> Result<Vec<Command>, ProgramError> {
+pub fn parse_command_sequence(
+ sequence: &str,
+ con: &AppContext,
+) -> Result<Vec<Command>, ProgramError> {
let mut tokenizer = CommandSequenceTokenizer::from(sequence);
let mut commands: Vec<Command> = Vec::new();
let mut leftover: Option<CommandSequenceToken> = None;
@@ -84,12 +85,12 @@ pub fn parse_command_sequence(sequence: &str, con: &AppContext) -> Result<Vec<Co
CommandSequenceToken::VerbKey(key) => {
let verb = match con.verb_store.search(&key) {
PrefixSearchResult::NoMatch => {
- return Err(ProgramError::UnknownVerb{key});
+ return Err(ProgramError::UnknownVerb { key });
}
PrefixSearchResult::TooManyMatches => {
- return Err(ProgramError::AmbiguousVerbKey{key});
+ return Err(ProgramError::AmbiguousVerbKey { key });
}
- PrefixSearchResult::Match(verb) => verb
+ PrefixSearchResult::Match(verb) => verb,
};
let mut raw = format!(":{}", key);
if let Some(args_regex) = &verb.args_parser {
@@ -111,7 +112,7 @@ pub fn parse_command_sequence(sequence: &str, con: &AppContext) -> Result<Vec<Co
}
}
if nb_valid_args == 0 && !args_regex.is_match("") {
- return Err(ProgramError::UnmatchingVerbArgs{key});
+ return Err(ProgramError::UnmatchingVerbArgs { key });
}
for (i, arg) in args.drain(..).enumerate() {
if i < nb_valid_args {
@@ -124,16 +125,15 @@ pub fn parse_command_sequence(sequence: &str, con: &AppContext) -> Result<Vec<Co
}
raw
}
- CommandSequenceToken::Standard(raw) => raw
+ CommandSequenceToken::Standard(raw) => raw,
};
commands.push(Command::from(raw));
}
if let Some(token) = leftover.take() {
- commands.push(Command::from(match token{
+ commands.push(Command::from(match token {
CommandSequenceToken::Standard(raw) => raw,
CommandSequenceToken::VerbKey(raw) => format!(":{}", raw),
}));
}
Ok(commands)
}
-
diff --git a/src/commands.rs b/src/commands.rs
index bafd62d..967da1e 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -2,15 +2,15 @@
//! in the input. It's independant of the state of the application
//! (verbs arent checked at this point)
-use regex::Regex;
-use crossterm::{KeyEvent};
use crate::verb_invocation::VerbInvocation;
+use crossterm::KeyEvent;
+use regex::Regex;
#[derive(Debug, Clone)]
pub struct Command {
pub raw: String, // what's visible in the input
parts: CommandParts, // the parsed parts of the visible input
- pub action: Action, // what's required, based on the last key (which may be not visible, like esc)
+ pub action: Action, // what's required, based on the last key (which may be not visible, like esc)
}
/// An intermediate parsed representation of the raw string
diff --git a/src/conf.rs b/src/conf.rs
index e3cd1cd..5f9b939 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -1,7 +1,8 @@
//! manage reading the verb shortcuts from the configuration file,
//! initializing if if it doesn't yet exist
-use crossterm::{Attribute};
+use crossterm::Attribute;
+use crossterm::ObjectStyle;
use directories::ProjectDirs;
use std::collections::HashMap;
use std::fs;
@@ -9,7 +10,6 @@ use std::io;
use std::path::{Path, PathBuf};
use std::result::Result;
use toml::{self, Value};
-use crossterm::ObjectStyle;
use crate::errors::ConfError;
use crate::skin_conf;
@@ -60,7 +60,6 @@ pub fn dir() -> PathBuf {
}
impl Conf {
-
pub fn default_location() -> PathBuf {
dir().join("conf.toml")
}
@@ -118,9 +117,11 @@ impl Conf {
let from_shell = bool_field(verb_value, "from_shell");
let leave_broot = bool_field(verb_value, "leave_broot");
if leave_broot == Some(false) && from_shell == Some(true) {
- eprintln!("Invalid [[verbs]] entry in configuration");
- eprintln!("You can't simultaneously have leave_broot=false and from_shell=true");
- continue;
+ eprintln!("Invalid [[verbs]] entry in configuration");
+ eprintln!(
+ "You can't simultaneously have leave_broot=false and from_shell=true"
+ );
+ continue;
}
verbs.push(VerbConf {
invocation,
@@ -139,17 +140,18 @@ impl Conf {
for (k, v) in entries_tbl.iter() {
if let Some(s) = v.as_str() {
match skin_conf::parse_object_style(s) {
- Ok(ske) => { skin.insert(k.to_string(), ske); },
- Err(e) => { eprintln!("{}", e); }
+ Ok(ske) => {
+ skin.insert(k.to_string(), ske);
+ }
+ Err(e) => {
+ eprintln!("{}", e);
+ }
}
}
}
}
- Ok(Conf {
- verbs,
- skin,
- })
+ Ok(Conf { verbs, skin })
}
}
@@ -190,4 +192,39 @@ name = "view"
invocation = "view"
execution = "less {file}"
+#####################
+# Skin
+
+# If you want to change the colors of broot,
+# uncomment the following bloc and start messing
+# with the various values
+#
+# [skin]
+# tree = "rgb(89, 73, 101) none"
+# file = "gray(21) none"
+# directory = "rgb(255, 152, 0) none bold"
+# exe = "rgb(17, 164, 181) none"
+# link = "Magenta none"
+# pruning = "rgb(89, 73, 101) none Italic"
+# permissions = "gray(12) none "
+# selected_line = "none gray(3)"
+# size_bar = "black rgb(255, 152, 0)"
+# size_no_bar = "gray(15) gray(2)"
+# char_match = "yellow none"
+# file_error = "Red none"
+# flag_label = "gray(16) none"
+# flag_value = "rgb(255, 152, 0) none bold"
+# input = "White none"
+# spinner = "gray(10) gray(2)"
+# status_error = "Red gray(2)"
+# status_normal = "gray(20) gray(2)"
+# scrollbar_track = "rgb(80, 50, 0) none"
+# scrollbar_thumb = "rgb(255, 187, 0) none"
+# help_paragraph = "gray(20) none"
+# help_bold = "rgb(255, 187, 0) none bold"
+# help_italic = "Magenta rgb(30, 30, 40) italic"
+# help_code = "gray(21) gray(3)"
+# help_headers = "rgb(255, 187, 0) none"
+# help_table_border = "rgb(170, 136, 0) none"
+#
"#;
diff --git a/src/displayable_tree.rs b/src/displayable_tree.rs
index 20c215a..710f09a 100644
--- a/src/displayable_tree.rs
+++ b/src/displayable_tree.rs
@@ -1,5 +1,5 @@
-use std::fmt;
use crossterm::{ClearType, Terminal};
+use std::fmt;
use crate::file_sizes::Size;
use crate::flat_tree::{LineType, Tree, TreeLine};
@@ -26,9 +26,27 @@ pub struct DisplayableTree<'s, 't> {
pub in_app: bool, // if true we show the selection and scrollbar
}
-impl DisplayableTree<'_, '_> {
+impl<'s, 't> DisplayableTree<'s, 't> {
+ pub fn out_of_app(tree: &'t Tree, skin: &'s Skin, width: u16) -> DisplayableTree<'s, 't> {
+ DisplayableTree {
+ tree,
+ skin,
+ area: termimad::Area {
+ left: 0,
+ top: 0,
+ width,
+ height: tree.lines.len() as u16,
+ },
+ in_app: false,
+ }
+ }
- fn write_line_size(&self, f: &mut fmt::Formatter<'_>, line: &TreeLine, total_size: Size) -> fmt::Result {
+ fn write_line_size(
+ &self,
+ f: &mut fmt::Formatter<'_>,
+ line: &TreeLine,
+ total_size: Size,
+ ) -> fmt::Result {
if let Some(s) = line.size {
let dr: usize = s.discrete_ratio(total_size, 8) as usize;
let s: Vec<char> = s.to_string().chars().collect();
@@ -49,8 +67,10 @@ impl DisplayableTree<'_, '_> {
}
fn write_mode(&self, f: &mut fmt::Formatter<'_>, mode: u32) -> fmt::Result {
- write!(f, "{}", self.skin.permissions.apply_to(
- format!(
+ write!(
+ f,
+ "{}",
+ self.skin.permissions.apply_to(format!(
"{}{}{}{}{}{}{}{}{}",
if (mode & (1 << 8)) != 0 { 'r' } else { '-' },
if (mode & (1 << 7)) != 0 { 'w' } else { '-' },
@@ -61,8 +81,8 @@ impl DisplayableTree<'_, '_> {
if (mode & (1 << 2)) != 0 { 'r' } else { '-' },
if (mode & (1 << 1)) != 0 { 'w' } else { '-' },
if (mode & 1) != 0 { 'x' } else { '-' },
- )
- ))
+ ))
+ )
}
fn write_line_name(
@@ -76,7 +96,11 @@ impl DisplayableTree<'_, '_> {
let style = match &line.line_type {
LineType::Dir => &self.skin.directory,
LineType::File => {
- if line.is_exe() { &self.skin.exe } else { &self.skin.file }
+ if line.is_exe() {
+ &self.skin.exe
+ } else {
+ &self.skin.file
+ }
}
LineType::SymLinkToFile(_) | LineType::SymLinkToDir(_) => &self.skin.link,
LineType::Pruning => &self.skin.pruning,
@@ -93,11 +117,7 @@ impl DisplayableTree<'_, '_> {
write!(
f,
"{}",
- pattern.style(
- &line.name,
- &style,
- &self.skin.char_match,
- ),
+ pattern.style(&line.name, &style, &self.skin.char_match,),
)?;
}
match &line.line_type {
@@ -111,7 +131,11 @@ impl DisplayableTree<'_, '_> {
if line.has_error {
self.skin.file_error.write(f, &target)?;
} else {
- let target_style = if line.is_dir() { &s