Move icon generation into file name module

This commit makes adding icons to file names something that the file name renderer does, rather than something that each individual view does. This is now possible thanks to the previous commit a1869f2, which moved the option to do this into the same module. The repeated code has been removed.

It happens to fix a bug where the width of each column was being incorrectly calculated for the grid-details view, making lines slightly too long for the terminal because the icon wasn't being taken into account.
This commit is contained in:
Benjamin Sago 2020-10-24 18:03:36 +01:00
parent b05f18cae0
commit f1e3e7c7ff
7 changed files with 43 additions and 90 deletions

View File

@ -65,7 +65,7 @@ use std::mem::MaybeUninit;
use std::path::PathBuf; use std::path::PathBuf;
use std::vec::IntoIter as VecIntoIter; use std::vec::IntoIter as VecIntoIter;
use ansi_term::{ANSIGenericString, Style}; use ansi_term::Style;
use scoped_threadpool::Pool; use scoped_threadpool::Pool;
use crate::fs::{Dir, File}; use crate::fs::{Dir, File};
@ -74,7 +74,6 @@ use crate::fs::feature::git::GitCache;
use crate::fs::feature::xattr::{Attribute, FileAttributes}; use crate::fs::feature::xattr::{Attribute, FileAttributes};
use crate::fs::filter::FileFilter; use crate::fs::filter::FileFilter;
use crate::output::cell::TextCell; use crate::output::cell::TextCell;
use crate::output::icons::painted_icon;
use crate::output::file_name::Options as FileStyle; use crate::output::file_name::Options as FileStyle;
use crate::output::table::{Table, Options as TableOptions, Row as TableRow}; use crate::output::table::{Table, Options as TableOptions, Row as TableRow};
use crate::output::tree::{TreeTrunk, TreeParams, TreeDepth}; use crate::output::tree::{TreeTrunk, TreeParams, TreeDepth};
@ -137,7 +136,6 @@ struct Egg<'a> {
errors: Vec<(io::Error, Option<PathBuf>)>, errors: Vec<(io::Error, Option<PathBuf>)>,
dir: Option<Dir>, dir: Option<Dir>,
file: &'a File<'a>, file: &'a File<'a>,
icon: Option<String>,
} }
impl<'a> AsRef<File<'a>> for Egg<'a> { impl<'a> AsRef<File<'a>> for Egg<'a> {
@ -266,10 +264,7 @@ impl<'a> Render<'a> {
} }
}; };
let icon = if self.file_style.icons { Some(painted_icon(file, self.theme)) } let egg = Egg { table_row, xattrs, errors, dir, file };
else { None };
let egg = Egg { table_row, xattrs, errors, dir, file, icon };
unsafe { std::ptr::write(file_eggs.lock().unwrap()[idx].as_mut_ptr(), egg) } unsafe { std::ptr::write(file_eggs.lock().unwrap()[idx].as_mut_ptr(), egg) }
}); });
} }
@ -287,22 +282,15 @@ impl<'a> Render<'a> {
t.add_widths(row); t.add_widths(row);
} }
let mut name_cell = TextCell::default(); let file_name = self.file_style.for_file(egg.file, self.theme)
if let Some(icon) = egg.icon {
name_cell.push(ANSIGenericString::from(icon), 2)
}
let style = self.file_style.for_file(egg.file, self.theme)
.with_link_paths() .with_link_paths()
.paint() .paint()
.promote(); .promote();
name_cell.append(style);
let row = Row { let row = Row {
tree: tree_params, tree: tree_params,
cells: egg.table_row, cells: egg.table_row,
name: name_cell, name: file_name,
}; };
rows.push(row); rows.push(row);

View File

