mirror of
https://github.com/eza-community/eza
synced 2024-09-30 05:06:30 +00:00
feat(flags): Add BSD file flags
This commit is contained in:
parent
c7950dc9bd
commit
458a6f5b1e
|
@ -200,6 +200,9 @@ These options are available when running with `--long` (`-l`):
|
|||
`-n`, `--numeric`
|
||||
: List numeric user and group IDs.
|
||||
|
||||
`-O`, `--flags`
|
||||
: List file flags. See chflags(1) for a list of file flags and their meanings. (Mac and BSD only)
|
||||
|
||||
`-S`, `--blocksize`
|
||||
: List each file’s size of allocated file system blocks.
|
||||
|
||||
|
|
|
@ -300,6 +300,9 @@ LIST OF CODES
|
|||
`Sl`
|
||||
: SELinux level
|
||||
|
||||
`ff`
|
||||
: BSD file flags
|
||||
|
||||
Values in `EXA_COLORS` override those given in `LS_COLORS`, so you don’t need to re-write an existing `LS_COLORS` variable with proprietary extensions.
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ pub type time_t = i64;
|
|||
/// The type of a file’s user ID.
|
||||
pub type uid_t = u32;
|
||||
|
||||
/// The type of user file flags
|
||||
pub type flag_t = u32;
|
||||
|
||||
/// The file’s base type, which gets displayed in the very first column of the
|
||||
/// details output.
|
||||
///
|
||||
|
@ -274,3 +277,7 @@ impl Default for SubdirGitRepo {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The user file flags on the file. This will only ever be a number;
|
||||
/// looking up the flags is done in the `display` module.
|
||||
pub struct Flags(pub flag_t);
|
||||
|
|
|
@ -875,6 +875,39 @@ impl<'dir> File<'dir> {
|
|||
context: SecurityContextType::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// User file flags.
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
pub fn flags(&self) -> f::Flags {
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
use std::os::dragonfly::fs::MetadataExt;
|
||||
#[cfg(target_os = "freebsd")]
|
||||
use std::os::freebsd::fs::MetadataExt;
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::os::macos::fs::MetadataExt;
|
||||
#[cfg(target_os = "netbsd")]
|
||||
use std::os::netbsd::fs::MetadataExt;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
use std::os::openbsd::fs::MetadataExt;
|
||||
f::Flags(self.metadata.st_flags())
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
)))]
|
||||
pub fn flags(&self) -> f::Flags {
|
||||
f::Flags(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsRef<File<'a>> for File<'a> {
|
||||
|
|
|
@ -81,6 +81,7 @@ pub static EXTENDED: Arg = Arg { short: Some(b'@'), long: "extended",
|
|||
pub static OCTAL: Arg = Arg { short: Some(b'o'), long: "octal-permissions", takes_value: TakesValue::Forbidden };
|
||||
pub static SECURITY_CONTEXT: Arg = Arg { short: Some(b'Z'), long: "context", takes_value: TakesValue::Forbidden };
|
||||
pub static STDIN: Arg = Arg { short: None, long: "stdin", takes_value: TakesValue::Forbidden };
|
||||
pub static FILE_FLAGS: Arg = Arg { short: Some(b'O'), long: "flags", takes_value: TakesValue::Forbidden };
|
||||
|
||||
pub static ALL_ARGS: Args = Args(&[
|
||||
&VERSION, &HELP,
|
||||
|
@ -97,5 +98,5 @@ pub static ALL_ARGS: Args = Args(&[
|
|||
&NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &SMART_GROUP,
|
||||
|
||||
&GIT, &NO_GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT,
|
||||
&EXTENDED, &OCTAL, &SECURITY_CONTEXT, &STDIN,
|
||||
&EXTENDED, &OCTAL, &SECURITY_CONTEXT, &STDIN, &FILE_FLAGS
|
||||
]);
|
||||
|
|
|
@ -59,8 +59,9 @@ 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
|
||||
-M, --mounts show mount details (Linux and MacOS only)
|
||||
-M, --mounts show mount details (Linux and Mac only)
|
||||
-n, --numeric list numeric user and group IDs
|
||||
-O, --flags list file flags (Mac and BSD only)
|
||||
-S, --blocksize show size of allocated file system blocks
|
||||
-t, --time FIELD which timestamp field to list (modified, accessed, created)
|
||||
-u, --accessed use the accessed timestamp field
|
||||
|
|
|
@ -270,6 +270,7 @@ impl Columns {
|
|||
let links = matches.has(&flags::LINKS)?;
|
||||
let octal = matches.has(&flags::OCTAL)?;
|
||||
let security_context = xattr::ENABLED && matches.has(&flags::SECURITY_CONTEXT)?;
|
||||
let file_flags = matches.has(&flags::FILE_FLAGS)?;
|
||||
|
||||
let permissions = !matches.has(&flags::NO_PERMISSIONS)?;
|
||||
let filesize = !matches.has(&flags::NO_FILESIZE)?;
|
||||
|
@ -286,6 +287,7 @@ impl Columns {
|
|||
subdir_git_repos_no_stat,
|
||||
octal,
|
||||
security_context,
|
||||
file_flags,
|
||||
permissions,
|
||||
filesize,
|
||||
user,
|
||||
|
|
10
src/output/render/flags.rs
Normal file
10
src/output/render/flags.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
use ansiterm::Style;
|
||||
|
||||
use crate::fs::fields as f;
|
||||
use crate::output::cell::TextCell;
|
||||
|
||||
impl f::Flags {
|
||||
pub fn render(self, style: Style) -> TextCell {
|
||||
TextCell::paint(style, "-".to_string())
|
||||
}
|
||||
}
|
39
src/output/render/flags_bsd.rs
Normal file
39
src/output/render/flags_bsd.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use ansiterm::Style;
|
||||
use std::ffi::CStr;
|
||||
|
||||
use crate::fs::fields as f;
|
||||
use crate::output::cell::TextCell;
|
||||
|
||||
extern "C" {
|
||||
fn fflagstostr(flags: libc::c_ulong) -> *const libc::c_char;
|
||||
}
|
||||
|
||||
/// Wrapper around the C library call fflagstostr. If returned string is NULL
|
||||
/// or empty a "-" is returned
|
||||
fn flags_to_string(flags: f::flag_t) -> String {
|
||||
// SAFETY: Calling external "C" function
|
||||
let flags_c_str = unsafe { fflagstostr(libc::c_ulong::from(flags)) };
|
||||
|
||||
if flags_c_str.is_null() {
|
||||
"-".to_string()
|
||||
} else {
|
||||
let flags_str = unsafe { CStr::from_ptr(flags_c_str) };
|
||||
let flags = flags_str
|
||||
.to_str()
|
||||
.map_or("-", |s| if s.is_empty() { "-" } else { s })
|
||||
.to_string();
|
||||
|
||||
// SAFETY: Calling external "C" function to free memory allocated by fflagstostr
|
||||
unsafe {
|
||||
libc::free(flags_c_str.cast_mut().cast());
|
||||
}
|
||||
|
||||
flags
|
||||
}
|
||||
}
|
||||
|
||||
impl f::Flags {
|
||||
pub fn render(self, style: Style) -> TextCell {
|
||||
TextCell::paint(style, flags_to_string(self.0))
|
||||
}
|
||||
}
|
|
@ -45,3 +45,21 @@ pub use self::octal::Render as OctalPermissionsRender;
|
|||
|
||||
mod securityctx;
|
||||
pub use self::securityctx::Colours as SecurityCtxColours;
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
))]
|
||||
mod flags_bsd;
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "dragonfly"
|
||||
)))]
|
||||
mod flags;
|
||||
|
|
|
@ -49,6 +49,7 @@ pub struct Columns {
|
|||
pub subdir_git_repos_no_stat: bool,
|
||||
pub octal: bool,
|
||||
pub security_context: bool,
|
||||
pub file_flags: bool,
|
||||
|
||||
// Defaults to true:
|
||||
pub permissions: bool,
|
||||
|
@ -98,6 +99,10 @@ impl Columns {
|
|||
columns.push(Column::Group);
|
||||
}
|
||||
|
||||
if self.file_flags {
|
||||
columns.push(Column::FileFlags);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if self.security_context {
|
||||
columns.push(Column::SecurityContext);
|
||||
|
@ -157,6 +162,7 @@ pub enum Column {
|
|||
Octal,
|
||||
#[cfg(unix)]
|
||||
SecurityContext,
|
||||
FileFlags,
|
||||
}
|
||||
|
||||
/// Each column can pick its own **Alignment**. Usually, numbers are
|
||||
|
@ -214,6 +220,7 @@ impl Column {
|
|||
Self::Octal => "Octal",
|
||||
#[cfg(unix)]
|
||||
Self::SecurityContext => "Security Context",
|
||||
Self::FileFlags => "Flags",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -512,6 +519,7 @@ impl<'a> Table<'a> {
|
|||
),
|
||||
#[cfg(unix)]
|
||||
Column::SecurityContext => file.security_context().render(self.theme),
|
||||
Column::FileFlags => file.flags().render(self.theme.ui.flags),
|
||||
Column::GitStatus => self.git_status(file).render(self.theme),
|
||||
Column::SubdirGitRepo(status) => self.subdir_git_repo(file, status).render(self.theme),
|
||||
#[cfg(unix)]
|
||||
|
|
|
@ -113,6 +113,7 @@ impl UiStyles {
|
|||
inode: Purple.normal(),
|
||||
blocks: Cyan.normal(),
|
||||
octal: Purple.normal(),
|
||||
flags: Style::default(),
|
||||
header: Style::default().underline(),
|
||||
|
||||
symlink_path: Cyan.normal(),
|
||||
|
|
|
@ -583,6 +583,7 @@ mod customs_test {
|
|||
test!(exa_lp: ls "", exa "lp=38;5;133" => colours c -> { c.symlink_path = Fixed(133).normal(); });
|
||||
test!(exa_cc: ls "", exa "cc=38;5;134" => colours c -> { c.control_char = Fixed(134).normal(); });
|
||||
test!(exa_oc: ls "", exa "oc=38;5;135" => colours c -> { c.octal = Fixed(135).normal(); });
|
||||
test!(exa_ff: ls "", exa "ff=38;5;136" => colours c -> { c.flags = Fixed(136).normal(); });
|
||||
test!(exa_bo: ls "", exa "bO=4" => colours c -> { c.broken_path_overlay = Style::default().underline(); });
|
||||
|
||||
test!(exa_mp: ls "", exa "mp=1;34;4" => colours c -> { c.filekinds.mount_point = Blue.bold().underline(); });
|
||||
|
|
|
@ -23,6 +23,7 @@ pub struct UiStyles {
|
|||
pub blocks: Style, // bl
|
||||
pub header: Style, // hd
|
||||
pub octal: Style, // oc
|
||||
pub flags: Style, // ff
|
||||
|
||||
pub symlink_path: Style, // lp
|
||||
pub control_char: Style, // cc
|
||||
|
@ -253,6 +254,7 @@ impl UiStyles {
|
|||
"bl" => self.blocks = pair.to_style(),
|
||||
"hd" => self.header = pair.to_style(),
|
||||
"oc" => self.octal = pair.to_style(),
|
||||
"ff" => self.flags = pair.to_style(),
|
||||
"lp" => self.symlink_path = pair.to_style(),
|
||||
"cc" => self.control_char = pair.to_style(),
|
||||
"bO" => self.broken_path_overlay = pair.to_style(),
|
||||
|
|
Loading…
Reference in a new issue