Merge pull request #514 from liketurbo/feat-480

feat: add option --smart-group
This commit is contained in:
Christina Sørensen 2023-10-15 05:45:40 +00:00 committed by GitHub
commit e58106a35b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 133 additions and 37 deletions

View file

@ -4,7 +4,7 @@ _eza() {
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
--help|-v|--version)
--help|-v|--version|--smart-group)
return
;;

View file

@ -24,6 +24,7 @@ complete -c eza -l icons -d "Display icons"
complete -c eza -l no-icons -d "Don't display icons"
complete -c eza -l no-quotes -d "Don't quote file names with spaces"
complete -c eza -l hyperlink -d "Display entries as hyperlinks"
complete -c eza -l smart-group -d "Only show group if it has a different name from owner"
# Filtering and sorting options
complete -c eza -l group-directories-first -d "Sort directories before other files"

View file

@ -55,4 +55,5 @@ export extern "eza" [
--git-repos-no-status # List each git-repos branch name (much faster)
--extended(-@) # List each file's extended attributes and sizes
--context(-Z) # List each file's security context
--smart-group # Only show group if it has a different name from owner
]

View file

@ -65,7 +65,8 @@ __eza() {
{-@,--extended}"[List each file's extended attributes and sizes]" \
{-Z,--context}"[List each file's security context]" \
{-M,--mounts}"[Show mount details (long mode only)]" \
'*:filename:_files'
'*:filename:_files' \
--smart-group"[Only show group if it has a different name from owner]"
}
__eza

View file

@ -103,6 +103,9 @@ Manually setting this option overrides `NO_COLOR` environment.
`-w`, `--width=COLS`
: Set screen width in columns.
`--smart-group`
: Only show group if it has a different name from owner
FILTERING AND SORTING OPTIONS
=============================

View file

