diff options
author | Canop <cano.petrole@gmail.com> | 2019-05-09 19:49:35 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2019-05-09 19:49:35 +0200 |
commit | 190cd280d1d7de884853eaf1e0f6471bbad7f5c3 (patch) | |
tree | 863cd8a1662a3e4d89b8d1dbe070fa84bef9f41a | |
parent | 854f17ae67a632386a5d5a0030d5551172271885 (diff) |
more things work - broot successfully launched on Win10 and linux
(with reduced set of feature - see live feature matrix in chat)
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/app.rs | 5 | ||||
-rw-r--r-- | src/browser_states.rs | 4 | ||||
-rw-r--r-- | src/cli.rs | 2 | ||||
-rw-r--r-- | src/conf.rs | 21 | ||||
-rw-r--r-- | src/file_sizes/file_sizes_unix.rs (renamed from src/file_sizes.rs) | 67 | ||||
-rw-r--r-- | src/file_sizes/mod.rs | 76 | ||||
-rw-r--r-- | src/input.rs | 4 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/patterns.rs | 4 | ||||
-rw-r--r-- | src/permissions/mod.rs | 10 | ||||
-rw-r--r-- | src/screens.rs | 4 | ||||
-rw-r--r-- | src/shell_install.rs | 7 | ||||
-rw-r--r-- | src/skin.rs | 11 | ||||
-rw-r--r-- | src/skin_conf.rs | 5 | ||||
-rw-r--r-- | src/status.rs | 8 | ||||
-rw-r--r-- | src/tree_build.rs | 17 | ||||
-rw-r--r-- | src/tree_views.rs | 54 |
19 files changed, 172 insertions, 131 deletions
@@ -100,7 +100,6 @@ dependencies = [ "opener 0.3.2 (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)", - "termion 1.5.1 (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)", ] @@ -11,7 +11,6 @@ categories = ["command-line-utilities"] readme = "README.md" [dependencies] -termion = "1.5" regex = "1" lazy_static = "1.2" directories = "1.0" @@ -7,12 +7,12 @@ //! - an operation which keeps the state //! - a request to quit broot //! - a request to launch an executable (thus leaving broot) -use std::io::{self, stdin, Write}; +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::{KeyEvent, InputEvent}; +use crossterm::{InputEvent}; use crate::app_context::AppContext; use crate::browser_states::BrowserState; @@ -156,6 +156,7 @@ impl App { screen.read_size(con)?; screen.write_input(&cmd)?; self.state().write_flags(screen, con)?; + screen.write_spinner(false)?; match self.mut_state().apply(&mut cmd, screen, con)? { AppStateCmdResult::Quit => { debug!("cmd result quit"); diff --git a/src/browser_states.rs b/src/browser_states.rs index f2d9ae9..3c961cb 100644 --- a/src/browser_states.rs +++ b/src/browser_states.rs @@ -6,8 +6,6 @@ use std::path::PathBuf; use std::result::Result; use std::time::Instant; -use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue}; - use crate::app::{AppState, AppStateCmdResult}; use crate::app_context::AppContext; use crate::commands::{Action, Command}; @@ -17,7 +15,6 @@ use crate::flat_tree::{LineType, Tree}; use crate::help_states::HelpState; use crate::patterns::Pattern; use crate::screens::Screen; -use crate::skin::{Skin, SkinEntry}; use crate::status::Status; use crate::task_sync::TaskLifetime; use crate::tree_build::TreeBuilder; @@ -266,6 +263,7 @@ impl AppState for BrowserState { fn display(&mut self, screen: &mut Screen, _con: &AppContext) -> io::Result<()> { let mut curs: Cursor<Vec<u8>> = Cursor::new(Vec::new()); let mut tree_view = TreeView::from_screen(screen, &mut curs); + screen.goto(1, 1); tree_view.write_tree(&self.displayed_tree())?; let terminal = crossterm::Terminal::new(); terminal.write(&String::from_utf8(curs.into_inner()).unwrap()); @@ -5,7 +5,7 @@ use crate::errors::{ProgramError, TreeBuildError}; use crate::tree_options::TreeOptions; use clap; use std::env; -use std::io::{self, stdin}; +use std::io; use std::path::PathBuf; use std::result::Result; diff --git a/src/conf.rs b/src/conf.rs index d311651..a2c7915 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -11,7 +11,6 @@ use std::result::Result; use toml::{self, Value}; use crate::errors::ConfError; -use crate::skin_conf; /// what's needed to handle a verb #[derive(Debug)] @@ -131,16 +130,16 @@ impl Conf { } // reading the skin let mut skin_entries = HashMap::new(); - if let Some(Value::Table(entries_tbl)) = &root.get("skin") { - for (k, v) in entries_tbl.iter() { - if let Some(s) = v.as_str() { - match skin_conf::parse_config_entry(k, s) { - Ok(ske) => { skin_entries.insert(k.to_string(), ske); }, - Err(e) => { eprintln!("{}", e); } - } - } - } - } + //if let Some(Value::Table(entries_tbl)) = &root.get("skin") { + // for (k, v) in entries_tbl.iter() { + // if let Some(s) = v.as_str() { + // match skin_conf::parse_config_entry(k, s) { + // Ok(ske) => { skin_entries.insert(k.to_string(), ske); }, + // Err(e) => { eprintln!("{}", e); } + // } + // } + // } + //} Ok(Conf { verbs, diff --git a/src/file_sizes.rs b/src/file_sizes/file_sizes_unix.rs index 1faf079..2a89c82 100644 --- a/src/file_sizes.rs +++ b/src/file_sizes/file_sizes_unix.rs @@ -1,8 +1,3 @@ -/// compute the summed size of directories. -/// A cache is used to avoid recomputing the -/// same directories again and again. -/// Hard links are checked to avoid counting -/// twice an inode. use crate::task_sync::TaskLifetime; use std::collections::{HashMap, HashSet}; use std::fs; @@ -18,25 +13,9 @@ use std::sync::Arc; use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering}; use std::time::Duration; -const SIZE_NAMES: &[&str] = &["", "K", "M", "G", "T", "P", "E", "Z", "Y"]; // Y: for when your disk is bigger than 1024 ZB - -#[derive(Debug, Copy, Clone)] -pub struct Size(u64); - -impl Size { - pub fn from_file(path: &Path) -> Size { - Size(match fs::metadata(path) { - Ok(m) => m.len(), - Err(_) => 0, - }) - } - - /// Return the size of the directory, either by computing it of by - /// fetching it from cache. - /// If the lifetime expires before complete computation, None is returned. - pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> { +pub fn compute_dir_size(path: &Path, tl: &TaskLifetime) -> Option<u64> { lazy_static! { - static ref SIZE_CACHE_MUTEX: Mutex<HashMap<PathBuf, Size>> = Mutex::new(HashMap::new()); + static ref SIZE_CACHE_MUTEX: Mutex<HashMap<PathBuf, u64>> = Mutex::new(HashMap::new()); } let mut size_cache = SIZE_CACHE_MUTEX.lock().unwrap(); if let Some(s) = size_cache.get(path) { @@ -105,46 +84,8 @@ impl Size { } let size: usize = size.load(Ordering::Relaxed); let size: u64 = size as u64; - let s = Size::from(size); - size_cache.insert(PathBuf::from(path), s); + size_cache.insert(PathBuf::from(path), size); debug!("size computation for {:?} took {:?}", path, start.elapsed()); - Some(s) - } - - /// format a number of bytes as a string - pub fn to_string(self) -> String { - let mut v = self.0; - let mut i = 0; - while v >= 9000 && i < SIZE_NAMES.len() - 1 { - v >>= 10; - i += 1; - } - format!("{}{}", v, &SIZE_NAMES[i]) - } - pub fn discrete_ratio(self, max: Size, r: u64) -> u64 { - if max.0 == 0 || self.0 == 0 { - 0 - } else { - ((r as f64) * (self.0 as f64).cbrt() / (max.0 as f64).cbrt()).round() as u64 - } - } -} - -impl From<u64> for Size { - fn from(s: u64) -> Size { - Size(s) - } -} - -impl AddAssign for Size { - fn add_assign(&mut self, other: Size) { - *self = Size(self.0 + other.0); - } -} - -impl Into<u64> for Size { - fn into(self) -> u64 { - self.0 - } + Some(size) } diff --git a/src/file_sizes/mod.rs b/src/file_sizes/mod.rs new file mode 100644 index 0000000..073da85 --- /dev/null +++ b/src/file_sizes/mod.rs @@ -0,0 +1,76 @@ +/// compute the summed size of directories. +/// A cache is used to avoid recomputing the +/// same directories again and again. +/// Hard links are checked to avoid counting +/// twice an inode. +use crate::task_sync::TaskLifetime; +use std::fs; +use std::ops::AddAssign; +use std::path::{Path, PathBuf}; + +#[cfg(unix)] +mod file_sizes_unix; + +const SIZE_NAMES: &[&str] = &["", "K", "M", "G", "T", "P", "E", "Z", "Y"]; // Y: for when your disk is bigger than 1024 ZB + +#[derive(Debug, Copy, Clone)] +pub struct Size(u64); + +impl Size { + pub fn from_file(path: &Path) -> Size { + Size(match fs::metadata(path) { + Ok(m) => m.len(), + Err(_) => 0, + }) + } + + #[cfg(windows)] + + pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> { + Some(Size::from(0)) // it's correct, sometimes + } + + #[cfg(unix)] + /// Return the size of the directory, either by computing it of by + /// fetching it from cache. + /// If the lifetime expires before complete computation, None is returned. + pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> { + file_sizes_unix::compute_dir_size(path, tl).map(|s| Size::from(s)) + } + + /// format a number of bytes as a string + pub fn to_string(self) -> String { + let mut v = self.0; + let mut i = 0; + while v >= 9000 && i < SIZE_NAMES.len() - 1 { + v >>= 10; + i += 1; + } + format!("{}{}", v, &SIZE_NAMES[i]) + } + pub fn discrete_ratio(self, max: Size, r: u64) -> u64 { + if max.0 == 0 || self.0 == 0 { + 0 + } else { + ((r as f64) * (self.0 as f64).cbrt() / (max.0 as f64).cbrt()).round() as u64 + } + } +} + +impl From<u64> for Size { + fn from(s: u64) -> Size { + Size(s) + } +} + +impl AddAssign for Size { + fn add_assign(&mut self, other: Size) { + *self = Size(self.0 + other.0); + } +} + +impl Into<u64> for Size { + fn into(self) -> u64 { + self.0 + } +} diff --git a/src/input.rs b/src/input.rs index ddcb1c2..1d6242e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -2,10 +2,11 @@ /// (reading is managed in the app module) use std::io::{self}; -use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue}; +use crossterm::Attribute; use crate::commands::Command; use crate::screens::Screen; +use crate::skin; pub trait Input { fn write_input(&mut self, cmd: &Command) -> io::Result<()>; @@ -13,6 +14,7 @@ pub trait Input { impl Input for Screen { fn write_input(&mut self, cmd: &Command) -> io::Result<()> { + skin::reset(); self.goto_clear(1, self.h); self.write(&format!( "{}{} {}", diff --git a/src/main.rs b/src/main.rs index 604f1fe..3999eef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ mod shell_bash; mod shell_fish; mod shell_install; mod skin; -mod skin_conf; +//mod skin_conf; disabled until rewrite mod spinner; mod status; mod task_sync; diff --git a/src/patterns.rs b/src/patterns.rs index 6f6f20b..85fa2ab 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -141,10 +141,10 @@ impl fmt::Display for MatchedString<'_> { if pos_idx < m.pos.len() && m.pos[pos_idx] == cand_idx { write!(f, "{}", self.base_style.apply_to( self.match_style.apply_to(cand_char) - )); + ))?; pos_idx += 1; } else { - write!(f, "{}", self.base_style.apply_to(cand_char)); + write!(f, "{}", self.base_style.apply_to(cand_char))?; } } return Ok(()) diff --git a/src/permissions/mod.rs b/src/permissions/mod.rs index df98c7d..fcdd81d 100644 --- a/src/permissions/mod.rs +++ b/src/permissions/mod.rs @@ -1,3 +1,4 @@ +use std::path::Path; //////////////////// UNIX @@ -28,6 +29,11 @@ pub fn supported() -> bool { } #[cfg(windows)] -pub fn from(path: &Path) -> Option<Permissions> { - unreachable!(); +pub fn user_name(uid: u32) -> String { + unreachable!() +} + +#[cfg(windows)] +pub fn group_name(gid: u32) -> String { + unreachable!() } diff --git a/src/screens.rs b/src/screens.rs index e763061..1585b37 100644 --- a/src/screens.rs +++ b/src/screens.rs @@ -35,7 +35,7 @@ impl Screen { screen.read_size(con)?; info!("screen size: {} x {}", screen.w, screen.h); let cursor = TerminalCursor::new(); - cursor.hide(); + cursor.hide().unwrap(); Ok(screen) } pub fn read_size(&mut self, con: &AppContext) -> io::Result<()> { @@ -62,7 +62,7 @@ impl Screen { } pub fn goto(&self, x: u16, y: u16) { let cursor = TerminalCursor::new(); - info!("goto x={}, y={}", x, y); + //debug!("goto x={}, y={}", x, y); cursor.goto(x-1, y-1).unwrap(); } pub fn clear_line(&self) { diff --git a/src/shell_install.rs b/src/shell_install.rs index c71b58a..a09f035 100644 --- a/src/shell_install.rs +++ b/src/shell_install.rs @@ -23,7 +23,7 @@ use std::fs::{self, OpenOptions}; use std::io::{self, BufRead, BufReader, Write}; -use std::os::unix::fs::symlink; +use std::os; use std::path::Path; use crossterm::Attribute; @@ -64,7 +64,10 @@ impl ShellFamily<'static> { } if !func_present || !link_present { info!("creating link from {:?} to {:?}", &link_path, &script_path); - symlink(&script_path, &link_path)?; + #[cfg(unix)] + os::unix::fs::symlink(&script_path, &link_path)?; + #[cfg(windows)] + os::windows::fs::symlink_file(&script_path, &link_path)?; } Ok(()) } diff --git a/src/skin.rs b/src/skin.rs index 218a324..e71a206 100644 --- a/src/skin.rs +++ b/src/skin.rs @@ -64,10 +64,13 @@ macro_rules! Skin { pub fn gray(level: u8) -> Option<Color> { Some(AnsiValue(0xE8 + level)) } +pub fn rgb(r: u8, g: u8, b: u8) -> Option<Color> { + Some(Rgb{r, g, b}) +} Skin! { // FIXME some colors to rebuild using Rgb - char_match: Some(Rgb{r:78, g:154, b:8}), None; + char_match: rgb(78, 154, 8), None; code: Some(White), gray(2); directory: Some(Blue), None; {Bold} exe: Some(Cyan), None; @@ -80,7 +83,7 @@ Skin! { link: Some(Magenta), None; permissions: gray(15), None; selected_line: None, gray(3); - size_bar_full: Some(White), Some(Magenta); + size_bar_full: Some(White), rgb(117, 80, 123); size_bar_void: Some(White), gray(2); size_text: gray(15), None; spinner: gray(10), gray(2); @@ -90,3 +93,7 @@ Skin! { tree: gray(5), None; unlisted: gray(13), None; } + +pub fn reset() { + print!("{}", Attribute::Reset); +} diff --git a/src/skin_conf.rs b/src/skin_conf.rs index 4d5981d..163f55a 100644 --- a/src/skin_conf.rs +++ b/src/skin_conf.rs @@ -1,3 +1,8 @@ + +// This file is ignored for now. I'll have to rewrite +// skin configuration parsing for crossterm when the +// rest is proven OK + use crate::errors::{ConfError, InvalidSkinError}; use regex::Regex; /// Manage conversion of a user provided string diff --git a/src/status.rs b/src/status.rs index 428650b..66964e7 100644 --- a/src/status.rs +++ b/src/status.rs @@ -6,7 +6,7 @@ use std::io::{self}; use crossterm::{Attribute::{self, Reset}, Color::{self, *}, Colored, Color::AnsiValue}; use crate::screens::Screen; -use crate::skin::SkinEntry; +use crate::skin::{self, SkinEntry}; pub trait Status { fn write_status_text(&self, text: &str) -> io::Result<()>; @@ -16,9 +16,13 @@ pub trait Status { impl Screen { fn write_status(&self, text: &str, skin: &SkinEntry) -> io::Result<()> { let mut text = String::from(text); - text.truncate(self.w as usize - 2); + text.truncate(self.w as usize - 3); self.goto_clear(2, self.h - 1); + skin.print_string(" "); skin.print_string(&text); + skin.print_bg(); + self.clear_line(); + skin::reset(); Ok(()) } } diff --git a/src/tree_build.rs b/src/tree_build.rs index f441da8..2f1e211 100644 --- a/src/tree_build.rs +++ b/src/tree_build.rs @@ -1,11 +1,13 @@ use std::cmp::{self, Ordering}; use std::collections::{BinaryHeap, VecDeque}; use std::fs; -use std::os::unix::fs::MetadataExt; use std::path::PathBuf; use std::result::Result; use std::time::{Duration, Instant}; +#[cfg(unix)] +use std::os::unix::fs::MetadataExt; + use crate::errors::TreeBuildError; use crate::flat_tree::{LineType, Tree, TreeLine}; use crate::git_ignore::GitIgnoreFilter; @@ -150,11 +152,16 @@ impl BLine { let mut uid = 0; let mut gid = 0; let mut has_error = self.has_error; - if let Ok(metadata) = fs::symlink_metadata(&self.path) { - mode = metadata.mode(); - uid = metadata.uid(); - gid = metadata.gid(); + + #[cfg(unix)] + { + if let Ok(metadata) = fs::symlink_metadata(&self.path) { + mode = metadata.mode(); + uid = metadata.uid(); + gid = metadata.gid(); + } } + let line_type = if self.file_type.is_dir() { LineType::Dir } else if self.file_type.is_symlink() { diff --git a/src/tree_views.rs b/src/tree_views.rs index c2784b5..18b2069 100644 --- a/src/tree_views.rs +++ b/src/tree_views.rs @@ -1,13 +1,13 @@ use std::borrow::Cow; use std::io::{self, Cursor, Write}; -use crossterm::{Attribute::{self, Reset}, ClearType, Color::{self, *}, Colored, Color::AnsiValue}; +use crossterm::{Attribute::{self, Reset}, ClearType, Color::{self, *}, Colored, Color::AnsiValue, TerminalCursor}; use crate::file_sizes::Size; use crate::flat_tree::{LineType, Tree, TreeLine}; use crate::patterns::Pattern; use crate::permissions; use crate::screens::{Screen, ScreenArea}; -use crate::skin::{Skin, SkinEntry}; +use crate::skin::{self, Skin, SkinEntry}; /// A tree writer, which can be used either to write on the screen in the application, /// or to write in a file or an exported string. @@ -26,7 +26,7 @@ pub struct TreeView<'a> { impl TreeView<'_> { - pub fn from_screen<'a>(screen: &'a mut Screen, out: &'a mut Write) -> TreeView<'a> { + pub fn from_screen<'a>(screen: &'a Screen, out: &'a mut Write) -> TreeView<'a> { TreeView { w: screen.w, h: screen.h-2, @@ -58,10 +58,9 @@ impl TreeView<'_> { content_length: tree.lines.len() as i32, width: self.w, }; + let cursor = TerminalCursor::new(); // TODO clean this out + let terminal = crossterm::Terminal::new(); // TODO clean this out let scrollbar = area.scrollbar(); - if self.in_app { - print!("{}", termion::cursor::Goto(1, 1)); - } for y in 1..self.h + 1 { let mut line_index = (y - 1) as usize; if line_index > 0 { @@ -121,7 +120,6 @@ impl TreeView<'_> { if selected { // hack to extend selection background -> improve self.skin.selected_line.print_bg(); - let terminal = crossterm::Terminal::new(); terminal.clear(ClearType::UntilNewLine).unwrap(); } } else if !self.in_app { @@ -129,10 +127,10 @@ impl TreeView<'_> { break; // no need to add empty lines } if self.in_app { - print!("{}", termion::clear::UntilNewline); + terminal.clear(ClearType::UntilNewLine).unwrap(); if let Some((sctop, scbottom)) = scrollbar { if sctop <= y && y <= scbottom { - print!("{}▐", termion::cursor::Goto(self.w, y),); + cursor.goto(self.w-1, y-1).unwrap(); } } } @@ -159,27 +157,23 @@ impl TreeView<'_> { } fn write_line_size(&mut self, line: &TreeLine, total_size: Size) { - // FIXME... - //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(); - // print!( - // "{}{}", - // self.skin.size_text.fg, self.skin.size_bar_full.bg, - // ); - // for i in 0..dr { - // print!("{}", if i < s.len() { s[i] } else { ' ' }); - // } - // print!("{}", self.skin.size_bar_void.bg); - // for i in dr..8 { - // print!("{}", if i < s.len() { s[i] } else { ' ' }); - // } - //} else { - // print!( - // "{}────────{} ", - // self.skin.tree.fg, self.skin.reset.fg, - // ) - //} + 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(); + self.skin.size_text.print_fg(); + self.skin.size_bar_full.print_bg(); + for i in 0..dr { + print!("{}", if i < s.len() { s[i] } else { ' ' }); + } + self.skin.size_bar_void.print_bg(); + for i in dr..8 { + print!("{}", if i < s.len() { s[i] } else { ' ' }); + } + skin::reset(); + print!(" "); + } else { + self.skin.tree.print_string("──────── "); + } } fn write_line_name( |