From 67a5ba9dd0f3cda44f4e1f44cd115c105281f987 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 13 Jan 2024 22:51:31 +0800 Subject: [PATCH] Add more filetypes --- yazi-config/src/theme/filetype.rs | 97 +++++++++++++++++++------------ yazi-plugin/src/bindings/cha.rs | 13 +++-- yazi-shared/src/fs/cha.rs | 64 +++++++++++++------- yazi-shared/src/fs/file.rs | 2 +- yazi-shared/src/fs/fns.rs | 6 +- 5 files changed, 112 insertions(+), 70 deletions(-) diff --git a/yazi-config/src/theme/filetype.rs b/yazi-config/src/theme/filetype.rs index e84a68aa..bd68e209 100644 --- a/yazi-config/src/theme/filetype.rs +++ b/yazi-config/src/theme/filetype.rs @@ -1,54 +1,36 @@ -use std::{path::Path, str::FromStr}; +use std::str::FromStr; +use anyhow::bail; use serde::{Deserialize, Deserializer}; -use yazi_shared::{fs::File, MIME_DIR}; +use yazi_shared::fs::File; use super::{Color, Style, StyleShadow}; use crate::Pattern; -#[derive(Deserialize)] -#[serde(try_from = "String")] -pub enum FileKind { - Executable, - Symlink, -} - -impl FromStr for FileKind { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s { - "executable" => Ok(Self::Executable), - "symlink" => Ok(Self::Symlink), - _ => Err(anyhow::anyhow!("invalid file kind")), - } - } -} - -impl TryFrom for FileKind { - type Error = anyhow::Error; - - fn try_from(s: String) -> Result { Self::from_str(&s) } -} - pub struct Filetype { + pub is: FiletypeIs, pub name: Option, pub mime: Option, - pub kind: Option, pub style: Style, } impl Filetype { pub fn matches(&self, file: &File, mime: Option<&str>) -> bool { - let is_dir = mime == Some(MIME_DIR); - let kind_check = self.kind.as_ref().is_some_and(|t| match t { - #[cfg(unix)] - FileKind::Executable => !file.cha.is_dir() && file.cha.permissions & 0o111 != 0, - FileKind::Symlink => file.cha.is_link(), - }); + let b = match self.is { + FiletypeIs::None => true, + FiletypeIs::Block => file.cha.is_block_device(), + FiletypeIs::Exec => file.cha.is_exec(), + FiletypeIs::Fifo => file.cha.is_fifo(), + FiletypeIs::Link => file.cha.is_link(), + FiletypeIs::Orphan => file.cha.is_orphan(), + FiletypeIs::Sock => file.cha.is_socket(), + FiletypeIs::Sticky => file.cha.is_sticky(), + }; + if !b { + return false; + } - kind_check - || self.name.as_ref().is_some_and(|n| n.match_path(&file.url, is_dir)) + self.name.as_ref().is_some_and(|n| n.match_path(&file.url, file.is_dir())) || self.mime.as_ref().zip(mime).map_or(false, |(m, s)| m.matches(s)) } } @@ -64,9 +46,10 @@ impl Filetype { } #[derive(Deserialize)] struct FiletypeRule { + #[serde(default)] + is: FiletypeIs, name: Option, mime: Option, - kind: Option, fg: Option, bg: Option, @@ -95,9 +78,9 @@ impl Filetype { .rules .into_iter() .map(|r| Filetype { + is: r.is, name: r.name, mime: r.mime, - kind: r.kind, style: StyleShadow { fg: r.fg, bg: r.bg, @@ -117,3 +100,41 @@ impl Filetype { ) } } + +// --- FiletypeIs +#[derive(Default, Deserialize)] +#[serde(try_from = "String")] +pub enum FiletypeIs { + #[default] + None, + Block, + Exec, + Fifo, + Link, + Orphan, + Sock, + Sticky, +} + +impl FromStr for FiletypeIs { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(match s { + "block" => Self::Block, + "exec" => Self::Exec, + "fifo" => Self::Fifo, + "link" => Self::Link, + "orphan" => Self::Orphan, + "sock" => Self::Sock, + "sticky" => Self::Sticky, + _ => bail!("invalid filetype: {s}"), + }) + } +} + +impl TryFrom for FiletypeIs { + type Error = anyhow::Error; + + fn try_from(s: String) -> Result { Self::from_str(&s) } +} diff --git a/yazi-plugin/src/bindings/cha.rs b/yazi-plugin/src/bindings/cha.rs index e3e7ec0b..68b81c05 100644 --- a/yazi-plugin/src/bindings/cha.rs +++ b/yazi-plugin/src/bindings/cha.rs @@ -12,17 +12,20 @@ impl Cha { reg.add_field_method_get("is_dir", |_, me| Ok(me.is_dir())); reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden())); reg.add_field_method_get("is_link", |_, me| Ok(me.is_link())); - reg.add_field_method_get("is_bad_link", |_, me| Ok(me.is_bad_link())); + reg.add_field_method_get("is_orphan", |_, me| Ok(me.is_orphan())); + reg.add_field_method_get("is_block_device", |_, me| Ok(me.is_block_device())); + reg.add_field_method_get("is_char_device", |_, me| Ok(me.is_char_device())); + reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo())); + reg.add_field_method_get("is_socket", |_, me| Ok(me.is_socket())); + reg.add_field_method_get("is_exec", |_, me| Ok(me.is_exec())); + reg.add_field_method_get("is_sticky", |_, me| Ok(me.is_sticky())); #[cfg(unix)] { - reg.add_field_method_get("is_block_device", |_, me| Ok(me.is_block_device())); - reg.add_field_method_get("is_char_device", |_, me| Ok(me.is_char_device())); - reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo())); - reg.add_field_method_get("is_socket", |_, me| Ok(me.is_socket())); reg.add_field_method_get("uid", |_, me| Ok(me.uid)); reg.add_field_method_get("gid", |_, me| Ok(me.gid)); } + reg.add_field_method_get("length", |_, me| Ok(me.len)); reg.add_field_method_get("created", |_, me| { Ok(me.created.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) diff --git a/yazi-shared/src/fs/cha.rs b/yazi-shared/src/fs/cha.rs index a28f2425..fd0eea22 100644 --- a/yazi-shared/src/fs/cha.rs +++ b/yazi-shared/src/fs/cha.rs @@ -5,16 +5,16 @@ use bitflags::bitflags; bitflags! { #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct ChaKind: u8 { - const DIR = 0b00000001; + const DIR = 0b00000001; - const HIDDEN = 0b00000010; - const LINK = 0b00000100; - const BAD_LINK = 0b00001000; + const HIDDEN = 0b00000010; + const LINK = 0b00000100; + const ORPHAN = 0b00001000; - const BLOCK_DEVICE = 0b00010000; - const CHAR_DEVICE = 0b00100000; - const FIFO = 0b01000000; - const SOCKET = 0b10000000; + const BLOCK_DEVICE = 0b00010000; + const CHAR_DEVICE = 0b00100000; + const FIFO = 0b01000000; + const SOCKET = 0b10000000; } } @@ -26,7 +26,7 @@ pub struct Cha { pub created: Option, pub modified: Option, #[cfg(unix)] - pub permissions: u32, + pub permissions: libc::mode_t, #[cfg(unix)] pub uid: u32, #[cfg(unix)] @@ -70,7 +70,7 @@ impl From for Cha { #[cfg(unix)] permissions: { use std::os::unix::prelude::PermissionsExt; - m.permissions().mode() + m.permissions().mode() as libc::mode_t }, #[cfg(unix)] uid: { @@ -96,30 +96,50 @@ impl Cha { impl Cha { #[inline] - pub fn is_dir(self) -> bool { self.kind.contains(ChaKind::DIR) } + pub fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) } #[inline] - pub fn is_hidden(self) -> bool { self.kind.contains(ChaKind::HIDDEN) } + pub fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) } #[inline] - pub fn is_link(self) -> bool { self.kind.contains(ChaKind::LINK) } + pub fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) } #[inline] - pub fn is_bad_link(self) -> bool { self.kind.contains(ChaKind::BAD_LINK) } + pub fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) } - #[cfg(unix)] #[inline] - pub fn is_block_device(self) -> bool { self.kind.contains(ChaKind::BLOCK_DEVICE) } + pub fn is_block_device(&self) -> bool { self.kind.contains(ChaKind::BLOCK_DEVICE) } - #[cfg(unix)] #[inline] - pub fn is_char_device(self) -> bool { self.kind.contains(ChaKind::CHAR_DEVICE) } + pub fn is_char_device(&self) -> bool { self.kind.contains(ChaKind::CHAR_DEVICE) } - #[cfg(unix)] #[inline] - pub fn is_fifo(self) -> bool { self.kind.contains(ChaKind::FIFO) } + pub fn is_fifo(&self) -> bool { self.kind.contains(ChaKind::FIFO) } - #[cfg(unix)] #[inline] - pub fn is_socket(self) -> bool { self.kind.contains(ChaKind::SOCKET) } + pub fn is_socket(&self) -> bool { self.kind.contains(ChaKind::SOCKET) } + + #[inline] + pub fn is_exec(&self) -> bool { + #[cfg(unix)] + { + self.permissions & libc::S_IXUSR != 0 + } + #[cfg(windows)] + { + false + } + } + + #[inline] + pub fn is_sticky(&self) -> bool { + #[cfg(unix)] + { + self.permissions & libc::S_ISVTX != 0 + } + #[cfg(windows)] + { + false + } + } } diff --git a/yazi-shared/src/fs/file.rs b/yazi-shared/src/fs/file.rs index 3b9c7e4e..6216f77a 100644 --- a/yazi-shared/src/fs/file.rs +++ b/yazi-shared/src/fs/file.rs @@ -37,7 +37,7 @@ impl File { } if is_link && meta.is_symlink() { - ck |= ChaKind::BAD_LINK; + ck |= ChaKind::ORPHAN; } if url.is_hidden() { diff --git a/yazi-shared/src/fs/fns.rs b/yazi-shared/src/fs/fns.rs index cfd1f6d7..c20735ca 100644 --- a/yazi-shared/src/fs/fns.rs +++ b/yazi-shared/src/fs/fns.rs @@ -94,11 +94,9 @@ pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver String { - use libc::{mode_t, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR}; - +pub fn permissions(m: libc::mode_t) -> String { + use libc::{S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFSOCK, S_IRGRP, S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR}; let mut s = String::with_capacity(10); - let m = mode as mode_t; // File type s.push(match m & S_IFMT {