@ -6,6 +6,7 @@ use ansi_term::{ANSIString, Style};
use crate::fs::{File, FileTarget}; use crate::fs::{File, FileTarget};
use crate::output::cell::TextCellContents; use crate::output::cell::TextCellContents;
use crate::output::escape; use crate::output::escape;
use crate::output::icons::{icon_for_file, iconify_style};
use crate::output::render::FiletypeColours; use crate::output::render::FiletypeColours;
@ -111,6 +112,14 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
pub fn paint(&self) -> TextCellContents { pub fn paint(&self) -> TextCellContents {
let mut bits = Vec::new(); let mut bits = Vec::new();
if self.options.icons {
let style = iconify_style(self.colours.colour_file(self.file));
let file_icon = icon_for_file(self.file).to_string();
bits.push(style.paint(file_icon));
bits.push(Style::default().paint(" "));
}
if self.file.parent_dir.is_none() { if self.file.parent_dir.is_none() {
if let Some(parent) = self.file.path.parent() { if let Some(parent) = self.file.path.parent() {
self.add_parent_bits(&mut bits, parent); self.add_parent_bits(&mut bits, parent);

View File

@ -3,9 +3,7 @@ use std::io::{self, Write};
use term_grid as tg; use term_grid as tg;
use crate::fs::File; use crate::fs::File;
use crate::output::cell::DisplayWidth;
use crate::output::file_name::Options as FileStyle; use crate::output::file_name::Options as FileStyle;
use crate::output::icons::painted_icon;
use crate::theme::Theme; use crate::theme::Theme;
@ -40,17 +38,11 @@ impl<'a> Render<'a> {
grid.reserve(self.files.len()); grid.reserve(self.files.len());
for file in &self.files { for file in &self.files {
let icon = if self.file_style.icons { Some(painted_icon(file, self.theme)) }
else { None };
let filename = self.file_style.for_file(file, self.theme).paint(); let filename = self.file_style.for_file(file, self.theme).paint();
let width = if self.file_style.icons { DisplayWidth::from(2) + filename.width() }
else { filename.width() };
grid.add(tg::Cell { grid.add(tg::Cell {
contents: format!("{}{}", &icon.unwrap_or_default(), filename.strings()), contents: filename.strings().to_string(),
width: *width, width: *filename.width(),
}); });
} }
@ -62,10 +54,6 @@ impl<'a> Render<'a> {
// This isnt *quite* the same as the lines view, which also // This isnt *quite* the same as the lines view, which also
// displays full link paths. // displays full link paths.
for file in &self.files { for file in &self.files {
if self.file_style.icons {
write!(w, "{}", painted_icon(file, self.theme))?;
}
let name_cell = self.file_style.for_file(file, self.theme).paint(); let name_cell = self.file_style.for_file(file, self.theme).paint();
writeln!(w, "{}", name_cell.strings())?; writeln!(w, "{}", name_cell.strings())?;
} }

View File

@ -2,7 +2,7 @@
use std::io::{self, Write}; use std::io::{self, Write};
use ansi_term::{ANSIGenericString, ANSIStrings}; use ansi_term::ANSIStrings;
use term_grid as grid; use term_grid as grid;
use crate::fs::{Dir, File}; use crate::fs::{Dir, File};
@ -13,7 +13,6 @@ use crate::output::cell::TextCell;
use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender}; use crate::output::details::{Options as DetailsOptions, Row as DetailsRow, Render as DetailsRender};
use crate::output::file_name::Options as FileStyle; use crate::output::file_name::Options as FileStyle;
use crate::output::grid::Options as GridOptions; use crate::output::grid::Options as GridOptions;
use crate::output::icons::painted_icon;
use crate::output::table::{Table, Row as TableRow, Options as TableOptions}; use crate::output::table::{Table, Row as TableRow, Options as TableOptions};
use crate::output::tree::{TreeParams, TreeDepth}; use crate::output::tree::{TreeParams, TreeDepth};
use crate::theme::Theme; use crate::theme::Theme;
@ -155,18 +154,7 @@ impl<'a> Render<'a> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let file_names = self.files.iter() let file_names = self.files.iter()
.map(|file| { .map(|file| self.file_style.for_file(file, self.theme).paint().promote())
if self.file_style.icons {
let mut icon_cell = TextCell::default();
icon_cell.push(ANSIGenericString::from(painted_icon(file, self.theme)), 2);
let file_cell = self.file_style.for_file(file, self.theme).paint().promote();
icon_cell.append(file_cell);
icon_cell
}
else {
self.file_style.for_file(file, self.theme).paint().promote()
}
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender); let mut last_working_table = self.make_grid(1, options, &file_names, rows.clone(), &drender);

View File

@ -2,7 +2,6 @@ use ansi_term::Style;
use crate::fs::File; use crate::fs::File;
use crate::info::filetype::FileExtensions; use crate::info::filetype::FileExtensions;
use crate::theme::Theme;
pub trait FileIcon { pub trait FileIcon {
@ -28,33 +27,24 @@ impl Icons {
} }
pub fn painted_icon(file: &File<'_>, theme: &Theme) -> String { pub fn iconify_style<'a>(style: Style) -> Style {
use crate::output::file_name::Colours; if style.is_underline {
match style.foreground {
let file_icon = icon(file).to_string();
let c = theme.colour_file(file);
// Remove underline from icon
let painted =
if c.is_underline {
match c.foreground {
Some(color) => { Some(color) => {
Style::from(color).paint(file_icon).to_string() Style::from(color)
} }
None => { None => {
Style::default().paint(file_icon).to_string() Style::default()
} }
} }
} }
else { else {
c.paint(file_icon).to_string() style
}; }
format!("{} ", painted)
} }
fn icon(file: &File<'_>) -> char { pub fn icon_for_file(file: &File<'_>) -> char {
let extensions = Box::new(FileExtensions); let extensions = Box::new(FileExtensions);
if file.points_to_directory() { if file.points_to_directory() {

View File

@ -1,11 +1,10 @@
use std::io::{self, Write}; use std::io::{self, Write};
use ansi_term::{ANSIStrings, ANSIGenericString}; use ansi_term::ANSIStrings;
use crate::fs::File; use crate::fs::File;
use crate::output::cell::{TextCell, TextCellContents}; use crate::output::cell::TextCellContents;
use crate::output::file_name::{Options as FileStyle}; use crate::output::file_name::{Options as FileStyle};
use crate::output::icons::painted_icon;
use crate::theme::Theme; use crate::theme::Theme;
@ -20,18 +19,8 @@ impl<'a> Render<'a> {
pub fn render<W: Write>(&self, w: &mut W) -> io::Result<()> { pub fn render<W: Write>(&self, w: &mut W) -> io::Result<()> {
for file in &self.files { for file in &self.files {
let name_cell = self.render_file(file); let name_cell = self.render_file(file);
if self.file_style.icons {
// Create a TextCell for the icon then append the text to it
let mut cell = TextCell::default();
let icon = painted_icon(file, self.theme);
cell.push(ANSIGenericString::from(icon), 2);
cell.append(name_cell.promote());
writeln!(w, "{}", ANSIStrings(&cell))?;
}
else {
writeln!(w, "{}", ANSIStrings(&name_cell))?; writeln!(w, "{}", ANSIStrings(&name_cell))?;
} }
}
Ok(()) Ok(())
} }

View File

@ -1,6 +1,7 @@
 1_bytes  3_bytes  5_bytes  7_bytes  9_bytes  11_bytes  13_bytes  1_bytes  3_KiB  5_MiB  8_bytes  10_KiB  12_MiB
 1_KiB  3_KiB  5_KiB  7_KiB  9_KiB  11_KiB  13_KiB  1_KiB  3_MiB  6_bytes  8_KiB  10_MiB  13_bytes
 1_MiB  3_MiB  5_MiB  7_MiB  9_MiB  11_MiB  13_MiB  1_MiB  4_bytes  6_KiB  8_MiB  11_bytes  13_KiB
 2_bytes  4_bytes  6_bytes  8_bytes  10_bytes  12_bytes  2_bytes  4_KiB  6_MiB  9_bytes  11_KiB  13_MiB
 2_KiB  4_KiB  6_KiB  8_KiB  10_KiB  12_KiB  2_KiB  4_MiB  7_bytes  9_KiB  11_MiB
 2_MiB  4_MiB  6_MiB  8_MiB  10_MiB  12_MiB  2_MiB  5_bytes  7_KiB  9_MiB  12_bytes
 3_bytes  5_KiB  7_MiB  10_bytes  12_KiB