@ -40,23 +40,24 @@ const SORTS: Values = &[ "name", "Name", "size", "extension",
"created", "inode", "type", "none" ];
// display options
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 NUMERIC: Arg = Arg { short: Some(b'n'), long: "numeric", 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 };
pub static LINKS: Arg = Arg { short: Some(b'H'), long: "links", takes_value: TakesValue::Forbidden };
pub static MODIFIED: Arg = Arg { short: Some(b'm'), long: "modified", takes_value: TakesValue::Forbidden };
pub static CHANGED: Arg = Arg { short: None, long: "changed", takes_value: TakesValue::Forbidden };
pub static BLOCKSIZE: Arg = Arg { short: Some(b'S'), long: "blocksize", takes_value: TakesValue::Forbidden };
pub static TIME: Arg = Arg { short: Some(b't'), long: "time", takes_value: TakesValue::Necessary(Some(TIMES)) };
pub static ACCESSED: Arg = Arg { short: Some(b'u'), long: "accessed", takes_value: TakesValue::Forbidden };
pub static CREATED: Arg = Arg { short: Some(b'U'), long: "created", takes_value: TakesValue::Forbidden };
pub static TIME_STYLE: Arg = Arg { short: None, long: "time-style", takes_value: TakesValue::Necessary(Some(TIME_STYLES)) };
pub static HYPERLINK: Arg = Arg { short: None, long: "hyperlink", takes_value: TakesValue::Forbidden };
pub static MOUNTS: Arg = Arg { short: Some(b'M'), long: "mounts", takes_value: TakesValue::Forbidden };
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 NUMERIC: Arg = Arg { short: Some(b'n'), long: "numeric", 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 };
pub static LINKS: Arg = Arg { short: Some(b'H'), long: "links", takes_value: TakesValue::Forbidden };
pub static MODIFIED: Arg = Arg { short: Some(b'm'), long: "modified", takes_value: TakesValue::Forbidden };
pub static CHANGED: Arg = Arg { short: None, long: "changed", takes_value: TakesValue::Forbidden };
pub static BLOCKSIZE: Arg = Arg { short: Some(b'S'), long: "blocksize", takes_value: TakesValue::Forbidden };
pub static TIME: Arg = Arg { short: Some(b't'), long: "time", takes_value: TakesValue::Necessary(Some(TIMES)) };
pub static ACCESSED: Arg = Arg { short: Some(b'u'), long: "accessed", takes_value: TakesValue::Forbidden };
pub static CREATED: Arg = Arg { short: Some(b'U'), long: "created", takes_value: TakesValue::Forbidden };
pub static TIME_STYLE: Arg = Arg { short: None, long: "time-style", takes_value: TakesValue::Necessary(Some(TIME_STYLES)) };
pub static HYPERLINK: Arg = Arg { short: None, long: "hyperlink", takes_value: TakesValue::Forbidden };
pub static MOUNTS: Arg = Arg { short: Some(b'M'), long: "mounts", takes_value: TakesValue::Forbidden };
pub static SMART_GROUP: Arg = Arg { short: None, long: "smart-group", takes_value: TakesValue::Forbidden };
const TIMES: Values = &["modified", "changed", "accessed", "created"];
const TIME_STYLES: Values = &["default", "long-iso", "full-iso", "iso", "relative"];
@ -87,7 +88,7 @@ pub static ALL_ARGS: Args = Args(&[
&BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
&BLOCKSIZE, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK, &MOUNTS,
&NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &NO_ICONS,
&NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &NO_ICONS, &SMART_GROUP,
&GIT, &NO_GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT,
&EXTENDED, &OCTAL, &SECURITY_CONTEXT

View file

@ -27,6 +27,7 @@ DISPLAY OPTIONS
--no-quotes don't quote file names with spaces
--hyperlink display entries as hyperlinks
-w, --width COLS set screen width in columns
--smart-group only show group if it has a different name from owner
FILTERING AND SORTING OPTIONS

View file

@ -3,7 +3,9 @@ use crate::options::parser::MatchedFlags;
use crate::options::{flags, NumberSource, OptionsError, Vars};
use crate::output::file_name::Options as FileStyle;
use crate::output::grid_details::{self, RowThreshold};
use crate::output::table::{Columns, Options as TableOptions, SizeFormat, TimeTypes, UserFormat};
use crate::output::table::{
Columns, GroupFormat, Options as TableOptions, SizeFormat, TimeTypes, UserFormat,
};
use crate::output::time::TimeFormat;
use crate::output::{details, grid, Mode, TerminalWidth, View};
@ -231,11 +233,13 @@ impl TableOptions {
let time_format = TimeFormat::deduce(matches, vars)?;
let size_format = SizeFormat::deduce(matches)?;
let user_format = UserFormat::deduce(matches)?;
let group_format = GroupFormat::deduce(matches)?;
let columns = Columns::deduce(matches, vars)?;
Ok(Self {
size_format,
time_format,
user_format,
group_format,
columns,
})
}
@ -341,6 +345,13 @@ impl UserFormat {
}
}
impl GroupFormat {
fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
let flag = matches.has(&flags::SMART_GROUP)?;
Ok(if flag { Self::Smart } else { Self::Regular })
}
}
impl TimeTypes {
/// Determine which of a files time fields should be displayed for it
/// based on the users options.

View file

@ -3,14 +3,15 @@ use uzers::{Groups, Users};
use crate::fs::fields as f;
use crate::output::cell::TextCell;
use crate::output::table::UserFormat;
use crate::output::table::{GroupFormat, UserFormat};
pub trait Render {
fn render<C: Colours, U: Users + Groups>(
self,
colours: &C,
users: &U,
format: UserFormat,
user_format: UserFormat,
group_format: GroupFormat,
) -> TextCell;
}
@ -19,7 +20,8 @@ impl Render for Option<f::Group> {
self,
colours: &C,
users: &U,
format: UserFormat,
user_format: UserFormat,
group_format: GroupFormat,
) -> TextCell {
use uzers::os::unix::GroupExt;
@ -46,11 +48,26 @@ impl Render for Option<f::Group> {
style = colours.root_group();
}
let group_name = match format {
let mut group_name = match user_format {
UserFormat::Name => group.name().to_string_lossy().into(),
UserFormat::Numeric => group.gid().to_string(),
};
group_name = match group_format {
GroupFormat::Smart => {
if let Some(current_user) = users.get_user_by_uid(current_uid) {
if current_user.name() == group.name() {
":".to_string()
} else {
group_name
}
} else {
group_name
}
}
GroupFormat::Regular => group_name,
};
TextCell::paint(style, group_name)
}
}
@ -68,7 +85,7 @@ pub mod test {
use super::{Colours, Render};
use crate::fs::fields as f;
use crate::output::cell::TextCell;
use crate::output::table::UserFormat;
use crate::output::table::{GroupFormat, UserFormat};
use ansiterm::Colour::*;
use ansiterm::Style;
@ -95,13 +112,18 @@ pub mod test {
let expected = TextCell::paint_str(Fixed(81).normal(), "folk");
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Name)
group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Regular)
);
let expected = TextCell::paint_str(Fixed(81).normal(), "100");
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Numeric)
group.render(
&TestColours,
&users,
UserFormat::Numeric,
GroupFormat::Regular
)
);
}
@ -113,11 +135,16 @@ pub mod test {
let expected = TextCell::paint_str(Fixed(81).normal(), "100");
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Name)
group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Regular)
);
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Numeric)
group.render(
&TestColours,
&users,
UserFormat::Numeric,
GroupFormat::Regular
)
);
}
@ -131,7 +158,7 @@ pub mod test {
let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Name)
group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Regular)
)
}
@ -147,7 +174,7 @@ pub mod test {
let expected = TextCell::paint_str(Fixed(80).normal(), "folk");
assert_eq!(
expected,
group.render(&TestColours, &users, UserFormat::Name)
group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Regular)
)
}
@ -160,8 +187,42 @@ pub mod test {
group.render(
&TestColours,
&MockUsers::with_current_uid(0),
UserFormat::Numeric
UserFormat::Numeric,
GroupFormat::Regular
)
);
}
#[test]
fn smart() {
let mut users = MockUsers::with_current_uid(1000);
users.add_user(User::new(1000, "user", 110));
users.add_group(Group::new(100, "user"));
users.add_group(Group::new(101, "http"));
let same_group = Some(f::Group(100));
let expected = TextCell::paint_str(Fixed(81).normal(), ":");
assert_eq!(
expected,
same_group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Smart)
);
let expected = TextCell::paint_str(Fixed(81).normal(), ":");
assert_eq!(
expected,
same_group.render(
&TestColours,
&users,
UserFormat::Numeric,
GroupFormat::Smart
)
);
let http_group = Some(f::Group(101));
let expected = TextCell::paint_str(Fixed(81).normal(), "http");
assert_eq!(
expected,
http_group.render(&TestColours, &users, UserFormat::Name, GroupFormat::Smart)
);
}
}

