Skip to content

Commit

Permalink
Don't color each path component separately
Browse files Browse the repository at this point in the history
It can be expensive to color each path component separately, requiring a
stat() call on each component.  For deep hierarchies this can result in
quadratic overhead.  Instead, just color the path up to the basename as
a directory.

Fixes #720.
  • Loading branch information
tavianator committed Sep 17, 2021
1 parent 9b69aa8 commit 70c3529
Showing 1 changed file with 30 additions and 10 deletions.
40 changes: 30 additions & 10 deletions src/output.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::borrow::Cow;
use std::io::{self, StdoutLock, Write};
use std::path::Path;
use std::process;

use lscolors::{LsColors, Style};
use lscolors::{Indicator, LsColors, Style};

use crate::error::print_error;
use crate::exit_codes::ExitCode;
Expand Down Expand Up @@ -45,21 +46,40 @@ fn print_entry_colorized(
config: &Options,
ls_colors: &LsColors,
) -> io::Result<()> {
let default_style = ansi_term::Style::default();
// Split the path between the parent and the last component
let mut offset = 0;
let path_str = path.to_string_lossy();

// Traverse the path and colorize each component
for (component, style) in ls_colors.style_for_path_components(path) {
let style = style
.map(Style::to_ansi_term_style)
.unwrap_or(default_style);
if let Some(parent) = path.parent() {
offset = parent.to_string_lossy().len();
for c in path_str[offset..].chars() {
if std::path::is_separator(c) {
offset += c.len_utf8();
} else {
break;
}
}
}

let mut path_string = component.to_string_lossy();
if offset > 0 {
let mut parent_str = Cow::from(&path_str[..offset]);
if let Some(ref separator) = config.path_separator {
*path_string.to_mut() = replace_path_separator(&path_string, separator);
*parent_str.to_mut() = replace_path_separator(&parent_str, separator);
}
write!(stdout, "{}", style.paint(path_string))?;

let style = ls_colors
.style_for_indicator(Indicator::Directory)
.map(Style::to_ansi_term_style)
.unwrap_or_default();
write!(stdout, "{}", style.paint(parent_str))?;
}

let style = ls_colors
.style_for_path(path)
.map(Style::to_ansi_term_style)
.unwrap_or_default();
write!(stdout, "{}", style.paint(&path_str[offset..]))?;

if config.null_separator {
write!(stdout, "\0")
} else {
Expand Down

0 comments on commit 70c3529

Please sign in to comment.