chore: replace #[allow(unused)] by #[cfg(unix)] when appropriate

Biggest change is splitting platform-specific code from permissions.rs
(similarly to flags.rs in the same directory).
This commit is contained in:
ariasuni
2026-03-08 03:20:56 +01:00
parent c0fe456ba5
commit dd6628b60b
7 changed files with 355 additions and 324 deletions
+10 -7
View File
@@ -21,18 +21,19 @@
#![allow(clippy::struct_excessive_bools)]
/// The type of a file’s group ID.
#[cfg(unix)]
pub type gid_t = u32;
/// The type of a file’s inode.
#[allow(unused)]
#[cfg(unix)]
pub type ino_t = u64;
/// The type of a file’s number of links.
#[allow(unused)]
#[cfg(unix)]
pub type nlink_t = u64;
/// The type of a file’s user ID.
#[allow(unused)]
#[cfg(unix)]
pub type uid_t = u32;
/// The type of user file flags
@@ -68,6 +69,7 @@ impl Type {
/// The file’s Unix permission bitfield, with one entry per bit.
#[derive(Copy, Clone)]
#[rustfmt::skip]
#[cfg(unix)]
pub struct Permissions {
pub user_read: bool,
pub user_write: bool,
@@ -116,6 +118,7 @@ pub struct PermissionsPlus {
/// The permissions encoded as octal values
#[derive(Copy, Clone)]
#[cfg(unix)]
pub struct OctalPermissions {
pub permissions: Permissions,
}
@@ -126,7 +129,7 @@ pub struct OctalPermissions {
/// multiple directories. However, it’s rare (but occasionally useful!) for a
/// regular file to have a link count greater than 1, so we highlight the
/// block count specifically for this case.
#[allow(unused)]
#[cfg(unix)]
#[derive(Copy, Clone)]
pub struct Links {
/// The actual link count.
@@ -139,7 +142,7 @@ pub struct Links {
/// A file’s inode. Every directory entry on a Unix filesystem has an inode,
/// including directories and links, so this is applicable to everything exa
/// can deal with.
#[allow(unused)]
#[cfg(unix)]
#[derive(Copy, Clone)]
pub struct Inode(pub ino_t);
@@ -156,12 +159,12 @@ pub enum Blocksize {
/// The ID of the user that owns a file. This will only ever be a number;
/// looking up the username is done in the `display` module.
#[allow(unused)]
#[cfg(unix)]
#[derive(Copy, Clone)]
pub struct User(pub uid_t);
/// The ID of the group that a file belongs to.
#[allow(unused)]
#[cfg(unix)]
#[derive(Copy, Clone)]
pub struct Group(pub gid_t);
+3 -3
View File
@@ -27,7 +27,7 @@ pub struct MountedFs {
}
#[derive(Debug)]
#[non_exhaustive]
#[cfg(any(target_os = "macos", target_os = "linux"))]
pub enum Error {
#[cfg(target_os = "macos")]
GetFSStatError(i32),
@@ -35,18 +35,18 @@ pub enum Error {
IOError(std::io::Error),
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
impl std::error::Error for Error {}
#[cfg(any(target_os = "macos", target_os = "linux"))]
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Allow unreachable_patterns for windows build
#[allow(unreachable_patterns)]
match self {
#[cfg(target_os = "macos")]
Error::GetFSStatError(err) => write!(f, "getfsstat failed: {err}"),
#[cfg(target_os = "linux")]
Error::IOError(err) => write!(f, "failed to read /proc/mounts: {err}"),
_ => write!(f, "Unknown error"),
}
}
}
+5
View File
@@ -30,6 +30,10 @@ pub use self::links::Colours as LinksColours;
mod permissions;
pub use self::permissions::{Colours as PermissionsColours, PermissionsPlusRender};
#[cfg(unix)]
mod permissions_unix;
#[cfg(windows)]
mod permissions_windows;
mod size;
pub use self::size::Colours as SizeColours;
@@ -45,6 +49,7 @@ pub use self::users::Colours as UserColours;
#[cfg(unix)]
pub use self::users::Render as UserRender;
#[cfg(unix)]
mod octal;
#[cfg(unix)]
pub use self::octal::Render as OctalPermissionsRender;
-1
View File
@@ -9,7 +9,6 @@ use nu_ansi_term::Style;
use crate::fs::fields as f;
use crate::output::cell::TextCell;
#[allow(unused)]
pub trait Render {
fn render(&self, style: Style) -> TextCell;
}
+3 -313
View File
@@ -4,167 +4,16 @@
// SPDX-FileCopyrightText: 2023-2024 Christina Sørensen, eza contributors
// SPDX-FileCopyrightText: 2014 Benjamin Sago
// SPDX-License-Identifier: MIT
use std::iter;
use nu_ansi_term::{AnsiString as ANSIString, Style};
use crate::fs::fields as f;
use crate::output::cell::{DisplayWidth, TextCell};
use crate::output::cell::TextCell;
use crate::output::render::FiletypeColours;
use nu_ansi_term::Style;
pub trait PermissionsPlusRender {
fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell;
}
impl PermissionsPlusRender for Option<f::PermissionsPlus> {
#[cfg(unix)]
fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
if let Some(p) = self {
let mut chars = vec![p.file_type.render(colours)];
let permissions = p.permissions;
chars.extend(Some(permissions).render(colours, p.file_type.is_regular_file()));
if p.xattrs {
chars.push(colours.attribute().paint("@"));
}
// As these are all ASCII characters, we can guarantee that they’re
// all going to be one character wide, and don’t need to compute the
// cell’s display width.
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
} else {
let chars: Vec<_> = iter::repeat_n(colours.dash().paint("-"), 10).collect();
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
}
}
#[cfg(windows)]
fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
match self {
Some(p) => {
let mut chars = vec![p.attributes.render_type(colours)];
chars.extend(p.attributes.render(colours));
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
}
None => TextCell {
width: DisplayWidth::from(0),
contents: vec![].into(),
},
}
}
}
#[allow(unused)]
pub trait RenderPermissions {
fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>>;
}
impl RenderPermissions for Option<f::Permissions> {
fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>> {
match self {
Some(p) => {
let bit = |bit, chr: &'static str, style: Style| {
if bit {
style.paint(chr)
} else {
colours.dash().paint("-")
}
};
vec![
bit(p.user_read, "r", colours.user_read()),
bit(p.user_write, "w", colours.user_write()),
p.user_execute_bit(colours, is_regular_file),
bit(p.group_read, "r", colours.group_read()),
bit(p.group_write, "w", colours.group_write()),
p.group_execute_bit(colours),
bit(p.other_read, "r", colours.other_read()),
bit(p.other_write, "w", colours.other_write()),
p.other_execute_bit(colours),
]
}
None => iter::repeat_n(colours.dash().paint("-"), 9).collect(),
}
}
}
impl f::Permissions {
fn user_execute_bit<C: Colours>(
&self,
colours: &C,
is_regular_file: bool,
) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.user_execute, self.setuid, is_regular_file) {
(false, false, _) => colours.dash().paint("-"),
(true, false, false) => colours.user_execute_other().paint("x"),
(true, false, true) => colours.user_execute_file().paint("x"),
(false, true, _) => colours.special_other().paint("S"),
(true, true, false) => colours.special_other().paint("s"),
(true, true, true) => colours.special_user_file().paint("s"),
};
}
fn group_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.group_execute, self.setgid) {
(false, false) => colours.dash().paint("-"),
(true, false) => colours.group_execute().paint("x"),
(false, true) => colours.special_other().paint("S"),
(true, true) => colours.special_other().paint("s"),
};
}
fn other_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.other_execute, self.sticky) {
(false, false) => colours.dash().paint("-"),
(true, false) => colours.other_execute().paint("x"),
(false, true) => colours.special_other().paint("T"),
(true, true) => colours.special_other().paint("t"),
};
}
}
#[cfg(windows)]
impl f::Attributes {
pub fn render<C: Colours + FiletypeColours>(self, colours: &C) -> Vec<ANSIString<'static>> {
let bit = |bit, chr: &'static str, style: Style| {
if bit {
style.paint(chr)
} else {
colours.dash().paint("-")
}
};
vec![
bit(self.archive, "a", colours.normal()),
bit(self.readonly, "r", colours.user_read()),
bit(self.hidden, "h", colours.special_user_file()),
bit(self.system, "s", colours.special_other()),
]
}
pub fn render_type<C: Colours + FiletypeColours>(self, colours: &C) -> ANSIString<'static> {
if self.reparse_point {
return colours.pipe().paint("l");
} else if self.directory {
return colours.directory().paint("d");
}
colours.dash().paint("-")
}
}
pub trait Colours {
fn dash(&self) -> Style;
@@ -186,162 +35,3 @@ pub trait Colours {
fn attribute(&self) -> Style;
}
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use super::{Colours, RenderPermissions};
use crate::fs::fields as f;
use crate::output::cell::TextCellContents;
use nu_ansi_term::Color::*;
use nu_ansi_term::Style;
struct TestColours;
#[rustfmt::skip]
impl Colours for TestColours {
fn dash(&self) -> Style { Fixed(11).normal() }
fn user_read(&self) -> Style { Fixed(101).normal() }
fn user_write(&self) -> Style { Fixed(102).normal() }
fn user_execute_file(&self) -> Style { Fixed(103).normal() }
fn user_execute_other(&self) -> Style { Fixed(113).normal() }
fn group_read(&self) -> Style { Fixed(104).normal() }
fn group_write(&self) -> Style { Fixed(105).normal() }
fn group_execute(&self) -> Style { Fixed(106).normal() }
fn other_read(&self) -> Style { Fixed(107).normal() }
fn other_write(&self) -> Style { Fixed(108).normal() }
fn other_execute(&self) -> Style { Fixed(109).normal() }
fn special_user_file(&self) -> Style { Fixed(110).normal() }
fn special_other(&self) -> Style { Fixed(111).normal() }
fn attribute(&self) -> Style { Fixed(112).normal() }
}
#[test]
fn negate() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: false,
setuid: false,
group_read: false,
group_write: false,
group_execute: false,
setgid: false,
other_read: false,
other_write: false,
other_execute: false,
sticky: false,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
]);
assert_eq!(expected, bits.render(&TestColours, false).into());
}
#[test]
fn affirm() {
let bits = Some(f::Permissions {
user_read: true,
user_write: true,
user_execute: true,
setuid: false,
group_read: true,
group_write: true,
group_execute: true,
setgid: false,
other_read: true,
other_write: true,
other_execute: true,
sticky: false,
});
let expected = TextCellContents::from(vec![
Fixed(101).paint("r"),
Fixed(102).paint("w"),
Fixed(103).paint("x"),
Fixed(104).paint("r"),
Fixed(105).paint("w"),
Fixed(106).paint("x"),
Fixed(107).paint("r"),
Fixed(108).paint("w"),
Fixed(109).paint("x"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
#[test]
fn specials() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: true,
setuid: true,
group_read: false,
group_write: false,
group_execute: true,
setgid: true,
other_read: false,
other_write: false,
other_execute: true,
sticky: true,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(110).paint("s"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("s"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("t"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
#[test]
fn extra_specials() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: false,
setuid: true,
group_read: false,
group_write: false,
group_execute: false,
setgid: true,
other_read: false,
other_write: false,
other_execute: false,
sticky: true,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("S"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("S"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("T"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
}
+273
View File
@@ -0,0 +1,273 @@
// SPDX-FileCopyrightText: 2024 Christina Sørensen
// SPDX-License-Identifier: EUPL-1.2
//
// SPDX-FileCopyrightText: 2023-2024 Christina Sørensen, eza contributors
// SPDX-FileCopyrightText: 2014 Benjamin Sago
// SPDX-License-Identifier: MIT
use std::iter;
use super::{PermissionsColours as Colours, PermissionsPlusRender};
use crate::fs::fields as f;
use crate::output::cell::{DisplayWidth, TextCell};
use crate::output::render::FiletypeColours;
use nu_ansi_term::{AnsiString as ANSIString, Style};
impl PermissionsPlusRender for Option<f::PermissionsPlus> {
fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
if let Some(p) = self {
let mut chars = vec![p.file_type.render(colours)];
let permissions = p.permissions;
chars.extend(Some(permissions).render(colours, p.file_type.is_regular_file()));
if p.xattrs {
chars.push(colours.attribute().paint("@"));
}
// As these are all ASCII characters, we can guarantee that they’re
// all going to be one character wide, and don’t need to compute the
// cell’s display width.
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
} else {
let chars: Vec<_> = iter::repeat_n(colours.dash().paint("-"), 10).collect();
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
}
}
}
pub trait RenderPermissions {
fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>>;
}
impl RenderPermissions for Option<f::Permissions> {
fn render<C: Colours>(&self, colours: &C, is_regular_file: bool) -> Vec<ANSIString<'static>> {
match self {
Some(p) => {
let bit = |bit, chr: &'static str, style: Style| {
if bit {
style.paint(chr)
} else {
colours.dash().paint("-")
}
};
vec![
bit(p.user_read, "r", colours.user_read()),
bit(p.user_write, "w", colours.user_write()),
p.user_execute_bit(colours, is_regular_file),
bit(p.group_read, "r", colours.group_read()),
bit(p.group_write, "w", colours.group_write()),
p.group_execute_bit(colours),
bit(p.other_read, "r", colours.other_read()),
bit(p.other_write, "w", colours.other_write()),
p.other_execute_bit(colours),
]
}
None => std::iter::repeat_n(colours.dash().paint("-"), 9).collect(),
}
}
}
impl f::Permissions {
fn user_execute_bit<C: Colours>(
&self,
colours: &C,
is_regular_file: bool,
) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.user_execute, self.setuid, is_regular_file) {
(false, false, _) => colours.dash().paint("-"),
(true, false, false) => colours.user_execute_other().paint("x"),
(true, false, true) => colours.user_execute_file().paint("x"),
(false, true, _) => colours.special_other().paint("S"),
(true, true, false) => colours.special_other().paint("s"),
(true, true, true) => colours.special_user_file().paint("s"),
};
}
fn group_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.group_execute, self.setgid) {
(false, false) => colours.dash().paint("-"),
(true, false) => colours.group_execute().paint("x"),
(false, true) => colours.special_other().paint("S"),
(true, true) => colours.special_other().paint("s"),
};
}
fn other_execute_bit<C: Colours>(&self, colours: &C) -> ANSIString<'static> {
#[rustfmt::skip]
return match (self.other_execute, self.sticky) {
(false, false) => colours.dash().paint("-"),
(true, false) => colours.other_execute().paint("x"),
(false, true) => colours.special_other().paint("T"),
(true, true) => colours.special_other().paint("t"),
};
}
}
#[cfg(test)]
#[allow(unused_results)]
pub mod test {
use nu_ansi_term::Color::*;
use nu_ansi_term::Style;
use super::*;
use crate::output::cell::TextCellContents;
struct TestColours;
#[rustfmt::skip]
impl Colours for TestColours {
fn dash(&self) -> Style { Fixed(11).normal() }
fn user_read(&self) -> Style { Fixed(101).normal() }
fn user_write(&self) -> Style { Fixed(102).normal() }
fn user_execute_file(&self) -> Style { Fixed(103).normal() }
fn user_execute_other(&self) -> Style { Fixed(113).normal() }
fn group_read(&self) -> Style { Fixed(104).normal() }
fn group_write(&self) -> Style { Fixed(105).normal() }
fn group_execute(&self) -> Style { Fixed(106).normal() }
fn other_read(&self) -> Style { Fixed(107).normal() }
fn other_write(&self) -> Style { Fixed(108).normal() }
fn other_execute(&self) -> Style { Fixed(109).normal() }
fn special_user_file(&self) -> Style { Fixed(110).normal() }
fn special_other(&self) -> Style { Fixed(111).normal() }
fn attribute(&self) -> Style { Fixed(112).normal() }
}
#[test]
#[cfg(unix)]
fn negate() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: false,
setuid: false,
group_read: false,
group_write: false,
group_execute: false,
setgid: false,
other_read: false,
other_write: false,
other_execute: false,
sticky: false,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
]);
assert_eq!(expected, bits.render(&TestColours, false).into());
}
#[test]
#[cfg(unix)]
fn affirm() {
let bits = Some(f::Permissions {
user_read: true,
user_write: true,
user_execute: true,
setuid: false,
group_read: true,
group_write: true,
group_execute: true,
setgid: false,
other_read: true,
other_write: true,
other_execute: true,
sticky: false,
});
let expected = TextCellContents::from(vec![
Fixed(101).paint("r"),
Fixed(102).paint("w"),
Fixed(103).paint("x"),
Fixed(104).paint("r"),
Fixed(105).paint("w"),
Fixed(106).paint("x"),
Fixed(107).paint("r"),
Fixed(108).paint("w"),
Fixed(109).paint("x"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
#[test]
fn specials() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: true,
setuid: true,
group_read: false,
group_write: false,
group_execute: true,
setgid: true,
other_read: false,
other_write: false,
other_execute: true,
sticky: true,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(110).paint("s"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("s"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("t"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
#[test]
fn extra_specials() {
let bits = Some(f::Permissions {
user_read: false,
user_write: false,
user_execute: false,
setuid: true,
group_read: false,
group_write: false,
group_execute: false,
setgid: true,
other_read: false,
other_write: false,
other_execute: false,
sticky: true,
});
let expected = TextCellContents::from(vec![
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("S"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("S"),
Fixed(11).paint("-"),
Fixed(11).paint("-"),
Fixed(111).paint("T"),
]);
assert_eq!(expected, bits.render(&TestColours, true).into());
}
}
+61
View File
@@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: 2024 Christina Sørensen
// SPDX-License-Identifier: EUPL-1.2
//
// SPDX-FileCopyrightText: 2023-2024 Christina Sørensen, eza contributors
// SPDX-FileCopyrightText: 2014 Benjamin Sago
// SPDX-License-Identifier: MIT
use crate::fs::fields as f;
use crate::output::cell::{DisplayWidth, TextCell};
use crate::output::render::FiletypeColours;
use super::{PermissionsColours as Colours, PermissionsPlusRender};
use nu_ansi_term::{AnsiString as ANSIString, Style};
impl PermissionsPlusRender for Option<f::PermissionsPlus> {
fn render<C: Colours + FiletypeColours>(&self, colours: &C) -> TextCell {
match self {
Some(p) => {
let mut chars = vec![p.attributes.render_type(colours)];
chars.extend(p.attributes.render(colours));
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
}
None => TextCell {
width: DisplayWidth::from(0),
contents: vec![].into(),
},
}
}
}
impl f::Attributes {
pub fn render<C: Colours + FiletypeColours>(self, colours: &C) -> Vec<ANSIString<'static>> {
let bit = |bit, chr: &'static str, style: Style| {
if bit {
style.paint(chr)
} else {
colours.dash().paint("-")
}
};
vec![
bit(self.archive, "a", colours.normal()),
bit(self.readonly, "r", colours.user_read()),
bit(self.hidden, "h", colours.special_user_file()),
bit(self.system, "s", colours.special_other()),
]
}
pub fn render_type<C: Colours + FiletypeColours>(self, colours: &C) -> ANSIString<'static> {
if self.reparse_point {
return colours.pipe().paint("l");
} else if self.directory {
return colours.directory().paint("d");
}
colours.dash().paint("-")
}
}