View file

@ -25,6 +25,7 @@ pub struct Options {
pub size_format: SizeFormat,
pub time_format: TimeFormat,
pub user_format: UserFormat,
pub group_format: GroupFormat,
pub columns: Columns,
}
@ -239,6 +240,15 @@ pub enum UserFormat {
Name,
}
/// Formatting options for group only.
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum GroupFormat {
/// Numeric or text value
Regular,
/// Show ":" if user-group value is the same
Smart,
}
impl Default for SizeFormat {
fn default() -> Self {
Self::DecimalBytes
@ -355,6 +365,8 @@ pub struct Table<'a> {
size_format: SizeFormat,
#[cfg(unix)]
user_format: UserFormat,
#[cfg(unix)]
group_format: GroupFormat,
git: Option<&'a GitCache>,
}
@ -379,6 +391,8 @@ impl<'a> Table<'a> {
size_format: options.size_format,
#[cfg(unix)]
user_format: options.user_format,
#[cfg(unix)]
group_format: options.group_format,
}
}
@ -457,10 +471,12 @@ impl<'a> Table<'a> {
.render(self.theme, &*self.env.lock_users(), self.user_format)
}
#[cfg(unix)]
Column::Group => {
file.group()
.render(self.theme, &*self.env.lock_users(), self.user_format)
}
Column::Group => file.group().render(
self.theme,
&*self.env.lock_users(),
self.user_format,
self.group_format,
),
#[cfg(unix)]
Column::SecurityContext => file.security_context().render(self.theme),
Column::GitStatus => self.git_status(file).render(self.theme),