summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2020-06-28 15:33:43 +0200
committerCanop <cano.petrole@gmail.com>2020-06-28 15:33:43 +0200
commit3accec2a8ea0827b84b7014744cfe94834cc18d5 (patch)
tree33455c638391102566c2c3db8d4bed876b7cd2a7 /src
parent6ae4cc421ef3db9f6f458a023780af899313f821 (diff)
new `cols_order` attribute in configurationv0.18.1
Allows setting the order of columns, most notably the position of the branch (left of the tree, just before the name, or in between). Fix #127
Diffstat (limited to 'src')
-rw-r--r--src/app/context.rs22
-rw-r--r--src/browser/browser_state.rs3
-rw-r--r--src/cli.rs4
-rw-r--r--src/conf/conf.rs6
-rw-r--r--src/conf/default_conf.rs30
-rw-r--r--src/display/col.rs70
-rw-r--r--src/display/displayable_tree.rs318
-rw-r--r--src/display/mod.rs2
-rw-r--r--src/errors.rs3
-rw-r--r--src/launchable.rs9
-rw-r--r--src/print.rs8
-rw-r--r--src/skin/app_skin.rs7
-rw-r--r--src/skin/style_map.rs2
-rw-r--r--src/tree/tree_options.rs4
14 files changed, 319 insertions, 169 deletions
diff --git a/src/app/context.rs b/src/app/context.rs
index ffd9e14..d5fe915 100644
--- a/src/app/context.rs
+++ b/src/app/context.rs
@@ -1,6 +1,7 @@
use crate::{
cli::AppLaunchArgs,
conf::Conf,
+ display::{Cols, DEFAULT_COLS},
pattern::SearchModeMap,
tree::SpecialPath,
verb::VerbStore,
@@ -9,27 +10,40 @@ use crate::{
/// The immutable container that can be passed around
/// to provide the configuration things
pub struct AppContext {
+
+ /// where's the config file we're using
pub config_path: String,
+
+ /// all the arguments specified at launch
pub launch_args: AppLaunchArgs,
+
+ /// the verbs in use (builtins and configured ones)
pub verb_store: VerbStore,
+
+ /// the paths for which there's a special behavior to follow (come from conf)
pub special_paths: Vec<SpecialPath>,
+
+ /// the map between search prefixes and the search mode to apply
pub search_modes: SearchModeMap,
+
+ /// order of columns in tree display
+ pub cols: Cols,
}
impl AppContext {
pub fn from(
launch_args: AppLaunchArgs,
verb_store: VerbStore,
- special_paths: Vec<SpecialPath>,
- search_modes: SearchModeMap,
+ config: &Conf,
) -> Self {
let config_path = Conf::default_location().to_string_lossy().to_string();
Self {
config_path,
launch_args,
verb_store,
- special_paths,
- search_modes,
+ special_paths: config.special_paths.clone(),
+ search_modes: config.search_modes.clone(),
+ cols: config.cols_order.unwrap_or(DEFAULT_COLS).clone(),
}
}
}
diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs
index 0da7406..dab6c85 100644
--- a/src/browser/browser_state.rs
+++ b/src/browser/browser_state.rs
@@ -698,11 +698,12 @@ impl AppState for BrowserState {
_screen: &Screen,
area: Area,
panel_skin: &PanelSkin,
- _con: &AppContext,
+ con: &AppContext,
) -> Result<(), ProgramError> {
let dp = DisplayableTree {
tree: &self.displayed_tree(),
skin: &panel_skin.styles,
+ cols: &con.cols,
area,
in_app: true,
};
diff --git a/src/cli.rs b/src/cli.rs
index 42a46c5..4dab01d 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -192,9 +192,7 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> {
no_style,
};
- let context = AppContext::from(
- launch_args, verb_store, config.special_paths.clone(), config.search_modes.clone(),
- );
+ let context = AppContext::from(launch_args, verb_store, &config);
let mut w = display::writer();
let mut screen = Screen::new(&context, &config)?;
let app = App::new(&context, &screen)?;
diff --git a/src/conf/conf.rs b/src/conf/conf.rs
index 573963e..a17ce6a 100644
--- a/src/conf/conf.rs
+++ b/src/conf/conf.rs
@@ -6,6 +6,7 @@ use {
default_conf::DEFAULT_CONF_FILE,
},
crate::{
+ display::{Col, Cols},
errors::ConfError,
keys,
pattern::{SearchModeMap, SearchModeMapEntry},
@@ -34,6 +35,7 @@ pub struct Conf {
pub special_paths: Vec<SpecialPath>,
pub search_modes: SearchModeMap,
pub disable_mouse_capture: bool,
+ pub cols_order: Option<Cols>,
}
fn string_field(value: &Value, field_name: &str) -> Option<String> {
@@ -116,6 +118,10 @@ impl Conf {
if let Some(mouse_capture) = bool_field(&root, "capture_mouse") {
self.disable_mouse_capture = !mouse_capture;
}
+ // cols order
+ self.cols_order = string_field(&root, "cols_order")
+ .map(|s| Col::parse_cols(&s))
+ .transpose()?;
// reading verbs
if let Some(Value::Array(verbs_value)) = &root.get("verbs") {
for verb_value in verbs_value.iter() {
diff --git a/src/conf/default_conf.rs b/src/conf/default_conf.rs
index e24eff5..21d6c83 100644
--- a/src/conf/default_conf.rs
+++ b/src/conf/default_conf.rs
@@ -28,14 +28,6 @@ pub const DEFAULT_CONF_FILE: &str = r#"
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
@@ -46,6 +38,28 @@ default_flags = ""
# "/home/dys/my-link-I-want-to-explore" = "enter"
###############################################################
+# 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"
+
+###############################################################
+# Column order
+# cols_order, if specified, must be a permutation of "gbpdscn"
+# where every char denotes a column:
+# g : Git file info
+# b : branch (shows the depth and parent in the tree)
+# p : permissions (mode, user, group)
+# d : last modification date
+# s : size (with size bar when sorting)
+# c : count, number of files in directories
+# n : file name
+#
+# cols_order = "gbdscn"
+
+###############################################################
# Verbs and shortcuts
# You can define your own commands which would be applied to
# the selection.
diff --git a/src/display/col.rs b/src/display/col.rs
new file mode 100644
index 0000000..df4957d
--- /dev/null
+++ b/src/display/col.rs
@@ -0,0 +1,70 @@
+use {
+ crate::{
+ errors::ConfError,
+ },
+};
+
+// number of columns in enum
+const COLS_COUNT: usize = 7;
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum Col {
+ Git,
+ Branch,
+ Permission,
+ Date,
+ Size, // includes the size bar in sort mode
+ Count,
+ Name, // name or subpath, depending on sort
+}
+impl Col {
+ pub fn parse(c: char) -> Result<Self, ConfError> {
+ Ok(match c {
+ 'g' => Self::Git,
+ 'b' => Self::Branch,
+ 'd' => Self::Date,
+ 's' => Self::Size,
+ 'c' => Self::Count,
+ 'n' => Self::Name,
+ _ => Err(ConfError::InvalidCols { details: format!("column not recognized : {}", c) })?,
+ })
+ }
+ pub fn index_in(self, cols: &Cols) -> Option<usize> {
+ for (idx, col) in cols.iter().enumerate() {
+ if *col==self {
+ return Some(idx);
+ }
+ }
+ None
+ }
+ /// return a Cols which tries to take the s setting into account
+ /// but is guaranteed to have every Col exactly once.
+ pub fn parse_cols(s: &str) -> Result<Cols, ConfError> {
+ let mut cols = DEFAULT_COLS.clone();
+ for (idx, c) in s.chars().enumerate() {
+ if idx >= COLS_COUNT {
+ return Err(ConfError::InvalidCols { details: format!("too long: {:?}", s) });
+ }
+ // we swap the cols, to ensure both keeps being present
+ let col = Col::parse(c)?;
+ let dest_idx = col.index_in(&cols).unwrap(); // can't be none by construct
+ cols[dest_idx] = cols[idx];
+ cols[idx] = col;
+ }
+ Ok(cols)
+ }
+}
+
+pub type Cols = [Col;COLS_COUNT];
+
+/// Default column order
+pub static DEFAULT_COLS: Cols = [
+ Col::Git,
+ Col::Size,
+ Col::Count,
+ Col::Permission,
+ Col::Date,
+ Col::Branch,
+ Col::Name,
+];
+
diff --git a/src/display/displayable_tree.rs b/src/display/displayable_tree.rs
index 99ae99d..8b71183 100644
--- a/src/display/displayable_tree.rs
+++ b/src/display/displayable_tree.rs
@@ -1,5 +1,7 @@
use {
super::{
+ Col,
+ Cols,
CropWriter,
GitStatusDisplay,
MatchedString,
@@ -40,14 +42,21 @@ pub struct DisplayableTree<'s, 't> {
pub skin: &'s StyleMap,
pub area: termimad::Area,
pub in_app: bool, // if true we show the selection and scrollbar
+ pub cols: &'s Cols,
}
impl<'s, 't> DisplayableTree<'s, 't> {
- pub fn out_of_app(tree: &'t Tree, skin: &'s StyleMap, width: u16) -> DisplayableTree<'s, 't> {
+ pub fn out_of_app(
+ tree: &'t Tree,
+ skin: &'s StyleMap,
+ cols: &'s Cols,
+ width: u16,
+ ) -> DisplayableTree<'s, 't> {
DisplayableTree {
tree,
skin,
+ cols,
area: termimad::Area {
left: 0,
top: 0,
@@ -73,113 +82,102 @@ impl<'s, 't> DisplayableTree<'s, 't> {
}
}
- fn write_line_count<'w, W>(
+ fn write_line_count<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
line: &TreeLine,
selected: bool,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
- if let Some(s) = line.sum {
+ ) -> Result<usize, termimad::Error> {
+ Ok(if let Some(s) = line.sum {
cond_bg!(count_style, self, selected, self.skin.count);
cw.queue_string(&count_style, format!("{:>8}", s.to_count()))?;
- cw.queue_char(&self.skin.default, ' ')
+ 1
} else {
- cw.queue_str(&self.skin.tree, "─────────")
- }
+ 9
+ })
}
- fn write_line_size<'w, W>(
+ fn write_line_size<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
line: &TreeLine,
selected: bool,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
- if let Some(s) = line.sum {
+ ) -> Result<usize, termimad::Error> {
+ Ok(if let Some(s) = line.sum {
cond_bg!(size_style, self, selected, self.name_style(&line));
- cw.queue_string(&size_style, s.to_size_string())?;
- cw.queue_char(&self.skin.default, ' ')
+ cw.queue_string(&size_style, format!("{:>5}", s.to_size_string()))?;
+ 1
} else {
- cw.queue_str(&self.skin.tree, "─────")
- }
+ 6
+ })
}
/// only makes sense when there's only one level
/// (so in sort mode)
- fn write_line_size_with_bar<'w, W>(
+ fn write_line_size_with_bar<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
line: &TreeLine,
total_size: FileSum,
selected: bool,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
- if let Some(s) = line.sum {
+ ) -> Result<usize, termimad::Error> {
+ Ok(if let Some(s) = line.sum {
let pb = ProgressBar::new(s.part_of_size(total_size), 10);
cond_bg!(size_style, self, selected, self.name_style(&line));
cond_bg!(sparse_style, self, selected, self.skin.sparse);
cw.queue_string(&size_style, format!("{:>5}", s.to_size_string()))?;
cw.queue_char(&sparse_style, if s.is_sparse() { 's' } else { ' ' })?;
- cw.queue_string(&size_style, format!("{:<10} ", pb))
+ cw.queue_string(&size_style, format!("{:<10}", pb))?;
+ 1
} else {
- cw.queue_str(&self.skin.tree, "─────────────────")
- }
+ 17
+ })
}
- fn write_line_git_status<'w, W>(
+ fn write_line_git_status<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
line: &TreeLine,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
+ selected: bool,
+ ) -> Result<usize, termimad::Error> {
+ let (style, char) =
if !line.is_selectable() {
- cw.queue_char(&self.skin.tree, ' ')
+ (&self.skin.tree, ' ')
} else {
match line.git_status.map(|s| s.status) {
- Some(Status::CURRENT) => cw.queue_char(&self.skin.git_status_current, ' '),
- Some(Status::WT_NEW) => cw.queue_char(&self.skin.git_status_new, 'N'),
- Some(Status::CONFLICTED) => cw.queue_char(&self.skin.git_status_conflicted, 'C'),
- Some(Status::WT_MODIFIED) => cw.queue_char(&self.skin.git_status_modified, 'M'),
- Some(Status::IGNORED) => cw.queue_char(&self.skin.git_status_ignored, 'I'),
- None => cw.queue_char(&self.skin.tree, ' '),
- _ => cw.queue_char(&self.skin.git_status_other, '?'),
+ Some(Status::CURRENT) => (&self.skin.git_status_current, ' '),
+ Some(Status::WT_NEW) => (&self.skin.git_status_new, 'N'),
+ Some(Status::CONFLICTED) => (&self.skin.git_status_conflicted, 'C'),
+ Some(Status::WT_MODIFIED) => (&self.skin.git_status_modified, 'M'),
+ Some(Status::IGNORED) => (&self.skin.git_status_ignored, 'I'),
+ None => (&self.skin.tree, ' '),
+ _ => (&self.skin.git_status_other, '?'),
}
- }
+ };
+ cond_bg!(git_style, self, selected, style);
+ cw.queue_char(git_style, char)?;
+ Ok(0)
}
- fn write_date<'w, W>(
+ fn write_date<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
seconds: i64,
selected: bool,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
+ ) -> Result<usize, termimad::Error> {
let date_time: DateTime<Local> = Local.timestamp(seconds, 0);
cond_bg!(date_style, self, selected, self.skin.dates);
- cw.queue_string(date_style, date_time.format(self.tree.options.date_time_format).to_string())
+ cw.queue_string(date_style, date_time.format(self.tree.options.date_time_format).to_string())?;
+ Ok(1)
}
#[cfg(unix)]
- fn write_mode<'w, W>(
+ fn write_mode<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
mode: Mode,
selected: bool,
- ) -> Result<(), termimad::Error>
- where
- W: Write,
- {
+ ) -> Result<(), termimad::Error> {
cond_bg!(n_style, self, selected, self.skin.perm__);
cond_bg!(r_style, self, selected, self.skin.perm_r);
cond_bg!(w_style, self, selected, self.skin.perm_w);
@@ -236,18 +234,71 @@ impl<'s, 't> DisplayableTree<'s, 't> {
Ok(())
}
+ #[cfg(unix)]
+ fn write_permissions<'w, W: Write>(
+ &self,
+ cw: &mut CropWriter<'w, W>,
+ line: &TreeLine,
+ user_group_max_lengths: (usize, usize),
+ selected: bool,
+ ) -> Result<usize, ProgramError> {
+ Ok(if line.is_selectable() {
+ self.write_mode(cw, line.mode(), selected)?;
+ let owner = permissions::user_name(line.metadata.uid());
+ cond_bg!(owner_style, self, selected, self.skin.owner);
+ cw.queue_string(
+ &owner_style,
+ format!(" {:w$}", &owner, w = user_group_max_lengths.0),
+ )?;
+ let group = permissions::group_name(line.metadata.gid());
+ cond_bg!(group_style, self, selected, self.skin.group);
+ cw.queue_string(
+ &group_style,
+ format!(" {:w$}", &group, w = user_group_max_lengths.1),
+ )?;
+ 1
+ } else {
+ 9 + 1 + user_group_max_lengths.0 + 1 + user_group_max_lengths.1 + 1
+ })
+ }
+
+ fn write_branch<'w, W: Write>(
+ &self,
+ cw: &mut CropWriter<'w, W>,
+ line_index: usize,
+ line: &TreeLine,
+ selected: bool,
+ ) -> Result<usize, ProgramError> {
+ cond_bg!(branch_style, self, selected, self.skin.tree);
+ for depth in 0..line.depth {
+ cw.queue_str(
+ &branch_style,
+ if line.left_branchs[depth as usize] {
+ if self.tree.has_branch(line_index + 1, depth as usize) {
+ if depth == line.depth - 1 {
+ "├──"
+ } else {
+ "│ "
+ }
+ } else {
+ "└──"
+ }
+ } else {
+ " "
+ },
+ )?;
+ }
+ Ok(0)
+ }
/// write the name or subpath, depending on the pattern_object
- fn write_line_label<'w, W>(
+ fn write_line_label<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
line: &TreeLine,
pattern_object: PatternObject,
selected: bool,
- ) -> Result<(), ProgramError>
- where
- W: Write,
- {
+ ) -> Result<usize, ProgramError> {
let style = match &line.line_type {
TreeLineType::Dir => &self.skin.directory,
TreeLineType::File => {
@@ -297,18 +348,15 @@ impl<'s, 't> DisplayableTree<'s, 't> {
}
_ => {}
}
- Ok(())
+ Ok(1)
}
- fn write_content_extract<'w, W>(
+ fn write_content_extract<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
extract: ContentMatch,
selected: bool,
- ) -> Result<(), ProgramError>
- where
- W: Write,
- {
+ ) -> Result<(), ProgramError> {
cond_bg!(extract_style, self, selected, self.skin.content_extract);
cond_bg!(match_style, self, selected, self.skin.content_match);
cw.queue_str(&extract_style, " ")?;
@@ -322,14 +370,11 @@ impl<'s, 't> DisplayableTree<'s, 't> {
Ok(())
}
- pub fn write_root_line<'w, W>(
+ pub fn write_root_line<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
selected: bool,
- ) -> Result<(), ProgramError>
- where
- W: Write,
- {
+ ) -> Result<(), ProgramError> {
cond_bg!(style, self, selected, self.skin.directory);
let title = self.tree.lines[0].path.to_string_lossy();
cw.queue_str(&style, &title)?;
@@ -351,14 +396,11 @@ impl<'s, 't> DisplayableTree<'s, 't> {
}
/// if in app, extend the background till the end of screen row
- pub fn extend_line_bg<'w, W>(
+ pub fn extend_line_bg<'w, W: Write>(
&self,
cw: &mut CropWriter<'w, W>,
selected: bool,
- ) -> Result<(), ProgramError>
- where
- W: Write,
- {
+ ) -> Result<(), ProgramError> {
if self.in_app {
if selected {
cw.queue_bg(&self.skin.selected_line)?;
@@ -371,10 +413,7 @@ impl<'s, 't> DisplayableTree<'s, 't> {
}
/// write the whole tree on the given `W`
- pub fn write_on<W>(&self, f: &mut W) -> Result<(), ProgramError>
- where
- W: Write,
- {
+ pub fn write_on<W: Write>(&self, f: &mut W) -> Result<(), ProgramError> {
let tree = self.tree;
#[cfg(unix)]
let user_group_max_lengths = user_group_max_lengths(&tree);
@@ -392,6 +431,15 @@ impl<'s, 't> DisplayableTree<'s, 't> {
let pattern_object = tree.options.pattern.pattern.object();
self.write_root_line(&mut cw, tree.selection == 0)?;
f.queue(SetBackgroundColor(Color::Reset))?;
+
+ // we compute the length of the dates, depending on the format
+ let date_len = if tree.options.show_dates {
+ let date_time: DateTime<Local> = Local::now();
+ date_time.format(tree.options.date_time_format).to_string().len()
+ } else {
+ 0 // we don't care
+ };
+
for y in 1..self.area.height {
if self.in_app {
f.queue(cursor::MoveTo(self.area.left, y + self.area.top))?;
@@ -408,72 +456,66 @@ impl<'s, 't> DisplayableTree<'s, 't> {
if line_index < tree.lines.len() {
let line = &tree.lines[line_index];
selected = self.in_app && line_index == tree.selection;
- if !tree.git_status.is_none() {
- self.write_line_git_status(cw, line)?;
- }
- for depth in 0..line.depth {
- cw.queue_str(
- &self.skin.tree,
- if line.left_branchs[depth as usize] {
- if self.tree.has_branch(line_index + 1, depth as usize) {
- if depth == line.depth - 1 {
- "├──"
- } else {
- "│ "
- }
+ let mut in_branch = false;
+ for col in self.cols {
+ let void_len = match col {
+
+ Col::Git if !tree.git_status.is_none() => {
+ self.write_line_git_status(cw, line, selected)?
+ }
+
+ Col::Branch => {
+ in_branch = true;
+ self.write_branch(cw, line_index, line, selected)?
+ }
+
+ #[cfg(unix)]
+ Col::Permission if tree.options.show_permissions => {
+ self.write_permissions(cw, line, user_group_max_lengths, selected)?
+ }
+
+ Col::Date if tree.options.show_dates => {
+ if let Some(seconds) = line.sum.and_then(|sum| sum.to_valid_seconds()) {
+ self.write_date(cw, seconds, selected)?
} else {
- "└──"
+ date_len + 1
}
- } else {
- " "
- },
- )?;
- }
- #[cfg(unix)]
- {
- if tree.options.show_permissions {
- if line.is_selectable() {
- self.write_mode(cw, line.mode(), selected)?;
- let owner = permissions::user_name(line.metadata.uid());
- cond_bg!(owner_style, self, selected, self.skin.owner);
- cw.queue_string(
- &owner_style,
- format!(" {:w$}", &owner, w = user_group_max_lengths.0,),
- )?;
- let group = permissions::group_name(line.metadata.gid());
- cond_bg!(group_style, self, selected, self.skin.group);
- cw.queue_string(
- &group_style,
- format!(" {:w$} ", &group, w = user_group_max_lengths.1,),
- )?;
- } else {
- let length =
- 9 + 1 + user_group_max_lengths.0 + 1 + user_group_max_lengths.1 + 1;
- for _ in 0..length {
- cw.queue_char(&self.skin.tree, '─')?;
+ }
+
+ Col::Size if tree.options.show_sizes => {
+ if tree.options.sort.is_some() {
+ // as soon as there's only one level displayed we can show the size bars
+ self.write_line_size_with_bar(cw, line, total_size, selected)?
+ } else {
+ self.write_line_size(cw, line, selected)?
}
}
- }
- }
- if tree.options.show_dates {
- if let Some(seconds) = line.sum.and_then(|sum| sum.to_valid_seconds()) {
- self.write_date(cw, seconds, selected)?;
- } else {
- cw.queue_str(&self.skin.tree, "─────────────────")?;
- }
- }
- if tree.options.show_sizes {
- if tree.options.sort.is_some() {
- // as soon as there's only one level displayed we can show the size bars
- self.write_line_size_with_bar(cw, line, total_size, selected)?;
+
+ Col::Count if tree.options.show_counts => {
+ self.write_line_count(cw, line, selected)?
+ }
+
+ Col::Name => {
+ in_branch = false;
+ self.write_line_label(cw, line, pattern_object, selected)?
+ }
+
+ _ => {
+ 0 // we don't write the intercol
+ }
+ };
+ // void: intercol & replacing missing cells
+ let (void_base_style, void_char) = if in_branch && void_len > 2 {
+ (&self.skin.tree, '─')
} else {
- self.write_line_size(cw, line, selected)?;
+ (&self.skin.default, ' ')
+ };
+ cond_bg!(void_style, self, selected, void_base_style);
+ for _ in 0..void_len {
+ cw.queue_char(void_style, void_char)?;
}
}
- if tree.options.show_counts {
- self.write_line_count(cw, line, selected)?;
- }
- self.write_line_label(cw, line, pattern_object, selected)?;
+
if cw.allowed > 8 && pattern_object.content {
let extract = tree.options.pattern.pattern.search_content(&line.path, cw.allowed - 2);
if let Some(extract) = extract {
diff --git a/src/display/mod.rs b/src/display/mod.rs
index f073a73..97424ca 100644
--- a/src/display/mod.rs
+++ b/src/display/mod.rs
@@ -21,6 +21,7 @@ macro_rules! cond_bg {
}
mod areas;
+mod col;
mod crop_writer;
mod displayable_tree;
mod flags_display;
@@ -33,6 +34,7 @@ use std::io::BufWriter;
pub use {
areas::Areas,
+ col::{Col, Cols, DEFAULT_COLS},
crop_writer::CropWriter,
displayable_tree::DisplayableTree,
flags_display::write_flags,
diff --git a/src/errors.rs b/src/errors.rs
index 37bcb8e..640fb0e 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -38,7 +38,8 @@ custom_error! {pub ConfError
InvalidSearchMode {details: String} = "invalid search mode: {}",
InvalidKey {raw: String} = "not a valid key: {}",
ReservedKey {key: String} = "reserved key: {}",
- UnexpectedInternalArg { invocation: String} = "unexpected argument for internal: {}",
+ UnexpectedInternalArg {invocation: String} = "unexpected argument for internal: {}",
+ InvalidCols {details: String} = "invalid cols definition: {}",
}
// error which can be raised when parsing a pattern the user typed
diff --git a/src/launchable.rs b/src/launchable.rs
index 6c99796..0c81b22 100644
--- a/src/launchable.rs
+++ b/src/launchable.rs
@@ -1,6 +1,6 @@
use {
crate::{
- display::{DisplayableTree, Screen, W},
+ display::{Cols, DisplayableTree, Screen, W},
errors::ProgramError,
skin::StyleMap,
tree::Tree,
@@ -30,6 +30,7 @@ pub enum Launchable {
// print the tree on end of broot
tree: Box<Tree>,
skin: Box<StyleMap>,
+ cols: Cols,
width: u16,
},
Program {
@@ -70,10 +71,12 @@ impl Launchable {
tree: &Tree,
screen: &Screen,
style_map: StyleMap,
+ cols: Cols,
) -> Launchable {
Launchable::TreePrinter {
tree: Box::new(tree.clone()),
skin: Box::new(style_map),
+ cols,
width: screen.width,
}
}
@@ -95,8 +98,8 @@ impl Launchable {
println!("{}", to_print);
Ok(())
}
- Launchable::TreePrinter { tree, skin, width } => {
- let dp = DisplayableTree::out_of_app(&tree, &skin, *width);
+ Launchable::TreePrinter { tree, skin, cols, width } => {
+ let dp = DisplayableTree::out_of_app(&tree, &skin, &cols, *width);
dp.write_on(&mut std::io::stdout())
}
Launchable::Program { exe, args } => {
diff --git a/src/print.rs b/src/print.rs
index ea5552e..04b3352 100644
--- a/src/print.rs
+++ b/src/print.rs
@@ -3,7 +3,7 @@
use {
crate::{
app::{AppContext, AppStateCmdResult},
- display::{DisplayableTree, Screen},
+ display::{Cols, DisplayableTree, Screen},
errors::ProgramError,
launchable::Launchable,
skin::{PanelSkin, StyleMap},
@@ -56,9 +56,10 @@ fn print_tree_to_file(
tree: &Tree,
screen: &mut Screen,
file_path: &str,
+ cols: &Cols,
) -> Result<AppStateCmdResult, ProgramError> {
let no_style_skin = StyleMap::no_term();
- let dp = DisplayableTree::out_of_app(tree, &no_style_skin, screen.width);
+ let dp = DisplayableTree::out_of_app(tree, &no_style_skin, cols, screen.width);
let mut f = OpenOptions::new()
.create(true)
.append(true)
@@ -75,7 +76,7 @@ pub fn print_tree(
) -> Result<AppStateCmdResult, ProgramError> {
if let Some(ref output_path) = con.launch_args.file_export_path {
// an output path was provided, we write to it
- print_tree_to_file(tree, screen, output_path)
+ print_tree_to_file(tree, screen, output_path, &con.cols)
} else {
// no output path provided. We write on stdout, but we must
// do it after app closing to have the normal terminal
@@ -88,6 +89,7 @@ pub fn print_tree(
tree,
screen,
styles,
+ con.cols.clone(),
)))
}
}
diff --git a/src/skin/app_skin.rs b/src/skin/app_skin.rs
index 6196e1e..a0f85c4 100644
--- a/src/skin/app_skin.rs
+++ b/src/skin/app_skin.rs
@@ -15,18 +15,15 @@ pub struct AppSkin {
/// the skin used in unfocused panels
pub unfocused: PanelSkin,
-
}
impl AppSkin {
pub fn new(conf: &Conf) -> Self {
let StyleMaps { focused, unfocused } = StyleMaps::create(&conf.skin);
- let focused = PanelS