From 966d478789982237ffedb4d11f74ac3681258fa9 Mon Sep 17 00:00:00 2001 From: Lauri Niskanen Date: Mon, 8 Jul 2024 19:41:22 +0300 Subject: [PATCH] feat: support displaying files with inaccessible metadata --- cspell.json | 2 +- yazi-config/preset/theme.toml | 5 + yazi-config/src/theme/icons.rs | 1 + yazi-config/src/theme/is.rs | 21 +-- yazi-core/src/folder/files.rs | 16 +- yazi-core/src/folder/sorter.rs | 4 +- yazi-core/src/tab/commands/reveal.rs | 2 +- yazi-core/src/tab/preview.rs | 4 +- yazi-plugin/preset/components/linemode.lua | 8 +- yazi-plugin/preset/components/status.lua | 2 +- yazi-plugin/src/cha/cha.rs | 23 +-- yazi-plugin/src/utils/cache.rs | 2 +- yazi-shared/src/fs/cha.rs | 167 ++++++++++++++------- yazi-shared/src/fs/file.rs | 7 +- yazi-shared/src/fs/fns.rs | 9 +- 15 files changed, 178 insertions(+), 95 deletions(-) diff --git a/cspell.json b/cspell.json index adef6e126..436947dac 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","subsec"],"version":"0.2"} \ No newline at end of file +{"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","imagesize","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink"],"flagWords":[]} \ No newline at end of file diff --git a/yazi-config/preset/theme.toml b/yazi-config/preset/theme.toml index 444af5d1b..09e65b039 100644 --- a/yazi-config/preset/theme.toml +++ b/yazi-config/preset/theme.toml @@ -189,6 +189,10 @@ rules = [ { name = "*", is = "orphan", bg = "red" }, { name = "*", is = "exec" , fg = "green" }, + # Dummy files + { name = "*", is = "dummy", bg = "red" }, + { name = "*/", is = "dummy", bg = "red" }, + # Fallback # { name = "*", fg = "white" }, { name = "*/", fg = "blue" } @@ -771,6 +775,7 @@ conds = [ { if = "fifo" , text = "" }, { if = "sock" , text = "" }, { if = "sticky", text = "" }, + { if = "dummy", text = "" }, # Fallback { if = "dir", text = "󰉋" }, diff --git a/yazi-config/src/theme/icons.rs b/yazi-config/src/theme/icons.rs index 04c1e81b6..34ecfaf62 100644 --- a/yazi-config/src/theme/icons.rs +++ b/yazi-config/src/theme/icons.rs @@ -29,6 +29,7 @@ impl Icons { "hidden" => file.is_hidden(), "link" => file.is_link(), "orphan" => file.is_orphan(), + "dummy" => file.is_dummy(), "block" => file.is_block(), "char" => file.is_char(), "fifo" => file.is_fifo(), diff --git a/yazi-config/src/theme/is.rs b/yazi-config/src/theme/is.rs index 89a9ad7f4..f42f057d4 100644 --- a/yazi-config/src/theme/is.rs +++ b/yazi-config/src/theme/is.rs @@ -9,13 +9,14 @@ use yazi_shared::fs::Cha; pub enum Is { #[default] None, + Link, + Orphan, + Dummy, Block, Char, - Exec, Fifo, - Link, - Orphan, Sock, + Exec, Sticky, } @@ -24,13 +25,14 @@ impl FromStr for Is { fn from_str(s: &str) -> Result { Ok(match s { + "link" => Self::Link, + "orphan" => Self::Orphan, + "dummy" => Self::Dummy, "block" => Self::Block, "char" => Self::Char, - "exec" => Self::Exec, "fifo" => Self::Fifo, - "link" => Self::Link, - "orphan" => Self::Orphan, "sock" => Self::Sock, + "exec" => Self::Exec, "sticky" => Self::Sticky, _ => bail!("invalid filetype: {s}"), }) @@ -48,13 +50,14 @@ impl Is { pub fn check(&self, cha: &Cha) -> bool { match self { Self::None => true, + Self::Link => cha.is_link(), + Self::Orphan => cha.is_orphan(), + Self::Dummy => cha.is_dummy(), Self::Block => cha.is_block(), Self::Char => cha.is_char(), - Self::Exec => cha.is_exec(), Self::Fifo => cha.is_fifo(), - Self::Link => cha.is_link(), - Self::Orphan => cha.is_orphan(), Self::Sock => cha.is_sock(), + Self::Exec => cha.is_exec(), Self::Sticky => cha.is_sticky(), } } diff --git a/yazi-core/src/folder/files.rs b/yazi-core/src/folder/files.rs index f1297a7b8..a9bb0e2f3 100644 --- a/yazi-core/src/folder/files.rs +++ b/yazi-core/src/folder/files.rs @@ -54,9 +54,11 @@ impl Files { select! { _ = tx.closed() => break, result = item.metadata() => { - if let Ok(meta) = result { - tx.send(File::from_meta(Url::from(item.path()), meta).await).ok(); - } + let url = Url::from(item.path()); + _ = tx.send(match result { + Ok(meta) => File::from_meta(url, meta).await, + Err(_) => File::from_dummy(url, item.file_type().await.ok()) + }); } } } @@ -76,9 +78,11 @@ impl Files { async fn go(entities: &[DirEntry]) -> Vec { let mut files = Vec::with_capacity(entities.len() / 3 + 1); for entry in entities { - if let Ok(meta) = entry.metadata().await { - files.push(File::from_meta(Url::from(entry.path()), meta).await); - } + let url = Url::from(entry.path()); + files.push(match entry.metadata().await { + Ok(meta) => File::from_meta(url, meta).await, + Err(_) => File::from_dummy(url, entry.file_type().await.ok()), + }); } files } diff --git a/yazi-core/src/folder/sorter.rs b/yazi-core/src/folder/sorter.rs index e3bae173c..244f848e2 100644 --- a/yazi-core/src/folder/sorter.rs +++ b/yazi-core/src/folder/sorter.rs @@ -33,11 +33,11 @@ impl FilesSorter { match self.by { SortBy::None => {} SortBy::Modified => items.sort_unstable_by(|a, b| { - let ord = self.cmp(a.modified, b.modified, self.promote(a, b)); + let ord = self.cmp(a.mtime, b.mtime, self.promote(a, b)); if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord } }), SortBy::Created => items.sort_unstable_by(|a, b| { - let ord = self.cmp(a.created, b.created, self.promote(a, b)); + let ord = self.cmp(a.ctime, b.ctime, self.promote(a, b)); if ord == Ordering::Equal { by_alphabetical(a, b) } else { ord } }), SortBy::Extension => items.sort_unstable_by(|a, b| { diff --git a/yazi-core/src/tab/commands/reveal.rs b/yazi-core/src/tab/commands/reveal.rs index ef7f7fec8..a2171147c 100644 --- a/yazi-core/src/tab/commands/reveal.rs +++ b/yazi-core/src/tab/commands/reveal.rs @@ -30,7 +30,7 @@ impl Tab { }; self.cd(parent.clone()); - FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit(); + FilesOp::Creating(parent, vec![File::from_dummy(opt.target.clone(), None)]).emit(); ManagerProxy::hover(Some(opt.target)); } } diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index 8f1741e76..25d2fef5f 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -102,12 +102,12 @@ impl Preview { *url == lock.url && self.skip == lock.skip && cha.len == lock.cha.len - && cha.modified == lock.cha.modified + && cha.mtime == lock.cha.mtime && cha.kind == lock.cha.kind && { #[cfg(unix)] { - cha.permissions == lock.cha.permissions + cha.perm == lock.cha.perm } #[cfg(windows)] { diff --git a/yazi-plugin/preset/components/linemode.lua b/yazi-plugin/preset/components/linemode.lua index 9c329aed2..4c61af373 100644 --- a/yazi-plugin/preset/components/linemode.lua +++ b/yazi-plugin/preset/components/linemode.lua @@ -32,11 +32,9 @@ end function Linemode:permissions(file) return ui.Line(file.cha:permissions() or "") end function Linemode:owner(file) - if not ya.user_name then - return ui.Line("") - else - return ui.Line(ya.user_name(file.cha.uid) .. ":" .. ya.group_name(file.cha.gid)) - end + local user = file.cha.uid and ya.user_name(file.cha.uid) or file.cha.uid + local group = file.cha.gid and ya.group_name(file.cha.gid) or file.cha.gid + return ui.Line(string.format("%s:%s", user or "-", group or "-")) end function Linemode:render(files) diff --git a/yazi-plugin/preset/components/status.lua b/yazi-plugin/preset/components/status.lua index f82195410..c755f21ea 100644 --- a/yazi-plugin/preset/components/status.lua +++ b/yazi-plugin/preset/components/status.lua @@ -73,7 +73,7 @@ function Status:permissions() for i = 1, #perm do local c = perm:sub(i, i) local style = THEME.status.permissions_t - if c == "-" then + if c == "-" or c == "?" then style = THEME.status.permissions_s elseif c == "r" then style = THEME.status.permissions_r diff --git a/yazi-plugin/src/cha/cha.rs b/yazi-plugin/src/cha/cha.rs index 96830beec..c369c9c89 100644 --- a/yazi-plugin/src/cha/cha.rs +++ b/yazi-plugin/src/cha/cha.rs @@ -16,6 +16,7 @@ impl Cha { 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_orphan", |_, me| Ok(me.is_orphan())); + reg.add_field_method_get("is_dummy", |_, me| Ok(me.is_dummy())); reg.add_field_method_get("is_block", |_, me| Ok(me.is_block())); reg.add_field_method_get("is_char", |_, me| Ok(me.is_char())); reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo())); @@ -25,25 +26,25 @@ impl Cha { #[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("nlink", |_, me| Ok(me.nlink)); + reg.add_field_method_get("uid", |_, me| Ok((!me.is_dummy()).then_some(me.uid))); + reg.add_field_method_get("gid", |_, me| Ok((!me.is_dummy()).then_some(me.gid))); + reg.add_field_method_get("nlink", |_, me| Ok((!me.is_dummy()).then_some(me.nlink))); } 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())) + Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) }); reg.add_field_method_get("modified", |_, me| { - Ok(me.modified.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) + Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) }); reg.add_field_method_get("accessed", |_, me| { - Ok(me.accessed.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) + Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())) }); reg.add_method("permissions", |_, me, ()| { Ok( #[cfg(unix)] - Some(yazi_shared::fs::permissions(me.permissions)), + Some(yazi_shared::fs::permissions(me.perm, me.is_dummy())), #[cfg(windows)] None::, ) @@ -72,11 +73,11 @@ impl Cha { Self::cast(lua, yazi_shared::fs::Cha { kind, len: t.raw_get("len").unwrap_or_default(), - accessed: parse_time(t.raw_get("atime").ok())?, - created: parse_time(t.raw_get("ctime").ok())?, - modified: parse_time(t.raw_get("mtime").ok())?, + atime: parse_time(t.raw_get("atime").ok())?, + ctime: parse_time(t.raw_get("ctime").ok())?, + mtime: parse_time(t.raw_get("mtime").ok())?, #[cfg(unix)] - permissions: t.raw_get("permissions").unwrap_or_default(), + perm: t.raw_get("permissions").unwrap_or_default(), #[cfg(unix)] uid: t.raw_get("uid").unwrap_or_default(), #[cfg(unix)] diff --git a/yazi-plugin/src/utils/cache.rs b/yazi-plugin/src/utils/cache.rs index a090436b9..828927973 100644 --- a/yazi-plugin/src/utils/cache.rs +++ b/yazi-plugin/src/utils/cache.rs @@ -17,7 +17,7 @@ impl Utils { let hex = { let mut digest = Md5::new_with_prefix(file.url.as_os_str().as_encoded_bytes()); - digest.update(&format!("//{:?}//{}", file.cha.modified, t.raw_get("skip").unwrap_or(0))); + digest.update(&format!("//{:?}//{}", file.cha.mtime, t.raw_get("skip").unwrap_or(0))); format!("{:x}", digest.finalize()) }; diff --git a/yazi-shared/src/fs/cha.rs b/yazi-shared/src/fs/cha.rs index 310ec706a..f50fa5f17 100644 --- a/yazi-shared/src/fs/cha.rs +++ b/yazi-shared/src/fs/cha.rs @@ -1,4 +1,4 @@ -use std::{fs::Metadata, time::SystemTime}; +use std::{fs::{FileType, Metadata}, time::SystemTime}; use bitflags::bitflags; @@ -11,28 +11,25 @@ bitflags! { const LINK = 0b00000100; const ORPHAN = 0b00001000; - const BLOCK = 0b00010000; - const CHAR = 0b00100000; - const FIFO = 0b01000000; - const SOCKET = 0b10000000; + const DUMMY = 0b00010000; } } #[derive(Clone, Copy, Debug, Default)] pub struct Cha { - pub kind: ChaKind, - pub len: u64, - pub accessed: Option, - pub created: Option, - pub modified: Option, + pub kind: ChaKind, + pub len: u64, + pub atime: Option, + pub ctime: Option, + pub mtime: Option, #[cfg(unix)] - pub permissions: libc::mode_t, + pub perm: libc::mode_t, #[cfg(unix)] - pub uid: libc::uid_t, + pub uid: libc::uid_t, #[cfg(unix)] - pub gid: libc::gid_t, + pub gid: libc::gid_t, #[cfg(unix)] - pub nlink: libc::nlink_t, + pub nlink: libc::nlink_t, } impl From for Cha { @@ -42,47 +39,30 @@ impl From for Cha { ck |= ChaKind::DIR; } - #[cfg(unix)] - { - use std::os::unix::prelude::FileTypeExt; - if m.file_type().is_block_device() { - ck |= ChaKind::BLOCK; - } - if m.file_type().is_char_device() { - ck |= ChaKind::CHAR; - } - if m.file_type().is_fifo() { - ck |= ChaKind::FIFO; - } - if m.file_type().is_socket() { - ck |= ChaKind::SOCKET; - } - } - Self { - kind: ck, - len: m.len(), - accessed: m.accessed().ok(), - created: m.created().ok(), - modified: m.modified().ok(), + kind: ck, + len: m.len(), + atime: m.accessed().ok(), + ctime: m.created().ok(), + mtime: m.modified().ok(), #[cfg(unix)] - permissions: { + perm: { use std::os::unix::prelude::PermissionsExt; m.permissions().mode() as _ }, #[cfg(unix)] - uid: { + uid: { use std::os::unix::fs::MetadataExt; m.uid() as _ }, #[cfg(unix)] - gid: { + gid: { use std::os::unix::fs::MetadataExt; m.gid() as _ }, #[cfg(unix)] - nlink: { + nlink: { use std::os::unix::fs::MetadataExt; m.nlink() as _ }, @@ -90,6 +70,50 @@ impl From for Cha { } } +impl From for Cha { + fn from(t: FileType) -> Self { + let mut kind = ChaKind::DUMMY; + + #[cfg(unix)] + let perm = { + use std::os::unix::fs::FileTypeExt; + if t.is_dir() { + kind |= ChaKind::DIR; + libc::S_IFDIR + } else if t.is_symlink() { + kind |= ChaKind::LINK; + libc::S_IFLNK + } else if t.is_block_device() { + libc::S_IFBLK + } else if t.is_char_device() { + libc::S_IFCHR + } else if t.is_fifo() { + libc::S_IFIFO + } else if t.is_socket() { + libc::S_IFSOCK + } else { + 0 + } + }; + + #[cfg(windows)] + { + if t.is_dir() { + kind |= ChaKind::DIR; + } else if t.is_symlink() { + kind |= ChaKind::LINK; + } + } + + Self { + kind, + #[cfg(unix)] + perm, + ..Default::default() + } + } +} + impl Cha { #[inline] pub fn with_kind(mut self, kind: ChaKind) -> Self { @@ -100,34 +124,73 @@ impl Cha { impl Cha { #[inline] - pub fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) } + pub const fn is_dir(&self) -> bool { self.kind.contains(ChaKind::DIR) } #[inline] - pub fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) } + pub const fn is_hidden(&self) -> bool { self.kind.contains(ChaKind::HIDDEN) } #[inline] - pub fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) } + pub const fn is_link(&self) -> bool { self.kind.contains(ChaKind::LINK) } #[inline] - pub fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) } + pub const fn is_orphan(&self) -> bool { self.kind.contains(ChaKind::ORPHAN) } #[inline] - pub fn is_block(&self) -> bool { self.kind.contains(ChaKind::BLOCK) } + pub const fn is_dummy(&self) -> bool { self.kind.contains(ChaKind::DUMMY) } #[inline] - pub fn is_char(&self) -> bool { self.kind.contains(ChaKind::CHAR) } + pub const fn is_block(&self) -> bool { + #[cfg(unix)] + { + self.perm & libc::S_IFMT == libc::S_IFBLK + } + #[cfg(windows)] + { + false + } + } + + #[inline] + pub const fn is_char(&self) -> bool { + #[cfg(unix)] + { + self.perm & libc::S_IFMT == libc::S_IFCHR + } + #[cfg(windows)] + { + false + } + } #[inline] - pub fn is_fifo(&self) -> bool { self.kind.contains(ChaKind::FIFO) } + pub const fn is_fifo(&self) -> bool { + #[cfg(unix)] + { + self.perm & libc::S_IFMT == libc::S_IFIFO + } + #[cfg(windows)] + { + false + } + } #[inline] - pub fn is_sock(&self) -> bool { self.kind.contains(ChaKind::SOCKET) } + pub const fn is_sock(&self) -> bool { + #[cfg(unix)] + { + self.perm & libc::S_IFMT == libc::S_IFSOCK + } + #[cfg(windows)] + { + false + } + } #[inline] - pub fn is_exec(&self) -> bool { + pub const fn is_exec(&self) -> bool { #[cfg(unix)] { - self.permissions & libc::S_IXUSR != 0 + self.perm & libc::S_IXUSR != 0 } #[cfg(windows)] { @@ -136,10 +199,10 @@ impl Cha { } #[inline] - pub fn is_sticky(&self) -> bool { + pub const fn is_sticky(&self) -> bool { #[cfg(unix)] { - self.permissions & libc::S_ISVTX != 0 + self.perm & libc::S_ISVTX != 0 } #[cfg(windows)] { diff --git a/yazi-shared/src/fs/file.rs b/yazi-shared/src/fs/file.rs index eb3eebf57..bd7fdca28 100644 --- a/yazi-shared/src/fs/file.rs +++ b/yazi-shared/src/fs/file.rs @@ -1,4 +1,4 @@ -use std::{cell::Cell, ffi::OsStr, fs::Metadata, ops::Deref}; +use std::{cell::Cell, ffi::OsStr, fs::{FileType, Metadata}, ops::Deref}; use anyhow::Result; use tokio::fs; @@ -63,7 +63,10 @@ impl File { } #[inline] - pub fn from_dummy(url: &Url) -> Self { Self { url: url.to_owned(), ..Default::default() } } + pub fn from_dummy(url: Url, ft: Option) -> Self { + // TODO: set dummy=true + Self { url: url.to_owned(), cha: ft.map_or_else(Cha::default, Cha::from), ..Default::default() } + } } impl File { diff --git a/yazi-shared/src/fs/fns.rs b/yazi-shared/src/fs/fns.rs index e201807be..051c4b124 100644 --- a/yazi-shared/src/fs/fns.rs +++ b/yazi-shared/src/fs/fns.rs @@ -264,11 +264,11 @@ pub fn copy_with_progress( // Convert a file mode to a string representation #[cfg(unix)] #[allow(clippy::collapsible_else_if)] -pub fn permissions(m: libc::mode_t) -> String { +pub fn permissions(m: libc::mode_t, dummy: bool) -> 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); - // File type + // Filetype s.push(match m & S_IFMT { S_IFBLK => 'b', S_IFCHR => 'c', @@ -279,6 +279,11 @@ pub fn permissions(m: libc::mode_t) -> String { _ => '-', }); + if dummy { + s.push_str("?????????"); + return s; + } + // Owner s.push(if m & S_IRUSR != 0 { 'r' } else { '-' }); s.push(if m & S_IWUSR != 0 { 'w' } else { '-' });