Merge branch 'better-icons'

This commit is contained in:
Benjamin Sago 2020-10-24 19:51:34 +01:00
commit bfcefd3f82
23 changed files with 423 additions and 354 deletions

View File

@ -208,6 +208,12 @@ Limits the grid-details view (`exa --grid --long`) so its only activate
With widescreen displays, its possible for the grid to look very wide and sparse, on just one or two lines with none of the columns lining up. With widescreen displays, its possible for the grid to look very wide and sparse, on just one or two lines with none of the columns lining up.
By specifying a minimum number of rows, you can only use the view if its going to be worth using. By specifying a minimum number of rows, you can only use the view if its going to be worth using.
## `EXA_ICON_SPACING`
Specifies the number of spaces to print between an icon (see the `--icons` option) and its file name.
Different terminals display icons differently, as they usually take up more than one character width on screen, so theres no “standard” number of spaces that exa can use to separate an icon from text. One space may place the icon too close to the text, and two spaces may place it too far away. So the choice is left up to the user to configure depending on their terminal emulator.
## `LS_COLORS`, `EXA_COLORS` ## `LS_COLORS`, `EXA_COLORS`
Specifies the colour scheme used to highlight files based on their name and kind, as well as highlighting metadata and parts of the UI. Specifies the colour scheme used to highlight files based on their name and kind, as well as highlighting metadata and parts of the UI.

View File

@ -1,15 +1,16 @@
use crate::options::{flags, OptionsError}; use crate::options::{flags, OptionsError};
use crate::options::parser::MatchedFlags; use crate::options::parser::MatchedFlags;
use crate::options::vars::{self, Vars};
use crate::output::file_name::{Options, Classify}; use crate::output::file_name::{Options, Classify, ShowIcons};
impl Options { impl Options {
pub fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> { pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
let classify = Classify::deduce(matches)?; let classify = Classify::deduce(matches)?;
let icons = matches.has(&flags::ICONS)?; let show_icons = ShowIcons::deduce(matches, vars)?;
Ok(Self { classify, icons }) Ok(Self { classify, show_icons })
} }
} }
@ -21,3 +22,20 @@ impl Classify {
else { Ok(Self::JustFilenames) } else { Ok(Self::JustFilenames) }
} }
} }
impl ShowIcons {
pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
if ! matches.has(&flags::ICONS)? {
Ok(Self::Off)
}
else if let Some(columns) = vars.get(vars::EXA_ICON_SPACING).and_then(|s| s.into_string().ok()) {
match columns.parse() {
Ok(width) => Ok(Self::On(width)),
Err(e) => Err(OptionsError::FailedParse(e)),
}
}
else {
Ok(Self::On(1))
}
}
}

View File

