Measure, rather than calculating, cell widths

exa deals with cells and widths a lot: the items in a grid need to be aligned according to their *contents’* widths, rather than the length of their strings, which often included ANSI escape characters. As an optimisation, it used to calculate this separately based on the filename, and dealing with any extra characters (such as the classify ones) in that function too.

Recently, though, file names have become a lot more complicated. Classification added zero to one extra characters, and now with escaped control characters in file names, it’s not so easy to calculate the display width of a filename.

This commit removes the function that calculated the width, in favour of building the output string (it’s going to be displayed anyway) and just getting the width of what it displays instead.
This commit is contained in:
Benjamin Sago 2017-05-01 14:11:16 +01:00
parent 28fce347ff
commit a53c268c54
3 changed files with 15 additions and 21 deletions

View File

@ -5,8 +5,6 @@ use std::ops::{Add, Deref, DerefMut};
use ansi_term::{Style, ANSIString, ANSIStrings};
use unicode_width::UnicodeWidthStr;
use fs::File;
/// An individual cell that holds text in a table, used in the details and
/// lines views to store ANSI-terminal-formatted data before it is printed.
@ -161,6 +159,11 @@ impl TextCellContents {
pub fn strings(&self) -> ANSIStrings {
ANSIStrings(&self.0)
}
pub fn width(&self) -> DisplayWidth {
let foo = self.0.iter().map(|anstr| anstr.chars().count()).sum();
DisplayWidth(foo)
}
}
@ -180,19 +183,6 @@ impl TextCellContents {
#[derive(PartialEq, Debug, Clone, Copy, Default)]
pub struct DisplayWidth(usize);
impl DisplayWidth {
pub fn from_file(file: &File, classify: bool) -> DisplayWidth {
let name_width = *DisplayWidth::from(&*file.name);
if classify {
if file.is_executable_file() || file.is_directory() ||
file.is_pipe() || file.is_link() || file.is_socket() {
return DisplayWidth(name_width + 1);
}
}
DisplayWidth(name_width)
}
}
impl<'a> From<&'a str> for DisplayWidth {
fn from(input: &'a str) -> DisplayWidth {
DisplayWidth(UnicodeWidthStr::width(input))

View File

@ -306,7 +306,9 @@ impl Details {
for (index, egg) in file_eggs.into_iter().enumerate() {
let mut files = Vec::new();
let mut errors = egg.errors;
let mut width = DisplayWidth::from_file(&egg.file, self.classify);
let filename = filename(&egg.file, &self.colours, true, self.classify);
let mut width = filename.width();
if egg.file.dir.is_none() {
if let Some(parent) = egg.file.path.parent() {
@ -315,7 +317,7 @@ impl Details {
}
let name = TextCell {
contents: filename(&egg.file, &self.colours, true, self.classify),
contents: filename,
width: width,
};
@ -456,7 +458,8 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
}
pub fn filename_cell(&self, file: File, links: bool) -> TextCell {
let mut width = DisplayWidth::from_file(&file, self.opts.classify);
let filename = filename(&file, &self.opts.colours, links, self.opts.classify);
let mut width = filename.width();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
@ -465,7 +468,7 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
}
TextCell {
contents: filename(&file, &self.opts.colours, links, self.opts.classify),
contents: filename,
width: width,
}
}

View File

@ -29,8 +29,9 @@ impl Grid {
grid.reserve(files.len());
for file in files.iter() {
let mut width = DisplayWidth::from_file(file, self.classify);
let filename = filename(file, &self.colours, false, self.classify);
let mut width = filename.width();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
@ -38,7 +39,7 @@ impl Grid {
}
grid.add(grid::Cell {
contents: filename(file, &self.colours, false, self.classify).strings().to_string(),
contents: filename.strings().to_string(),
width: *width,
});
}