From c160970c82f4ac67cf1bdf8e5e9c82333e66c369 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 19 Jun 2021 15:35:59 +0800 Subject: [PATCH 1/7] ls: Refactored options and other long constants to fix formatting Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 293 ++++++++++++--------------------------- src/uu/ls/src/options.rs | 136 ++++++++++++++++++ 2 files changed, 226 insertions(+), 203 deletions(-) create mode 100644 src/uu/ls/src/options.rs diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 0bffa2e52ad..1642edd43ea 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -13,6 +13,7 @@ extern crate uucore; #[macro_use] extern crate lazy_static; +mod options; mod quoting_style; mod version_cmp; @@ -45,86 +46,10 @@ use unicode_width::UnicodeWidthStr; #[cfg(unix)] use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR}; -static ABOUT: &str = " - By default, ls will list the files and contents of any directories on - the command line, expect that it will ignore files and directories - whose names start with '.' -"; -static AFTER_HELP: &str = "The TIME_STYLE argument can be full-iso, long-iso, iso. -Also the TIME_STYLE environment variable sets the default style to use."; - fn get_usage() -> String { format!("{0} [OPTION]... [FILE]...", executable!()) } -pub mod options { - pub mod format { - pub static ONE_LINE: &str = "1"; - pub static LONG: &str = "long"; - pub static COLUMNS: &str = "C"; - pub static ACROSS: &str = "x"; - pub static COMMAS: &str = "m"; - pub static LONG_NO_OWNER: &str = "g"; - pub static LONG_NO_GROUP: &str = "o"; - pub static LONG_NUMERIC_UID_GID: &str = "numeric-uid-gid"; - } - pub mod files { - pub static ALL: &str = "all"; - pub static ALMOST_ALL: &str = "almost-all"; - } - pub mod sort { - pub static SIZE: &str = "S"; - pub static TIME: &str = "t"; - pub static NONE: &str = "U"; - pub static VERSION: &str = "v"; - pub static EXTENSION: &str = "X"; - } - pub mod time { - pub static ACCESS: &str = "u"; - pub static CHANGE: &str = "c"; - } - pub mod size { - pub static HUMAN_READABLE: &str = "human-readable"; - pub static SI: &str = "si"; - } - pub mod quoting { - pub static ESCAPE: &str = "escape"; - pub static LITERAL: &str = "literal"; - pub static C: &str = "quote-name"; - } - pub static QUOTING_STYLE: &str = "quoting-style"; - pub mod indicator_style { - pub static SLASH: &str = "p"; - pub static FILE_TYPE: &str = "file-type"; - pub static CLASSIFY: &str = "classify"; - } - pub mod dereference { - pub static ALL: &str = "dereference"; - pub static ARGS: &str = "dereference-command-line"; - pub static DIR_ARGS: &str = "dereference-command-line-symlink-to-dir"; - } - pub static HIDE_CONTROL_CHARS: &str = "hide-control-chars"; - pub static SHOW_CONTROL_CHARS: &str = "show-control-chars"; - pub static WIDTH: &str = "width"; - pub static AUTHOR: &str = "author"; - pub static NO_GROUP: &str = "no-group"; - pub static FORMAT: &str = "format"; - pub static SORT: &str = "sort"; - pub static TIME: &str = "time"; - pub static IGNORE_BACKUPS: &str = "ignore-backups"; - pub static DIRECTORY: &str = "directory"; - pub static INODE: &str = "inode"; - pub static REVERSE: &str = "reverse"; - pub static RECURSIVE: &str = "recursive"; - pub static COLOR: &str = "color"; - pub static PATHS: &str = "paths"; - pub static INDICATOR_STYLE: &str = "indicator-style"; - pub static TIME_STYLE: &str = "time-style"; - pub static FULL_TIME: &str = "full-time"; - pub static HIDE: &str = "hide"; - pub static IGNORE: &str = "ignore"; -} - #[derive(PartialEq, Eq)] enum Format { Columns, @@ -560,16 +485,24 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let app = App::new(executable!()) .version(crate_version!()) - .about(ABOUT) + .about(options::ABOUT) .usage(&usage[..]) - // Format arguments .arg( Arg::with_name(options::FORMAT) .long(options::FORMAT) .help("Set the display format.") .takes_value(true) - .possible_values(&["long", "verbose", "single-column", "columns", "vertical", "across", "horizontal", "commas"]) + .possible_values(&[ + "long", + "verbose", + "single-column", + "columns", + "vertical", + "across", + "horizontal", + "commas", + ]) .hide_possible_values(true) .require_equals(true) .overrides_with_all(&[ @@ -639,41 +572,48 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::format::ONE_LINE) .short(options::format::ONE_LINE) .help("List one file per line.") - .multiple(true) + .multiple(true), ) .arg( Arg::with_name(options::format::LONG_NO_GROUP) .short(options::format::LONG_NO_GROUP) - .help("Long format without group information. Identical to --format=long with --no-group.") - .multiple(true) + .help(options::format::LONG_NO_GROUP_HELP) + .multiple(true), ) .arg( Arg::with_name(options::format::LONG_NO_OWNER) .short(options::format::LONG_NO_OWNER) .help("Long format without owner information.") - .multiple(true) + .multiple(true), ) .arg( Arg::with_name(options::format::LONG_NUMERIC_UID_GID) .short("n") .long(options::format::LONG_NUMERIC_UID_GID) .help("-l with numeric UIDs and GIDs.") - .multiple(true) + .multiple(true), ) - // Quoting style .arg( Arg::with_name(options::QUOTING_STYLE) .long(options::QUOTING_STYLE) .takes_value(true) .help("Set quoting style.") - .possible_values(&["literal", "shell", "shell-always", "shell-escape", "shell-escape-always", "c", "escape"]) + .possible_values(&[ + "literal", + "shell", + "shell-always", + "shell-escape", + "shell-escape-always", + "c", + "escape", + ]) .overrides_with_all(&[ options::QUOTING_STYLE, options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]) + ]), ) .arg( Arg::with_name(options::quoting::LITERAL) @@ -685,7 +625,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]) + ]), ) .arg( Arg::with_name(options::quoting::ESCAPE) @@ -697,7 +637,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]) + ]), ) .arg( Arg::with_name(options::quoting::C) @@ -709,76 +649,53 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::quoting::LITERAL, options::quoting::ESCAPE, options::quoting::C, - ]) + ]), ) - // Control characters .arg( Arg::with_name(options::HIDE_CONTROL_CHARS) .short("q") .long(options::HIDE_CONTROL_CHARS) .help("Replace control characters with '?' if they are not escaped.") - .overrides_with_all(&[ - options::HIDE_CONTROL_CHARS, - options::SHOW_CONTROL_CHARS, - ]) + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), ) .arg( Arg::with_name(options::SHOW_CONTROL_CHARS) .long(options::SHOW_CONTROL_CHARS) .help("Show control characters 'as is' if they are not escaped.") - .overrides_with_all(&[ - options::HIDE_CONTROL_CHARS, - options::SHOW_CONTROL_CHARS, - ]) + .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]), ) - // Time arguments .arg( Arg::with_name(options::TIME) .long(options::TIME) - .help("Show time in :\n\ + .help( + "Show time in :\n\ \taccess time (-u): atime, access, use;\n\ \tchange time (-t): ctime, status.\n\ - \tbirth time: birth, creation;") + \tbirth time: birth, creation;", + ) .value_name("field") .takes_value(true) - .possible_values(&["atime", "access", "use", "ctime", "status", "birth", "creation"]) + .possible_values(&[ + "atime", "access", "use", "ctime", "status", "birth", "creation", + ]) .hide_possible_values(true) .require_equals(true) - .overrides_with_all(&[ - options::TIME, - options::time::ACCESS, - options::time::CHANGE, - ]) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), ) .arg( Arg::with_name(options::time::CHANGE) .short(options::time::CHANGE) - .help("If the long listing format (e.g., -l, -o) is being used, print the status \ - change time (the ‘ctime’ in the inode) instead of the modification time. When \ - explicitly sorting by time (--sort=time or -t) or when not using a long listing \ - format, sort according to the status change time.") - .overrides_with_all(&[ - options::TIME, - options::time::ACCESS, - options::time::CHANGE, - ]) + .help(options::time::CHANGE_HELP) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), ) .arg( Arg::with_name(options::time::ACCESS) .short(options::time::ACCESS) - .help("If the long listing format (e.g., -l, -o) is being used, print the status \ - access time instead of the modification time. When explicitly sorting by time \ - (--sort=time or -t) or when not using a long listing format, sort according to the \ - access time.") - .overrides_with_all(&[ - options::TIME, - options::time::ACCESS, - options::time::CHANGE, - ]) + .help(options::time::ACCESS_HELP) + .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), ) - // Hide and ignore .arg( Arg::with_name(options::HIDE) @@ -786,7 +703,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .takes_value(true) .multiple(true) .value_name("PATTERN") - .help("do not list implied entries matching shell PATTERN (overridden by -a or -A)") + .help(options::HIDE_HELP), ) .arg( Arg::with_name(options::IGNORE) @@ -795,7 +712,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .takes_value(true) .multiple(true) .value_name("PATTERN") - .help("do not list implied entries matching shell PATTERN") + .help("do not list implied entries matching shell PATTERN"), ) .arg( Arg::with_name(options::IGNORE_BACKUPS) @@ -803,7 +720,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .long(options::IGNORE_BACKUPS) .help("Ignore entries which end with ~."), ) - // Sort arguments .arg( Arg::with_name(options::SORT) @@ -820,7 +736,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) .arg( Arg::with_name(options::sort::SIZE) @@ -833,7 +749,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) .arg( Arg::with_name(options::sort::TIME) @@ -846,7 +762,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) .arg( Arg::with_name(options::sort::VERSION) @@ -859,7 +775,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) .arg( Arg::with_name(options::sort::EXTENSION) @@ -872,14 +788,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) .arg( Arg::with_name(options::sort::NONE) .short(options::sort::NONE) - .help("Do not sort; list the files in whatever order they are stored in the \ - directory. This is especially useful when listing very large directories, \ - since not doing any sorting can be noticeably faster.") + .help(options::sort::NONE_HELP) .overrides_with_all(&[ options::SORT, options::sort::SIZE, @@ -887,63 +801,52 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::sort::NONE, options::sort::VERSION, options::sort::EXTENSION, - ]) + ]), ) - // Dereferencing .arg( Arg::with_name(options::dereference::ALL) .short("L") .long(options::dereference::ALL) - .help( - "When showing file information for a symbolic link, show information for the \ - file the link references rather than the link itself.", - ) + .help(options::dereference::ALL_HELP) .overrides_with_all(&[ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]) + ]), ) .arg( Arg::with_name(options::dereference::DIR_ARGS) .long(options::dereference::DIR_ARGS) - .help( - "Do not dereference symlinks except when they link to directories and are \ - given as command line arguments.", - ) + .help(options::dereference::DIR_ARGS_HELP) .overrides_with_all(&[ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]) + ]), ) .arg( Arg::with_name(options::dereference::ARGS) .short("H") .long(options::dereference::ARGS) - .help( - "Do not dereference symlinks except when given as command line arguments.", - ) + .help("Do not dereference symlinks except when given as command line arguments.") .overrides_with_all(&[ options::dereference::ALL, options::dereference::DIR_ARGS, options::dereference::ARGS, - ]) + ]), ) - // Long format options .arg( Arg::with_name(options::NO_GROUP) .long(options::NO_GROUP) .short("-G") - .help("Do not show group in long format.") + .help("Do not show group in long format."), ) .arg( Arg::with_name(options::AUTHOR) .long(options::AUTHOR) - .help("Show author in long format. On the supported platforms, the author \ - always matches the file owner.") + .help(options::AUTHOR_HELP), ) // Other Flags .arg( @@ -956,21 +859,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::files::ALMOST_ALL) .short("A") .long(options::files::ALMOST_ALL) - .help( - "In a directory, do not ignore all file names that start with '.', only ignore \ - '.' and '..'.", - ), + .help(options::files::ALMOST_ALL_HELP), ) .arg( Arg::with_name(options::DIRECTORY) .short("d") .long(options::DIRECTORY) - .help( - "Only list the names of directories, rather than listing directory contents. \ - This will not follow symbolic links unless one of `--dereference-command-line \ - (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ - specified.", - ), + .help(options::DIRECTORY_HELP), ) .arg( Arg::with_name(options::size::HUMAN_READABLE) @@ -982,7 +877,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::size::SI) .long(options::size::SI) - .help("Print human readable file sizes using powers of 1000 instead of 1024.") + .help("Print human readable file sizes using powers of 1000 instead of 1024."), ) .arg( Arg::with_name(options::INODE) @@ -994,9 +889,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::REVERSE) .short("r") .long(options::REVERSE) - .help("Reverse whatever the sorting method is--e.g., list files in reverse \ - alphabetical order, youngest first, smallest first, or whatever.", - )) + .help(options::REVERSE_HLEP), + ) .arg( Arg::with_name(options::RECURSIVE) .short("R") @@ -1009,7 +903,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .short("w") .help("Assume that the terminal is COLS columns wide.") .value_name("COLS") - .takes_value(true) + .takes_value(true), ) .arg( Arg::with_name(options::COLOR) @@ -1022,8 +916,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::INDICATOR_STYLE) .long(options::INDICATOR_STYLE) - .help(" append indicator with style WORD to entry names: none (default), slash\ - (-p), file-type (--file-type), classify (-F)") + .help(options::INDICATOR_STYLE_HELP) .takes_value(true) .possible_values(&["none", "slash", "file-type", "classify"]) .overrides_with_all(&[ @@ -1031,21 +924,19 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ])) - .arg( + ]), + ) + .arg( Arg::with_name(options::indicator_style::CLASSIFY) .short("F") .long(options::indicator_style::CLASSIFY) - .help("Append a character to each file name indicating the file type. Also, for \ - regular files that are executable, append '*'. The file type indicators are \ - '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ - '>' for doors, and nothing for regular files.") + .help(options::indicator_style::CLASSIFY_HELP) .overrides_with_all(&[ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ]) + ]), ) .arg( Arg::with_name(options::indicator_style::FILE_TYPE) @@ -1056,18 +947,19 @@ pub fn uumain(args: impl uucore::Args) -> i32 { options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ])) + ]), + ) .arg( Arg::with_name(options::indicator_style::SLASH) .short(options::indicator_style::SLASH) - .help("Append / indicator to directories." - ) + .help("Append / indicator to directories.") .overrides_with_all(&[ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, options::indicator_style::CLASSIFY, options::INDICATOR_STYLE, - ])) + ]), + ) .arg( //This still needs support for posix-*, +FORMAT Arg::with_name(options::TIME_STYLE) @@ -1075,27 +967,22 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .help("time/date format with -l; see TIME_STYLE below") .value_name("TIME_STYLE") .env("TIME_STYLE") - .possible_values(&[ - "full-iso", - "long-iso", - "iso", - "locale", - ]) - .overrides_with_all(&[ - options::TIME_STYLE - ]) + .possible_values(&["full-iso", "long-iso", "iso", "locale"]) + .overrides_with_all(&[options::TIME_STYLE]), ) .arg( Arg::with_name(options::FULL_TIME) - .long(options::FULL_TIME) - .overrides_with(options::FULL_TIME) - .help("like -l --time-style=full-iso") + .long(options::FULL_TIME) + .overrides_with(options::FULL_TIME) + .help("like -l --time-style=full-iso"), ) - - // Positional arguments - .arg(Arg::with_name(options::PATHS).multiple(true).takes_value(true)) - - .after_help(AFTER_HELP); + // Positional arguments + .arg( + Arg::with_name(options::PATHS) + .multiple(true) + .takes_value(true), + ) + .after_help(options::PATHS_AFTER_HELP); let matches = app.get_matches_from(args); diff --git a/src/uu/ls/src/options.rs b/src/uu/ls/src/options.rs new file mode 100644 index 00000000000..a9ab8ecc11f --- /dev/null +++ b/src/uu/ls/src/options.rs @@ -0,0 +1,136 @@ +pub mod format { + pub static ONE_LINE: &str = "1"; + pub static LONG: &str = "long"; + pub static COLUMNS: &str = "C"; + pub static ACROSS: &str = "x"; + pub static COMMAS: &str = "m"; + pub static LONG_NO_OWNER: &str = "g"; + pub static LONG_NO_GROUP: &str = "o"; + pub static LONG_NO_GROUP_HELP: &str = + "Long format without group information. Identical to --format=long with --no-group."; + pub static LONG_NUMERIC_UID_GID: &str = "numeric-uid-gid"; +} + +pub mod files { + pub static ALL: &str = "all"; + pub static ALMOST_ALL: &str = "almost-all"; + pub static ALMOST_ALL_HELP: &str = + "In a directory, do not ignore all file names that start with '.', only ignore \ + '.' and '..'."; +} + +pub mod sort { + pub static SIZE: &str = "S"; + pub static TIME: &str = "t"; + pub static NONE: &str = "U"; + pub static NONE_HELP: &str = + "Do not sort; list the files in whatever order they are stored in the \ + directory. This is especially useful when listing very large directories, \ + since not doing any sorting can be noticeably faster."; + pub static VERSION: &str = "v"; + pub static EXTENSION: &str = "X"; +} + +pub mod time { + pub static ACCESS: &str = "u"; + pub static ACCESS_HELP: &str = + "If the long listing format (e.g., -l, -o) is being used, print the status \ + access time instead of the modification time. When explicitly sorting by time \ + (--sort=time or -t) or when not using a long listing format, sort according to the \ + access time."; + pub static CHANGE: &str = "c"; + pub static CHANGE_HELP: &str = + "If the long listing format (e.g., -l, -o) is being used, print the status \ + change time (the ‘ctime’ in the inode) instead of the modification time. When \ + explicitly sorting by time (--sort=time or -t) or when not using a long listing \ + format, sort according to the status change time."; +} + +pub mod size { + pub static HUMAN_READABLE: &str = "human-readable"; + pub static SI: &str = "si"; +} + +pub mod quoting { + pub static ESCAPE: &str = "escape"; + pub static LITERAL: &str = "literal"; + pub static C: &str = "quote-name"; +} + +pub mod indicator_style { + pub static SLASH: &str = "p"; + pub static FILE_TYPE: &str = "file-type"; + pub static CLASSIFY: &str = "classify"; + pub static CLASSIFY_HELP: &str = + "Append a character to each file name indicating the file type. Also, for \ + regular files that are executable, append '*'. The file type indicators are \ + '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ + '>' for doors, and nothing for regular files."; +} + +pub mod dereference { + pub static ALL: &str = "dereference"; + pub static ALL_HELP: &str = + "When showing file information for a symbolic link, show information for the \ + file the link references rather than the link itself."; + pub static ARGS: &str = "dereference-command-line"; + pub static DIR_ARGS: &str = "dereference-command-line-symlink-to-dir"; + pub static DIR_ARGS_HELP: &str = + "Do not dereference symlinks except when they link to directories and are \ + given as command line arguments."; +} + +pub static QUOTING_STYLE: &str = "quoting-style"; +pub static HIDE_CONTROL_CHARS: &str = "hide-control-chars"; +pub static SHOW_CONTROL_CHARS: &str = "show-control-chars"; +pub static WIDTH: &str = "width"; + +pub static AUTHOR: &str = "author"; +pub static AUTHOR_HELP: &str = + "Show author in long format. On the supported platforms, the author \ +always matches the file owner."; + +pub static NO_GROUP: &str = "no-group"; +pub static FORMAT: &str = "format"; +pub static SORT: &str = "sort"; +pub static TIME: &str = "time"; +pub static IGNORE_BACKUPS: &str = "ignore-backups"; + +pub static DIRECTORY: &str = "directory"; +pub static DIRECTORY_HELP: &str = + "Only list the names of directories, rather than listing directory contents. \ +This will not follow symbolic links unless one of `--dereference-command-line \ +(-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ +specified."; + +pub static INODE: &str = "inode"; + +pub static REVERSE: &str = "reverse"; +pub static REVERSE_HLEP: &str = + "Reverse whatever the sorting method is--e.g., list files in reverse \ +alphabetical order, youngest first, smallest first, or whatever."; + +pub static RECURSIVE: &str = "recursive"; +pub static COLOR: &str = "color"; + +pub static PATHS: &str = "paths"; +pub static PATHS_AFTER_HELP: &str = "The TIME_STYLE argument can be full-iso, long-iso, iso. +Also the TIME_STYLE environment variable sets the default style to use."; + +pub static INDICATOR_STYLE: &str = "indicator-style"; +pub static INDICATOR_STYLE_HELP: &str = + " append indicator with style WORD to entry names: none (default), slash\ +(-p), file-type (--file-type), classify (-F)"; + +pub static TIME_STYLE: &str = "time-style"; +pub static FULL_TIME: &str = "full-time"; +pub static HIDE: &str = "hide"; +pub static HIDE_HELP: &str = + "do not list implied entries matching shell PATTERN (overridden by -a or -A)"; +pub static IGNORE: &str = "ignore"; + +pub static ABOUT: &str = " + By default, ls will list the files and contents of any directories on + the command line, expect that it will ignore files and directories + whose names start with '.' +"; From 4d2f0de97152e2607b05e9ca8425fd1545b20150 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 19 Jun 2021 18:25:19 +0800 Subject: [PATCH 2/7] Keep one of the texts in-place Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 4 +++- src/uu/ls/src/options.rs | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 1642edd43ea..be2106fec83 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -703,7 +703,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .takes_value(true) .multiple(true) .value_name("PATTERN") - .help(options::HIDE_HELP), + .help( + "do not list implied entries matching shell PATTERN (overridden by -a or -A)", + ), ) .arg( Arg::with_name(options::IGNORE) diff --git a/src/uu/ls/src/options.rs b/src/uu/ls/src/options.rs index a9ab8ecc11f..32114ceb9a5 100644 --- a/src/uu/ls/src/options.rs +++ b/src/uu/ls/src/options.rs @@ -125,8 +125,6 @@ pub static INDICATOR_STYLE_HELP: &str = pub static TIME_STYLE: &str = "time-style"; pub static FULL_TIME: &str = "full-time"; pub static HIDE: &str = "hide"; -pub static HIDE_HELP: &str = - "do not list implied entries matching shell PATTERN (overridden by -a or -A)"; pub static IGNORE: &str = "ignore"; pub static ABOUT: &str = " From 78f064c5b06ed0617f66db1731078d1d638ed7e1 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 19 Jun 2021 19:05:30 +0800 Subject: [PATCH 3/7] Reduced the fix to just formatting changes Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 162 ++++++++++++++++++++++++++++++++++----- src/uu/ls/src/options.rs | 134 -------------------------------- 2 files changed, 143 insertions(+), 153 deletions(-) delete mode 100644 src/uu/ls/src/options.rs diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index be2106fec83..79261abe7d5 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -13,7 +13,6 @@ extern crate uucore; #[macro_use] extern crate lazy_static; -mod options; mod quoting_style; mod version_cmp; @@ -50,6 +49,83 @@ fn get_usage() -> String { format!("{0} [OPTION]... [FILE]...", executable!()) } +pub mod options { + + pub mod format { + pub static ONE_LINE: &str = "1"; + pub static LONG: &str = "long"; + pub static COLUMNS: &str = "C"; + pub static ACROSS: &str = "x"; + pub static COMMAS: &str = "m"; + pub static LONG_NO_OWNER: &str = "g"; + pub static LONG_NO_GROUP: &str = "o"; + pub static LONG_NUMERIC_UID_GID: &str = "numeric-uid-gid"; + } + + pub mod files { + pub static ALL: &str = "all"; + pub static ALMOST_ALL: &str = "almost-all"; + } + + pub mod sort { + pub static SIZE: &str = "S"; + pub static TIME: &str = "t"; + pub static NONE: &str = "U"; + pub static VERSION: &str = "v"; + pub static EXTENSION: &str = "X"; + } + + pub mod time { + pub static ACCESS: &str = "u"; + pub static CHANGE: &str = "c"; + } + + pub mod size { + pub static HUMAN_READABLE: &str = "human-readable"; + pub static SI: &str = "si"; + } + + pub mod quoting { + pub static ESCAPE: &str = "escape"; + pub static LITERAL: &str = "literal"; + pub static C: &str = "quote-name"; + } + + pub mod indicator_style { + pub static SLASH: &str = "p"; + pub static FILE_TYPE: &str = "file-type"; + pub static CLASSIFY: &str = "classify"; + } + + pub mod dereference { + pub static ALL: &str = "dereference"; + pub static ARGS: &str = "dereference-command-line"; + pub static DIR_ARGS: &str = "dereference-command-line-symlink-to-dir"; + } + + pub static QUOTING_STYLE: &str = "quoting-style"; + pub static HIDE_CONTROL_CHARS: &str = "hide-control-chars"; + pub static SHOW_CONTROL_CHARS: &str = "show-control-chars"; + pub static WIDTH: &str = "width"; + pub static AUTHOR: &str = "author"; + pub static NO_GROUP: &str = "no-group"; + pub static FORMAT: &str = "format"; + pub static SORT: &str = "sort"; + pub static TIME: &str = "time"; + pub static IGNORE_BACKUPS: &str = "ignore-backups"; + pub static DIRECTORY: &str = "directory"; + pub static INODE: &str = "inode"; + pub static REVERSE: &str = "reverse"; + pub static RECURSIVE: &str = "recursive"; + pub static COLOR: &str = "color"; + pub static PATHS: &str = "paths"; + pub static INDICATOR_STYLE: &str = "indicator-style"; + pub static TIME_STYLE: &str = "time-style"; + pub static FULL_TIME: &str = "full-time"; + pub static HIDE: &str = "hide"; + pub static IGNORE: &str = "ignore"; +} + #[derive(PartialEq, Eq)] enum Format { Columns, @@ -485,7 +561,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let app = App::new(executable!()) .version(crate_version!()) - .about(options::ABOUT) + .about( + "By default, ls will list the files and contents of any directories on \ + the command line, expect that it will ignore files and directories \ + whose names start with '.'.", + ) .usage(&usage[..]) // Format arguments .arg( @@ -577,7 +657,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::format::LONG_NO_GROUP) .short(options::format::LONG_NO_GROUP) - .help(options::format::LONG_NO_GROUP_HELP) + .help( + "Long format without group information. \ + Identical to --format=long with --no-group.", + ) .multiple(true), ) .arg( @@ -687,13 +770,23 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::time::CHANGE) .short(options::time::CHANGE) - .help(options::time::CHANGE_HELP) + .help( + "If the long listing format (e.g., -l, -o) is being used, print the status \ + change time (the ‘ctime’ in the inode) instead of the modification time. When \ + explicitly sorting by time (--sort=time or -t) or when not using a long listing \ + format, sort according to the status change time.", + ) .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), ) .arg( Arg::with_name(options::time::ACCESS) .short(options::time::ACCESS) - .help(options::time::ACCESS_HELP) + .help( + "If the long listing format (e.g., -l, -o) is being used, print the status \ + access time instead of the modification time. When explicitly sorting by time \ + (--sort=time or -t) or when not using a long listing format, sort according to the \ + access time.", + ) .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]), ) // Hide and ignore @@ -795,7 +888,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::sort::NONE) .short(options::sort::NONE) - .help(options::sort::NONE_HELP) + .help( + "Do not sort; list the files in whatever order they are stored in the \ + directory. This is especially useful when listing very large directories, \ + since not doing any sorting can be noticeably faster.", + ) .overrides_with_all(&[ options::SORT, options::sort::SIZE, @@ -810,7 +907,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::dereference::ALL) .short("L") .long(options::dereference::ALL) - .help(options::dereference::ALL_HELP) + .help( + "When showing file information for a symbolic link, show information for the \ + file the link references rather than the link itself.", + ) .overrides_with_all(&[ options::dereference::ALL, options::dereference::DIR_ARGS, @@ -820,7 +920,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::dereference::DIR_ARGS) .long(options::dereference::DIR_ARGS) - .help(options::dereference::DIR_ARGS_HELP) + .help( + "Do not dereference symlinks except when they link to directories and are \ + given as command line arguments.", + ) .overrides_with_all(&[ options::dereference::ALL, options::dereference::DIR_ARGS, @@ -845,11 +948,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .short("-G") .help("Do not show group in long format."), ) - .arg( - Arg::with_name(options::AUTHOR) - .long(options::AUTHOR) - .help(options::AUTHOR_HELP), - ) + .arg(Arg::with_name(options::AUTHOR).long(options::AUTHOR).help( + "Show author in long format. \ + On the supported platforms, the author always matches the file owner.", + )) // Other Flags .arg( Arg::with_name(options::files::ALL) @@ -861,13 +963,21 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::files::ALMOST_ALL) .short("A") .long(options::files::ALMOST_ALL) - .help(options::files::ALMOST_ALL_HELP), + .help( + "In a directory, do not ignore all file names that start with '.', \ +only ignore '.' and '..'.", + ), ) .arg( Arg::with_name(options::DIRECTORY) .short("d") .long(options::DIRECTORY) - .help(options::DIRECTORY_HELP), + .help( + "Only list the names of directories, rather than listing directory contents. \ + This will not follow symbolic links unless one of `--dereference-command-line \ + (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ + specified.", + ), ) .arg( Arg::with_name(options::size::HUMAN_READABLE) @@ -891,7 +1001,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::REVERSE) .short("r") .long(options::REVERSE) - .help(options::REVERSE_HLEP), + .help( + "Reverse whatever the sorting method is e.g., list files in reverse \ + alphabetical order, youngest first, smallest first, or whatever.", + ), ) .arg( Arg::with_name(options::RECURSIVE) @@ -918,7 +1031,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::INDICATOR_STYLE) .long(options::INDICATOR_STYLE) - .help(options::INDICATOR_STYLE_HELP) + .help( + "Append indicator with style WORD to entry names: \ + none (default), slash (-p), file-type (--file-type), classify (-F)", + ) .takes_value(true) .possible_values(&["none", "slash", "file-type", "classify"]) .overrides_with_all(&[ @@ -932,7 +1048,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 { Arg::with_name(options::indicator_style::CLASSIFY) .short("F") .long(options::indicator_style::CLASSIFY) - .help(options::indicator_style::CLASSIFY_HELP) + .help( + "Append a character to each file name indicating the file type. Also, for \ + regular files that are executable, append '*'. The file type indicators are \ + '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ + '>' for doors, and nothing for regular files.", + ) .overrides_with_all(&[ options::indicator_style::FILE_TYPE, options::indicator_style::SLASH, @@ -984,7 +1105,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .multiple(true) .takes_value(true), ) - .after_help(options::PATHS_AFTER_HELP); + .after_help( + "The TIME_STYLE argument can be full-iso, long-iso, iso. \ + Also the TIME_STYLE environment variable sets the default style to use.", + ); let matches = app.get_matches_from(args); diff --git a/src/uu/ls/src/options.rs b/src/uu/ls/src/options.rs deleted file mode 100644 index 32114ceb9a5..00000000000 --- a/src/uu/ls/src/options.rs +++ /dev/null @@ -1,134 +0,0 @@ -pub mod format { - pub static ONE_LINE: &str = "1"; - pub static LONG: &str = "long"; - pub static COLUMNS: &str = "C"; - pub static ACROSS: &str = "x"; - pub static COMMAS: &str = "m"; - pub static LONG_NO_OWNER: &str = "g"; - pub static LONG_NO_GROUP: &str = "o"; - pub static LONG_NO_GROUP_HELP: &str = - "Long format without group information. Identical to --format=long with --no-group."; - pub static LONG_NUMERIC_UID_GID: &str = "numeric-uid-gid"; -} - -pub mod files { - pub static ALL: &str = "all"; - pub static ALMOST_ALL: &str = "almost-all"; - pub static ALMOST_ALL_HELP: &str = - "In a directory, do not ignore all file names that start with '.', only ignore \ - '.' and '..'."; -} - -pub mod sort { - pub static SIZE: &str = "S"; - pub static TIME: &str = "t"; - pub static NONE: &str = "U"; - pub static NONE_HELP: &str = - "Do not sort; list the files in whatever order they are stored in the \ - directory. This is especially useful when listing very large directories, \ - since not doing any sorting can be noticeably faster."; - pub static VERSION: &str = "v"; - pub static EXTENSION: &str = "X"; -} - -pub mod time { - pub static ACCESS: &str = "u"; - pub static ACCESS_HELP: &str = - "If the long listing format (e.g., -l, -o) is being used, print the status \ - access time instead of the modification time. When explicitly sorting by time \ - (--sort=time or -t) or when not using a long listing format, sort according to the \ - access time."; - pub static CHANGE: &str = "c"; - pub static CHANGE_HELP: &str = - "If the long listing format (e.g., -l, -o) is being used, print the status \ - change time (the ‘ctime’ in the inode) instead of the modification time. When \ - explicitly sorting by time (--sort=time or -t) or when not using a long listing \ - format, sort according to the status change time."; -} - -pub mod size { - pub static HUMAN_READABLE: &str = "human-readable"; - pub static SI: &str = "si"; -} - -pub mod quoting { - pub static ESCAPE: &str = "escape"; - pub static LITERAL: &str = "literal"; - pub static C: &str = "quote-name"; -} - -pub mod indicator_style { - pub static SLASH: &str = "p"; - pub static FILE_TYPE: &str = "file-type"; - pub static CLASSIFY: &str = "classify"; - pub static CLASSIFY_HELP: &str = - "Append a character to each file name indicating the file type. Also, for \ - regular files that are executable, append '*'. The file type indicators are \ - '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \ - '>' for doors, and nothing for regular files."; -} - -pub mod dereference { - pub static ALL: &str = "dereference"; - pub static ALL_HELP: &str = - "When showing file information for a symbolic link, show information for the \ - file the link references rather than the link itself."; - pub static ARGS: &str = "dereference-command-line"; - pub static DIR_ARGS: &str = "dereference-command-line-symlink-to-dir"; - pub static DIR_ARGS_HELP: &str = - "Do not dereference symlinks except when they link to directories and are \ - given as command line arguments."; -} - -pub static QUOTING_STYLE: &str = "quoting-style"; -pub static HIDE_CONTROL_CHARS: &str = "hide-control-chars"; -pub static SHOW_CONTROL_CHARS: &str = "show-control-chars"; -pub static WIDTH: &str = "width"; - -pub static AUTHOR: &str = "author"; -pub static AUTHOR_HELP: &str = - "Show author in long format. On the supported platforms, the author \ -always matches the file owner."; - -pub static NO_GROUP: &str = "no-group"; -pub static FORMAT: &str = "format"; -pub static SORT: &str = "sort"; -pub static TIME: &str = "time"; -pub static IGNORE_BACKUPS: &str = "ignore-backups"; - -pub static DIRECTORY: &str = "directory"; -pub static DIRECTORY_HELP: &str = - "Only list the names of directories, rather than listing directory contents. \ -This will not follow symbolic links unless one of `--dereference-command-line \ -(-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \ -specified."; - -pub static INODE: &str = "inode"; - -pub static REVERSE: &str = "reverse"; -pub static REVERSE_HLEP: &str = - "Reverse whatever the sorting method is--e.g., list files in reverse \ -alphabetical order, youngest first, smallest first, or whatever."; - -pub static RECURSIVE: &str = "recursive"; -pub static COLOR: &str = "color"; - -pub static PATHS: &str = "paths"; -pub static PATHS_AFTER_HELP: &str = "The TIME_STYLE argument can be full-iso, long-iso, iso. -Also the TIME_STYLE environment variable sets the default style to use."; - -pub static INDICATOR_STYLE: &str = "indicator-style"; -pub static INDICATOR_STYLE_HELP: &str = - " append indicator with style WORD to entry names: none (default), slash\ -(-p), file-type (--file-type), classify (-F)"; - -pub static TIME_STYLE: &str = "time-style"; -pub static FULL_TIME: &str = "full-time"; -pub static HIDE: &str = "hide"; -pub static IGNORE: &str = "ignore"; - -pub static ABOUT: &str = " - By default, ls will list the files and contents of any directories on - the command line, expect that it will ignore files and directories - whose names start with '.' -"; From 4039dbdb77767f8612616fd061671a4c8d3d8e0e Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 19 Jun 2021 16:17:54 +0800 Subject: [PATCH 4/7] ls: Implement --size to display size in blocks Signed-off-by: Hanif Bin Ariffin Added tests for ls --size Signed-off-by: Hanif Bin Ariffin Fixed tests for windows Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 212 +++++++++++++++++++-------------------- tests/by-util/test_ls.rs | 35 +++++++ 2 files changed, 141 insertions(+), 106 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 79261abe7d5..845e73d4103 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -206,6 +206,7 @@ struct Config { quoting_style: QuotingStyle, indicator_style: IndicatorStyle, time_style: TimeStyle, + show_size: bool, } // Fields that can be removed or added to the long format @@ -529,6 +530,8 @@ impl Config { Dereference::DirArgs }; + let show_size = options.is_present(options::size::S); + Config { format, files, @@ -548,6 +551,7 @@ impl Config { quoting_style, indicator_style, time_style, + show_size, } } } @@ -991,6 +995,12 @@ only ignore '.' and '..'.", .long(options::size::SI) .help("Print human readable file sizes using powers of 1000 instead of 1024."), ) + .arg( + Arg::with_name(options::size::S) + .short(options::size::S) + .long(options::size::SIZE) + .help("print the allocated size of each file, in blocks."), + ) .arg( Arg::with_name(options::INODE) .short("i") @@ -1350,40 +1360,13 @@ fn get_metadata(entry: &Path, dereference: bool) -> std::io::Result { } } -fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize) { - if let Some(md) = entry.md() { - ( - display_symlink_count(md).len(), - display_size_or_rdev(md, config).len(), - ) - } else { - (0, 0) - } -} - fn pad_left(string: String, count: usize) -> String { format!("{:>width$}", string, width = count) } fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter) { if config.format == Format::Long { - let (mut max_links, mut max_width) = (1, 1); - let mut total_size = 0; - - for item in items { - let (links, width) = display_dir_entry_size(item, config); - max_links = links.max(max_links); - max_width = width.max(max_width); - total_size += item.md().map_or(0, |md| get_block_size(md, config)); - } - - if total_size > 0 { - let _ = writeln!(out, "total {}", display_size(total_size, config)); - } - - for item in items { - display_item_long(item, max_links, max_width, config, out); - } + display_item_long(items, config, out); } else { let names = items.iter().filter_map(|i| display_file_name(i, config)); @@ -1395,32 +1378,11 @@ fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter { - let term_width = width_opt.unwrap_or(1); - let mut current_col = 0; - let mut names = names; - if let Some(name) = names.next() { - let _ = write!(out, "{}", name.contents); - current_col = name.width as u16 + 2; - } - for name in names { - let name_width = name.width as u16; - if current_col + name_width + 1 > term_width { - current_col = name_width + 2; - let _ = write!(out, ",\n{}", name.contents); - } else { - current_col += name_width + 2; - let _ = write!(out, ", {}", name.contents); - } - } - // Current col is never zero again if names have been printed. - // So we print a newline. - if current_col > 0 { - let _ = writeln!(out,); - } + display_comma(names, width_opt.unwrap_or(1).into(), out); } _ => { for name in names { - let _ = writeln!(out, "{}", name.contents); + writeln!(out, "{}", name.contents).unwrap(); } } } @@ -1478,59 +1440,64 @@ fn display_grid( use uucore::fs::display_permissions; -fn display_item_long( - item: &PathData, - max_links: usize, - max_size: usize, - config: &Config, - out: &mut BufWriter, -) { - let md = match item.md() { - None => { - show_error!("could not show file: {}", &item.p_buf.display()); - return; +fn display_item_long(paths: &[PathData], config: &Config, out: &mut BufWriter) { + let metadatas = paths + .iter() + // FIXME: For now it just unwraps. Perhaps introduce better error messages? + .map(|path| path.md().unwrap()) + .collect::>(); + let (max_links, max_width, total_size) = metadatas + .iter() + .map(|md| { + ( + display_symlink_count(md).len(), + display_size_or_rdev(md, config).len(), + get_block_size(md, config), + ) + }) + .fold((1, 1, 0u64), |(a, b, c), (d, e, f)| { + (a.max(d), b.max(e), c.saturating_add(f)) + }); + if total_size > 0 { + writeln!(out, "total {}", display_size(total_size, config)).unwrap(); + } + for (item, md) in paths.iter().zip(metadatas.iter()) { + #[cfg(unix)] + { + if config.inode { + write!(out, "{} ", get_inode(md)).unwrap(); + } } - Some(md) => md, - }; - - #[cfg(unix)] - { - if config.inode { - let _ = write!(out, "{} ", get_inode(md)); + write!( + out, + "{} {}", + display_permissions(md, true), + pad_left(display_symlink_count(md), max_links), + ) + .unwrap(); + if config.long.owner { + write!(out, " {}", display_uname(md, config)).unwrap(); } + if config.long.group { + write!(out, " {}", display_group(md, config)).unwrap(); + } + // Author is only different from owner on GNU/Hurd, so we reuse + // the owner, since GNU/Hurd is not currently supported by Rust. + if config.long.author { + write!(out, " {}", display_uname(md, config)).unwrap(); + } + writeln!( + out, + " {} {} {}", + pad_left(display_size_or_rdev(md, config), max_width), + display_date(md, config), + // unwrap is fine because it fails when metadata is not available + // but we already know that it is because it's checked at the + // start of the function. + display_file_name(item, config).unwrap().contents, + ) + .unwrap(); } - - let _ = write!( - out, - "{} {}", - display_permissions(md, true), - pad_left(display_symlink_count(md), max_links), - ); - - if config.long.owner { - let _ = write!(out, " {}", display_uname(md, config)); - } - - if config.long.group { - let _ = write!(out, " {}", display_group(md, config)); - } - - // Author is only different from owner on GNU/Hurd, so we reuse - // the owner, since GNU/Hurd is not currently supported by Rust. - if config.long.author { - let _ = write!(out, " {}", display_uname(md, config)); - } - - let _ = writeln!( - out, - " {} {} {}", - pad_left(display_size_or_rdev(md, config), max_size), - display_date(md, config), - // unwrap is fine because it fails when metadata is not available - // but we already know that it is because it's checked at the - // start of the function. - display_file_name(item, config).unwrap().contents, - ); } #[cfg(unix)] @@ -1750,9 +1717,15 @@ fn display_file_name(path: &PathData, config: &Config) -> Option { } } + let file_size = if config.show_size { + format!("{} ", get_block_size(path.md().unwrap(), config)) + } else { + String::new() + }; + // We need to keep track of the width ourselves instead of letting term_grid // infer it because the color codes mess up term_grid's width calculation. - let mut width = name.width(); + let mut width = name.width() + file_size.width(); if let Some(ls_colors) = &config.color { name = color_name(ls_colors, &path.p_buf, name, path.md()?); @@ -1793,10 +1766,9 @@ fn display_file_name(path: &PathData, config: &Config) -> Option { } } - Some(Cell { - contents: name, - width, - }) + let contents = format!("{}{}", file_size, name); + + Some(Cell { contents, width }) } fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String { @@ -1817,3 +1789,31 @@ fn display_symlink_count(_metadata: &Metadata) -> String { fn display_symlink_count(metadata: &Metadata) -> String { metadata.nlink().to_string() } + +fn display_comma( + names: impl Iterator, + term_width: usize, + out: &mut BufWriter, +) { + let mut current_col = 0; + let mut names = names; + if let Some(name) = names.next() { + let _ = write!(out, "{}", name.contents); + current_col = name.width + 2; + } + for name in names { + let name_width = name.width; + if current_col + name_width + 1 > term_width { + current_col = name_width + 2; + let _ = write!(out, ",\n{}", name.contents); + } else { + current_col += name_width + 2; + let _ = write!(out, ", {}", name.contents); + } + } + // Current col is never zero again if names have been printed. + // So we print a newline. + if current_col > 0 { + let _ = writeln!(out,); + } +} diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index f8aa4453b4f..1d4130fee62 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -2021,3 +2021,38 @@ fn test_ls_path() { .run() .stdout_is(expected_stdout); } + +#[test] +fn test_ls_size() { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + at.touch("test-1"); + at.append( + "test-1", + &std::iter::repeat("a\n").take(123456).collect::(), + ); + at.touch("test-2"); + at.append( + "test-2", + &std::iter::repeat("a\n").take(234567).collect::(), + ); + at.touch("test-3"); + at.append( + "test-3", + &std::iter::repeat("a\n").take(345678).collect::(), + ); + at.touch("test-4"); + at.append( + "test-4", + &std::iter::repeat("a\n").take(456789).collect::(), + ); + + scene.ucmd().arg("-s").succeeds(); + + let result = scene.ucmd().arg("-s").succeeds(); + #[cfg(not(windows))] + result.stdout_only("244 test-1\n460 test-2\n676 test-3\n896 test-4\n"); + #[cfg(windows)] + result.stdout_only("246912 test-1 469134 test-2 691356 test-3 913578 test-4\n"); +} From 906003b4ae2a0d3ae0bab3b63dc57739fdd69ee7 Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sat, 19 Jun 2021 19:16:52 +0800 Subject: [PATCH 5/7] Some fixes from rebasing Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index 845e73d4103..ecb5c765f34 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -83,6 +83,8 @@ pub mod options { pub mod size { pub static HUMAN_READABLE: &str = "human-readable"; pub static SI: &str = "si"; + pub static S: &str = "s"; + pub static SIZE: &str = "size"; } pub mod quoting { @@ -999,13 +1001,13 @@ only ignore '.' and '..'.", Arg::with_name(options::size::S) .short(options::size::S) .long(options::size::SIZE) - .help("print the allocated size of each file, in blocks."), + .help("Print the allocated size of each file, in blocks."), ) .arg( Arg::with_name(options::INODE) .short("i") .long(options::INODE) - .help("print the index number of each file"), + .help("Print the index number of each file."), ) .arg( Arg::with_name(options::REVERSE) From 2970645d573e7747fb5cffe7582798e2fc9e245b Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Sun, 20 Jun 2021 08:39:14 +0800 Subject: [PATCH 6/7] Clippy fixes Signed-off-by: Hanif Bin Ariffin --- tests/by-util/test_ls.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index 1d4130fee62..43d3b888985 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -2033,20 +2033,11 @@ fn test_ls_size() { &std::iter::repeat("a\n").take(123456).collect::(), ); at.touch("test-2"); - at.append( - "test-2", - &std::iter::repeat("a\n").take(234567).collect::(), - ); + at.append("test-2", &"a\n".repeat(234567)); at.touch("test-3"); - at.append( - "test-3", - &std::iter::repeat("a\n").take(345678).collect::(), - ); + at.append("test-3", &"a\n".repeat(345678)); at.touch("test-4"); - at.append( - "test-4", - &std::iter::repeat("a\n").take(456789).collect::(), - ); + at.append("test-4", &"a\n".repeat(456789)); scene.ucmd().arg("-s").succeeds(); From 0fa5fa4cb6004358230e4a41bdd3092665c1911d Mon Sep 17 00:00:00 2001 From: Hanif Bin Ariffin Date: Mon, 5 Jul 2021 14:22:29 +0800 Subject: [PATCH 7/7] Fixed block size for FreeBSD to be 512 bytes Signed-off-by: Hanif Bin Ariffin --- src/uu/ls/src/ls.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/uu/ls/src/ls.rs b/src/uu/ls/src/ls.rs index f2356532a1d..dbdb383b2f2 100644 --- a/src/uu/ls/src/ls.rs +++ b/src/uu/ls/src/ls.rs @@ -49,6 +49,12 @@ fn get_usage() -> String { format!("{0} [OPTION]... [FILE]...", executable!()) } +#[cfg(not(target_os = "freebsd"))] +static LS_BLOCK_SIZE: u64 = 1024; + +#[cfg(target_os = "freebsd")] +static LS_BLOCK_SIZE: u64 = 512; + pub mod options { pub mod format { @@ -776,7 +782,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 { .arg( Arg::with_name(options::time::CHANGE) .short(options::time::CHANGE) - .help("If the long listing format (e.g., -l, -o) is being used, print the status \ + .help( + "If the long listing format (e.g., -l, -o) is being used, print the status \ change time (the 'ctime' in the inode) instead of the modification time. When \ explicitly sorting by time (--sort=time or -t) or when not using a long listing \ format, sort according to the status change time.", @@ -1398,11 +1405,10 @@ fn get_block_size(md: &Metadata, config: &Config) -> u64 { #[cfg(unix)] { // hard-coded for now - enabling setting this remains a TODO - let ls_block_size = 1024; match config.size_format { SizeFormat::Binary => md.blocks() * 512, SizeFormat::Decimal => md.blocks() * 512, - SizeFormat::Bytes => md.blocks() * 512 / ls_block_size, + SizeFormat::Bytes => md.blocks() * 512 / LS_BLOCK_SIZE, } }