Procházet zdrojové kódy

Add options for -n or --numeric-gid-uid.

This option is only avaialable in -l.
There's test for rendering, but no test for option parsing.
(I don't understand that section of code.)
b05902132 před 4 roky
rodič
revize
4ea79ee11d

+ 1 - 0
completions/completions.fish

@@ -65,6 +65,7 @@ complete -c exa -s 't' -l 'time'  -x -d "Which timestamp field to list" -a "
     created\t'Display created time'
 "
 complete -c exa -s 'm' -l 'modified'      -d "Use the modified timestamp field"
+complete -c -exa -s 'n' -l 'numeric-uid-gid' -d "List numeric user and group IDs."
 complete -c exa        -l 'changed'       -d "Use the changed timestamp field"
 complete -c exa -s 'u' -l 'accessed'      -d "Use the accessed timestamp field"
 complete -c exa -s 'U' -l 'created'       -d "Use the created timestamp field"

+ 1 - 0
completions/completions.zsh

@@ -39,6 +39,7 @@ __exa() {
         {-H,--links}"[List each file's number of hard links]" \
         {-i,--inode}"[List each file's inode number]" \
         {-m,--modified}"[Use the modified timestamp field]" \
+        {-n, --numeric-uid-gid}"[List numeric user and group IDs.]" \
         {-S,--blocks}"[List each file's number of filesystem blocks]" \
         {-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \
         --time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso)" \

+ 3 - 0
man/exa.1.md

@@ -140,6 +140,9 @@ These options are available when running with `--long` (`-l`):
 `-m`, `--modified`
 : Use the modified timestamp field.
 
+`-n`, `--numeric-uid-gid`
+: List numeric user and group IDs.
+
 `-S`, `--blocks`
 : List each file’s number of file system blocks.
 

+ 2 - 1
src/options/flags.rs

@@ -39,6 +39,7 @@ const SORTS: Values = &[ "name", "Name", "size", "extension",
 pub static BINARY:     Arg = Arg { short: Some(b'b'), long: "binary",     takes_value: TakesValue::Forbidden };
 pub static BYTES:      Arg = Arg { short: Some(b'B'), long: "bytes",      takes_value: TakesValue::Forbidden };
 pub static GROUP:      Arg = Arg { short: Some(b'g'), long: "group",      takes_value: TakesValue::Forbidden };
+pub static NUM_UGID:   Arg = Arg { short: Some(b'n'), long: "numeric-uid-gid", takes_value: TakesValue::Forbidden };
 pub static HEADER:     Arg = Arg { short: Some(b'h'), long: "header",     takes_value: TakesValue::Forbidden };
 pub static ICONS:      Arg = Arg { short: None,       long: "icons",      takes_value: TakesValue::Forbidden };
 pub static INODE:      Arg = Arg { short: Some(b'i'), long: "inode",      takes_value: TakesValue::Forbidden };
@@ -74,7 +75,7 @@ pub static ALL_ARGS: Args = Args(&[
     &ALL, &LIST_DIRS, &LEVEL, &REVERSE, &SORT, &DIRS_FIRST,
     &IGNORE_GLOB, &GIT_IGNORE, &ONLY_DIRS,
 
-    &BINARY, &BYTES, &GROUP, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
+    &BINARY, &BYTES, &GROUP, &NUM_UGID, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
     &BLOCKS, &TIME, &ACCESSED, &CREATED, &TIME_STYLE,
     &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME,
 

+ 1 - 0
src/options/help.rs

@@ -46,6 +46,7 @@ LONG VIEW OPTIONS
   -H, --links          list each file's number of hard links
   -i, --inode          list each file's inode number
   -m, --modified       use the modified timestamp field
+  -n, --numeric-uid-gid list numeric user and group IDs
   -S, --blocks         show number of file system blocks
   -t, --time FIELD     which timestamp field to list (modified, accessed, created)
   -u, --accessed       use the accessed timestamp field

+ 11 - 2
src/options/view.rs

@@ -4,7 +4,7 @@ use crate::options::parser::MatchedFlags;
 use crate::output::{View, Mode, TerminalWidth, grid, details};
 use crate::output::grid_details::{self, RowThreshold};
 use crate::output::file_name::Options as FileStyle;
-use crate::output::table::{TimeTypes, SizeFormat, Columns, Options as TableOptions};
+use crate::output::table::{TimeTypes, SizeFormat, UserFormat, Columns, Options as TableOptions};
 use crate::output::time::TimeFormat;
 
 
@@ -183,8 +183,9 @@ impl TableOptions {
     fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         let time_format = TimeFormat::deduce(matches, vars)?;
         let size_format = SizeFormat::deduce(matches)?;
+        let user_format = UserFormat::deduce(matches)?;
         let columns = Columns::deduce(matches)?;
-        Ok(Self { time_format, size_format, columns })
+        Ok(Self { time_format, size_format, columns , user_format})
     }
 }
 
@@ -265,6 +266,14 @@ impl TimeFormat {
     }
 }
 
+impl UserFormat {
+    fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
+        let flag = matches.has(&flags::NUM_UGID)?;
+        Ok(if flag { Self::Numeric } else { Self::Name })
+    }
+
+}
+
 
 impl TimeTypes {
 

+ 19 - 7
src/output/render/groups.rs

@@ -3,10 +3,11 @@ use users::{Users, Groups};
 
 use crate::fs::fields as f;
 use crate::output::cell::TextCell;
+use crate::output::table::UserFormat;
 
 
 impl f::Group {
-    pub fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U) -> TextCell {
+    pub fn render<C: Colours, U: Users+Groups>(self, colours: &C, users: &U, format: UserFormat) -> TextCell {
         use users::os::unix::GroupExt;
 
         let mut style = colours.not_yours();
@@ -26,7 +27,12 @@ impl f::Group {
             }
         }
 
-        TextCell::paint(style, group.name().to_string_lossy().into())
+        let group_name = match format {
+            UserFormat::Name => group.name().to_string_lossy().into(),
+            UserFormat::Numeric => group.gid().to_string(),
+        };
+
+        TextCell::paint(style, group_name)
     }
 }
 
@@ -43,6 +49,7 @@ pub mod test {
     use super::Colours;
     use crate::fs::fields as f;
     use crate::output::cell::TextCell;
+    use crate::output::table::UserFormat;
 
     use users::{User, Group};
     use users::mock::MockUsers;
@@ -66,16 +73,21 @@ pub mod test {
 
         let group = f::Group(100);
         let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users))
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name));
+
+        let expected = TextCell::paint_str(Fixed(81).normal(), "100");
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Numeric));
     }
 
