Skip to content

Commit

Permalink
Print the root path relative to the initial root
Browse files Browse the repository at this point in the history
  • Loading branch information
9999years committed Oct 11, 2023
1 parent 51c71d6 commit 4be8d8b
Show file tree
Hide file tree
Showing 16 changed files with 103 additions and 35 deletions.
3 changes: 3 additions & 0 deletions man/page
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ Show folders and files alike
\fB\-\-show\-root\-fs\fR
Show filesystem info on top
.TP
\fB\-\-root\-relative\-path\fR
Show the root path relative to the launch directory
.TP
\fB\-g\fR, \fB\-\-show\-git\-info\fR
Show git statuses on files and stats on repo
.TP
Expand Down
4 changes: 4 additions & 0 deletions src/app/app_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ pub struct AppContext {
/// Initial tree options
pub initial_tree_options: TreeOptions,

/// Initial working directory. This is where `broot` is launched, not the root path!
pub initial_working_dir: PathBuf,

/// where's the config file we're using
/// This vec can't be empty
pub config_paths: Vec<PathBuf>,
Expand Down Expand Up @@ -159,6 +162,7 @@ impl AppContext {
initial_root,
initial_file,
initial_tree_options,
initial_working_dir: std::env::current_dir()?,
config_paths,
launch_args,
verb_store,
Expand Down
15 changes: 15 additions & 0 deletions src/app/panel_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,21 @@ pub trait PanelState {
con,
)
}
Internal::toggle_root_relative => {
self.with_new_options(
screen,
&|o| {
o.relative_root ^= true;
if o.relative_root {
"*displaying root relative to launch dir*"
} else {
"*displaying root as absolute path*"
}
},
bang,
con,
)
}
Internal::toggle_git_ignore => {
self.with_new_options(
screen,
Expand Down
2 changes: 1 addition & 1 deletion src/browser/browser_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ impl PanelState for BrowserState {
disc: &DisplayContext,
) -> Result<(), ProgramError> {
let dp = DisplayableTree {
app_state: Some(disc.app_state),
display_context: Some(disc),
tree: self.displayed_tree(),
skin: &disc.panel_skin.styles,
ext_colors: &disc.con.ext_colors,
Expand Down
4 changes: 4 additions & 0 deletions src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub struct Args {
#[arg(long)]
pub show_root_fs: bool,

/// Show the root path relative to the launch directory.
#[arg(long)]
pub root_relative_path: bool,

/// Show git statuses on files and stats on repo
#[arg(short='g', long)]
pub show_git_info: bool,
Expand Down
3 changes: 3 additions & 0 deletions src/conf/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ pub struct Conf {

#[serde(alias="content-search-max-file-size", deserialize_with="file_size::deserialize", default)]
pub content_search_max_file_size: Option<u64>,

#[serde(alias="root-relative-path")]
pub root_relative_path: Option<bool>,
}

impl Conf {
Expand Down
25 changes: 17 additions & 8 deletions src/display/displayable_tree.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use crate::app::DisplayContext;
use crate::path::relativize_path;

use {
super::{
cond_bg,
Expand All @@ -9,7 +12,6 @@ use {
SPACE_FILLING, BRANCH_FILLING,
},
crate::{
app::AppState,
content_search::ContentMatch,
errors::ProgramError,
file_sum::FileSum,
Expand Down Expand Up @@ -37,7 +39,7 @@ use {
/// - a scrollbar may be drawn
/// - the empty lines will be erased
pub struct DisplayableTree<'a, 's, 't> {
pub app_state: Option<&'a AppState>,
pub display_context: Option<&'a DisplayContext<'a>>,
pub tree: &'t Tree,
pub skin: &'s StyleMap,
pub area: termimad::Area,
Expand All @@ -55,7 +57,7 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> {
height: u16,
) -> DisplayableTree<'a, 's, 't> {
DisplayableTree {
app_state: None,
display_context: None,
tree,
skin,
ext_colors,
Expand Down Expand Up @@ -413,8 +415,15 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> {
)?;
}
}
let title = line.path.to_string_lossy();
cw.queue_str(style, &title)?;
match self.display_context {
Some(context) if self.tree.options.relative_root => {
cw.queue_str(style, &relativize_path(&line.path, context.con)?)?;
},
_ => {
cw.queue_str(style, &line.path.to_string_lossy())?;
},
}

if self.in_app && !cw.is_full() {
if let ComputationResult::Done(git_status) = &self.tree.git_status {
let git_status_display = GitStatusDisplay::from(
Expand Down Expand Up @@ -486,7 +495,7 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> {
.options
.cols_order
.iter()
.filter(|col| col.is_visible(tree, self.app_state))
.filter(|col| col.is_visible(tree, self.display_context.map(|con| con.app_state)))
.cloned()
.collect();

Expand Down Expand Up @@ -536,8 +545,8 @@ impl<'a, 's, 't> DisplayableTree<'a, 's, 't> {
if visible_cols[0].needs_left_margin() {
cw.queue_char(space_style, ' ')?;
}
let staged = self.app_state
.map_or(false, |a| a.stage.contains(&line.path));
let staged = self.display_context
.map_or(false, |a| a.app_state.stage.contains(&line.path));
for col in &visible_cols {
let void_len = match col {

Expand Down
2 changes: 2 additions & 0 deletions src/path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod closest;
mod from;
mod normalize;
mod special_path;
mod relative;

pub use {
anchor::*,
Expand All @@ -12,4 +13,5 @@ pub use {
from::*,
normalize::*,
special_path::*,
relative::*,
};
23 changes: 23 additions & 0 deletions src/path/relative.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::io;
use std::path::Path;

use crate::app::AppContext;

pub fn relativize_path(path: &Path, con: &AppContext) -> io::Result<String> {
let relative_path = match pathdiff::diff_paths(path, &con.initial_working_dir) {
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Cannot relativize {path:?}"), // does this happen ? how ?
));
}
Some(p) => p,
};
Ok(
if relative_path.components().next().is_some() {
relative_path.to_string_lossy().to_string()
} else {
".".to_string()
}
)
}
2 changes: 1 addition & 1 deletion src/preview/dir_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl DirView {
self.page_height = Some(page_height);
}
let dp = DisplayableTree {
app_state: None,
display_context: None,
tree: &self.tree,
skin: &disc.panel_skin.styles,
ext_colors: &disc.con.ext_colors,
Expand Down
27 changes: 3 additions & 24 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! functions printing a tree or a path
use crate::path::relativize_path;

use {
crate::{
app::*,
Expand All @@ -10,11 +12,7 @@ use {
tree::Tree,
},
crokey::crossterm::tty::IsTty,
pathdiff,
std::{
io::{self, stdout},
path::Path,
},
std::io::{self, stdout},
};

fn print_string(string: String, _con: &AppContext) -> io::Result<CmdResult> {
Expand Down Expand Up @@ -42,25 +40,6 @@ pub fn print_paths(sel_info: SelInfo, con: &AppContext) -> io::Result<CmdResult>
print_string(string, con)
}

fn relativize_path(path: &Path, con: &AppContext) -> io::Result<String> {
let relative_path = match pathdiff::diff_paths(path, &con.initial_root) {
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Cannot relativize {path:?}"), // does this happen ? how ?
));
}
Some(p) => p,
};
Ok(
if relative_path.components().next().is_some() {
relative_path.to_string_lossy().to_string()
} else {
".".to_string()
}
)
}

pub fn print_relative_paths(sel_info: SelInfo, con: &AppContext) -> io::Result<CmdResult> {
let string = match sel_info {
SelInfo::None => "".to_string(),
Expand Down
12 changes: 11 additions & 1 deletion src/tree/tree_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub struct TreeOptions {
pub show_device_id: bool,
pub show_root_fs: bool, // show information relative to the fs of the root
pub trim_root: bool, // whether to cut out direct children of root
/// Show root directory relative to the program's current working directory.
pub relative_root: bool,
pub show_permissions: bool, // show classic rwx unix permissions (only on unix)
pub respect_git_ignore: bool, // hide files as requested by .gitignore ?
pub filter_by_git_status: bool, // only show files whose git status is not nul
Expand Down Expand Up @@ -51,6 +53,7 @@ impl TreeOptions {
show_device_id: self.show_device_id,
show_root_fs: self.show_root_fs,
trim_root: self.trim_root,
relative_root: self.relative_root,
pattern: InputPattern::none(),
date_time_format: self.date_time_format,
sort: self.sort,
Expand Down Expand Up @@ -85,7 +88,7 @@ impl TreeOptions {
let conf_matches = Args::try_parse_from(vec!["broot", &flags_args])
.map_err(|_| ConfError::InvalidDefaultFlags {
flags: default_flags.to_string()
})?;
})?;
self.apply_launch_args(&conf_matches);
}
if let Some(b) = config.show_selection_mark {
Expand All @@ -97,6 +100,9 @@ impl TreeOptions {
if let Some(b) = config.show_matching_characters_on_path_searches {
self.show_matching_characters_on_path_searches = b;
}
if let Some(b) = config.root_relative_path {
self.relative_root = b;
}
self.cols_order = config
.cols_order
.as_ref()
Expand Down Expand Up @@ -183,6 +189,9 @@ impl TreeOptions {
} else if cli_args.no_trim_root {
self.trim_root = false;
}
if cli_args.root_relative_path {
self.relative_root = true;
}
}
}

Expand All @@ -199,6 +208,7 @@ impl Default for TreeOptions {
show_device_id: false,
show_root_fs: false,
trim_root: false,
relative_root: false,
show_permissions: false,
respect_git_ignore: true,
filter_by_git_status: false,
Expand Down
1 change: 1 addition & 0 deletions src/verb/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Internals! {
toggle_git_file_info: "toggle display of git file information" false,
toggle_git_status: "toggle showing only files relevant for git status" false,
toggle_root_fs: "toggle showing filesystem info on top" false,
toggle_root_relative: "toggle displaying root path relative to launch dir" false,
toggle_hidden: "toggle showing hidden files" false,
toggle_perm: "toggle showing file permissions" false,
toggle_sizes: "toggle showing sizes" false,
Expand Down
1 change: 1 addition & 0 deletions src/verb/verb_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl VerbStore {
self.add_internal(toggle_git_file_info).with_shortcut("gf");
self.add_internal(toggle_git_status).with_shortcut("gs");
self.add_internal(toggle_root_fs).with_shortcut("rfs");
self.add_internal(toggle_root_relative);
self.add_internal(toggle_hidden)
.with_key(key!(alt-h))
.with_shortcut("h");
Expand Down
13 changes: 13 additions & 0 deletions website/docs/conf_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,16 @@ show_matching_characters_on_path_searches = false
which gives this:

![not shown](img/subpath-match-not-shown.png)

## Show the root path relative to the launch directory

If you'd prefer the root path (the top line in the tree display) to be
displayed relative to the directory `broot` is launched in (not the root
directory passed on the command line), you can use this option:

```Hjson
root-relative-path: true
```
```TOML
root_relative_path = true
```
1 change: 1 addition & 0 deletions website/docs/conf_verbs.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ invocation | default key | default shortcut | behavior / details
:toggle_stage | <kbd>ctrl</kbd><kbd>g</kbd> | - | add or remove selection to staging area
:toggle_staging_area | - | tsa | open/close the staging area panel
:toggle_trim_root | - | - | toggle trimming of top level files in tree display
:toggle_root_relative | - | - | toggle display of root path relative to launch dir or absolute
:unstage | <kbd>-</kbd> | - | remove selection from staging area
:up_tree | - | - | focus the parent of the current root

Expand Down

0 comments on commit 4be8d8b

Please sign in to comment.