mirror of
https://github.com/lsd-rs/lsd
synced 2024-12-14 22:22:26 +00:00
Implementation
This commit is contained in:
parent
48b5adf929
commit
92d4e96622
15 changed files with 386 additions and 117 deletions
|
@ -68,8 +68,8 @@ pub struct Cli {
|
|||
#[arg(short, long, conflicts_with_all = ["depth", "recursive"])]
|
||||
pub directory_only: bool,
|
||||
|
||||
/// How to display permissions [default: rwx]
|
||||
#[arg(long, value_name = "MODE", value_parser = ["rwx", "octal", "disable"])]
|
||||
/// How to display permissions [default: rwx for non-windows, attributes for windows]
|
||||
#[arg(long, value_name = "MODE", value_parser = ["rwx", "octal", "attributes", "disable"])]
|
||||
pub permission: Option<String>,
|
||||
|
||||
/// How to display size [default: default]
|
||||
|
|
17
src/color.rs
17
src/color.rs
|
@ -38,6 +38,12 @@ pub enum Elem {
|
|||
Acl,
|
||||
Context,
|
||||
|
||||
/// Attributes
|
||||
Archive,
|
||||
AttributeRead,
|
||||
Hidden,
|
||||
System,
|
||||
|
||||
/// Last Time Modified
|
||||
DayOld,
|
||||
HourOld,
|
||||
|
@ -112,6 +118,11 @@ impl Elem {
|
|||
Elem::Acl => theme.permission.acl,
|
||||
Elem::Context => theme.permission.context,
|
||||
|
||||
Elem::Archive => theme.attributes.archive,
|
||||
Elem::AttributeRead => theme.attributes.read,
|
||||
Elem::Hidden => theme.attributes.hidden,
|
||||
Elem::System => theme.attributes.system,
|
||||
|
||||
Elem::DayOld => theme.date.day_old,
|
||||
Elem::HourOld => theme.date.hour_old,
|
||||
Elem::Older => theme.date.older,
|
||||
|
@ -399,6 +410,12 @@ mod elem {
|
|||
acl: Color::DarkCyan,
|
||||
context: Color::Cyan,
|
||||
},
|
||||
attributes: color::Attributes {
|
||||
read: Color::Green,
|
||||
archive: Color::Yellow,
|
||||
hidden: Color::Red,
|
||||
system: Color::Magenta,
|
||||
},
|
||||
file_type: color::FileType {
|
||||
file: color::File {
|
||||
exec_uid: Color::AnsiValue(40), // Green3
|
||||
|
|
|
@ -299,8 +299,8 @@ size: default
|
|||
|
||||
# == Permission ==
|
||||
# Specify the format of the permission column.
|
||||
# Possible value: rwx, octal
|
||||
permission: rwx
|
||||
# Possible value: rwx, octal, attributes, disable
|
||||
# permission: rwx
|
||||
|
||||
# == Sorting ==
|
||||
sorting:
|
||||
|
@ -363,7 +363,6 @@ mod tests {
|
|||
use crate::flags::color::{ColorOption, ThemeOption};
|
||||
use crate::flags::icons::{IconOption, IconTheme};
|
||||
use crate::flags::layout::Layout;
|
||||
use crate::flags::permission::PermissionFlag;
|
||||
use crate::flags::size::SizeFlag;
|
||||
use crate::flags::sorting::{DirGrouping, SortColumn};
|
||||
use crate::flags::HyperlinkOption;
|
||||
|
@ -402,7 +401,7 @@ mod tests {
|
|||
depth: None,
|
||||
}),
|
||||
size: Some(SizeFlag::Default),
|
||||
permission: Some(PermissionFlag::Rwx),
|
||||
permission: None,
|
||||
sorting: Some(config_file::Sorting {
|
||||
column: Some(SortColumn::Name),
|
||||
reverse: Some(false),
|
||||
|
|
10
src/core.rs
10
src/core.rs
|
@ -1,8 +1,7 @@
|
|||
use crate::color::Colors;
|
||||
use crate::display;
|
||||
use crate::flags::{
|
||||
ColorOption, Display, Flags, HyperlinkOption, Layout, Literal, PermissionFlag, SortOrder,
|
||||
ThemeOption,
|
||||
ColorOption, Display, Flags, HyperlinkOption, Layout, Literal, SortOrder, ThemeOption,
|
||||
};
|
||||
use crate::git::GitCache;
|
||||
use crate::icon::Icons;
|
||||
|
@ -106,11 +105,8 @@ impl Core {
|
|||
};
|
||||
|
||||
for path in paths {
|
||||
let mut meta = match Meta::from_path(
|
||||
&path,
|
||||
self.flags.dereference.0,
|
||||
self.flags.permission == PermissionFlag::Disable,
|
||||
) {
|
||||
let mut meta =
|
||||
match Meta::from_path(&path, self.flags.dereference.0, self.flags.permission) {
|
||||
Ok(meta) => meta,
|
||||
Err(err) => {
|
||||
print_error!("{}: {}.", path.display(), err);
|
||||
|
|
|
@ -347,8 +347,10 @@ fn get_output(
|
|||
Block::Permission => {
|
||||
block_vec.extend([
|
||||
meta.file_type.render(colors),
|
||||
match meta.permissions {
|
||||
Some(permissions) => permissions.render(colors, flags),
|
||||
match &meta.permissions_or_attributes {
|
||||
Some(permissions_or_attributes) => {
|
||||
permissions_or_attributes.render(colors, flags)
|
||||
}
|
||||
None => colorize_missing("?????????"),
|
||||
},
|
||||
match &meta.access_control {
|
||||
|
@ -491,7 +493,7 @@ mod tests {
|
|||
use crate::app::Cli;
|
||||
use crate::color;
|
||||
use crate::color::Colors;
|
||||
use crate::flags::{HyperlinkOption, IconOption, IconTheme as FlagTheme};
|
||||
use crate::flags::{HyperlinkOption, IconOption, IconTheme as FlagTheme, PermissionFlag};
|
||||
use crate::icon::Icons;
|
||||
use crate::meta::{FileType, Name};
|
||||
use crate::Config;
|
||||
|
@ -686,7 +688,7 @@ mod tests {
|
|||
dir.child("one.d").create_dir_all().unwrap();
|
||||
dir.child("one.d/two").touch().unwrap();
|
||||
dir.child("one.d/.hidden").touch().unwrap();
|
||||
let mut metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let mut metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(42, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -719,7 +721,7 @@ mod tests {
|
|||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
dir.child("dir").create_dir_all().unwrap();
|
||||
dir.child("dir/file").touch().unwrap();
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(42, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -760,7 +762,7 @@ mod tests {
|
|||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
dir.child("dir").create_dir_all().unwrap();
|
||||
dir.child("dir/file").touch().unwrap();
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(42, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -800,7 +802,7 @@ mod tests {
|
|||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
dir.child("one.d").create_dir_all().unwrap();
|
||||
dir.child("one.d/two").touch().unwrap();
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(42, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -831,7 +833,7 @@ mod tests {
|
|||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
dir.child("testdir").create_dir_all().unwrap();
|
||||
dir.child("test").touch().unwrap();
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(1, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -865,7 +867,7 @@ mod tests {
|
|||
|
||||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
dir.child("testdir").create_dir_all().unwrap();
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, false)
|
||||
let metas = Meta::from_path(Path::new(dir.path()), false, PermissionFlag::Rwx)
|
||||
.unwrap()
|
||||
.recurse_into(1, &flags, None)
|
||||
.unwrap()
|
||||
|
@ -895,11 +897,11 @@ mod tests {
|
|||
|
||||
let file_path = tmp_dir.path().join("file");
|
||||
std::fs::File::create(&file_path).expect("failed to create the file");
|
||||
let file = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let file = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let dir_path = tmp_dir.path().join("dir");
|
||||
std::fs::create_dir(&dir_path).expect("failed to create the dir");
|
||||
let dir = Meta::from_path(&dir_path, false, false).unwrap();
|
||||
let dir = Meta::from_path(&dir_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
display_folder_path(&dir),
|
||||
|
@ -945,15 +947,15 @@ mod tests {
|
|||
|
||||
let file_path = tmp_dir.path().join("file");
|
||||
std::fs::File::create(&file_path).expect("failed to create the file");
|
||||
let file = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let file = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let dir_path = tmp_dir.path().join("dir");
|
||||
std::fs::create_dir(&dir_path).expect("failed to create the dir");
|
||||
let dir = Meta::from_path(&dir_path, false, false).unwrap();
|
||||
let dir = Meta::from_path(&dir_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let link_path = tmp_dir.path().join("link");
|
||||
std::os::unix::fs::symlink("dir", &link_path).unwrap();
|
||||
let link = Meta::from_path(&link_path, false, false).unwrap();
|
||||
let link = Meta::from_path(&link_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let grid_flags = Flags {
|
||||
layout: Layout::Grid,
|
||||
|
|
|
@ -13,10 +13,13 @@ use serde::Deserialize;
|
|||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum PermissionFlag {
|
||||
/// The variant to show file permissions in rwx format
|
||||
#[default]
|
||||
#[cfg_attr(not(target_os = "windows"), default)]
|
||||
Rwx,
|
||||
/// The variant to show file permissions in octal format
|
||||
Octal,
|
||||
/// (windows only): Attributes from powershell's `Get-ChildItem`
|
||||
#[cfg_attr(target_os = "windows", default)]
|
||||
Attributes,
|
||||
/// Disable the display of owner and permissions, may be used to speed up in Windows
|
||||
Disable,
|
||||
}
|
||||
|
@ -26,6 +29,7 @@ impl PermissionFlag {
|
|||
match value {
|
||||
"rwx" => Self::Rwx,
|
||||
"octal" => Self::Octal,
|
||||
"attributes" => Self::Attributes,
|
||||
"disable" => Self::Disable,
|
||||
// Invalid value should be handled by `clap` when building an `Cli`
|
||||
other => unreachable!("Invalid value '{other}' for 'permission'"),
|
||||
|
@ -75,7 +79,12 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
assert_eq!(PermissionFlag::Rwx, PermissionFlag::default());
|
||||
let expected = if cfg!(target_os = "windows") {
|
||||
PermissionFlag::Attributes
|
||||
} else {
|
||||
PermissionFlag::Rwx
|
||||
};
|
||||
assert_eq!(expected, PermissionFlag::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -99,6 +108,16 @@ mod test {
|
|||
assert_eq!(Some(PermissionFlag::Octal), PermissionFlag::from_cli(&cli));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_cli_attributes() {
|
||||
let argv = ["lsd", "--permission", "attributes"];
|
||||
let cli = Cli::try_parse_from(argv).unwrap();
|
||||
assert_eq!(
|
||||
Some(PermissionFlag::Attributes),
|
||||
PermissionFlag::from_cli(&cli)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_cli_permissions_disable() {
|
||||
let argv = ["lsd", "--permission", "disable"];
|
||||
|
|
24
src/icon.rs
24
src/icon.rs
|
@ -75,7 +75,7 @@ impl Icons {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{IconTheme, Icons};
|
||||
use crate::flags::{IconOption, IconTheme as FlagTheme};
|
||||
use crate::flags::{IconOption, IconTheme as FlagTheme, PermissionFlag};
|
||||
use crate::meta::Meta;
|
||||
use std::fs::File;
|
||||
use tempfile::tempdir;
|
||||
|
@ -85,7 +85,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icons = Icons::new(true, IconOption::Never, FlagTheme::Fancy, " ".to_string());
|
||||
let icon = icons.get(&meta.name);
|
||||
|
@ -97,7 +97,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icons = Icons::new(false, IconOption::Never, FlagTheme::Fancy, " ".to_string());
|
||||
let icon = icons.get(&meta.name);
|
||||
|
@ -110,7 +110,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icons = Icons::new(false, IconOption::Auto, FlagTheme::Fancy, " ".to_string());
|
||||
let icon = icons.get(&meta.name);
|
||||
|
@ -122,7 +122,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icons = Icons::new(true, IconOption::Auto, FlagTheme::Fancy, " ".to_string());
|
||||
let icon = icons.get(&meta.name);
|
||||
|
@ -135,7 +135,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(true, IconOption::Always, FlagTheme::Fancy, " ".to_string());
|
||||
let icon_str = icon.get(&meta.name);
|
||||
|
@ -148,7 +148,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(false, IconOption::Always, FlagTheme::Fancy, " ".to_string());
|
||||
let icon_str = icon.get(&meta.name);
|
||||
|
@ -161,7 +161,7 @@ mod test {
|
|||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path().join("file");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(
|
||||
false,
|
||||
|
@ -178,7 +178,7 @@ mod test {
|
|||
fn get_icon_default_directory() {
|
||||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path();
|
||||
let meta = Meta::from_path(file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(false, IconOption::Always, FlagTheme::Fancy, " ".to_string());
|
||||
let icon_str = icon.get(&meta.name);
|
||||
|
@ -190,7 +190,7 @@ mod test {
|
|||
fn get_icon_default_directory_unicode() {
|
||||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let file_path = tmp_dir.path();
|
||||
let meta = Meta::from_path(file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(
|
||||
false,
|
||||
|
@ -210,7 +210,7 @@ mod test {
|
|||
for (file_name, file_icon) in &IconTheme::get_default_icons_by_name() {
|
||||
let file_path = tmp_dir.path().join(file_name);
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(false, IconOption::Always, FlagTheme::Fancy, " ".to_string());
|
||||
let icon_str = icon.get(&meta.name);
|
||||
|
@ -226,7 +226,7 @@ mod test {
|
|||
for (ext, file_icon) in &IconTheme::get_default_icons_by_extension() {
|
||||
let file_path = tmp_dir.path().join(format!("file.{ext}"));
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let icon = Icons::new(false, IconOption::Always, FlagTheme::Fancy, " ".to_string());
|
||||
let icon_str = icon.get(&meta.name);
|
||||
|
|
|
@ -110,6 +110,10 @@ mod test {
|
|||
use super::FileType;
|
||||
use crate::color::{Colors, ThemeOption};
|
||||
#[cfg(unix)]
|
||||
use crate::flags::PermissionFlag;
|
||||
#[cfg(unix)]
|
||||
use crate::meta::permissions_or_attributes::PermissionsOrAttributes;
|
||||
#[cfg(unix)]
|
||||
use crate::meta::Permissions;
|
||||
use crossterm::style::{Color, Stylize};
|
||||
use std::fs::File;
|
||||
|
@ -144,14 +148,19 @@ mod test {
|
|||
fn test_dir_type() {
|
||||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
#[cfg(not(windows))]
|
||||
let meta = crate::meta::Meta::from_path(tmp_dir.path(), false, false)
|
||||
let meta = crate::meta::Meta::from_path(tmp_dir.path(), false, PermissionFlag::Rwx)
|
||||
.expect("failed to get tempdir path");
|
||||
let metadata = tmp_dir.path().metadata().expect("failed to get metas");
|
||||
|
||||
let colors = Colors::new(ThemeOption::NoLscolors);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let file_type = FileType::new(&metadata, None, &meta.permissions.unwrap());
|
||||
let file_type = match meta.permissions_or_attributes {
|
||||
Some(PermissionsOrAttributes::Permissions(permissions)) => {
|
||||
FileType::new(&metadata, None, &permissions)
|
||||
}
|
||||
_ => panic!("unexpected"),
|
||||
};
|
||||
#[cfg(windows)]
|
||||
let file_type = FileType::new(&metadata, None, tmp_dir.path());
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@ mod locale;
|
|||
pub mod name;
|
||||
mod owner;
|
||||
mod permissions;
|
||||
mod permissions_or_attributes;
|
||||
mod size;
|
||||
mod symlink;
|
||||
mod windows_attributes;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod windows_utils;
|
||||
|
@ -25,6 +27,7 @@ pub use self::links::Links;
|
|||
pub use self::name::Name;
|
||||
pub use self::owner::Owner;
|
||||
pub use self::permissions::Permissions;
|
||||
use self::permissions_or_attributes::PermissionsOrAttributes;
|
||||
pub use self::size::Size;
|
||||
pub use self::symlink::SymLink;
|
||||
|
||||
|
@ -35,11 +38,13 @@ use crate::git::GitCache;
|
|||
use std::io::{self, Error, ErrorKind};
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
#[cfg(windows)]
|
||||
use self::windows_attributes::get_attributes;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Meta {
|
||||
pub name: Name,
|
||||
pub path: PathBuf,
|
||||
pub permissions: Option<Permissions>,
|
||||
pub permissions_or_attributes: Option<PermissionsOrAttributes>,
|
||||
pub date: Option<Date>,
|
||||
pub owner: Option<Owner>,
|
||||
pub file_type: FileType,
|
||||
|
@ -97,7 +102,7 @@ impl Meta {
|
|||
let mut parent_meta = Self::from_path(
|
||||
&self.path.join(Component::ParentDir),
|
||||
flags.dereference.0,
|
||||
flags.permission == PermissionFlag::Disable,
|
||||
flags.permission,
|
||||
)?;
|
||||
parent_meta.name.name = "..".to_owned();
|
||||
|
||||
|
@ -141,11 +146,8 @@ impl Meta {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
let mut entry_meta = match Self::from_path(
|
||||
&path,
|
||||
flags.dereference.0,
|
||||
flags.permission == PermissionFlag::Disable,
|
||||
) {
|
||||
let mut entry_meta = match Self::from_path(&path, flags.dereference.0, flags.permission)
|
||||
{
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
print_error!("{}: {}.", path.display(), err);
|
||||
|
@ -250,7 +252,11 @@ impl Meta {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_path(path: &Path, dereference: bool, disable_permission: bool) -> io::Result<Self> {
|
||||
pub fn from_path(
|
||||
path: &Path,
|
||||
dereference: bool,
|
||||
permission_flag: PermissionFlag,
|
||||
) -> io::Result<Self> {
|
||||
let mut metadata = path.symlink_metadata()?;
|
||||
let mut symlink_meta = None;
|
||||
let mut broken_link = false;
|
||||
|
@ -275,21 +281,30 @@ impl Meta {
|
|||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
let (owner, permissions) = if disable_permission {
|
||||
(None, None)
|
||||
} else {
|
||||
(
|
||||
let (owner, permissions) = match permission_flag {
|
||||
PermissionFlag::Disable => (None, None),
|
||||
_ => (
|
||||
Some(Owner::from(&metadata)),
|
||||
Some(Permissions::from(&metadata)),
|
||||
)
|
||||
),
|
||||
};
|
||||
#[cfg(unix)]
|
||||
let permissions_or_attributes = permissions.map(PermissionsOrAttributes::Permissions);
|
||||
|
||||
#[cfg(windows)]
|
||||
let (owner, permissions) = if disable_permission {
|
||||
(None, None)
|
||||
} else {
|
||||
match windows_utils::get_file_data(path) {
|
||||
Ok((owner, permissions)) => (Some(owner), Some(permissions)),
|
||||
let (owner, permissions_or_attributes) = match permission_flag {
|
||||
PermissionFlag::Disable => (None, None),
|
||||
PermissionFlag::Attributes => (
|
||||
None,
|
||||
Some(PermissionsOrAttributes::WindowsAttributes(get_attributes(
|
||||
&metadata,
|
||||
))),
|
||||
),
|
||||
_ => match windows_utils::get_file_data(path) {
|
||||
Ok((owner, permissions)) => (
|
||||
Some(owner),
|
||||
Some(PermissionsOrAttributes::Permissions(permissions)),
|
||||
),
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"lsd: {}: {}(Hint: Consider using `--permission disabled`.)",
|
||||
|
@ -298,7 +313,7 @@ impl Meta {
|
|||
);
|
||||
(None, None)
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
@ -313,7 +328,8 @@ impl Meta {
|
|||
|
||||
let name = Name::new(path, file_type);
|
||||
|
||||
let (inode, links, size, date, owner, permissions, access_control) = match broken_link {
|
||||
let (inode, links, size, date, owner, permissions_or_attributes, access_control) =
|
||||
match broken_link {
|
||||
true => (None, None, None, None, None, None, None),
|
||||
false => (
|
||||
Some(INode::from(&metadata)),
|
||||
|
@ -321,7 +337,7 @@ impl Meta {
|
|||
Some(Size::from(&metadata)),
|
||||
Some(Date::from(&metadata)),
|
||||
Some(owner),
|
||||
Some(permissions),
|
||||
Some(permissions_or_attributes),
|
||||
Some(AccessControl::for_path(path)),
|
||||
),
|
||||
};
|
||||
|
@ -335,7 +351,7 @@ impl Meta {
|
|||
date,
|
||||
indicator: Indicator::from(file_type),
|
||||
owner: owner.unwrap_or_default(),
|
||||
permissions: permissions.unwrap_or_default(),
|
||||
permissions_or_attributes: permissions_or_attributes.unwrap_or_default(),
|
||||
name,
|
||||
file_type,
|
||||
content: None,
|
||||
|
@ -347,6 +363,8 @@ impl Meta {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::flags::PermissionFlag;
|
||||
|
||||
use super::Meta;
|
||||
use std::fs::File;
|
||||
use tempfile::tempdir;
|
||||
|
@ -355,15 +373,15 @@ mod tests {
|
|||
#[test]
|
||||
fn test_from_path_path() {
|
||||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
let meta = Meta::from_path(dir.path(), false, false).unwrap();
|
||||
let meta = Meta::from_path(dir.path(), false, PermissionFlag::Rwx).unwrap();
|
||||
assert_eq!(meta.path, dir.path())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_path_disable_permission() {
|
||||
let dir = assert_fs::TempDir::new().unwrap();
|
||||
let meta = Meta::from_path(dir.path(), false, true).unwrap();
|
||||
assert!(meta.permissions.is_none());
|
||||
let meta = Meta::from_path(dir.path(), false, PermissionFlag::Disable).unwrap();
|
||||
assert!(meta.permissions_or_attributes.is_none());
|
||||
assert!(meta.owner.is_none());
|
||||
}
|
||||
|
||||
|
@ -373,7 +391,8 @@ mod tests {
|
|||
|
||||
let path_a = tmp_dir.path().join("aaa.aa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_b = tmp_dir.path().join("bbb.bb");
|
||||
let path_c = tmp_dir.path().join("ccc.cc");
|
||||
|
@ -388,7 +407,8 @@ mod tests {
|
|||
std::os::windows::fs::symlink_file(path_c, &path_b)
|
||||
.expect("failed to create broken symlink");
|
||||
|
||||
let meta_b = Meta::from_path(&path_b, true, false).expect("failed to get meta");
|
||||
let meta_b =
|
||||
Meta::from_path(&path_b, true, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
assert!(
|
||||
meta_a.inode.is_some()
|
||||
|
@ -396,7 +416,7 @@ mod tests {
|
|||
&& meta_a.size.is_some()
|
||||
&& meta_a.date.is_some()
|
||||
&& meta_a.owner.is_some()
|
||||
&& meta_a.permissions.is_some()
|
||||
&& meta_a.permissions_or_attributes.is_some()
|
||||
&& meta_a.access_control.is_some()
|
||||
);
|
||||
|
||||
|
@ -406,7 +426,7 @@ mod tests {
|
|||
&& meta_b.size.is_none()
|
||||
&& meta_b.date.is_none()
|
||||
&& meta_b.owner.is_none()
|
||||
&& meta_b.permissions.is_none()
|
||||
&& meta_b.permissions_or_attributes.is_none()
|
||||
&& meta_b.access_control.is_none()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -222,6 +222,7 @@ mod test {
|
|||
use super::DisplayOption;
|
||||
use super::Name;
|
||||
use crate::color::{self, Colors};
|
||||
use crate::flags::PermissionFlag;
|
||||
use crate::flags::{HyperlinkOption, IconOption, IconTheme as FlagTheme};
|
||||
use crate::icon::Icons;
|
||||
use crate::meta::FileType;
|
||||
|
@ -274,7 +275,7 @@ mod test {
|
|||
// Create the directory
|
||||
let dir_path = tmp_dir.path().join("directory");
|
||||
fs::create_dir(&dir_path).expect("failed to create the dir");
|
||||
let meta = Meta::from_path(&dir_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&dir_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let colors = Colors::new(color::ThemeOption::NoLscolors);
|
||||
|
||||
|
@ -398,7 +399,7 @@ mod test {
|
|||
// Create the file;
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let colors = Colors::new(color::ThemeOption::NoColor);
|
||||
|
||||
|
@ -424,7 +425,7 @@ mod test {
|
|||
// Create the file;
|
||||
let file_path = tmp_dir.path().join("file.txt");
|
||||
File::create(&file_path).expect("failed to create file");
|
||||
let meta = Meta::from_path(&file_path, false, false).unwrap();
|
||||
let meta = Meta::from_path(&file_path, false, PermissionFlag::Rwx).unwrap();
|
||||
|
||||
let colors = Colors::new(color::ThemeOption::NoColor);
|
||||
|
||||
|
|
|
@ -122,6 +122,8 @@ impl Permissions {
|
|||
|
||||
colors.colorize(octals, &Elem::Octal).to_string()
|
||||
}
|
||||
// technically this should be an error, hmm
|
||||
PermissionFlag::Attributes => colors.colorize('-', &Elem::NoAccess).to_string(),
|
||||
PermissionFlag::Disable => colors.colorize('-', &Elem::NoAccess).to_string(),
|
||||
};
|
||||
|
||||
|
|
27
src/meta/permissions_or_attributes.rs
Normal file
27
src/meta/permissions_or_attributes.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
#[cfg(windows)]
|
||||
use super::windows_attributes::WindowsAttributes;
|
||||
use crate::{
|
||||
color::{ColoredString, Colors},
|
||||
flags::Flags,
|
||||
};
|
||||
|
||||
use super::Permissions;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PermissionsOrAttributes {
|
||||
Permissions(Permissions),
|
||||
#[cfg(windows)]
|
||||
WindowsAttributes(WindowsAttributes),
|
||||
}
|
||||
|
||||
impl PermissionsOrAttributes {
|
||||
pub fn render(&self, colors: &Colors, flags: &Flags) -> ColoredString {
|
||||
match self {
|
||||
PermissionsOrAttributes::Permissions(permissions) => permissions.render(colors, flags),
|
||||
#[cfg(windows)]
|
||||
PermissionsOrAttributes::WindowsAttributes(attributes) => {
|
||||
attributes.render(colors, flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
126
src/meta/windows_attributes.rs
Normal file
126
src/meta/windows_attributes.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
#[cfg(windows)]
|
||||
use crate::{
|
||||
color::{ColoredString, Colors, Elem},
|
||||
flags::Flags,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WindowsAttributes {
|
||||
pub archive: bool,
|
||||
pub readonly: bool,
|
||||
pub hidden: bool,
|
||||
pub system: bool,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn get_attributes(metadata: &std::fs::Metadata) -> WindowsAttributes {
|
||||
use windows::Win32::Storage::FileSystem::{
|
||||
FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_READONLY,
|
||||
FILE_ATTRIBUTE_SYSTEM, FILE_FLAGS_AND_ATTRIBUTES,
|
||||
};
|
||||
|
||||
let bits = metadata.file_attributes();
|
||||
let has_bit = |bit: FILE_FLAGS_AND_ATTRIBUTES| bits & bit.0 == bit.0;
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||
WindowsAttributes {
|
||||
archive: has_bit(FILE_ATTRIBUTE_ARCHIVE),
|
||||
readonly: has_bit(FILE_ATTRIBUTE_READONLY),
|
||||
hidden: has_bit(FILE_ATTRIBUTE_HIDDEN),
|
||||
system: has_bit(FILE_ATTRIBUTE_SYSTEM),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl WindowsAttributes {
|
||||
pub fn render(&self, colors: &Colors, _flags: &Flags) -> ColoredString {
|
||||
let res = [
|
||||
match self.archive {
|
||||
true => colors.colorize("a", &Elem::Archive),
|
||||
false => colors.colorize('-', &Elem::NoAccess),
|
||||
},
|
||||
match self.readonly {
|
||||
true => colors.colorize("r", &Elem::AttributeRead),
|
||||
false => colors.colorize('-', &Elem::NoAccess),
|
||||
},
|
||||
match self.hidden {
|
||||
true => colors.colorize("h", &Elem::Hidden),
|
||||
false => colors.colorize('-', &Elem::NoAccess),
|
||||
},
|
||||
match self.system {
|
||||
true => colors.colorize("s", &Elem::System),
|
||||
false => colors.colorize('-', &Elem::NoAccess),
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.fold(String::with_capacity(4), |mut acc, x| {
|
||||
acc.push_str(&x.to_string());
|
||||
acc
|
||||
});
|
||||
ColoredString::new(Colors::default_style(), res)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::{
|
||||
color::{Colors, ThemeOption},
|
||||
flags::Flags,
|
||||
};
|
||||
|
||||
use super::get_attributes;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
pub fn archived_file() {
|
||||
let attribute_string = create_and_process_file_with_attributes("archived_file.txt", "+A");
|
||||
assert_eq!("a---", attribute_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn readonly_file() {
|
||||
let attribute_string = create_and_process_file_with_attributes("readonly_file.txt", "+R");
|
||||
assert_eq!("ar--", attribute_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn hidden_file() {
|
||||
let attribute_string = create_and_process_file_with_attributes("hidden_file.txt", "+H");
|
||||
assert_eq!("a-h-", attribute_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn system_file() {
|
||||
let attribute_string = create_and_process_file_with_attributes("system_file.txt", "+S");
|
||||
assert_eq!("a--s", attribute_string);
|
||||
}
|
||||
|
||||
fn create_and_process_file_with_attributes(name: &str, attrs: &str) -> String {
|
||||
let tmp_dir = tempdir().expect("failed to create temp dir");
|
||||
let path = tmp_dir.path().join(name);
|
||||
let mut file = fs::File::create(path.clone()).unwrap();
|
||||
writeln!(file, "Test content").unwrap();
|
||||
Command::new("attrib")
|
||||
.arg(attrs)
|
||||
.arg(&path)
|
||||
.output()
|
||||
.expect("able to set attributes");
|
||||
let metadata = file.metadata().expect("able to get metadata");
|
||||
|
||||
let colors = Colors::new(ThemeOption::NoColor);
|
||||
|
||||
let attributes = get_attributes(&metadata);
|
||||
attributes
|
||||
.render(&colors, &Flags::default())
|
||||
.content()
|
||||
.to_string()
|
||||
}
|
||||
}
|
74
src/sort.rs
74
src/sort.rs
|
@ -80,7 +80,7 @@ fn by_git_status(a: &Meta, b: &Meta) -> Ordering {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::flags::Flags;
|
||||
use crate::flags::{Flags, PermissionFlag};
|
||||
use std::fs::{create_dir, File};
|
||||
use std::io::prelude::*;
|
||||
use std::process::Command;
|
||||
|
@ -93,12 +93,14 @@ mod tests {
|
|||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.dir_grouping = DirGrouping::First;
|
||||
|
@ -121,12 +123,14 @@ mod tests {
|
|||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.dir_grouping = DirGrouping::Last;
|
||||
|
@ -147,12 +151,14 @@ mod tests {
|
|||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("aaa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("zzz");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.dir_grouping = DirGrouping::None;
|
||||
|
@ -175,12 +181,14 @@ mod tests {
|
|||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.dir_grouping = DirGrouping::None;
|
||||
|
@ -203,7 +211,8 @@ mod tests {
|
|||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("aaa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create the file;
|
||||
let path_z = tmp_dir.path().join("zzz");
|
||||
|
@ -229,7 +238,8 @@ mod tests {
|
|||
.success();
|
||||
|
||||
assert!(success, "failed to change file timestamp");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.column = SortColumn::Time;
|
||||
|
@ -251,22 +261,26 @@ mod tests {
|
|||
// Create the file with rs extension;
|
||||
let path_a = tmp_dir.path().join("aaa.rs");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create the file with rs extension;
|
||||
let path_z = tmp_dir.path().join("zzz.rs");
|
||||
File::create(&path_z).expect("failed to create file");
|
||||
let meta_z = Meta::from_path(&path_z, false, false).expect("failed to get meta");
|
||||
let meta_z =
|
||||
Meta::from_path(&path_z, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create the file with js extension;
|
||||
let path_j = tmp_dir.path().join("zzz.js");
|
||||
File::create(&path_j).expect("failed to create file");
|
||||
let meta_j = Meta::from_path(&path_j, false, false).expect("failed to get meta");
|
||||
let meta_j =
|
||||
Meta::from_path(&path_j, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
// Create the file with txt extension;
|
||||
let path_t = tmp_dir.path().join("zzz.txt");
|
||||
File::create(&path_t).expect("failed to create file");
|
||||
let meta_t = Meta::from_path(&path_t, false, false).expect("failed to get meta");
|
||||
let meta_t =
|
||||
Meta::from_path(&path_t, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.column = SortColumn::Extension;
|
||||
|
@ -288,15 +302,18 @@ mod tests {
|
|||
|
||||
let path_a = tmp_dir.path().join("2");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_b = tmp_dir.path().join("11");
|
||||
File::create(&path_b).expect("failed to create file");
|
||||
let meta_b = Meta::from_path(&path_b, false, false).expect("failed to get meta");
|
||||
let meta_b =
|
||||
Meta::from_path(&path_b, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_c = tmp_dir.path().join("12");
|
||||
File::create(&path_c).expect("failed to create file");
|
||||
let meta_c = Meta::from_path(&path_c, false, false).expect("failed to get meta");
|
||||
let meta_c =
|
||||
Meta::from_path(&path_c, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.column = SortColumn::Version;
|
||||
|
@ -314,19 +331,23 @@ mod tests {
|
|||
|
||||
let path_a = tmp_dir.path().join("aaa.aa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_b = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_b).expect("failed to create dir");
|
||||
let meta_b = Meta::from_path(&path_b, false, false).expect("failed to get meta");
|
||||
let meta_b =
|
||||
Meta::from_path(&path_b, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_c = tmp_dir.path().join("zzz.zz");
|
||||
File::create(&path_c).expect("failed to create file");
|
||||
let meta_c = Meta::from_path(&path_c, false, false).expect("failed to get meta");
|
||||
let meta_c =
|
||||
Meta::from_path(&path_c, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_d = tmp_dir.path().join("zzz");
|
||||
create_dir(&path_d).expect("failed to create dir");
|
||||
let meta_d = Meta::from_path(&path_d, false, false).expect("failed to get meta");
|
||||
let meta_d =
|
||||
Meta::from_path(&path_d, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sorting.column = SortColumn::None;
|
||||
|
@ -359,14 +380,16 @@ mod tests {
|
|||
.expect("failed to create file")
|
||||
.write_all(b"1, 2, 3")
|
||||
.expect("failed to write to file");
|
||||
let meta_a = Meta::from_path(&path_a, false, false).expect("failed to get meta");
|
||||
let meta_a =
|
||||
Meta::from_path(&path_a, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_b = tmp_dir.path().join("bbb.bb");
|
||||
File::create(&path_b)
|
||||
.expect("failed to create file")
|
||||
.write_all(b"1, 2, 3, 4, 5, 6, 7, 8, 9, 10")
|
||||
.expect("failed to write file");
|
||||
let meta_b = Meta::from_path(&path_b, false, false).expect("failed to get meta");
|
||||
let meta_b =
|
||||
Meta::from_path(&path_b, false, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
let path_c = tmp_dir.path().join("ccc.cc");
|
||||
let path_d = tmp_dir.path().join("ddd.dd");
|
||||
|
@ -381,7 +404,8 @@ mod tests {
|
|||
std::os::windows::fs::symlink_file(path_d, &path_c)
|
||||
.expect("failed to create broken symlink");
|
||||
|
||||
let meta_c = Meta::from_path(&path_c, true, false).expect("failed to get meta");
|
||||
let meta_c =
|
||||
Meta::from_path(&path_c, true, PermissionFlag::Rwx).expect("failed to get meta");
|
||||
|
||||
assert_eq!(by_size(&meta_a, &meta_a), Ordering::Equal);
|
||||
assert_eq!(by_size(&meta_a, &meta_b), Ordering::Greater);
|
||||
|
|
|
@ -89,6 +89,7 @@ pub struct ColorTheme {
|
|||
#[serde(deserialize_with = "deserialize_color")]
|
||||
pub group: Color,
|
||||
pub permission: Permission,
|
||||
pub attributes: Attributes,
|
||||
pub date: Date,
|
||||
pub size: Size,
|
||||
pub inode: INode,
|
||||
|
@ -124,6 +125,21 @@ pub struct Permission {
|
|||
pub context: Color,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(default)]
|
||||
pub struct Attributes {
|
||||
#[serde(deserialize_with = "deserialize_color")]
|
||||
pub archive: Color,
|
||||
#[serde(deserialize_with = "deserialize_color")]
|
||||
pub read: Color,
|
||||
#[serde(deserialize_with = "deserialize_color")]
|
||||
pub hidden: Color,
|
||||
#[serde(deserialize_with = "deserialize_color")]
|
||||
pub system: Color,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
|
@ -274,6 +290,16 @@ impl Default for Permission {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl Default for Attributes {
|
||||
fn default() -> Self {
|
||||
Attributes {
|
||||
archive: Color::DarkGreen,
|
||||
read: Color::DarkYellow,
|
||||
hidden: Color::AnsiValue(13), // Pink,
|
||||
system: Color::AnsiValue(13), // Pink,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Default for FileType {
|
||||
fn default() -> Self {
|
||||
FileType {
|
||||
|
@ -381,6 +407,7 @@ impl ColorTheme {
|
|||
user: Color::AnsiValue(230), // Cornsilk1
|
||||
group: Color::AnsiValue(187), // LightYellow3
|
||||
permission: Permission::default(),
|
||||
attributes: Attributes::default(),
|
||||
file_type: FileType::default(),
|
||||
date: Date::default(),
|
||||
size: Size::default(),
|
||||
|
|
Loading…
Reference in a new issue