From 7a4cde75ebeb166edf4f026ef485f1c54b7375b8 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Tue, 6 Apr 2021 15:18:37 +0200 Subject: [PATCH 01/21] =?UTF-8?q?Use=20thousand=20separators=20again=20and?= =?UTF-8?q?=20fix=20alignement=20when=20it=E2=80=99s=20not=20ASCII?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/output/render/size.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/output/render/size.rs b/src/output/render/size.rs index 7f1acb7..94f751b 100644 --- a/src/output/render/size.rs +++ b/src/output/render/size.rs @@ -36,20 +36,20 @@ impl f::Size { }; let (prefix, n) = match result { - NumberPrefix::Standalone(b) => return TextCell::paint(colours.size(None), b.to_string()), + NumberPrefix::Standalone(b) => return TextCell::paint(colours.size(None), numerics.format_int(b)), NumberPrefix::Prefixed(p, n) => (p, n), }; let symbol = prefix.symbol(); - let decimal_to_diplay = if n < 10_f64 { 1 } else { 0 }; - let number = numerics.format_float(n, decimal_to_diplay); + let number = if n < 10_f64 { + numerics.format_float(n, 1) + } else { + numerics.format_int(n.round() as isize) + }; - // The numbers and symbols are guaranteed to be written in ASCII, so - // we can skip the display width calculation. - let width = DisplayWidth::from(number.len() + symbol.len()); - TextCell { - width, + // symbol is guaranteed to be ASCII since unit prefixes are hardcoded. + width: DisplayWidth::from(&*number) + symbol.len(), contents: vec![ colours.size(Some(prefix)).paint(number), colours.unit(Some(prefix)).paint(symbol), From c729e226da0a4696ccee47d62f6627a406d07f6f Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 16:16:05 +0200 Subject: [PATCH 02/21] Fix EXA_GRID_ROWS not working in some cases --- src/output/grid_details.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index df8e53c..35ff023 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -174,22 +174,21 @@ impl<'a> Render<'a> { }; if the_grid_fits { - if column_count == file_names.len() { - return Some((grid, column_count)); - } else { - last_working_grid = grid; - } - } else { - // If we’ve figured out how many columns can fit in the user’s - // terminal, and it turns out there aren’t enough rows to - // make it worthwhile, then just resort to the lines view. + last_working_grid = grid; + } + + if !the_grid_fits || column_count == file_names.len() { + let last_column_count = if the_grid_fits { column_count } else { column_count - 1 }; + // If we’ve figured out how many columns can fit in the user’s terminal, + // and it turns out there aren’t enough rows to make it worthwhile + // (according to EXA_GRID_ROWS), then just resort to the lines view. if let RowThreshold::MinimumRows(thresh) = self.row_threshold { - if last_working_grid.fit_into_columns(column_count - 1).row_count() < thresh { + if last_working_grid.fit_into_columns(last_column_count).row_count() < thresh { return None; } } - return Some((last_working_grid, column_count - 1)); + return Some((last_working_grid, last_column_count)); } } From 050931e48fefacf57badfaeda9aecc98685c6787 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 16:29:31 +0200 Subject: [PATCH 03/21] Fix a typo in test descriptions --- xtests/grid-details-view.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xtests/grid-details-view.toml b/xtests/grid-details-view.toml index a76ba15..7289956 100644 --- a/xtests/grid-details-view.toml +++ b/xtests/grid-details-view.toml @@ -81,7 +81,7 @@ tags = [ 'env', 'long', 'grid' ] # check if exa is using the minimum number of columns with headers [[cmd]] -name = "‘COLUMN=200 exa -lGh’ with one file don’t produce extra columns even if there place for more" +name = "‘COLUMNS=200 exa -lGh’ with one file don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_bytes" environment = { COLUMNS = "200" } stdout = { file = "outputs/files_paths_long_grid_header_1file.ansitxt" } @@ -90,7 +90,7 @@ status = 0 tags = [ 'env', 'long', 'grid' ] [[cmd]] -name = "‘COLUMN=200 exa -lGh’ with several files don’t produce extra columns even if there place for more" +name = "‘COLUMNS=200 exa -lGh’ with several files don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_{bytes,KiB}" environment = { COLUMNS = "200" } stdout = { file = "outputs/files_paths_long_grid_header_2files.ansitxt" } From a0457f9c87bf9035e9daa19477ccaf7375ffcada Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 17:24:33 +0200 Subject: [PATCH 04/21] Fix misleading name of some test files --- xtests/grid-details-view.toml | 4 ++-- ...der_1file.ansitxt => files_long_grid_header_1file.ansitxt} | 0 ...r_2files.ansitxt => files_long_grid_header_2files.ansitxt} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename xtests/outputs/{files_paths_long_grid_header_1file.ansitxt => files_long_grid_header_1file.ansitxt} (100%) rename xtests/outputs/{files_paths_long_grid_header_2files.ansitxt => files_long_grid_header_2files.ansitxt} (100%) diff --git a/xtests/grid-details-view.toml b/xtests/grid-details-view.toml index 7289956..cfe5d37 100644 --- a/xtests/grid-details-view.toml +++ b/xtests/grid-details-view.toml @@ -84,7 +84,7 @@ tags = [ 'env', 'long', 'grid' ] name = "‘COLUMNS=200 exa -lGh’ with one file don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_bytes" environment = { COLUMNS = "200" } -stdout = { file = "outputs/files_paths_long_grid_header_1file.ansitxt" } +stdout = { file = "outputs/files_long_grid_header_1file.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'env', 'long', 'grid' ] @@ -93,7 +93,7 @@ tags = [ 'env', 'long', 'grid' ] name = "‘COLUMNS=200 exa -lGh’ with several files don’t produce extra columns even if there place for more" shell = "exa -lGh /testcases/files/10_{bytes,KiB}" environment = { COLUMNS = "200" } -stdout = { file = "outputs/files_paths_long_grid_header_2files.ansitxt" } +stdout = { file = "outputs/files_long_grid_header_2files.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'env', 'long', 'grid' ] diff --git a/xtests/outputs/files_paths_long_grid_header_1file.ansitxt b/xtests/outputs/files_long_grid_header_1file.ansitxt similarity index 100% rename from xtests/outputs/files_paths_long_grid_header_1file.ansitxt rename to xtests/outputs/files_long_grid_header_1file.ansitxt diff --git a/xtests/outputs/files_paths_long_grid_header_2files.ansitxt b/xtests/outputs/files_long_grid_header_2files.ansitxt similarity index 100% rename from xtests/outputs/files_paths_long_grid_header_2files.ansitxt rename to xtests/outputs/files_long_grid_header_2files.ansitxt From beaf56108685e5dc3f73e9ed3da3576ed399d857 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 17:40:03 +0200 Subject: [PATCH 05/21] Add xtests for EXA_GRID_ROWS --- xtests/grid-details-view.toml | 30 +++++++++++++++++++ ...s_long_grid_exa_grid_rows_2_3files.ansitxt | 3 ++ ..._long_grid_exa_grid_rows_5_15files.ansitxt | 5 ++++ ..._long_grid_exa_grid_rows_6_15files.ansitxt | 15 ++++++++++ 4 files changed, 53 insertions(+) create mode 100644 xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt create mode 100644 xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt create mode 100644 xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt diff --git a/xtests/grid-details-view.toml b/xtests/grid-details-view.toml index cfe5d37..3488acf 100644 --- a/xtests/grid-details-view.toml +++ b/xtests/grid-details-view.toml @@ -97,3 +97,33 @@ stdout = { file = "outputs/files_long_grid_header_2files.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'env', 'long', 'grid' ] + + +# check if EXA_GRID_ROWS is working + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=2 exa -lG’ with three files produces a grid details of 1 column" +shell = "exa -lG /testcases/files/1_*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "2" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=5 exa -lG’ with 15 files produces a grid details of 3 columns" +shell = "exa -lG /testcases/files/1*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "5" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] + +[[cmd]] +name = "‘COLUMNS=200 EXA_GRID_ROWS=6 exa -lG’ with 15 files produces a grid details of 1 column" +shell = "exa -lG /testcases/files/1*" +environment = { COLUMNS = "200", EXA_GRID_ROWS = "6" } +stdout = { file = "outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'env', 'long', 'grid' ] diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt new file mode 100644 index 0000000..1a50d75 --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_2_3files.ansitxt @@ -0,0 +1,3 @@ +.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt new file mode 100644 index 0000000..e02074e --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_5_15files.ansitxt @@ -0,0 +1,5 @@ +.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB +.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 14M cassowary  1 Jan 12:34 /testcases/files/13_MiB +.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB diff --git a/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt b/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt new file mode 100644 index 0000000..98ff7d1 --- /dev/null +++ b/xtests/outputs/files_long_grid_exa_grid_rows_6_15files.ansitxt @@ -0,0 +1,15 @@ +.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes +.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB +.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB +.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes +.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB +.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB +.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes +.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB +.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/11_MiB +.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes +.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB +.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/12_MiB +.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes +.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB +.rw-r--r-- 14M cassowary  1 Jan 12:34 /testcases/files/13_MiB From 3a8005c8404c28701f3c6cabf3883d2d946ff01f Mon Sep 17 00:00:00 2001 From: ariasuni Date: Thu, 31 Dec 2020 21:18:18 +0100 Subject: [PATCH 06/21] Fix month name not following locale when date is in current year --- src/output/time.rs | 72 +++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 52 deletions(-) diff --git a/src/output/time.rs b/src/output/time.rs index 79b3554..cb18c54 100644 --- a/src/output/time.rs +++ b/src/output/time.rs @@ -2,7 +2,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; -use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Month}; +use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece}; use datetime::fmt::DateFormat; use lazy_static::lazy_static; @@ -75,40 +75,25 @@ impl TimeFormat { #[allow(trivial_numeric_casts)] fn default_local(time: SystemTime) -> String { let date = LocalDateTime::at(systemtime_epoch(time)); - - if date.year() == *CURRENT_YEAR { - format!("{:2} {} {:02}:{:02}", - date.day(), month_to_abbrev(date.month()), - date.hour(), date.minute()) - } - else { - let date_format = match *MAXIMUM_MONTH_WIDTH { - 4 => &*FOUR_WIDE_DATE_TIME, - 5 => &*FIVE_WIDE_DATE_TIME, - _ => &*OTHER_WIDE_DATE_TIME, - }; - - date_format.format(&date, &*LOCALE) - } + let date_format = get_dateformat(&date); + date_format.format(&date, &*LOCALE) } #[allow(trivial_numeric_casts)] fn default_zoned(time: SystemTime, zone: &TimeZone) -> String { let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time))); + let date_format = get_dateformat(&date); + date_format.format(&date, &*LOCALE) +} - if date.year() == *CURRENT_YEAR { - format!("{:2} {} {:02}:{:02}", - date.day(), month_to_abbrev(date.month()), - date.hour(), date.minute()) - } - else { - let date_format = match *MAXIMUM_MONTH_WIDTH { - 4 => &*FOUR_WIDE_DATE_YEAR, - 5 => &*FIVE_WIDE_DATE_YEAR, - _ => &*OTHER_WIDE_DATE_YEAR, - }; - - date_format.format(&date, &*LOCALE) +fn get_dateformat(date: &LocalDateTime) -> &'static DateFormat<'static> { + match (is_recent(&date), *MAXIMUM_MONTH_WIDTH) { + (true, 4) => &FOUR_WIDE_DATE_TIME, + (true, 5) => &FIVE_WIDE_DATE_TIME, + (true, _) => &OTHER_WIDE_DATE_TIME, + (false, 4) => &FOUR_WIDE_DATE_YEAR, + (false, 5) => &FIVE_WIDE_DATE_YEAR, + (false, _) => &OTHER_WIDE_DATE_YEAR, } } @@ -153,7 +138,7 @@ fn full_zoned(time: SystemTime, zone: &TimeZone) -> String { fn iso_local(time: SystemTime) -> String { let date = LocalDateTime::at(systemtime_epoch(time)); - if is_recent(date) { + if is_recent(&date) { format!("{:02}-{:02} {:02}:{:02}", date.month() as usize, date.day(), date.hour(), date.minute()) @@ -168,7 +153,7 @@ fn iso_local(time: SystemTime) -> String { fn iso_zoned(time: SystemTime, zone: &TimeZone) -> String { let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time))); - if is_recent(date) { + if is_recent(&date) { format!("{:02}-{:02} {:02}:{:02}", date.month() as usize, date.day(), date.hour(), date.minute()) @@ -206,27 +191,10 @@ fn systemtime_nanos(time: SystemTime) -> u32 { }) } -fn is_recent(date: LocalDateTime) -> bool { +fn is_recent(date: &LocalDateTime) -> bool { date.year() == *CURRENT_YEAR } -fn month_to_abbrev(month: Month) -> &'static str { - match month { - Month::January => "Jan", - Month::February => "Feb", - Month::March => "Mar", - Month::April => "Apr", - Month::May => "May", - Month::June => "Jun", - Month::July => "Jul", - Month::August => "Aug", - Month::September => "Sep", - Month::October => "Oct", - Month::November => "Nov", - Month::December => "Dec", - } -} - lazy_static! { @@ -250,15 +218,15 @@ lazy_static! { }; static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {4<:M} {2>:h}:{02>:m}" + "{2>:D} {4<:M} {02>:h}:{02>:m}" ).unwrap(); static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {5<:M} {2>:h}:{02>:m}" + "{2>:D} {5<:M} {02>:h}:{02>:m}" ).unwrap(); static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse( - "{2>:D} {:M} {2>:h}:{02>:m}" + "{2>:D} {:M} {02>:h}:{02>:m}" ).unwrap(); static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse( From f673e018b5fd8a5b06e58f49f973fb6251b0ccee Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 18:46:10 +0200 Subject: [PATCH 07/21] Add a test checking that date of the current year follows locale --- xtests/details-view-dates.toml | 13 ++++++- .../dates_long_currentyear_localefr.ansitxt | 39 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 xtests/outputs/dates_long_currentyear_localefr.ansitxt diff --git a/xtests/details-view-dates.toml b/xtests/details-view-dates.toml index 50c2646..30cefeb 100644 --- a/xtests/details-view-dates.toml +++ b/xtests/details-view-dates.toml @@ -68,7 +68,7 @@ tags = [ 'long', 'time-style' ] [[cmd]] name = "‘exa -l’ using a locale with 4-character-long month abbreviations (‘ja_JP’) sizes the date column correctly" shell = "exa -l /testcases/dates" -environment = { LC_ALL = "ja_JP.UTF-8", LANG = "ja_JP.UTF-8" } +environment = { LC_TIME = "ja_JP.UTF-8", LANG = "ja_JP.UTF-8" } stdout = { file = "outputs/dates_long_localejp.ansitxt" } stderr = { empty = true } status = 0 @@ -77,8 +77,17 @@ tags = [ 'long', 'locales' ] [[cmd]] name = "‘exa -l’ using a locale with 5-character-long month abbreviations (‘fr_FR’) sizes the date column correctly" shell = "exa -l /testcases/dates" -environment = { LC_ALL = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } +environment = { LC_TIME = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } stdout = { file = "outputs/dates_long_localefr.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'locales' ] + +[[cmd]] +name = "‘exa -l’ using a locale (‘fr_FR’) display dates of the current year with localized month name" +shell = "exa -l /testcases/files" +environment = { LC_TIME = "fr_FR.UTF-8", LANG = "fr_FR.UTF-8" } +stdout = { file = "outputs/dates_long_currentyear_localefr.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'locales' ] diff --git a/xtests/outputs/dates_long_currentyear_localefr.ansitxt b/xtests/outputs/dates_long_currentyear_localefr.ansitxt new file mode 100644 index 0000000..728df17 --- /dev/null +++ b/xtests/outputs/dates_long_currentyear_localefr.ansitxt @@ -0,0 +1,39 @@ +.rw-r--r-- 1 cassowary  1 janv. 12:34 1_bytes +.rw-r--r-- 1,0k cassowary  1 janv. 12:34 1_KiB +.rw-r--r-- 1,0M cassowary  1 janv. 12:34 1_MiB +.rw-r--r-- 2 cassowary  1 janv. 12:34 2_bytes +.rw-r--r-- 2,0k cassowary  1 janv. 12:34 2_KiB +.rw-r--r-- 2,1M cassowary  1 janv. 12:34 2_MiB +.rw-r--r-- 3 cassowary  1 janv. 12:34 3_bytes +.rw-r--r-- 3,1k cassowary  1 janv. 12:34 3_KiB +.rw-r--r-- 3,1M cassowary  1 janv. 12:34 3_MiB +.rw-r--r-- 4 cassowary  1 janv. 12:34 4_bytes +.rw-r--r-- 4,1k cassowary  1 janv. 12:34 4_KiB +.rw-r--r-- 4,2M cassowary  1 janv. 12:34 4_MiB +.rw-r--r-- 5 cassowary  1 janv. 12:34 5_bytes +.rw-r--r-- 5,1k cassowary  1 janv. 12:34 5_KiB +.rw-r--r-- 5,2M cassowary  1 janv. 12:34 5_MiB +.rw-r--r-- 6 cassowary  1 janv. 12:34 6_bytes +.rw-r--r-- 6,1k cassowary  1 janv. 12:34 6_KiB +.rw-r--r-- 6,3M cassowary  1 janv. 12:34 6_MiB +.rw-r--r-- 7 cassowary  1 janv. 12:34 7_bytes +.rw-r--r-- 7,2k cassowary  1 janv. 12:34 7_KiB +.rw-r--r-- 7,3M cassowary  1 janv. 12:34 7_MiB +.rw-r--r-- 8 cassowary  1 janv. 12:34 8_bytes +.rw-r--r-- 8,2k cassowary  1 janv. 12:34 8_KiB +.rw-r--r-- 8,4M cassowary  1 janv. 12:34 8_MiB +.rw-r--r-- 9 cassowary  1 janv. 12:34 9_bytes +.rw-r--r-- 9,2k cassowary  1 janv. 12:34 9_KiB +.rw-r--r-- 9,4M cassowary  1 janv. 12:34 9_MiB +.rw-r--r-- 10 cassowary  1 janv. 12:34 10_bytes +.rw-r--r-- 10k cassowary  1 janv. 12:34 10_KiB +.rw-r--r-- 10M cassowary  1 janv. 12:34 10_MiB +.rw-r--r-- 11 cassowary  1 janv. 12:34 11_bytes +.rw-r--r-- 11k cassowary  1 janv. 12:34 11_KiB +.rw-r--r-- 12M cassowary  1 janv. 12:34 11_MiB +.rw-r--r-- 12 cassowary  1 janv. 12:34 12_bytes +.rw-r--r-- 12k cassowary  1 janv. 12:34 12_KiB +.rw-r--r-- 13M cassowary  1 janv. 12:34 12_MiB +.rw-r--r-- 13 cassowary  1 janv. 12:34 13_bytes +.rw-r--r-- 13k cassowary  1 janv. 12:34 13_KiB +.rw-r--r-- 14M cassowary  1 janv. 12:34 13_MiB From 8c10feec515bf88556bf4dad60711e04ee2d96b0 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Fri, 9 Apr 2021 21:30:35 +0200 Subject: [PATCH 08/21] Fix --git deducing ignored state in unintuitive way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes sense to consider that a directory has the aggregated status of all the files under it. The exception is that for the ignored status, it’s more useful and intuitive to consider that it applies to everything under it. - A directory containing an ignored file is no longer considered ignored - A file inside an ignored directory is now considered ignored --- src/fs/feature/git.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/fs/feature/git.rs b/src/fs/feature/git.rs index 61689f2..7372a97 100644 --- a/src/fs/feature/git.rs +++ b/src/fs/feature/git.rs @@ -252,15 +252,21 @@ impl Git { .unwrap_or_default() } - /// Get the combined status for all the files whose paths begin with the - /// path that gets passed in. This is used for getting the status of - /// directories, which don’t really have an ‘official’ status. + /// Get the combined, user-facing status of a file or directory. + /// Statuses are aggregating (for example, a directory is considered + /// modified if any file under it has the status modified), except + /// for ignored which applies to files under (for example, a file is + /// considered ignored if one of its parent directories is ignored) fn dir_status(&self, dir: &Path) -> f::Git { let path = reorient(dir); let s = self.statuses.iter() - .filter(|p| p.0.starts_with(&path)) - .fold(git2::Status::empty(), |a, b| a | b.1); + .filter(|p| if p.1 == git2::Status::IGNORED { + path.starts_with(&p.0) + } else { + p.0.starts_with(&path) + }) + .fold(git2::Status::empty(), |a, b| a | b.1); let staged = index_status(s); let unstaged = working_tree_status(s); From bd4f1448846d1f49f537ad12e2946e0e5280f163 Mon Sep 17 00:00:00 2001 From: ariasuni Date: Sat, 10 Apr 2021 00:53:31 +0200 Subject: [PATCH 09/21] Fix deducing git ignored state for files too, not only directories --- src/fs/feature/git.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/fs/feature/git.rs b/src/fs/feature/git.rs index 7372a97..40bc80d 100644 --- a/src/fs/feature/git.rs +++ b/src/fs/feature/git.rs @@ -242,21 +242,30 @@ impl Git { else { self.file_status(index) } } - /// Get the status for the file at the given path. + /// Get the user-facing status of a file. + /// We check the statuses directly applying to a file, and for the ignored + /// status we check if any of its parents directories is ignored by git. fn file_status(&self, file: &Path) -> f::Git { let path = reorient(file); - self.statuses.iter() - .find(|p| p.0.as_path() == path) - .map(|&(_, s)| f::Git { staged: index_status(s), unstaged: working_tree_status(s) }) - .unwrap_or_default() + let s = self.statuses.iter() + .filter(|p| if p.1 == git2::Status::IGNORED { + path.starts_with(&p.0) + } else { + p.0 == path + }) + .fold(git2::Status::empty(), |a, b| a | b.1); + + let staged = index_status(s); + let unstaged = working_tree_status(s); + f::Git { staged, unstaged } } - /// Get the combined, user-facing status of a file or directory. + /// Get the combined, user-facing status of a directory. /// Statuses are aggregating (for example, a directory is considered - /// modified if any file under it has the status modified), except - /// for ignored which applies to files under (for example, a file is - /// considered ignored if one of its parent directories is ignored) + /// modified if any file under it has the status modified), except for + /// ignored status which applies to files under (for example, a directory + /// is considered ignored if one of its parent directories is ignored). fn dir_status(&self, dir: &Path) -> f::Git { let path = reorient(dir); From f6e66d982d788af4849f40a72a40262091c43b4a Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Fri, 9 Apr 2021 23:59:54 +0100 Subject: [PATCH 10/21] Add tests for device IDs in file size column --- xtests/details-view-filesizes.toml | 11 +++++++++++ xtests/outputs/dev_long.ansitxt | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 xtests/outputs/dev_long.ansitxt diff --git a/xtests/details-view-filesizes.toml b/xtests/details-view-filesizes.toml index 6682d25..a496db6 100644 --- a/xtests/details-view-filesizes.toml +++ b/xtests/details-view-filesizes.toml @@ -61,3 +61,14 @@ stdout = { file = "outputs/files_long_colourscale_bytes.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'colour-scale', 'bytes' ] + +[[cmd]] +name = "‘exa -l’ produces a details table with major and minor device IDs" +shell = "cd /dev; exa -l mem null port zero full random urandom --sort=none" +stdout = { file = "outputs/dev_long.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'dev' ] + +# these particular device IDs should be fixed: +# https://raw.githubusercontent.com/torvalds/linux/master/Documentation/admin-guide/devices.txt diff --git a/xtests/outputs/dev_long.ansitxt b/xtests/outputs/dev_long.ansitxt new file mode 100644 index 0000000..2f394a9 --- /dev/null +++ b/xtests/outputs/dev_long.ansitxt @@ -0,0 +1,7 @@ +crw-r----- 1,1 root  9 Apr 19:35 mem +crw-rw-rw- 1,3 root  9 Apr 19:35 null +crw-r----- 1,4 root  9 Apr 19:35 port +crw-rw-rw- 1,5 root  9 Apr 19:35 zero +crw-rw-rw- 1,7 root  9 Apr 19:35 full +crw-rw-rw- 1,8 root  9 Apr 19:35 random +crw-rw-rw- 1,9 root  9 Apr 19:35 urandom From bfd2644869f479526f3c4688a12d47220b86670d Mon Sep 17 00:00:00 2001 From: ariasuni Date: Sat, 10 Apr 2021 01:06:22 +0200 Subject: [PATCH 11/21] Add xtests for new git ignored status deducing logic --- devtools/dev-create-test-filesystem.sh | 2 ++ xtests/git.toml | 12 ++++++++++-- xtests/outputs/git1+2_long_nested.ansitxt | 2 +- xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt | 2 +- xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt | 1 + xtests/outputs/git2_ignoreds_long_gitignore.ansitxt | 1 + .../git2_ignoreds_long_grid_gitignore.ansitxt | 2 +- .../git2_ignoreds_long_recurse_gitignore.ansitxt | 3 +++ .../git2_ignoreds_long_tree_gitignore.ansitxt | 5 +++-- xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt | 5 +++-- xtests/outputs/git2_long_ignoredcontent.ansitxt | 1 + xtests/outputs/git2_long_ignoreddir.ansitxt | 2 +- xtests/outputs/git2_long_ignorednested.ansitxt | 1 + xtests/outputs/git2_long_multiple.ansitxt | 3 ++- xtests/outputs/git2_long_recurse.ansitxt | 6 +++++- xtests/outputs/git2_long_recurse_gitignore.ansitxt | 3 +++ xtests/outputs/git2_long_tree.ansitxt | 10 ++++++---- xtests/outputs/git2_long_tree_gitignore.ansitxt | 5 +++-- xtests/outputs/git2_tree_gitignore.ansitxt | 5 +++-- 19 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 xtests/outputs/git2_long_ignoredcontent.ansitxt diff --git a/devtools/dev-create-test-filesystem.sh b/devtools/dev-create-test-filesystem.sh index afc19c0..112b569 100755 --- a/devtools/dev-create-test-filesystem.sh +++ b/devtools/dev-create-test-filesystem.sh @@ -300,6 +300,8 @@ touch "ignoreds/music.m4a" mkdir "ignoreds/nested" touch "ignoreds/nested/70s grove.mp3" touch "ignoreds/nested/funky chicken.m4a" +mkdir "ignoreds/nested2" +touch "ignoreds/nested2/ievan polkka.mp3" mkdir "target" touch "target/another ignored file" diff --git a/xtests/git.toml b/xtests/git.toml index d6c0b71..c262e9e 100644 --- a/xtests/git.toml +++ b/xtests/git.toml @@ -101,13 +101,21 @@ status = 0 tags = [ 'long', 'git' ] [[cmd]] -name = "‘exa --git -l’ with an ignored directory argument does not flag the contents as ignored" +name = "‘exa --git -l’ with an ignored directory argument flags the contents as ignored" shell = "exa --git -l /testcases/git2/target" stdout = { file = "outputs/git2_long_ignoreddir.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'git' ] +[[cmd]] +name = "‘exa --git -l --list-dirs’ with a directory argument doesn’t flag it as ignored if only the content is" +shell = "exa --git -l --list-dirs /testcases/git2/ignoreds/nested2" +stdout = { file = "outputs/git2_long_ignoredcontent.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'git' ] + [[cmd]] name = "‘exa --git -l’ with a nested repository argument uses the sub-repository rules" shell = "exa --git -l /testcases/git2/deeply/nested/repository" @@ -155,7 +163,7 @@ status = 0 tags = [ 'long', 'git' ] [[cmd]] -name = "‘exa --git -l’ shows a Git status column for multiple repositories across multiple directories" +name = "‘exa --git -l’ shows a Git status column for multiple repositories across multiple directories 2" shell = "exa --git -l /testcases/{git2/deeply/nested/directory,git/edits,git2/target,git2/deeply,git}" stdout = { file = "outputs/git1+2_long_nested.ansitxt" } stderr = { empty = true } diff --git a/xtests/outputs/git1+2_long_nested.ansitxt b/xtests/outputs/git1+2_long_nested.ansitxt index 186707a..21c8bb3 100644 --- a/xtests/outputs/git1+2_long_nested.ansitxt +++ b/xtests/outputs/git1+2_long_nested.ansitxt @@ -8,7 +8,7 @@ .rw-rw-r-- 20 cassowary  1 Jan 12:34 -M unstaged /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file /testcases/git2/deeply: drwxrwxr-x - cassowary  1 Jan 12:34 -N nested diff --git a/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt index 611f077..2ef959a 100644 --- a/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_grid_gitignore.ansitxt @@ -1 +1 @@ -music.m4a nested +music.m4a nested nested2 diff --git a/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt index 97fab8c..ac6e7f3 100644 --- a/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_lines_gitignore.ansitxt @@ -1,2 +1,3 @@ music.m4a nested +nested2 diff --git a/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt index 83a274f..710d840 100644 --- a/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_gitignore.ansitxt @@ -1,2 +1,3 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 diff --git a/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt index ff8567b..5543504 100644 --- a/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_grid_gitignore.ansitxt @@ -1 +1 @@ -.rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested drwxrwxr-x - cassowary  1 Jan 12:34 nested2 diff --git a/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt index 07df2c6..2ea2167 100644 --- a/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_recurse_gitignore.ansitxt @@ -1,5 +1,8 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 funky chicken.m4a + +/testcases/git2/ignoreds/nested2: diff --git a/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt index 39b5a1f..0c1605e 100644 --- a/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_long_tree_gitignore.ansitxt @@ -1,4 +1,5 @@ drwxrwxr-x - cassowary  1 Jan 12:34 /testcases/git2/ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34 ├── music.m4a -drwxrwxr-x - cassowary  1 Jan 12:34 └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34  └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 └── nested2 diff --git a/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt b/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt index a727537..d9b969a 100644 --- a/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_ignoreds_tree_gitignore.ansitxt @@ -1,4 +1,5 @@ /testcases/git2/ignoreds ├── music.m4a -└── nested - └── funky chicken.m4a +├── nested +│ └── funky chicken.m4a +└── nested2 diff --git a/xtests/outputs/git2_long_ignoredcontent.ansitxt b/xtests/outputs/git2_long_ignoredcontent.ansitxt new file mode 100644 index 0000000..238c3b0 --- /dev/null +++ b/xtests/outputs/git2_long_ignoredcontent.ansitxt @@ -0,0 +1 @@ +drwxrwxr-x - cassowary  1 Jan 12:34 -- /testcases/git2/ignoreds/nested2 diff --git a/xtests/outputs/git2_long_ignoreddir.ansitxt b/xtests/outputs/git2_long_ignoreddir.ansitxt index 6a636a0..fff9898 100644 --- a/xtests/outputs/git2_long_ignoreddir.ansitxt +++ b/xtests/outputs/git2_long_ignoreddir.ansitxt @@ -1 +1 @@ -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_ignorednested.ansitxt b/xtests/outputs/git2_long_ignorednested.ansitxt index d44d313..6e81c36 100644 --- a/xtests/outputs/git2_long_ignorednested.ansitxt +++ b/xtests/outputs/git2_long_ignorednested.ansitxt @@ -1,3 +1,4 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 diff --git a/xtests/outputs/git2_long_multiple.ansitxt b/xtests/outputs/git2_long_multiple.ansitxt index 280e8c9..8654aaf 100644 --- a/xtests/outputs/git2_long_multiple.ansitxt +++ b/xtests/outputs/git2_long_multiple.ansitxt @@ -5,6 +5,7 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_recurse.ansitxt b/xtests/outputs/git2_long_recurse.ansitxt index fcee924..8eb1b3a 100644 --- a/xtests/outputs/git2_long_recurse.ansitxt +++ b/xtests/outputs/git2_long_recurse.ansitxt @@ -20,10 +20,14 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I music.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -N nested +drwxrwxr-x - cassowary  1 Jan 12:34 -- nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I 70s grove.mp3 .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N funky chicken.m4a +/testcases/git2/ignoreds/nested2: +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I ievan polkka.mp3 + /testcases/git2/target: -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -- another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I another ignored file diff --git a/xtests/outputs/git2_long_recurse_gitignore.ansitxt b/xtests/outputs/git2_long_recurse_gitignore.ansitxt index 5f98671..140808e 100644 --- a/xtests/outputs/git2_long_recurse_gitignore.ansitxt +++ b/xtests/outputs/git2_long_recurse_gitignore.ansitxt @@ -18,6 +18,9 @@ /testcases/git2/ignoreds: .rw-rw-r-- 0 cassowary  1 Jan 12:34 music.m4a drwxrwxr-x - cassowary  1 Jan 12:34 nested +drwxrwxr-x - cassowary  1 Jan 12:34 nested2 /testcases/git2/ignoreds/nested: .rw-rw-r-- 0 cassowary  1 Jan 12:34 funky chicken.m4a + +/testcases/git2/ignoreds/nested2: diff --git a/xtests/outputs/git2_long_tree.ansitxt b/xtests/outputs/git2_long_tree.ansitxt index f206507..ca0d2bb 100644 --- a/xtests/outputs/git2_long_tree.ansitxt +++ b/xtests/outputs/git2_long_tree.ansitxt @@ -9,8 +9,10 @@ drwxrwxr-x - cassowary  1 Jan 12:34 -N ├── ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ ├── music.m4a .rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ ├── music.mp3 -drwxrwxr-x - cassowary  1 Jan 12:34 -N │ └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ ├── 70s grove.mp3 -.rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 -N │ ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ │ ├── 70s grove.mp3 +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -N │ │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34 -- │ └── nested2 +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I │ └── ievan polkka.mp3 drwxrwxr-x - cassowary  1 Jan 12:34 -I └── target -.rw-rw-r-- 0 cassowary  1 Jan 12:34 --  └── another ignored file +.rw-rw-r-- 0 cassowary  1 Jan 12:34 -I  └── another ignored file diff --git a/xtests/outputs/git2_long_tree_gitignore.ansitxt b/xtests/outputs/git2_long_tree_gitignore.ansitxt index 3513fea..824b459 100644 --- a/xtests/outputs/git2_long_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_long_tree_gitignore.ansitxt @@ -8,5 +8,6 @@ .rw-rw-r-- 0 cassowary  1 Jan 12:34 │ └── subfile drwxrwxr-x - cassowary  1 Jan 12:34 └── ignoreds .rw-rw-r-- 0 cassowary  1 Jan 12:34  ├── music.m4a -drwxrwxr-x - cassowary  1 Jan 12:34  └── nested -.rw-rw-r-- 0 cassowary  1 Jan 12:34  └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34  ├── nested +.rw-rw-r-- 0 cassowary  1 Jan 12:34  │ └── funky chicken.m4a +drwxrwxr-x - cassowary  1 Jan 12:34  └── nested2 diff --git a/xtests/outputs/git2_tree_gitignore.ansitxt b/xtests/outputs/git2_tree_gitignore.ansitxt index b1a3f2f..053699b 100644 --- a/xtests/outputs/git2_tree_gitignore.ansitxt +++ b/xtests/outputs/git2_tree_gitignore.ansitxt @@ -8,5 +8,6 @@ │ └── subfile └── ignoreds  ├── music.m4a - └── nested - └── funky chicken.m4a + ├── nested + │ └── funky chicken.m4a + └── nested2 From d19d66d57a78e353e4022d51d20fd1b3cda6a407 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 11 Apr 2021 23:34:14 +0100 Subject: [PATCH 12/21] Fix device IDs test so it works every time It inadvertently contained the machine build time, which meant it stopped working once the Vagrant machine was rebuild. --- xtests/details-view-filesizes.toml | 2 +- xtests/outputs/dev_long.ansitxt | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/xtests/details-view-filesizes.toml b/xtests/details-view-filesizes.toml index a496db6..271db54 100644 --- a/xtests/details-view-filesizes.toml +++ b/xtests/details-view-filesizes.toml @@ -64,7 +64,7 @@ tags = [ 'long', 'colour-scale', 'bytes' ] [[cmd]] name = "‘exa -l’ produces a details table with major and minor device IDs" -shell = "cd /dev; exa -l mem null port zero full random urandom --sort=none" +shell = "cd /dev; exa -l mem null port zero full random urandom --sort=none --no-time" stdout = { file = "outputs/dev_long.ansitxt" } stderr = { empty = true } status = 0 diff --git a/xtests/outputs/dev_long.ansitxt b/xtests/outputs/dev_long.ansitxt index 2f394a9..40128c6 100644 --- a/xtests/outputs/dev_long.ansitxt +++ b/xtests/outputs/dev_long.ansitxt @@ -1,7 +1,7 @@ -crw-r----- 1,1 root  9 Apr 19:35 mem -crw-rw-rw- 1,3 root  9 Apr 19:35 null -crw-r----- 1,4 root  9 Apr 19:35 port -crw-rw-rw- 1,5 root  9 Apr 19:35 zero -crw-rw-rw- 1,7 root  9 Apr 19:35 full -crw-rw-rw- 1,8 root  9 Apr 19:35 random -crw-rw-rw- 1,9 root  9 Apr 19:35 urandom +crw-r----- 1,1 root mem +crw-rw-rw- 1,3 root null +crw-r----- 1,4 root port +crw-rw-rw- 1,5 root zero +crw-rw-rw- 1,7 root full +crw-rw-rw- 1,8 root random +crw-rw-rw- 1,9 root urandom From 311c9baf659b4ca084f407a6335e7439e45859db Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 11 Apr 2021 23:34:29 +0100 Subject: [PATCH 13/21] Explain device IDs with a comment --- src/fs/file.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/fs/file.rs b/src/fs/file.rs index 0df998c..b57777d 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -319,10 +319,15 @@ impl<'dir> File<'dir> { f::Size::None } else if self.is_char_device() || self.is_block_device() { - let dev = self.metadata.rdev(); + let device_ids = self.metadata.rdev().to_be_bytes(); + + // In C-land, getting the major and minor device IDs is done with + // preprocessor macros called `major` and `minor` that depend on + // the size of `dev_t`, but we just take the second-to-last and + // last bytes. f::Size::DeviceIDs(f::DeviceIDs { - major: (dev / 256) as u8, - minor: (dev % 256) as u8, + major: device_ids[6], + minor: device_ids[7], }) } else { From 31043462af3c23b528be7d99ebd9bdbeb5031885 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Sun, 11 Apr 2021 23:43:36 +0100 Subject: [PATCH 14/21] Improve help text for -d flag Fixes GH-202. --- man/exa.1.md | 2 +- src/options/help.rs | 2 +- xtests/outputs/help.ansitxt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/exa.1.md b/man/exa.1.md index 6e00a47..c96c477 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -84,7 +84,7 @@ FILTERING AND SORTING OPTIONS Use this twice to also show the ‘`.`’ and ‘`..`’ directories. `-d`, `--list-dirs` -: List directories like regular files. +: List directories as regular files, rather than recursing and listing their contents. `-L`, `--level=DEPTH` : Limit the depth of recursion. diff --git a/src/options/help.rs b/src/options/help.rs index 8f47a73..f3f4009 100644 --- a/src/options/help.rs +++ b/src/options/help.rs @@ -27,7 +27,7 @@ DISPLAY OPTIONS FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files - -d, --list-dirs list directories like regular files + -d, --list-dirs list directories as files; don't list their contents -L, --level DEPTH limit the depth of recursion -r, --reverse reverse the sort order -s, --sort SORT_FIELD which field to sort by diff --git a/xtests/outputs/help.ansitxt b/xtests/outputs/help.ansitxt index 750a66f..4e8cf52 100644 --- a/xtests/outputs/help.ansitxt +++ b/xtests/outputs/help.ansitxt @@ -20,7 +20,7 @@ DISPLAY OPTIONS FILTERING AND SORTING OPTIONS -a, --all show hidden and 'dot' files - -d, --list-dirs list directories like regular files + -d, --list-dirs list directories as files; don't list their contents -L, --level DEPTH limit the depth of recursion -r, --reverse reverse the sort order -s, --sort SORT_FIELD which field to sort by From 550f2d29c2c4e7e1326df4cdcccb7d47d2e81cd5 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 21:42:45 +0100 Subject: [PATCH 15/21] Add context to all option number parse errors Fixes GH-839. --- src/options/dir_action.rs | 22 +++-- src/options/error.rs | 24 +++++- src/options/file_name.rs | 11 ++- src/options/mod.rs | 2 +- src/options/view.rs | 20 +++-- xtests/errors.toml | 82 +++++++++++++++++++ xtests/outputs/error_columns_invalid.ansitxt | 1 + xtests/outputs/error_columns_nines.ansitxt | 1 + .../outputs/error_grid_rows_invalid.ansitxt | 1 + xtests/outputs/error_grid_rows_nines.ansitxt | 1 + .../error_icon_spacing_invalid.ansitxt | 1 + .../outputs/error_icon_spacing_nines.ansitxt | 1 + xtests/outputs/error_level_invalid.ansitxt | 1 + xtests/outputs/error_level_nines.ansitxt | 1 + 14 files changed, 149 insertions(+), 20 deletions(-) create mode 100644 xtests/outputs/error_columns_invalid.ansitxt create mode 100644 xtests/outputs/error_columns_nines.ansitxt create mode 100644 xtests/outputs/error_grid_rows_invalid.ansitxt create mode 100644 xtests/outputs/error_grid_rows_nines.ansitxt create mode 100644 xtests/outputs/error_icon_spacing_invalid.ansitxt create mode 100644 xtests/outputs/error_icon_spacing_nines.ansitxt create mode 100644 xtests/outputs/error_level_invalid.ansitxt create mode 100644 xtests/outputs/error_level_nines.ansitxt diff --git a/src/options/dir_action.rs b/src/options/dir_action.rs index 0cc31fa..e729b86 100644 --- a/src/options/dir_action.rs +++ b/src/options/dir_action.rs @@ -1,7 +1,7 @@ //! Parsing the options for `DirAction`. use crate::options::parser::MatchedFlags; -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::fs::dir_action::{DirAction, RecurseOptions}; @@ -55,17 +55,21 @@ impl RecurseOptions { /// determined earlier. The maximum level should be a number, and this /// will fail with an `Err` if it isn’t. pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result { - let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? { - match level.to_string_lossy().parse() { - Ok(l) => Some(l), - Err(e) => return Err(OptionsError::FailedParse(e)), + if let Some(level) = matches.get(&flags::LEVEL)? { + let arg_str = level.to_string_lossy(); + match arg_str.parse() { + Ok(l) => { + Ok(Self { tree, max_depth: Some(l) }) + } + Err(e) => { + let source = NumberSource::Arg(&flags::LEVEL); + Err(OptionsError::FailedParse(arg_str.to_string(), source, e)) + } } } else { - None - }; - - Ok(Self { tree, max_depth }) + Ok(Self { tree, max_depth: None }) + } } } diff --git a/src/options/error.rs b/src/options/error.rs index 2b724e1..1b1aa87 100644 --- a/src/options/error.rs +++ b/src/options/error.rs @@ -37,18 +37,38 @@ pub enum OptionsError { TreeAllAll, /// A numeric option was given that failed to be parsed as a number. - FailedParse(ParseIntError), + FailedParse(String, NumberSource, ParseIntError), /// A glob ignore was given that failed to be parsed as a pattern. FailedGlobPattern(String), } +/// The source of a string that failed to be parsed as a number. +#[derive(PartialEq, Debug)] +pub enum NumberSource { + + /// It came... from a command-line argument! + Arg(&'static Arg), + + /// It came... from the enviroment! + Env(&'static str), +} + impl From for OptionsError { fn from(error: glob::PatternError) -> Self { Self::FailedGlobPattern(error.to_string()) } } +impl fmt::Display for NumberSource { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Arg(arg) => write!(f, "option {}", arg), + Self::Env(env) => write!(f, "environment variable {}", env), + } + } +} + impl fmt::Display for OptionsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::options::parser::TakesValue; @@ -71,7 +91,7 @@ impl fmt::Display for OptionsError { Self::Useless(a, true, b) => write!(f, "Option {} is useless given option {}", a, b), Self::Useless2(a, b1, b2) => write!(f, "Option {} is useless without options {} or {}", a, b1, b2), Self::TreeAllAll => write!(f, "Option --tree is useless given --all --all"), - Self::FailedParse(ref e) => write!(f, "Failed to parse number: {}", e), + Self::FailedParse(s, n, e) => write!(f, "Value {:?} not valid for {}: {}", s, n, e), Self::FailedGlobPattern(ref e) => write!(f, "Failed to parse glob pattern: {}", e), } } diff --git a/src/options/file_name.rs b/src/options/file_name.rs index 96131bb..2c1db1a 100644 --- a/src/options/file_name.rs +++ b/src/options/file_name.rs @@ -1,4 +1,4 @@ -use crate::options::{flags, OptionsError}; +use crate::options::{flags, OptionsError, NumberSource}; use crate::options::parser::MatchedFlags; use crate::options::vars::{self, Vars}; @@ -30,8 +30,13 @@ impl ShowIcons { } 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)), + Ok(width) => { + Ok(Self::On(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_ICON_SPACING); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/src/options/mod.rs b/src/options/mod.rs index 26e9c81..747213b 100644 --- a/src/options/mod.rs +++ b/src/options/mod.rs @@ -84,7 +84,7 @@ mod theme; mod view; mod error; -pub use self::error::OptionsError; +pub use self::error::{OptionsError, NumberSource}; mod help; use self::help::HelpString; diff --git a/src/options/view.rs b/src/options/view.rs index 6f13c87..6d7abac 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -1,5 +1,5 @@ use crate::fs::feature::xattr; -use crate::options::{flags, OptionsError, Vars}; +use crate::options::{flags, OptionsError, NumberSource, Vars}; use crate::options::parser::MatchedFlags; use crate::output::{View, Mode, TerminalWidth, grid, details}; use crate::output::grid_details::{self, RowThreshold}; @@ -151,8 +151,13 @@ impl TerminalWidth { if let Some(columns) = vars.get(vars::COLUMNS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::Set(width)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(width) => { + Ok(Self::Set(width)) + } + Err(e) => { + let source = NumberSource::Env(vars::COLUMNS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { @@ -168,8 +173,13 @@ impl RowThreshold { if let Some(columns) = vars.get(vars::EXA_GRID_ROWS).and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(rows) => Ok(Self::MinimumRows(rows)), - Err(e) => Err(OptionsError::FailedParse(e)), + Ok(rows) => { + Ok(Self::MinimumRows(rows)) + } + Err(e) => { + let source = NumberSource::Env(vars::EXA_GRID_ROWS); + Err(OptionsError::FailedParse(columns, source, e)) + } } } else { diff --git a/xtests/errors.toml b/xtests/errors.toml index 150e73e..ed50d9d 100644 --- a/xtests/errors.toml +++ b/xtests/errors.toml @@ -15,3 +15,85 @@ stdout = { empty = true } stderr = { string = "To sort newest files last, try \"--sort newest\", or just \"-snew\""} status = 3 tags = [ 'error', 'long', 'sort' ] + + +# Invalid values for $COLUMNS + +[[cmd]] +name = "‘COLUMNS=999... exa’ shows an error about the number size" +shell = "exa" +environment = { "COLUMNS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘COLUMNS=abcdef exa’ shows an error about invalid digits" +shell = "exa" +environment = { "COLUMNS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_columns_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_GRID_ROWS + +[[cmd]] +name = "‘EXA_GRID_ROWS=999... exa -lG’ shows an error about the number size" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + +[[cmd]] +name = "‘EXA_GRID_ROWS=abcdef exa -lG’ shows an error about invalid digits" +shell = "exa -lG" +environment = { "EXA_GRID_ROWS" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_grid_rows_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env' ] + + +# Invalid values for $EXA_ICON_SPACING + +[[cmd]] +name = "‘EXA_ICON_SPACING=999... exa --icons’ shows an error about the number size" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "99999999999999999999999" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_nines.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + +[[cmd]] +name = "‘EXA_ICON_SPACING=abcdef exa --icons’ shows an error about invalid digits" +shell = "exa --icons" +environment = { "EXA_ICON_SPACING" = "abcdef" } +stdout = { empty = true } +stderr = { file = "outputs/error_icon_spacing_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'env', 'icons' ] + + +# Invalid values for --level (-L) + +[[cmd]] +name = "‘exa -TL999...’ shows an error about the number size" +shell = "exa -TL99999999999999999999999" +stdout = { empty = true } +stderr = { file = "outputs/error_level_nines.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] + +[[cmd]] +name = "‘exa -TLabcdef’ shows an error about invalid digits" +shell = "exa -TLabcdef" +stdout = { empty = true } +stderr = { file = "outputs/error_level_invalid.ansitxt" } +status = 3 +tags = [ 'error', 'tree', 'level' ] diff --git a/xtests/outputs/error_columns_invalid.ansitxt b/xtests/outputs/error_columns_invalid.ansitxt new file mode 100644 index 0000000..1455322 --- /dev/null +++ b/xtests/outputs/error_columns_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable COLUMNS: invalid digit found in string diff --git a/xtests/outputs/error_columns_nines.ansitxt b/xtests/outputs/error_columns_nines.ansitxt new file mode 100644 index 0000000..f1ecc7f --- /dev/null +++ b/xtests/outputs/error_columns_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable COLUMNS: number too large to fit in target type diff --git a/xtests/outputs/error_grid_rows_invalid.ansitxt b/xtests/outputs/error_grid_rows_invalid.ansitxt new file mode 100644 index 0000000..c1474d9 --- /dev/null +++ b/xtests/outputs/error_grid_rows_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_GRID_ROWS: invalid digit found in string diff --git a/xtests/outputs/error_grid_rows_nines.ansitxt b/xtests/outputs/error_grid_rows_nines.ansitxt new file mode 100644 index 0000000..35750bb --- /dev/null +++ b/xtests/outputs/error_grid_rows_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_GRID_ROWS: number too large to fit in target type diff --git a/xtests/outputs/error_icon_spacing_invalid.ansitxt b/xtests/outputs/error_icon_spacing_invalid.ansitxt new file mode 100644 index 0000000..aaec7f3 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for environment variable EXA_ICON_SPACING: invalid digit found in string diff --git a/xtests/outputs/error_icon_spacing_nines.ansitxt b/xtests/outputs/error_icon_spacing_nines.ansitxt new file mode 100644 index 0000000..44f3ad1 --- /dev/null +++ b/xtests/outputs/error_icon_spacing_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for environment variable EXA_ICON_SPACING: number too large to fit in target type diff --git a/xtests/outputs/error_level_invalid.ansitxt b/xtests/outputs/error_level_invalid.ansitxt new file mode 100644 index 0000000..d7f4a03 --- /dev/null +++ b/xtests/outputs/error_level_invalid.ansitxt @@ -0,0 +1 @@ +exa: Value "abcdef" not valid for option --level (-L): invalid digit found in string diff --git a/xtests/outputs/error_level_nines.ansitxt b/xtests/outputs/error_level_nines.ansitxt new file mode 100644 index 0000000..895fc0a --- /dev/null +++ b/xtests/outputs/error_level_nines.ansitxt @@ -0,0 +1 @@ +exa: Value "99999999999999999999999" not valid for option --level (-L): number too large to fit in target type From b1c49341c0466861f63ceea1d7c4d867cfda0b9c Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 21:55:22 +0100 Subject: [PATCH 16/21] Add tests for common command-line errors Specifically, making sure that they start with "exa", which is something that's been bugging me recently. --- xtests/errors.toml | 19 +++++++++++++++++++ xtests/outputs/error_invalid_option.ansitxt | 1 + xtests/outputs/error_tree_all_all.ansitxt | 1 + 3 files changed, 21 insertions(+) create mode 100644 xtests/outputs/error_invalid_option.ansitxt create mode 100644 xtests/outputs/error_tree_all_all.ansitxt diff --git a/xtests/errors.toml b/xtests/errors.toml index ed50d9d..7ca0a08 100644 --- a/xtests/errors.toml +++ b/xtests/errors.toml @@ -1,3 +1,22 @@ +# Command-line errors + +[[cmd]] +name = "‘exa --aoeu’ displays an error" +shell = "exa --aoeu" +stdout = { empty = true } +stderr = { file = "outputs/error_invalid_option.ansitxt" } +status = 3 +tags = [ 'error' ] + +[[cmd]] +name = "‘exa -Taa’ displays an error" +shell = "exa -Taa" +stdout = { empty = true } +stderr = { file = "outputs/error_tree_all_all.ansitxt" } +status = 3 +tags = [ 'error' ] + + # Error suggestions [[cmd]] diff --git a/xtests/outputs/error_invalid_option.ansitxt b/xtests/outputs/error_invalid_option.ansitxt new file mode 100644 index 0000000..39825d4 --- /dev/null +++ b/xtests/outputs/error_invalid_option.ansitxt @@ -0,0 +1 @@ +exa: Unknown argument --aoeu diff --git a/xtests/outputs/error_tree_all_all.ansitxt b/xtests/outputs/error_tree_all_all.ansitxt new file mode 100644 index 0000000..b7e21c2 --- /dev/null +++ b/xtests/outputs/error_tree_all_all.ansitxt @@ -0,0 +1 @@ +exa: Option --tree is useless given --all --all From dbd11d38042284cc890fdd91760c2f93b65e8553 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 22:02:30 +0100 Subject: [PATCH 17/21] Add classify char to symlink targets Fixes GH-589. --- src/output/file_name.rs | 24 ++++++++++++++-------- xtests/details-view.toml | 8 ++++++++ xtests/outputs/links_long_classify.ansitxt | 10 +++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 xtests/outputs/links_long_classify.ansitxt diff --git a/src/output/file_name.rs b/src/output/file_name.rs index 627467c..b6a38c0 100644 --- a/src/output/file_name.rs +++ b/src/output/file_name.rs @@ -173,7 +173,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { show_icons: ShowIcons::Off, }; - let target = FileName { + let target_name = FileName { file: target, colours: self.colours, target: None, @@ -181,9 +181,15 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { options: target_options, }; - for bit in target.coloured_file_name() { + for bit in target_name.coloured_file_name() { bits.push(bit); } + + if let Classify::AddFileIndicators = self.options.classify { + if let Some(class) = self.classify_char(target) { + bits.push(Style::default().paint(class)); + } + } } } @@ -206,7 +212,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { } } else if let Classify::AddFileIndicators = self.options.classify { - if let Some(class) = self.classify_char() { + if let Some(class) = self.classify_char(self.file) { bits.push(Style::default().paint(class)); } } @@ -235,20 +241,20 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { /// The character to be displayed after a file when classifying is on, if /// the file’s type has one associated with it. - fn classify_char(&self) -> Option<&'static str> { - if self.file.is_executable_file() { + fn classify_char(&self, file: &File<'_>) -> Option<&'static str> { + if file.is_executable_file() { Some("*") } - else if self.file.is_directory() { + else if file.is_directory() { Some("/") } - else if self.file.is_pipe() { + else if file.is_pipe() { Some("|") } - else if self.file.is_link() { + else if file.is_link() { Some("@") } - else if self.file.is_socket() { + else if file.is_socket() { Some("=") } else { diff --git a/xtests/details-view.toml b/xtests/details-view.toml index 331fa58..73874df 100644 --- a/xtests/details-view.toml +++ b/xtests/details-view.toml @@ -43,3 +43,11 @@ stdout = { file = "outputs/specials_long_classify.ansitxt" } stderr = { empty = true } status = 0 tags = [ 'long', 'classify' ] + +[[cmd]] +name = "‘exa -lF’ handles and classifies symlink kinds" +shell = "exa -lF --no-time /testcases/links" +stdout = { file = "outputs/links_long_classify.ansitxt" } +stderr = { empty = true } +status = 0 +tags = [ 'long', 'classify' ] diff --git a/xtests/outputs/links_long_classify.ansitxt b/xtests/outputs/links_long_classify.ansitxt new file mode 100644 index 0000000..9747e04 --- /dev/null +++ b/xtests/outputs/links_long_classify.ansitxt @@ -0,0 +1,10 @@ +lrwxrwxrwx 7 vagrant broken -> nowhere +lrwxrwxrwx 1 vagrant current_dir -> ./ +lrwxrwxrwx 12 vagrant forbidden -> /proc/1/root +lrwxrwxrwx 6 vagrant itself -> itself +lrwxrwxrwx 2 vagrant parent_dir -> ../ +lrwxrwxrwx 1 vagrant root -> // +.rw-rw-r-- 0 vagrant some_file +lrwxrwxrwx 26 vagrant some_file_absolute -> /testcases/links/some_file +lrwxrwxrwx 9 vagrant some_file_relative -> some_file +lrwxrwxrwx 4 vagrant usr -> /usr/ From 1f4e58ee529194f2f72ae20bc1b564c1bf7965ca Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 22:17:39 +0100 Subject: [PATCH 18/21] Explain Git characters in man page Fixes GH-778. --- man/exa.1.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/man/exa.1.md b/man/exa.1.md index c96c477..bd91a7c 100644 --- a/man/exa.1.md +++ b/man/exa.1.md @@ -183,6 +183,10 @@ These options are available when running with `--long` (`-l`): `--git` [if exa was built with git support] : List each file’s Git status, if tracked. +This adds a two-character column indicating the staged and unstaged statuses respectively. The status character can be ‘`-`’ for not modified, ‘`M`’ for a modified file, ‘`N`’ for a new file, ‘`D`’ for deleted, ‘`R`’ for renamed, ‘`T`’ for type-change, ‘`I`’ for ignored, and ‘`U`’ for conflicted. + +Directories will be shown to have the status of their contents, which is how ‘deleted’ is possible: if a directory contains a file that has a certain status, it will be shown to have that status. + ENVIRONMENT VARIABLES ===================== From e3e776a1fa6cb0949f4223e75f86ceff5b1ac075 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 22:23:51 +0100 Subject: [PATCH 19/21] Use better icon for TeX files Fixes GH-777. --- src/output/icons.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/output/icons.rs b/src/output/icons.rs index 2a9373d..5f6680b 100644 --- a/src/output/icons.rs +++ b/src/output/icons.rs @@ -128,7 +128,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "class" => '\u{e256}', //  "clj" => '\u{e768}', //  "cljs" => '\u{e76a}', //  - "cls" => '\u{e600}', //  + "cls" => '\u{f034}', //  "cmd" => '\u{e70f}', //  "coffee" => '\u{f0f4}', //  "conf" => '\u{e615}', //  @@ -209,7 +209,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "json" => '\u{e60b}', //  "jsx" => '\u{e7ba}', //  "ksh" => '\u{f489}', //  - "latex" => '\u{e600}', //  + "latex" => '\u{f034}', //  "less" => '\u{e758}', //  "lhs" => '\u{e777}', //  "license" => '\u{f718}', //  @@ -297,7 +297,7 @@ pub fn icon_for_file(file: &File<'_>) -> char { "taz" => '\u{f410}', //  "tbz" => '\u{f410}', //  "tbz2" => '\u{f410}', //  - "tex" => '\u{e600}', //  + "tex" => '\u{f034}', //  "tiff" => '\u{f1c5}', //  "toml" => '\u{e615}', //  "ts" => '\u{e628}', //  From c0df1fb6c25db71a91af88f1d9ea97c8f43d7757 Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 22:27:59 +0100 Subject: [PATCH 20/21] cargo update --- Cargo.lock | 86 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acac459..df94188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,24 +23,24 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.61" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed67cbde08356238e75fc4656be4749481eeffb09e19f320a25237d5221c985d" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" dependencies = [ "jobserver", ] [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "datetime" @@ -79,10 +79,20 @@ dependencies = [ ] [[package]] -name = "git2" -version = "0.13.11" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e094214efbc7fdbbdee952147e493b00e99a4e52817492277e98967ae918165" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "git2" +version = "0.13.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" dependencies = [ "bitflags", "libc", @@ -100,18 +110,18 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "idna" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" dependencies = [ "matches", "unicode-bidi", @@ -135,15 +145,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.79" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "libgit2-sys" -version = "0.12.14+1.1.0" +version = "0.12.18+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" +checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" dependencies = [ "cc", "libc", @@ -174,9 +184,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] @@ -211,18 +221,18 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "openssl-src" -version = "111.12.0+1.1.1h" +version = "111.15.0+1.1.1k" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61" +checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.58" +version = "0.9.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" dependencies = [ "autocfg", "cc", @@ -286,24 +296,33 @@ dependencies = [ [[package]] name = "tinyvec" -version = "0.3.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" dependencies = [ "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" dependencies = [ "tinyvec", ] @@ -316,10 +335,11 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "url" -version = "2.1.1" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ + "form_urlencoded", "idna", "matches", "percent-encoding", @@ -337,9 +357,9 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "winapi" From 293372a613932a084a4b84218cc7cc374d15955e Mon Sep 17 00:00:00 2001 From: Benjamin Sago Date: Mon, 12 Apr 2021 22:28:31 +0100 Subject: [PATCH 21/21] v0.10.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ebc5f25..1d42204 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"] homepage = "https://the.exa.website/" license = "MIT" repository = "https://github.com/ogham/exa" -version = "0.11.0-pre" +version = "0.10.1" [[bin]]