@ -39,6 +39,12 @@ pub static EXA_DEBUG: &str = "EXA_DEBUG";
/// number of rows of output. /// number of rows of output.
pub static EXA_GRID_ROWS: &str = "EXA_GRID_ROWS"; pub static EXA_GRID_ROWS: &str = "EXA_GRID_ROWS";
/// Environment variable used to specify how many spaces to print between an
/// icon and its file name. Different terminals display icons differently,
/// with 1 space bringing them too close together or 2 spaces putting them too
/// far apart, so this may be necessary depending on how they are shown.
pub static EXA_ICON_SPACING: &str = "EXA_ICON_SPACING";
/// Mockable wrapper for `std::env::var_os`. /// Mockable wrapper for `std::env::var_os`.
pub trait Vars { pub trait Vars {

View File

@ -12,7 +12,7 @@ impl View {
pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> { pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
let mode = Mode::deduce(matches, vars)?; let mode = Mode::deduce(matches, vars)?;
let width = TerminalWidth::deduce(vars)?; let width = TerminalWidth::deduce(vars)?;
let file_style = FileStyle::deduce(matches)?; let file_style = FileStyle::deduce(matches, vars)?;
Ok(Self { mode, width, file_style }) Ok(Self { mode, width, file_style })
} }
} }

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 { .with_link_paths()
name_cell.push(ANSIGenericString::from(icon), 2) .paint()
} .promote();
let style = self.file_style.for_file(egg.file, self.theme)
.with_link_paths()
.paint()
.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;
@ -17,7 +18,7 @@ pub struct Options {
pub classify: Classify, pub classify: Classify,
/// Whether to prepend icon characters before file names. /// Whether to prepend icon characters before file names.
pub icons: bool, pub show_icons: ShowIcons,
} }
impl Options { impl Options {
@ -71,6 +72,19 @@ impl Default for Classify {
} }
/// Whether and how to show icons.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum ShowIcons {
/// Dont show icons at all.
Off,
/// Show icons next to file names, with the given number of spaces between
/// the icon and the file name.
On(u32),
}
/// A **file name** holds all the information necessary to display the name /// A **file name** holds all the information necessary to display the name
/// of the given file. This is used in all of the views. /// of the given file. This is used in all of the views.
pub struct FileName<'a, 'dir, C> { pub struct FileName<'a, 'dir, C> {
@ -111,6 +125,19 @@ 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 let ShowIcons::On(spaces_count) = self.options.show_icons {
let style = iconify_style(self.style());
let file_icon = icon_for_file(self.file).to_string();
bits.push(style.paint(file_icon));
match spaces_count {
1 => bits.push(Style::default().paint(" ")),
2 => bits.push(Style::default().paint(" ")),
n => bits.push(Style::default().paint(spaces(n))),
}
}
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);
@ -143,7 +170,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
if ! target.name.is_empty() { if ! target.name.is_empty() {
let target_options = Options { let target_options = Options {
classify: Classify::JustFilenames, classify: Classify::JustFilenames,
icons: false, show_icons: ShowIcons::Off,
}; };
let target = FileName { let target = FileName {
@ -311,3 +338,9 @@ pub trait Colours: FiletypeColours {
fn colour_file(&self, file: &File<'_>) -> Style; fn colour_file(&self, file: &File<'_>) -> Style;
} }
/// Generate a string made of `n` spaces.
fn spaces(width: u32) -> String {
(0 .. width).into_iter().map(|_| ' ').collect()
}

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,22 @@ impl Icons {
} }
pub fn painted_icon(file: &File<'_>, theme: &Theme) -> String { /// Converts the style used to paint a file name into the style that should be
use crate::output::file_name::Colours; /// used to paint an icon.
///
let file_icon = icon(file).to_string(); /// - The background colour should be preferred to the foreground colour, as
let c = theme.colour_file(file); /// if one is set, its the more “obvious” colour choice.
/// - If neither is set, just use the default style.
// Remove underline from icon /// - Attributes such as bold or underline should not be used to paint the
let painted = /// icon, as they can make it look weird.
if c.is_underline { pub fn iconify_style<'a>(style: Style) -> Style {
match c.foreground { style.background.or(style.foreground)
Some(color) => { .map(Style::from)
Style::from(color).paint(file_icon).to_string() .unwrap_or_default()
}
None => {
Style::default().paint(file_icon).to_string()
}
}
}
else {
c.paint(file_icon).to_string()
};
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,17 +19,7 @@ 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 { writeln!(w, "{}", ANSIStrings(&name_cell))?;
// 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))?;
}
} }
Ok(()) Ok(())

View File

@ -77,3 +77,38 @@ stdout = { file = "outputs/links_oneline_icons.ansitxt" }
stderr = { empty = true } stderr = { empty = true }
status = 0 status = 0
tags = [ 'oneline', 'icons' ] tags = [ 'oneline', 'icons' ]
# icon spacing tests
[[cmd]]
name = "EXA_ICON_SPACING=0 exa -1 --icons puts no spaces between icons and file names"
shell = "EXA_ICON_SPACING=0 exa -1 --icons /testcases/links"
stdout = { file = "outputs/links_oneline_icons_width0.ansitxt" }
stderr = { empty = true }
status = 0
tags = [ 'env', 'oneline', 'icons' ]
[[cmd]]
name = "EXA_ICON_SPACING=1 exa -1 --icons puts one space between icons and file names"
shell = "EXA_ICON_SPACING=1 exa -1 --icons /testcases/links"
stdout = { file = "outputs/links_oneline_icons.ansitxt" } # same as the default
stderr = { empty = true }
status = 0
tags = [ 'env', 'oneline', 'icons' ]
[[cmd]]
name = "EXA_ICON_SPACING=2 exa -1 --icons puts two spaces between icons and file names"
shell = "EXA_ICON_SPACING=2 exa -1 --icons /testcases/links"
stdout = { file = "outputs/links_oneline_icons_width2.ansitxt" }
stderr = { empty = true }
status = 0
tags = [ 'env', 'oneline', 'icons' ]
[[cmd]]
name = "EXA_ICON_SPACING=3 exa -1 --icons puts three spaces between icons and file names"
shell = "EXA_ICON_SPACING=3 exa -1 --icons /testcases/links"
stdout = { file = "outputs/links_oneline_icons_width3.ansitxt" }
stderr = { empty = true }
status = 0
tags = [ 'env', 'oneline', 'icons' ]

View File

@ -1,26 +1,26 @@
 #SAVEFILE#  #SAVEFILE#
 backup~  backup~
 compiled.class  compiled.class
compiled.coffee  compiled.coffee
 compiled.js  compiled.js
 compiled.o  compiled.o
 compressed.deb  compressed.deb
 compressed.tar.gz  compressed.tar.gz
 compressed.tar.xz  compressed.tar.xz
 compressed.tgz  compressed.tgz
 compressed.txz  compressed.txz
 COMPRESSED.ZIP  COMPRESSED.ZIP
 crypto.asc  crypto.asc
 crypto.signature  crypto.signature
 document.pdf  document.pdf
 DOCUMENT.XLSX  DOCUMENT.XLSX
 file.tmp  file.tmp
 IMAGE.PNG  IMAGE.PNG
 image.svg  image.svg
 lossless.flac  lossless.flac
 lossless.wav  lossless.wav
 Makefile  Makefile
 music.mp3  music.mp3
 MUSIC.OGG  MUSIC.OGG
 VIDEO.AVI  VIDEO.AVI
 video.wmv  video.wmv

View File

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

View File

@ -1,39 +1,39 @@
.rw-r--r-- 1 cassowary  1 Jan 12:34  1_bytes .rw-r--r-- 1 cassowary  1 Jan 12:34  1_bytes
.rw-r--r-- 1.0k cassowary  1 Jan 12:34  1_KiB .rw-r--r-- 1.0k cassowary  1 Jan 12:34  1_KiB
.rw-r--r-- 1.0M cassowary  1 Jan 12:34  1_MiB .rw-r--r-- 1.0M cassowary  1 Jan 12:34  1_MiB
.rw-r--r-- 2 cassowary  1 Jan 12:34  2_bytes .rw-r--r-- 2 cassowary  1 Jan 12:34  2_bytes
.rw-r--r-- 2.0k cassowary  1 Jan 12:34  2_KiB .rw-r--r-- 2.0k cassowary  1 Jan 12:34  2_KiB
.rw-r--r-- 2.1M cassowary  1 Jan 12:34  2_MiB .rw-r--r-- 2.1M cassowary  1 Jan 12:34  2_MiB
.rw-r--r-- 3 cassowary  1 Jan 12:34  3_bytes .rw-r--r-- 3 cassowary  1 Jan 12:34  3_bytes
.rw-r--r-- 3.1k cassowary  1 Jan 12:34  3_KiB .rw-r--r-- 3.1k cassowary  1 Jan 12:34  3_KiB
.rw-r--r-- 3.1M cassowary  1 Jan 12:34  3_MiB .rw-r--r-- 3.1M cassowary  1 Jan 12:34  3_MiB
.rw-r--r-- 4 cassowary  1 Jan 12:34  4_bytes .rw-r--r-- 4 cassowary  1 Jan 12:34  4_bytes
.rw-r--r-- 4.1k cassowary  1 Jan 12:34  4_KiB .rw-r--r-- 4.1k cassowary  1 Jan 12:34  4_KiB
.rw-r--r-- 4.2M cassowary  1 Jan 12:34  4_MiB .rw-r--r-- 4.2M cassowary  1 Jan 12:34  4_MiB
.rw-r--r-- 5 cassowary  1 Jan 12:34  5_bytes .rw-r--r-- 5 cassowary  1 Jan 12:34  5_bytes
.rw-r--r-- 5.1k cassowary  1 Jan 12:34  5_KiB .rw-r--r-- 5.1k cassowary  1 Jan 12:34  5_KiB
.rw-r--r-- 5.2M cassowary  1 Jan 12:34  5_MiB .rw-r--r-- 5.2M cassowary  1 Jan 12:34  5_MiB
.rw-r--r-- 6 cassowary  1 Jan 12:34  6_bytes .rw-r--r-- 6 cassowary  1 Jan 12:34  6_bytes
.rw-r--r-- 6.1k cassowary  1 Jan 12:34  6_KiB .rw-r--r-- 6.1k cassowary  1 Jan 12:34  6_KiB
.rw-r--r-- 6.3M cassowary  1 Jan 12:34  6_MiB .rw-r--r-- 6.3M cassowary  1 Jan 12:34  6_MiB
.rw-r--r-- 7 cassowary  1 Jan 12:34  7_bytes .rw-r--r-- 7 cassowary  1 Jan 12:34  7_bytes
.rw-r--r-- 7.2k cassowary  1 Jan 12:34  7_KiB .rw-r--r-- 7.2k cassowary  1 Jan 12:34  7_KiB
.rw-r--r-- 7.3M cassowary  1 Jan 12:34  7_MiB .rw-r--r-- 7.3M cassowary  1 Jan 12:34  7_MiB
.rw-r--r-- 8 cassowary  1 Jan 12:34  8_bytes .rw-r--r-- 8 cassowary  1 Jan 12:34  8_bytes
.rw-r--r-- 8.2k cassowary  1 Jan 12:34  8_KiB .rw-r--r-- 8.2k cassowary  1 Jan 12:34  8_KiB
.rw-r--r-- 8.4M cassowary  1 Jan 12:34  8_MiB .rw-r--r-- 8.4M cassowary  1 Jan 12:34  8_MiB
.rw-r--r-- 9 cassowary  1 Jan 12:34  9_bytes .rw-r--r-- 9 cassowary  1 Jan 12:34  9_bytes
.rw-r--r-- 9.2k cassowary  1 Jan 12:34  9_KiB .rw-r--r-- 9.2k cassowary  1 Jan 12:34  9_KiB
.rw-r--r-- 9.4M cassowary  1 Jan 12:34  9_MiB .rw-r--r-- 9.4M cassowary  1 Jan 12:34  9_MiB
.rw-r--r-- 10 cassowary  1 Jan 12:34  10_bytes .rw-r--r-- 10 cassowary  1 Jan 12:34  10_bytes
.rw-r--r-- 10k cassowary  1 Jan 12:34  10_KiB .rw-r--r-- 10k cassowary  1 Jan 12:34  10_KiB
.rw-r--r-- 10M cassowary  1 Jan 12:34  10_MiB .rw-r--r-- 10M cassowary  1 Jan 12:34  10_MiB
.rw-r--r-- 11 cassowary  1 Jan 12:34  11_bytes .rw-r--r-- 11 cassowary  1 Jan 12:34  11_bytes
.rw-r--r-- 11k cassowary  1 Jan 12:34  11_KiB .rw-r--r-- 11k cassowary  1 Jan 12:34  11_KiB
.rw-r--r-- 11M cassowary  1 Jan 12:34  11_MiB .rw-r--r-- 11M cassowary  1 Jan 12:34  11_MiB
.rw-r--r-- 12 cassowary  1 Jan 12:34  12_bytes .rw-r--r-- 12 cassowary  1 Jan 12:34  12_bytes
.rw-r--r-- 12k cassowary  1 Jan 12:34  12_KiB .rw-r--r-- 12k cassowary  1 Jan 12:34  12_KiB
.rw-r--r-- 12M cassowary  1 Jan 12:34  12_MiB .rw-r--r-- 12M cassowary  1 Jan 12:34  12_MiB
.rw-r--r-- 13 cassowary  1 Jan 12:34  13_bytes .rw-r--r-- 13 cassowary  1 Jan 12:34  13_bytes
.rw-r--r-- 13k cassowary  1 Jan 12:34  13_KiB .rw-r--r-- 13k cassowary  1 Jan 12:34  13_KiB
.rw-r--r-- 13M cassowary  1 Jan 12:34  13_MiB .rw-r--r-- 13M cassowary  1 Jan 12:34  13_MiB

View File

@ -1,39 +1,39 @@
.rw-r--r-- 1 cassowary  1 Jan 12:34  1_bytes .rw-r--r-- 1 cassowary  1 Jan 12:34  1_bytes
.rw-r--r-- 1.0k cassowary  1 Jan 12:34  1_KiB .rw-r--r-- 1.0k cassowary  1 Jan 12:34  1_KiB
.rw-r--r-- 1.0M cassowary  1 Jan 12:34  1_MiB .rw-r--r-- 1.0M cassowary  1 Jan 12:34  1_MiB
.rw-r--r-- 2 cassowary  1 Jan 12:34  2_bytes .rw-r--r-- 2 cassowary  1 Jan 12:34  2_bytes
.rw-r--r-- 2.0k cassowary  1 Jan 12:34  2_KiB .rw-r--r-- 2.0k cassowary  1 Jan 12:34  2_KiB
.rw-r--r-- 2.1M cassowary  1 Jan 12:34  2_MiB .rw-r--r-- 2.1M cassowary  1 Jan 12:34  2_MiB
.rw-r--r-- 3 cassowary  1 Jan 12:34  3_bytes .rw-r--r-- 3 cassowary  1 Jan 12:34  3_bytes
.rw-r--r-- 3.1k cassowary  1 Jan 12:34  3_KiB .rw-r--r-- 3.1k cassowary  1 Jan 12:34  3_KiB
.rw-r--r-- 3.1M cassowary  1 Jan 12:34  3_MiB .rw-r--r-- 3.1M cassowary  1 Jan 12:34  3_MiB
.rw-r--r-- 4 cassowary  1 Jan 12:34  4_bytes .rw-r--r-- 4 cassowary  1 Jan 12:34  4_bytes
.rw-r--r-- 4.1k cassowary  1 Jan 12:34  4_KiB .rw-r--r-- 4.1k cassowary  1 Jan 12:34  4_KiB
.rw-r--r-- 4.2M cassowary  1 Jan 12:34  4_MiB .rw-r--r-- 4.2M cassowary  1 Jan 12:34  4_MiB
.rw-r--r-- 5 cassowary  1 Jan 12:34  5_bytes .rw-r--r-- 5 cassowary  1 Jan 12:34  5_bytes
.rw-r--r-- 5.1k cassowary  1 Jan 12:34  5_KiB .rw-r--r-- 5.1k cassowary  1 Jan 12:34  5_KiB
.rw-r--r-- 5.2M cassowary  1 Jan 12:34  5_MiB .rw-r--r-- 5.2M cassowary  1 Jan 12:34  5_MiB
.rw-r--r-- 6 cassowary  1 Jan 12:34  6_bytes .rw-r--r-- 6 cassowary  1 Jan 12:34  6_bytes
.rw-r--r-- 6.1k cassowary  1 Jan 12:34  6_KiB .rw-r--r-- 6.1k cassowary  1 Jan 12:34  6_KiB
.rw-r--r-- 6.3M cassowary  1 Jan 12:34  6_MiB .rw-r--r-- 6.3M cassowary  1 Jan 12:34  6_MiB
.rw-r--r-- 7 cassowary  1 Jan 12:34  7_bytes .rw-r--r-- 7 cassowary  1 Jan 12:34  7_bytes
.rw-r--r-- 7.2k cassowary  1 Jan 12:34  7_KiB .rw-r--r-- 7.2k cassowary  1 Jan 12:34  7_KiB
.rw-r--r-- 7.3M cassowary  1 Jan 12:34  7_MiB .rw-r--r-- 7.3M cassowary  1 Jan 12:34  7_MiB
.rw-r--r-- 8 cassowary  1 Jan 12:34  8_bytes .rw-r--r-- 8 cassowary  1 Jan 12:34  8_bytes
.rw-r--r-- 8.2k cassowary  1 Jan 12:34  8_KiB .rw-r--r-- 8.2k cassowary  1 Jan 12:34  8_KiB
.rw-r--r-- 8.4M cassowary  1 Jan 12:34  8_MiB .rw-r--r-- 8.4M cassowary  1 Jan 12:34  8_MiB
.rw-r--r-- 9 cassowary  1 Jan 12:34  9_bytes .rw-r--r-- 9 cassowary  1 Jan 12:34  9_bytes
.rw-r--r-- 9.2k cassowary  1 Jan 12:34  9_KiB .rw-r--r-- 9.2k cassowary  1 Jan 12:34  9_KiB
.rw-r--r-- 9.4M cassowary  1 Jan 12:34  9_MiB .rw-r--r-- 9.4M cassowary  1 Jan 12:34  9_MiB
.rw-r--r-- 10 cassowary  1 Jan 12:34  10_bytes .rw-r--r-- 10 cassowary  1 Jan 12:34  10_bytes
.rw-r--r-- 10k cassowary  1 Jan 12:34  10_KiB .rw-r--r-- 10k cassowary  1 Jan 12:34  10_KiB
.rw-r--r-- 10M cassowary  1 Jan 12:34  10_MiB .rw-r--r-- 10M cassowary  1 Jan 12:34  10_MiB
.rw-r--r-- 11 cassowary  1 Jan 12:34  11_bytes .rw-r--r-- 11 cassowary  1 Jan 12:34  11_bytes
.rw-r--r-- 11k cassowary  1 Jan 12:34  11_KiB .rw-r--r-- 11k cassowary  1 Jan 12:34  11_KiB
.rw-r--r-- 11M cassowary  1 Jan 12:34  11_MiB .rw-r--r-- 11M cassowary  1 Jan 12:34  11_MiB
.rw-r--r-- 12 cassowary  1 Jan 12:34  12_bytes .rw-r--r-- 12 cassowary  1 Jan 12:34  12_bytes
.rw-r--r-- 12k cassowary  1 Jan 12:34  12_KiB .rw-r--r-- 12k cassowary  1 Jan 12:34  12_KiB
.rw-r--r-- 12M cassowary  1 Jan 12:34  12_MiB .rw-r--r-- 12M cassowary  1 Jan 12:34  12_MiB
.rw-r--r-- 13 cassowary  1 Jan 12:34  13_bytes .rw-r--r-- 13 cassowary  1 Jan 12:34  13_bytes
.rw-r--r-- 13k cassowary  1 Jan 12:34  13_KiB .rw-r--r-- 13k cassowary  1 Jan 12:34  13_KiB
.rw-r--r-- 13M cassowary  1 Jan 12:34  13_MiB .rw-r--r-- 13M cassowary  1 Jan 12:34  13_MiB

View File

@ -1,40 +1,40 @@
drwxrwxr-x - vagrant 18 Oct 00:18 /testcases/files drwxrwxr-x - vagrant 18 Oct 00:18  /testcases/files
.rw-r--r-- 1 cassowary  1 Jan 12:34 ├──  1_bytes .rw-r--r-- 1 cassowary  1 Jan 12:34 ├──  1_bytes
.rw-r--r-- 1.0k cassowary  1 Jan 12:34 ├──  1_KiB .rw-r--r-- 1.0k cassowary  1 Jan 12:34 ├──  1_KiB
.rw-r--r-- 1.0M cassowary  1 Jan 12:34 ├──  1_MiB .rw-r--r-- 1.0M cassowary  1 Jan 12:34 ├──  1_MiB
.rw-r--r-- 2 cassowary  1 Jan 12:34 ├──  2_bytes .rw-r--r-- 2 cassowary  1 Jan 12:34 ├──  2_bytes
.rw-r--r-- 2.0k cassowary  1 Jan 12:34 ├──  2_KiB .rw-r--r-- 2.0k cassowary  1 Jan 12:34 ├──  2_KiB
.rw-r--r-- 2.1M cassowary  1 Jan 12:34 ├──  2_MiB .rw-r--r-- 2.1M cassowary  1 Jan 12:34 ├──  2_MiB
.rw-r--r-- 3 cassowary  1 Jan 12:34 ├──  3_bytes .rw-r--r-- 3 cassowary  1 Jan 12:34 ├──  3_bytes
.rw-r--r-- 3.1k cassowary  1 Jan 12:34 ├──  3_KiB .rw-r--r-- 3.1k cassowary  1 Jan 12:34 ├──  3_KiB
.rw-r--r-- 3.1M cassowary  1 Jan 12:34 ├──  3_MiB .rw-r--r-- 3.1M cassowary  1 Jan 12:34 ├──  3_MiB
.rw-r--r-- 4 cassowary  1 Jan 12:34 ├──  4_bytes .rw-r--r-- 4 cassowary  1 Jan 12:34 ├──  4_bytes
.rw-r--r-- 4.1k cassowary  1 Jan 12:34 ├──  4_KiB .rw-r--r-- 4.1k cassowary  1 Jan 12:34 ├──  4_KiB
.rw-r--r-- 4.2M cassowary  1 Jan 12:34 ├──  4_MiB .rw-r--r-- 4.2M cassowary  1 Jan 12:34 ├──  4_MiB
.rw-r--r-- 5 cassowary  1 Jan 12:34 ├──  5_bytes .rw-r--r-- 5 cassowary  1 Jan 12:34 ├──  5_bytes
.rw-r--r-- 5.1k cassowary  1 Jan 12:34 ├──  5_KiB .rw-r--r-- 5.1k cassowary  1 Jan 12:34 ├──  5_KiB
.rw-r--r-- 5.2M cassowary  1 Jan 12:34 ├──  5_MiB .rw-r--r-- 5.2M cassowary  1 Jan 12:34 ├──  5_MiB
.rw-r--r-- 6 cassowary  1 Jan 12:34 ├──  6_bytes .rw-r--r-- 6 cassowary  1 Jan 12:34 ├──  6_bytes
.rw-r--r-- 6.1k cassowary  1 Jan 12:34 ├──  6_KiB .rw-r--r-- 6.1k cassowary  1 Jan 12:34 ├──  6_KiB
.rw-r--r-- 6.3M cassowary  1 Jan 12:34 ├──  6_MiB .rw-r--r-- 6.3M cassowary  1 Jan 12:34 ├──  6_MiB
.rw-r--r-- 7 cassowary  1 Jan 12:34 ├──  7_bytes .rw-r--r-- 7 cassowary  1 Jan 12:34 ├──  7_bytes
.rw-r--r-- 7.2k cassowary  1 Jan 12:34 ├──  7_KiB .rw-r--r-- 7.2k cassowary  1 Jan 12:34 ├──  7_KiB
.rw-r--r-- 7.3M cassowary  1 Jan 12:34 ├──  7_MiB .rw-r--r-- 7.3M cassowary  1 Jan 12:34 ├──  7_MiB
.rw-r--r-- 8 cassowary  1 Jan 12:34 ├──  8_bytes .rw-r--r-- 8 cassowary  1 Jan 12:34 ├──  8_bytes
.rw-r--r-- 8.2k cassowary  1 Jan 12:34 ├──  8_KiB .rw-r--r-- 8.2k cassowary  1 Jan 12:34 ├──  8_KiB
.rw-r--r-- 8.4M cassowary  1 Jan 12:34 ├──  8_MiB .rw-r--r-- 8.4M cassowary  1 Jan 12:34 ├──  8_MiB
.rw-r--r-- 9 cassowary  1 Jan 12:34 ├──  9_bytes .rw-r--r-- 9 cassowary  1 Jan 12:34 ├──  9_bytes
.rw-r--r-- 9.2k cassowary  1 Jan 12:34 ├──  9_KiB .rw-r--r-- 9.2k cassowary  1 Jan 12:34 ├──  9_KiB
.rw-r--r-- 9.4M cassowary  1 Jan 12:34 ├──  9_MiB .rw-r--r-- 9.4M cassowary  1 Jan 12:34 ├──  9_MiB
.rw-r--r-- 10 cassowary  1 Jan 12:34 ├──  10_bytes .rw-r--r-- 10 cassowary  1 Jan 12:34 ├──  10_bytes
.rw-r--r-- 10k cassowary  1 Jan 12:34 ├──  10_KiB .rw-r--r-- 10k cassowary  1 Jan 12:34 ├──  10_KiB
.rw-r--r-- 10M cassowary  1 Jan 12:34 ├──  10_MiB .rw-r--r-- 10M cassowary  1 Jan 12:34 ├──  10_MiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 ├──  11_bytes .rw-r--r-- 11 cassowary  1 Jan 12:34 ├──  11_bytes
.rw-r--r-- 11k cassowary  1 Jan 12:34 ├──  11_KiB .rw-r--r-- 11k cassowary  1 Jan 12:34 ├──  11_KiB
.rw-r--r-- 11M cassowary  1 Jan 12:34 ├──  11_MiB .rw-r--r-- 11M cassowary  1 Jan 12:34 ├──  11_MiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 ├──  12_bytes .rw-r--r-- 12 cassowary  1 Jan 12:34 ├──  12_bytes
.rw-r--r-- 12k cassowary  1 Jan 12:34 ├──  12_KiB .rw-r--r-- 12k cassowary  1 Jan 12:34 ├──  12_KiB
.rw-r--r-- 12M cassowary  1 Jan 12:34 ├──  12_MiB .rw-r--r-- 12M cassowary  1 Jan 12:34 ├──  12_MiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 ├──  13_bytes .rw-r--r-- 13 cassowary  1 Jan 12:34 ├──  13_bytes
.rw-r--r-- 13k cassowary  1 Jan 12:34 ├──  13_KiB .rw-r--r-- 13k cassowary  1 Jan 12:34 ├──  13_KiB
.rw-r--r-- 13M cassowary  1 Jan 12:34 └──  13_MiB .rw-r--r-- 13M cassowary  1 Jan 12:34 └──  13_MiB

View File

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

View File

@ -1,40 +1,40 @@
/testcases/files  /testcases/files
├──  1_bytes ├──  1_bytes
├──  1_KiB ├──  1_KiB
├──  1_MiB ├──  1_MiB
├──  2_bytes ├──  2_bytes
├──  2_KiB ├──  2_KiB
├──  2_MiB ├──  2_MiB
├──  3_bytes ├──  3_bytes
├──  3_KiB ├──  3_KiB
├──  3_MiB ├──  3_MiB
├──  4_bytes ├──  4_bytes
├──  4_KiB ├──  4_KiB
├──  4_MiB ├──  4_MiB
├──  5_bytes ├──  5_bytes
├──  5_KiB ├──  5_KiB
├──  5_MiB ├──  5_MiB
├──  6_bytes ├──  6_bytes
├──  6_KiB ├──  6_KiB
├──  6_MiB ├──  6_MiB
├──  7_bytes ├──  7_bytes
├──  7_KiB ├──  7_KiB
├──  7_MiB ├──  7_MiB
├──  8_bytes ├──  8_bytes
├──  8_KiB ├──  8_KiB
├──  8_MiB ├──  8_MiB
├──  9_bytes ├──  9_bytes
├──  9_KiB ├──  9_KiB
├──  9_MiB ├──  9_MiB
├──  10_bytes ├──  10_bytes
├──  10_KiB ├──  10_KiB
├──  10_MiB ├──  10_MiB
├──  11_bytes ├──  11_bytes
├──  11_KiB ├──  11_KiB
├──  11_MiB ├──  11_MiB
├──  12_bytes ├──  12_bytes
├──  12_KiB ├──  12_KiB
├──  12_MiB ├──  12_MiB
├──  13_bytes ├──  13_bytes
├──  13_KiB ├──  13_KiB
└──  13_MiB └──  13_MiB

View File

@ -1,10 +1,10 @@
broken -> nowhere  broken -> nowhere
current_dir -> .  current_dir -> .
forbidden -> /proc/1/root  forbidden -> /proc/1/root
itself -> itself  itself -> itself
parent_dir -> ..  parent_dir -> ..
root -> /  root -> /
some_file  some_file
some_file_absolute -> /testcases/links/some_file  some_file_absolute -> /testcases/links/some_file
some_file_relative -> some_file  some_file_relative -> some_file
usr -> /usr  usr -> /usr

View File

@ -0,0 +1,10 @@
broken -> nowhere
current_dir -> .
forbidden -> /proc/1/root
itself -> itself
parent_dir -> ..
root -> /
some_file
some_file_absolute -> /testcases/links/some_file
some_file_relative -> some_file
usr -> /usr

View File

@ -0,0 +1,10 @@
 broken -> nowhere
 current_dir -> .
 forbidden -> /proc/1/root
 itself -> itself
 parent_dir -> ..
 root -> /
 some_file
 some_file_absolute -> /testcases/links/some_file
 some_file_relative -> some_file
 usr -> /usr

View File

@ -0,0 +1,10 @@
 broken -> nowhere
 current_dir -> .
 forbidden -> /proc/1/root
 itself -> itself
 parent_dir -> ..
 root -> /
 some_file
 some_file_absolute -> /testcases/links/some_file
 some_file_relative -> some_file
 usr -> /usr

View File

@ -1,22 +1,22 @@
000  000
001  001
002  002
004  004
010  010
020  020
040  040
100  100
200  200
400  400
644  644
755  755
777  777
1000  1000
1001  1001
2000  2000
2010  2010
4000  4000
4100  4100
7666  7666
7777  7777
forbidden-directory  forbidden-directory