+
     #[test]
     fn unnamed() {
         let users = MockUsers::with_current_uid(1000);
 
         let group = f::Group(100);
         let expected = TextCell::paint_str(Fixed(81).normal(), "100");
-        assert_eq!(expected, group.render(&TestColours, &users));
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name));
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Numeric));
     }
 
     #[test]
@@ -86,7 +98,7 @@ pub mod test {
 
         let group = f::Group(100);
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users))
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name))
     }
 
     #[test]
@@ -99,13 +111,13 @@ pub mod test {
 
         let group = f::Group(100);
         let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
-        assert_eq!(expected, group.render(&TestColours, &users))
+        assert_eq!(expected, group.render(&TestColours, &users, UserFormat::Name))
     }
 
     #[test]
     fn overflow() {
         let group = f::Group(2_147_483_648);
         let expected = TextCell::paint_str(Fixed(81).normal(), "2147483648");
-        assert_eq!(expected, group.render(&TestColours, &MockUsers::with_current_uid(0)));
+        assert_eq!(expected, group.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
     }
 }

+ 16 - 9
src/output/render/users.rs

@@ -3,13 +3,15 @@ use users::Users;
 
 use crate::fs::fields as f;
 use crate::output::cell::TextCell;
+use crate::output::table::UserFormat;
 
 
 impl f::User {
-    pub fn render<C: Colours, U: Users>(self, colours: &C, users: &U) -> TextCell {
-        let user_name = match users.get_user_by_uid(self.0) {
-            Some(user)  => user.name().to_string_lossy().into(),
-            None        => self.0.to_string(),
+    pub fn render<C: Colours, U: Users>(self, colours: &C, users: &U, format: UserFormat) -> TextCell {
+        let user_name = match (format, users.get_user_by_uid(self.0)) {
+            (_, None)                      => self.0.to_string(),
+            (UserFormat::Numeric, _)       => self.0.to_string(),
+            (UserFormat::Name, Some(user)) => user.name().to_string_lossy().into(),
         };
 
         let style = if users.get_current_uid() == self.0 { colours.you() }
@@ -31,6 +33,7 @@ pub mod test {
     use super::Colours;
     use crate::fs::fields as f;
     use crate::output::cell::TextCell;
+    use crate::output::table::UserFormat;
 
     use users::User;
     use users::mock::MockUsers;
@@ -53,7 +56,10 @@ pub mod test {
 
         let user = f::User(1000);
         let expected = TextCell::paint_str(Red.bold(), "enoch");
-        assert_eq!(expected, user.render(&TestColours, &users))
+        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
+
+        let expected = TextCell::paint_str(Red.bold(), "1000");
+        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
     }
 
     #[test]
@@ -62,7 +68,8 @@ pub mod test {
 
         let user = f::User(1000);
         let expected = TextCell::paint_str(Red.bold(), "1000");
-        assert_eq!(expected, user.render(&TestColours, &users));
+        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
+        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Numeric));
     }
 
     #[test]
@@ -72,20 +79,20 @@ pub mod test {
 
         let user = f::User(1000);
         let expected = TextCell::paint_str(Blue.underline(), "enoch");
-        assert_eq!(expected, user.render(&TestColours, &users));
+        assert_eq!(expected, user.render(&TestColours, &users, UserFormat::Name));
     }
 
     #[test]
     fn different_unnamed() {
         let user = f::User(1000);
         let expected = TextCell::paint_str(Blue.underline(), "1000");
-        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0)));
+        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
     }
 
     #[test]
     fn overflow() {
         let user = f::User(2_147_483_648);
         let expected = TextCell::paint_str(Blue.underline(), "2147483648");
-        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0)));
+        assert_eq!(expected, user.render(&TestColours, &MockUsers::with_current_uid(0), UserFormat::Numeric));
     }
 }

