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 serde::{Deserialize, Deserializer};
|
||||||
use yazi_shared::{fs::File, MIME_DIR};
|
use yazi_shared::fs::File;
|
||||||
|
|
||||||
use super::{Color, Style, StyleShadow};
|
use super::{Color, Style, StyleShadow};
|
||||||
use crate::Pattern;
|
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 struct Filetype {
|
||||||
|
pub is: FiletypeIs,
|
||||||
pub name: Option<Pattern>,
|
pub name: Option<Pattern>,
|
||||||
pub mime: Option<Pattern>,
|
pub mime: Option<Pattern>,
|
||||||
pub kind: Option<FileKind>,
|
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filetype {
|
impl Filetype {
|
||||||
pub fn matches(&self, file: &File, mime: Option<&str>) -> bool {
|
pub fn matches(&self, file: &File, mime: Option<&str>) -> bool {
|
||||||
let is_dir = mime == Some(MIME_DIR);
|
let b = match self.is {
|
||||||
let kind_check = self.kind.as_ref().is_some_and(|t| match t {
|
FiletypeIs::None => true,
|
||||||
#[cfg(unix)]
|
FiletypeIs::Block => file.cha.is_block_device(),
|
||||||
FileKind::Executable => !file.cha.is_dir() && file.cha.permissions & 0o111 != 0,
|
FiletypeIs::Exec => file.cha.is_exec(),
|
||||||
FileKind::Symlink => file.cha.is_link(),
|
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, file.is_dir()))
|
||||||
|| self.name.as_ref().is_some_and(|n| n.match_path(&file.url, is_dir))
|
|
||||||
|| self.mime.as_ref().zip(mime).map_or(false, |(m, s)| m.matches(s))
|
|| self.mime.as_ref().zip(mime).map_or(false, |(m, s)| m.matches(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,9 +46,10 @@ impl Filetype {
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct FiletypeRule {
|
struct FiletypeRule {
|
||||||
|
#[serde(default)]
|
||||||
|
is: FiletypeIs,
|
||||||
name: Option<Pattern>,
|
name: Option<Pattern>,
|
||||||
mime: Option<Pattern>,
|
mime: Option<Pattern>,
|
||||||
kind: Option<FileKind>,
|
|
||||||
|
|
||||||
fg: Option<Color>,
|
fg: Option<Color>,
|
||||||
bg: Option<Color>,
|
bg: Option<Color>,
|
||||||
|
|
@ -95,9 +78,9 @@ impl Filetype {
|
||||||
.rules
|
.rules
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|r| Filetype {
|
.map(|r| Filetype {
|
||||||
|
is: r.is,
|
||||||
name: r.name,
|
name: r.name,
|
||||||
mime: r.mime,
|
mime: r.mime,
|
||||||
kind: r.kind,
|
|
||||||
style: StyleShadow {
|
style: StyleShadow {
|
||||||
fg: r.fg,
|
fg: r.fg,
|
||||||
bg: r.bg,
|
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_dir", |_, me| Ok(me.is_dir()));
|
||||||
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
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_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)]
|
#[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("uid", |_, me| Ok(me.uid));
|
||||||
reg.add_field_method_get("gid", |_, me| Ok(me.gid));
|
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("length", |_, me| Ok(me.len));
|
||||||
reg.add_field_method_get("created", |_, me| {
|
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()))
|
Ok(me.created.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,16 @@ use bitflags::bitflags;
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct ChaKind: u8 {
|
pub struct ChaKind: u8 {
|
||||||
const DIR = 0b00000001;
|
const DIR = 0b00000001;
|
||||||
|
|
||||||
const HIDDEN = 0b00000010;
|
const HIDDEN = 0b00000010;
|
||||||
const LINK = 0b00000100;
|
const LINK = 0b00000100;
|
||||||
const BAD_LINK = 0b00001000;
|
const ORPHAN = 0b00001000;
|
||||||
|
|
||||||
const BLOCK_DEVICE = 0b00010000;
|
const BLOCK_DEVICE = 0b00010000;
|
||||||
const CHAR_DEVICE = 0b00100000;
|
const CHAR_DEVICE = 0b00100000;
|
||||||
const FIFO = 0b01000000;
|
const FIFO = 0b01000000;
|
||||||
const SOCKET = 0b10000000;
|
const SOCKET = 0b10000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub struct Cha {
|
||||||
pub created: Option<SystemTime>,
|
pub created: Option<SystemTime>,
|
||||||
pub modified: Option<SystemTime>,
|
pub modified: Option<SystemTime>,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub permissions: u32,
|
pub permissions: libc::mode_t,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub uid: u32,
|
pub uid: u32,
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|
@ -70,7 +70,7 @@ impl From<Metadata> for Cha {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
permissions: {
|
permissions: {
|
||||||
use std::os::unix::prelude::PermissionsExt;
|
use std::os::unix::prelude::PermissionsExt;
|
||||||
m.permissions().mode()
|
m.permissions().mode() as libc::mode_t
|
||||||
},
|
},
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
uid: {
|
uid: {
|
||||||
|
|
@ -96,30 +96,50 @@ impl Cha {
|
||||||
|
|
||||||
impl Cha {
|
impl Cha {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_dir(self) -> bool { self.kind.contains(ChaKind::DIR) }
|
pub fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_hidden(self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
pub fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_link(self) -> bool { self.kind.contains(ChaKind::LINK) }
|
pub fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) }
|
||||||
|
|
||||||
#[inline]
|
#[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]
|
#[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]
|
#[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]
|
#[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]
|
#[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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_link && meta.is_symlink() {
|
if is_link && meta.is_symlink() {
|
||||||
ck |= ChaKind::BAD_LINK;
|
ck |= ChaKind::ORPHAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if url.is_hidden() {
|
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
|
// Convert a file mode to a string representation
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[allow(clippy::collapsible_else_if)]
|
#[allow(clippy::collapsible_else_if)]
|
||||||
pub fn permissions(mode: u32) -> String {
|
pub fn permissions(m: libc::mode_t) -> 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};
|
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 mut s = String::with_capacity(10);
|
||||||
let m = mode as mode_t;
|
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
s.push(match m & S_IFMT {
|
s.push(match m & S_IFMT {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue