Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for user and group #174

Merged
merged 8 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ chrono = "0.4.24"
clap = { version = "4.1.1", features = ["derive"] }
clap_complete = "4.1.1"
dirs = "5.0"
errno = "0.3.1"
filesize = "0.2.0"
ignore = "0.4.2"
indextree = "4.6.0"
Expand Down
14 changes: 12 additions & 2 deletions src/context/output.rs → src/context/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::convert::From;

/// Utility struct to help store maximum column widths for attributes of each node. Each width is
/// measured as the number of columns of the tty's window.
pub struct ColumnProperties {
pub struct Properties {
pub max_size_width: usize,
pub max_size_unit_width: usize,

Expand All @@ -15,9 +15,15 @@ pub struct ColumnProperties {

#[cfg(unix)]
pub max_block_width: usize,

#[cfg(unix)]
pub max_owner_width: usize,

#[cfg(unix)]
pub max_group_width: usize,
}

impl From<&Context> for ColumnProperties {
impl From<&Context> for Properties {
fn from(ctx: &Context) -> Self {
let unit_width = match ctx.unit {
PrefixKind::Bin if ctx.human => 3,
Expand All @@ -34,6 +40,10 @@ impl From<&Context> for ColumnProperties {
max_ino_width: 0,
#[cfg(unix)]
max_block_width: 0,
#[cfg(unix)]
max_owner_width: 0,
#[cfg(unix)]
max_group_width: 0,
}
}
}
40 changes: 33 additions & 7 deletions src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use ignore::{
overrides::{Override, OverrideBuilder},
DirEntry,
};
use output::ColumnProperties;
use regex::Regex;
use std::{
borrow::Borrow,
Expand Down Expand Up @@ -35,7 +34,7 @@ pub mod file;
pub mod layout;

/// Utilities to print output.
pub mod output;
pub mod column;

/// Printing order kinds.
pub mod sort;
Expand Down Expand Up @@ -87,6 +86,21 @@ pub struct Context {
#[arg(short, long)]
pub long: bool,

/// Show file's groups
#[cfg(unix)]
#[arg(long)]
pub group: bool,

/// Show each file's ino
#[cfg(unix)]
#[arg(long)]
pub ino: bool,

/// Show the total number of hardlinks to the underlying inode
#[cfg(unix)]
#[arg(long)]
pub nlink: bool,

/// Show permissions in numeric octal format instead of symbolic
#[cfg(unix)]
#[arg(long, requires = "long")]
Expand Down Expand Up @@ -142,6 +156,10 @@ pub struct Context {
#[arg(short, long, value_enum, default_value_t = PrefixKind::default())]
pub unit: PrefixKind,

/// Which kind of layout to use when rendering the output
#[arg(short = 'y', long, value_enum, default_value_t = layout::Type::default())]
pub layout: layout::Type,

/// Show hidden files
#[arg(short = '.', long)]
pub hidden: bool,
Expand All @@ -158,10 +176,6 @@ pub struct Context {
#[arg(long)]
pub dirs_only: bool,

/// Which kind of layout to use when rendering the output
#[arg(long, value_enum, default_value_t = layout::Type::default())]
pub layout: layout::Type,

/// Don't read configuration file
#[arg(long)]
pub no_config: bool,
Expand Down Expand Up @@ -208,6 +222,16 @@ pub struct Context {
#[cfg(unix)]
pub max_block_width: usize,

/// Restricts column width of file owner for long view
#[clap(skip = usize::default())]
#[cfg(unix)]
pub max_owner_width: usize,

/// Restricts column width of file group for long view
#[clap(skip = usize::default())]
#[cfg(unix)]
pub max_group_width: usize,

/// Width of the terminal emulator's window
#[clap(skip)]
pub window_width: Option<usize>,
Expand Down Expand Up @@ -486,12 +510,14 @@ impl Context {
}

/// Update column width properties.
pub fn update_column_properties(&mut self, col_props: &ColumnProperties) {
pub fn update_column_properties(&mut self, col_props: &column::Properties) {
self.max_size_width = col_props.max_size_width;
self.max_size_unit_width = col_props.max_size_unit_width;

#[cfg(unix)]
{
self.max_owner_width = col_props.max_owner_width;
self.max_group_width = col_props.max_group_width;
self.max_nlink_width = col_props.max_nlink_width;
self.max_block_width = col_props.max_block_width;
self.max_ino_width = col_props.max_ino_width;
Expand Down
93 changes: 64 additions & 29 deletions src/disk_usage/file_size/byte.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::super::units::{BinPrefix, PrefixKind, SiPrefix, UnitPrefix};
use filesize::PathExt;
use std::{
cell::{Ref, RefCell},
fmt::{self, Display},
fs::Metadata,
path::Path,
Expand All @@ -14,6 +15,11 @@ pub struct Metric {
#[allow(dead_code)]
kind: MetricKind,
prefix_kind: PrefixKind,

/// To prevent allocating the same string twice. We allocate the first time
/// in [`crate::tree::update_column_properties`] in order to compute the max column width for
/// human-readable size and the second time during the actual render.
cached_display: RefCell<String>,
}

/// Represents the appropriate method in which to compute bytes. `Logical` represent the total amount
Expand All @@ -39,26 +45,29 @@ impl Metric {
human_readable,
kind,
prefix_kind,
cached_display: RefCell::default(),
}
}

/// Initializes an empty [Metric] used to represent the total amount of bytes of a file.
pub const fn init_empty_logical(human_readable: bool, prefix_kind: PrefixKind) -> Self {
pub fn init_empty_logical(human_readable: bool, prefix_kind: PrefixKind) -> Self {
Self {
value: 0,
human_readable,
kind: MetricKind::Logical,
prefix_kind,
cached_display: RefCell::default(),
}
}

/// Initializes an empty [Metric] used to represent the total disk space of a file in bytes.
pub const fn init_empty_physical(human_readable: bool, prefix_kind: PrefixKind) -> Self {
pub fn init_empty_physical(human_readable: bool, prefix_kind: PrefixKind) -> Self {
Self {
value: 0,
human_readable,
kind: MetricKind::Physical,
prefix_kind,
cached_display: RefCell::default(),
}
}

Expand All @@ -77,46 +86,66 @@ impl Metric {
human_readable,
kind,
prefix_kind,
cached_display: RefCell::default(),
}
}

/// Returns an immutable borrow of the `cached_display`.
pub fn cached_display(&self) -> Ref<'_, String> {
self.cached_display.borrow()
}
}

impl Display for Metric {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value = self.value as f64;
{
let cached_display = self.cached_display();

match self.prefix_kind {
PrefixKind::Si => {
if !self.human_readable {
return write!(f, "{} {}", self.value, SiPrefix::Base);
}
if cached_display.len() > 0 {
return write!(f, "{cached_display}");
}
}

let unit = SiPrefix::from(self.value);
let value = self.value as f64;

if matches!(unit, SiPrefix::Base) {
write!(f, "{} {unit}", self.value)
let display = match self.prefix_kind {
PrefixKind::Si => {
if self.human_readable {
let unit = SiPrefix::from(self.value);

if matches!(unit, SiPrefix::Base) {
format!("{} {unit}", self.value)
} else {
let base_value = unit.base_value();
let size = value / (base_value as f64);
format!("{size:.1} {unit}")
}
} else {
let base_value = unit.base_value();
let size = value / (base_value as f64);
write!(f, "{size:.2} {unit}")
format!("{} {}", self.value, SiPrefix::Base)
}
}
PrefixKind::Bin => {
if !self.human_readable {
return write!(f, "{} {}", self.value, BinPrefix::Base);
}

let unit = BinPrefix::from(self.value);

if matches!(unit, BinPrefix::Base) {
write!(f, "{} {unit}", self.value)
if self.human_readable {
let unit = BinPrefix::from(self.value);

if matches!(unit, BinPrefix::Base) {
format!("{} {unit}", self.value)
} else {
let base_value = unit.base_value();
let size = value / (base_value as f64);
format!("{size:.1} {unit}")
}
} else {
let base_value = unit.base_value();
let size = value / (base_value as f64);
write!(f, "{size:.2} {unit}")
format!("{} {}", self.value, BinPrefix::Base)
}
}
}
};

write!(f, "{display}")?;

self.cached_display.replace(display);

Ok(())
}
}

Expand All @@ -127,6 +156,7 @@ fn test_metric() {
kind: MetricKind::Logical,
human_readable: false,
prefix_kind: PrefixKind::Bin,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "100 B");

Expand All @@ -135,14 +165,16 @@ fn test_metric() {
kind: MetricKind::Logical,
human_readable: true,
prefix_kind: PrefixKind::Si,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "1.00 KB");
assert_eq!(format!("{}", metric), "1.0 KB");

let metric = Metric {
value: 1000,
kind: MetricKind::Logical,
human_readable: true,
prefix_kind: PrefixKind::Bin,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "1000 B");

Expand All @@ -151,22 +183,25 @@ fn test_metric() {
kind: MetricKind::Logical,
human_readable: true,
prefix_kind: PrefixKind::Bin,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "1.00 KiB");
assert_eq!(format!("{}", metric), "1.0 KiB");

let metric = Metric {
value: 2_u64.pow(20),
kind: MetricKind::Logical,
human_readable: true,
prefix_kind: PrefixKind::Bin,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "1.00 MiB");
assert_eq!(format!("{}", metric), "1.0 MiB");

let metric = Metric {
value: 123454,
kind: MetricKind::Logical,
human_readable: false,
prefix_kind: PrefixKind::Bin,
cached_display: RefCell::<String>::default(),
};
assert_eq!(format!("{}", metric), "123454 B");
}
Loading