+ 14 - 2
src/output/table.rs

@@ -23,6 +23,7 @@ use crate::theme::Theme;
 pub struct Options {
     pub size_format: SizeFormat,
     pub time_format: TimeFormat,
+    pub user_format: UserFormat,
     pub columns: Columns,
 }
 
@@ -180,6 +181,15 @@ pub enum SizeFormat {
     JustBytes,
 }
 
+/// Formatting options for user and group.
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub enum UserFormat {
+    /// The UID / GID
+    Numeric,
+    /// Show the name
+    Name,
+}
+
 impl Default for SizeFormat {
     fn default() -> Self {
         Self::DecimalBytes
@@ -311,6 +321,7 @@ pub struct Table<'a> {
     widths: TableWidths,
     time_format: TimeFormat,
     size_format: SizeFormat,
+    user_format: UserFormat,
     git: Option<&'a GitCache>,
 }
 
@@ -333,6 +344,7 @@ impl<'a, 'f> Table<'a> {
             env,
             time_format: options.time_format,
             size_format: options.size_format,
+            user_format: options.user_format,
         }
     }
 
@@ -392,10 +404,10 @@ impl<'a, 'f> Table<'a> {
                 file.blocks().render(self.theme)
             }
             Column::User => {
-                file.user().render(self.theme, &*self.env.lock_users())
+                file.user().render(self.theme, &*self.env.lock_users(), self.user_format)
             }
             Column::Group => {
-                file.group().render(self.theme, &*self.env.lock_users())
+                file.group().render(self.theme, &*self.env.lock_users(), self.user_format)
             }
             Column::GitStatus => {
                 self.git_status(file).render(self.theme)