Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/ruf4/src/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ fn draw_single_panel(
}
} else if entry.selected {
ctx.attr_foreground_rgba(ctx.indexed(theme.file_selected));
} else if entry.is_hidden {
ctx.attr_foreground_rgba(ctx.indexed(theme.file_hidden));
} else if entry.is_dir {
ctx.attr_foreground_rgba(ctx.indexed(theme.file_dir));
} else if entry.is_executable {
Expand Down
16 changes: 10 additions & 6 deletions crates/ruf4/src/panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct FileEntry {
pub is_hardlink: bool,
pub is_executable: bool,
pub is_readonly: bool,
pub is_hidden: bool,
pub size: u64,
pub modified: Option<SystemTime>,
pub selected: bool,
Expand Down Expand Up @@ -134,6 +135,7 @@ impl Panel {
is_hardlink: false,
is_executable: false,
is_readonly: false,
is_hidden: false,
size: 0,
modified: None,
selected: false,
Expand All @@ -144,18 +146,18 @@ impl Panel {
for entry in iter.flatten() {
let name = entry.file_name().to_string_lossy().into_owned();

if !self.show_hidden && name.starts_with('.') {
continue;
}

let is_symlink = entry.file_type().map(|t| t.is_symlink()).unwrap_or(false);
// Follow symlinks: fs::metadata resolves the target,
// while entry.metadata() returns the symlink itself.
let metadata = if is_symlink {
fs::metadata(entry.path()).ok()
} else {
entry.metadata().ok()
};

let is_hidden = platform::is_hidden(&name, metadata.as_ref());
if !self.show_hidden && is_hidden {
continue;
}

let is_dir = metadata.as_ref().map(|m| m.is_dir()).unwrap_or(false);
let size = metadata.as_ref().map(|m| m.len()).unwrap_or(0);
let modified = metadata.as_ref().and_then(|m| m.modified().ok());
Expand All @@ -178,6 +180,7 @@ impl Panel {
is_hardlink,
is_executable,
is_readonly,
is_hidden,
size,
modified,
selected: false,
Expand Down Expand Up @@ -449,6 +452,7 @@ pub fn make_entry(name: &str, is_dir: bool, size: u64) -> FileEntry {
is_hardlink: false,
is_executable: false,
is_readonly: false,
is_hidden: false,
size,
modified: None,
selected: false,
Expand Down
29 changes: 29 additions & 0 deletions crates/ruf4/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,35 @@ pub fn disk_free(_path: &Path) -> Option<u64> {

// ── File properties ────────────────────────────────────────────────────────

/// Detect whether a file should be considered hidden.
/// On Unix: dot-prefix. On Windows: FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM.
#[cfg(unix)]
pub fn is_hidden(name: &str, _metadata: Option<&std::fs::Metadata>) -> bool {
name.starts_with('.')
}

#[cfg(windows)]
pub fn is_hidden(name: &str, metadata: Option<&std::fs::Metadata>) -> bool {
use std::os::windows::fs::MetadataExt;
const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2;
const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4;
if name.starts_with('.') {
return true;
}
if let Some(m) = metadata {
let attrs = m.file_attributes();
if attrs & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM) != 0 {
return true;
}
}
false
}

#[cfg(not(any(unix, windows)))]
pub fn is_hidden(name: &str, _metadata: Option<&std::fs::Metadata>) -> bool {
name.starts_with('.')
}

/// Detect whether a file is a hard link and/or executable.
/// Returns `(is_hardlink, is_executable)`.
#[cfg(unix)]
Expand Down
7 changes: 6 additions & 1 deletion crates/ruf4/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct Theme {
pub file_dir: IndexedColor,
pub file_executable: IndexedColor,
pub file_readonly: IndexedColor,
pub file_hidden: IndexedColor,
pub file_normal: IndexedColor,

// ── Preview panel ──────────────────────────────────────────────────
Expand Down Expand Up @@ -161,6 +162,7 @@ pub const THEME_FIELDS: &[&str] = &[
"file_dir",
"file_executable",
"file_readonly",
"file_hidden",
"file_normal",
"preview_border",
"preview_text",
Expand Down Expand Up @@ -230,6 +232,7 @@ impl Theme {
"file_dir" => self.file_dir,
"file_executable" => self.file_executable,
"file_readonly" => self.file_readonly,
"file_hidden" => self.file_hidden,
"file_normal" => self.file_normal,
"preview_border" => self.preview_border,
"preview_text" => self.preview_text,
Expand Down Expand Up @@ -300,6 +303,7 @@ impl Theme {
"file_dir" => self.file_dir = color,
"file_executable" => self.file_executable = color,
"file_readonly" => self.file_readonly = color,
"file_hidden" => self.file_hidden = color,
"file_normal" => self.file_normal = color,
"preview_border" => self.preview_border = color,
"preview_text" => self.preview_text = color,
Expand Down Expand Up @@ -375,7 +379,8 @@ impl Theme {
file_selected: IndexedColor::BrightYellow,
file_dir: IndexedColor::BrightWhite,
file_executable: IndexedColor::BrightGreen,
file_readonly: IndexedColor::BrightBlack,
file_readonly: IndexedColor::Red,
file_hidden: IndexedColor::BrightBlack,
file_normal: IndexedColor::White,

// Preview
Expand Down
Loading