Mimic 'Mode' in gci

This commit is contained in:
Chester Liu 2021-03-30 17:13:00 +08:00
parent 78a3bc9838
commit 00f97a9738
4 changed files with 74 additions and 1 deletions

View File

@ -82,6 +82,17 @@ pub struct Permissions {
pub setuid: bool,
}
/// The file's FileAttributes field, available only on Windows.
#[derive(Copy, Clone)]
pub struct Attributes {
pub archive: bool,
pub directory: bool,
pub readonly: bool,
pub hidden: bool,
pub system: bool,
pub reparse_point: bool,
}
/// The three pieces of information that are displayed as a single column in
/// the details view. These values are fused together to make the output a
/// little more compressed.
@ -90,6 +101,8 @@ pub struct PermissionsPlus {
pub file_type: Type,
#[cfg(unix)]
pub permissions: Permissions,
#[cfg(windows)]
pub attributes: Attributes,
pub xattrs: bool,
}

View File

@ -3,6 +3,8 @@
use std::io;
#[cfg(unix)]
use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
#[cfg(windows)]
use std::os::windows::fs::MetadataExt;
use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
@ -463,6 +465,21 @@ impl<'dir> File<'dir> {
}
}
#[cfg(windows)]
pub fn attributes(&self) -> f::Attributes {
let bits = self.metadata.file_attributes();
let has_bit = |bit| bits & bit == bit;
f::Attributes {
directory: has_bit(0x10),
archive: has_bit(0x20),
readonly: has_bit(0x1),
hidden: has_bit(0x2),
system: has_bit(0x4),
reparse_point: has_bit(0x400),
}
}
/// Whether this files extension is any of the strings that get passed in.
///
/// This will always return `false` if the file has no extension.

View File

@ -6,9 +6,9 @@ use crate::output::render::FiletypeColours;
impl f::PermissionsPlus {
#[cfg(unix)]
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
let mut chars = vec![ self.file_type.render(colours) ];
#[cfg(unix)]
chars.extend(self.permissions.render(colours, self.file_type.is_regular_file()));
if self.xattrs {
@ -23,6 +23,17 @@ impl f::PermissionsPlus {
contents: chars.into(),
}
}
#[cfg(windows)]
pub fn render<C: Colours+FiletypeColours>(&self, colours: &C) -> TextCell {
let mut chars = vec![ self.attributes.render_type(colours) ];
chars.extend(self.attributes.render(colours));
TextCell {
width: DisplayWidth::from(chars.len()),
contents: chars.into(),
}
}
}
@ -77,6 +88,33 @@ impl f::Permissions {
}
}
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")
}
else {
return colours.dash().paint("-")
}
}
}
pub trait Colours {
fn dash(&self) -> Style;

View File

@ -171,7 +171,10 @@ impl Column {
/// to have a header row printed.
pub fn header(self) -> &'static str {
match self {
#[cfg(unix)]
Self::Permissions => "Permissions",
#[cfg(windows)]
Self::Permissions => "Mode",
Self::FileSize => "Size",
Self::Timestamp(t) => t.header(),
#[cfg(unix)]
@ -422,6 +425,8 @@ impl<'a, 'f> Table<'a> {
file_type: file.type_char(),
#[cfg(unix)]
permissions: file.permissions(),
#[cfg(windows)]
attributes: file.attributes(),
xattrs,
}
}