mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
ls: correct fallbacks for terminal width
If options::WIDTH is not given, we should try to use the terminal width. If that is unavailable, we should fall back to the 'COLUMNS' environment variable. If that is unavailable (or invalid), we should fall back to a default of 80.
This commit is contained in:
parent
13b6d003bb
commit
13a62489c5
2 changed files with 49 additions and 76 deletions
|
@ -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<LsColors>,
|
||||
long: LongFormat,
|
||||
width: Option<u16>,
|
||||
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::<u16>() {
|
||||
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<Stdout
|
|||
} else {
|
||||
let names = items.iter().filter_map(|i| display_file_name(i, config));
|
||||
|
||||
match (&config.format, config.width) {
|
||||
(Format::Columns, Some(width)) => {
|
||||
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<Stdout
|
|||
}
|
||||
for name in names {
|
||||
let name_width = name.width as u16;
|
||||
if current_col + name_width + 1 > term_width {
|
||||
if current_col + name_width + 1 > config.width {
|
||||
current_col = name_width + 2;
|
||||
let _ = write!(out, ",\n{}", name.contents);
|
||||
} else {
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue