mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
Add more filetypes
This commit is contained in:
parent
b7eac3a07a
commit
67a5ba9dd0
5 changed files with 112 additions and 70 deletions
|
|
@ -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<Self, Self::Err> {
|
||||
match s {
|
||||
"executable" => Ok(Self::Executable),
|
||||
"symlink" => Ok(Self::Symlink),
|
||||
_ => Err(anyhow::anyhow!("invalid file kind")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for FileKind {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
|
||||
}
|
||||
|
||||
pub struct Filetype {
|
||||
pub is: FiletypeIs,
|
||||
pub name: Option<Pattern>,
|
||||
pub mime: Option<Pattern>,
|
||||
pub kind: Option<FileKind>,
|
||||
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<Pattern>,
|
||||
mime: Option<Pattern>,
|
||||
kind: Option<FileKind>,
|
||||
|
||||
fg: Option<Color>,
|
||||
bg: Option<Color>,
|
||||
|
|
@ -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<Self, Self::Err> {
|
||||
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<String> for FiletypeIs {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
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("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()))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ bitflags! {
|
|||
|
||||
const HIDDEN = 0b00000010;
|
||||
const LINK = 0b00000100;
|
||||
const BAD_LINK = 0b00001000;
|
||||
const ORPHAN = 0b00001000;
|
||||
|
||||
const BLOCK_DEVICE = 0b00010000;
|
||||
const CHAR_DEVICE = 0b00100000;
|
||||
|
|
@ -26,7 +26,7 @@ pub struct Cha {
|
|||
pub created: Option<SystemTime>,
|
||||
pub modified: Option<SystemTime>,
|
||||
#[cfg(unix)]
|
||||
pub permissions: u32,
|
||||
pub permissions: libc::mode_t,
|
||||
#[cfg(unix)]
|
||||
pub uid: u32,
|
||||
#[cfg(unix)]
|
||||
|
|
@ -70,7 +70,7 @@ impl From<Metadata> 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) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_block_device(&self) -> bool { self.kind.contains(ChaKind::BLOCK_DEVICE) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_char_device(&self) -> bool { self.kind.contains(ChaKind::CHAR_DEVICE) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_fifo(&self) -> bool { self.kind.contains(ChaKind::FIFO) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_socket(&self) -> bool { self.kind.contains(ChaKind::SOCKET) }
|
||||
|
||||
#[inline]
|
||||
pub fn is_exec(&self) -> bool {
|
||||
#[cfg(unix)]
|
||||
#[inline]
|
||||
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) }
|
||||
|
||||
#[cfg(unix)]
|
||||
#[inline]
|
||||
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) }
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl File {
|
|||
}
|
||||
|
||||
if is_link && meta.is_symlink() {
|
||||
ck |= ChaKind::BAD_LINK;
|
||||
ck |= ChaKind::ORPHAN;
|
||||
}
|
||||
|
||||
if url.is_hidden() {
|
||||
|
|
|
|||
|
|
@ -94,11 +94,9 @@ pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver<Result<u64,
|
|||
// Convert a file mode to a string representation
|
||||
#[cfg(unix)]
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
pub fn permissions(mode: u32) -> 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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue