diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index ef314dfa8..44a374dbe 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -127,6 +127,8 @@ pub mod options { pub static IGNORE: &str = "ignore"; } +const DEFAULT_TERM_WIDTH: u16 = 80; + #[derive(Debug)] enum LsError { InvalidLineWidth(String), @@ -229,7 +231,7 @@ struct Config { inode: bool, color: Option, long: LongFormat, - width: Option, + width: u16, quoting_style: QuotingStyle, indicator_style: IndicatorStyle, time_style: TimeStyle, @@ -399,10 +401,25 @@ impl Config { let width = match options.value_of(options::WIDTH) { Some(x) => match x.parse::() { - Ok(u) => Some(u), + Ok(u) => u, Err(_) => return Err(LsError::InvalidLineWidth(x.into()).into()), }, - None => termsize::get().map(|s| s.cols), + None => match termsize::get() { + Some(size) => size.cols, + None => match std::env::var("COLUMNS") { + Ok(columns) => match columns.parse() { + Ok(columns) => columns, + Err(_) => { + show_error!( + "ignoring invalid width in environment variable COLUMNS: '{}'", + columns + ); + DEFAULT_TERM_WIDTH + } + }, + Err(_) => DEFAULT_TERM_WIDTH, + }, + }, }; #[allow(clippy::needless_bool)] @@ -1411,15 +1428,10 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter { - display_grid(names, width, Direction::TopToBottom, out) - } - (Format::Across, Some(width)) => { - display_grid(names, width, Direction::LeftToRight, out) - } - (Format::Commas, width_opt) => { - let term_width = width_opt.unwrap_or(1); + match config.format { + Format::Columns => display_grid(names, config.width, Direction::TopToBottom, out), + Format::Across => display_grid(names, config.width, Direction::LeftToRight, out), + Format::Commas => { let mut current_col = 0; let mut names = names; if let Some(name) = names.next() { @@ -1428,7 +1440,7 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter term_width { + if current_col + name_width + 1 > config.width { current_col = name_width + 2; let _ = write!(out, ",\n{}", name.contents); } else { diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 44d14c304..0a19a44fa 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -184,16 +184,10 @@ fn test_ls_columns() { // Columns is the default let result = scene.ucmd().succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-columns-1\ntest-columns-2\ntest-columns-3\ntest-columns-4\n"); - #[cfg(windows)] result.stdout_only("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n"); for option in &["-C", "--format=columns"] { let result = scene.ucmd().arg(option).succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-columns-1\ntest-columns-2\ntest-columns-3\ntest-columns-4\n"); - #[cfg(windows)] result.stdout_only("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n"); } @@ -205,6 +199,22 @@ fn test_ls_columns() { .succeeds() .stdout_only("test-columns-1 test-columns-3\ntest-columns-2 test-columns-4\n"); } + + for option in &["-C", "--format=columns"] { + scene + .ucmd() + .env("COLUMNS", "40") + .arg(option) + .succeeds() + .stdout_only("test-columns-1 test-columns-3\ntest-columns-2 test-columns-4\n"); + } + + scene + .ucmd() + .env("COLUMNS", "garbage") + .succeeds() + .stdout_is("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n") + .stderr_is("ls: ignoring invalid width in environment variable COLUMNS: 'garbage'"); } #[test] @@ -220,11 +230,7 @@ fn test_ls_across() { let result = scene.ucmd().arg(option).succeeds(); // Because the test terminal has width 0, this is the same output as // the columns option. - if cfg!(unix) { - result.stdout_only("test-across-1\ntest-across-2\ntest-across-3\ntest-across-4\n"); - } else { - result.stdout_only("test-across-1 test-across-2 test-across-3 test-across-4\n"); - } + result.stdout_only("test-across-1 test-across-2 test-across-3 test-across-4\n"); } for option in &["-x", "--format=across"] { @@ -250,11 +256,7 @@ fn test_ls_commas() { for option in &["-m", "--format=commas"] { let result = scene.ucmd().arg(option).succeeds(); - if cfg!(unix) { - result.stdout_only("test-commas-1,\ntest-commas-2,\ntest-commas-3,\ntest-commas-4\n"); - } else { - result.stdout_only("test-commas-1, test-commas-2, test-commas-3, test-commas-4\n"); - } + result.stdout_only("test-commas-1, test-commas-2, test-commas-3, test-commas-4\n"); } for option in &["-m", "--format=commas"] { @@ -571,13 +573,11 @@ fn test_ls_sort_name() { at.touch("test-1"); at.touch("test-2"); - let sep = if cfg!(unix) { "\n" } else { " " }; - scene .ucmd() .arg("--sort=name") .succeeds() - .stdout_is(["test-1", "test-2", "test-3\n"].join(sep)); + .stdout_is("test-1 test-2 test-3\n"); let scene_dot = TestScenario::new(util_name!()); let at = &scene_dot.fixtures; @@ -591,7 +591,7 @@ fn test_ls_sort_name() { .arg("--sort=name") .arg("-A") .succeeds() - .stdout_is([".a", ".b", "a", "b\n"].join(sep)); + .stdout_is(".a .b a b\n"); } #[test] @@ -612,27 +612,15 @@ fn test_ls_order_size() { scene.ucmd().arg("-al").succeeds(); let result = scene.ucmd().arg("-S").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); - #[cfg(windows)] result.stdout_only("test-4 test-3 test-2 test-1\n"); let result = scene.ucmd().arg("-S").arg("-r").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n"); - #[cfg(windows)] result.stdout_only("test-1 test-2 test-3 test-4\n"); let result = scene.ucmd().arg("--sort=size").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); - #[cfg(windows)] result.stdout_only("test-4 test-3 test-2 test-1\n"); let result = scene.ucmd().arg("--sort=size").arg("-r").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n"); - #[cfg(windows)] result.stdout_only("test-1 test-2 test-3 test-4\n"); } @@ -755,9 +743,6 @@ fn test_ls_styles() { at.touch("test2"); let result = scene.ucmd().arg("--full-time").arg("-x").succeeds(); - #[cfg(not(windows))] - assert_eq!(result.stdout_str(), "test\ntest2\n"); - #[cfg(windows)] assert_eq!(result.stdout_str(), "test test2\n"); } @@ -794,27 +779,15 @@ fn test_ls_order_time() { // ctime was changed at write, so the order is 4 3 2 1 let result = scene.ucmd().arg("-t").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); - #[cfg(windows)] result.stdout_only("test-4 test-3 test-2 test-1\n"); let result = scene.ucmd().arg("--sort=time").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); - #[cfg(windows)] result.stdout_only("test-4 test-3 test-2 test-1\n"); let result = scene.ucmd().arg("-tr").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n"); - #[cfg(windows)] result.stdout_only("test-1 test-2 test-3 test-4\n"); let result = scene.ucmd().arg("--sort=time").arg("-r").succeeds(); - #[cfg(not(windows))] - result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n"); - #[cfg(windows)] result.stdout_only("test-1 test-2 test-3 test-4\n"); // 3 was accessed last in the read @@ -826,19 +799,11 @@ fn test_ls_order_time() { // It seems to be dependent on the platform whether the access time is actually set if file3_access > file4_access { - if cfg!(not(windows)) { - result.stdout_only("test-3\ntest-4\ntest-2\ntest-1\n"); - } else { - result.stdout_only("test-3 test-4 test-2 test-1\n"); - } + result.stdout_only("test-3 test-4 test-2 test-1\n"); } else { // Access time does not seem to be set on Windows and some other // systems so the order is 4 3 2 1 - if cfg!(not(windows)) { - result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n"); - } else { - result.stdout_only("test-4 test-3 test-2 test-1\n"); - } + result.stdout_only("test-4 test-3 test-2 test-1\n"); } } @@ -847,7 +812,7 @@ fn test_ls_order_time() { #[cfg(unix)] { let result = scene.ucmd().arg("-tc").succeeds(); - result.stdout_only("test-2\ntest-4\ntest-3\ntest-1\n"); + result.stdout_only("test-2 test-4 test-3 test-1\n"); } } @@ -2009,11 +1974,7 @@ fn test_ls_path() { }; scene.ucmd().arg(&abs_path).run().stdout_is(expected_stdout); - let expected_stdout = if cfg!(windows) { - format!("{} {}\n", path, file1) - } else { - format!("{}\n{}\n", path, file1) - }; + let expected_stdout = format!("{} {}\n", path, file1); scene .ucmd() .arg(file1)