From 2e67c013771e4a27b9ea450daff22f7eee7c9729 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Sun, 22 Feb 2026 11:35:25 -0500 Subject: [PATCH] Add icons to TUI. --- Cargo.lock | 1 + Cargo.toml | 3 ++- libclide/Cargo.toml | 1 + libclide/src/fs.rs | 13 +++++++++++++ libclide/src/fs/entry_meta.rs | 4 ++++ src/gui/filesystem.rs | 10 +--------- src/tui/explorer.rs | 4 ++-- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fecb64b..0ae1fc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1170,6 +1170,7 @@ name = "libclide" version = "0.1.0" dependencies = [ "anyhow", + "devicons", "log", "strum", ] diff --git a/Cargo.toml b/Cargo.toml index f07c71a..2f18af2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [".", "libclide", "libclide-macros", ] anyhow = "1.0.100" strum = "0.27.2" log = { version = "0.4.27", features = [] } +devicons = "0.6.12" [dependencies] cxx = "1.0.95" @@ -23,12 +24,12 @@ ratatui = "0.30.0" tui-tree-widget = "0.24.0" tui-logger = "0.18.1" edtui = "0.11.1" -devicons = "0.6.12" libclide = { path = "./libclide" } libclide-macros = { path = "./libclide-macros" } anyhow = { workspace = true } strum = { workspace = true } log = { workspace = true } +devicons = { workspace = true } [build-dependencies] # The link_qt_object_files feature is required for statically linking Qt 6. diff --git a/libclide/Cargo.toml b/libclide/Cargo.toml index 7c037f0..e239386 100644 --- a/libclide/Cargo.toml +++ b/libclide/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" anyhow = { workspace = true } strum = { workspace = true } log = { workspace = true } +devicons = { workspace = true } diff --git a/libclide/src/fs.rs b/libclide/src/fs.rs index 04e84c0..484ea1e 100644 --- a/libclide/src/fs.rs +++ b/libclide/src/fs.rs @@ -3,3 +3,16 @@ // SPDX-License-Identifier: GNU General Public License v3.0 or later pub mod entry_meta; + +use devicons::FileIcon; +use std::path::Path; + +pub fn icon>(p: P) -> FileIcon { + let path = p.as_ref(); + if Path::new(&path).is_dir() { + // Ensures directories are given a folder icon and not mistakenly resolved to a language. + // For example, a directory named `cpp` would otherwise return a C++ icon. + return FileIcon::from("dir/"); + } + FileIcon::from(path) +} diff --git a/libclide/src/fs/entry_meta.rs b/libclide/src/fs/entry_meta.rs index 4d896d4..55749c9 100644 --- a/libclide/src/fs/entry_meta.rs +++ b/libclide/src/fs/entry_meta.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GNU General Public License v3.0 or later use anyhow::{Context, Result}; +use devicons::FileIcon; use std::path::{Path, PathBuf}; #[derive(Debug)] @@ -10,6 +11,7 @@ pub struct EntryMeta { pub abs_path: String, pub file_name: String, pub is_dir: bool, + pub icon: FileIcon, } impl EntryMeta { @@ -41,10 +43,12 @@ impl EntryMeta { .context(format!("Failed to get file name for path: {abs_path:?}"))? .to_string_lossy() .to_string(); + let icon = crate::fs::icon(&abs_path); Ok(EntryMeta { abs_path, file_name, is_dir, + icon, }) } } diff --git a/src/gui/filesystem.rs b/src/gui/filesystem.rs index 12dc077..1f58fd0 100644 --- a/src/gui/filesystem.rs +++ b/src/gui/filesystem.rs @@ -3,7 +3,6 @@ // SPDX-License-Identifier: GNU General Public License v3.0 or later use cxx_qt_lib::{QModelIndex, QString}; -use devicons::FileIcon; use dirs; use std::fs; use std::path::Path; @@ -142,13 +141,6 @@ impl qobject::FileSystem { } fn icon(self: std::pin::Pin<&mut Self>, path: &QString) -> QString { - let str = path.to_string(); - if Path::new(&str).is_dir() { - // Ensures directories are given a folder icon and not mistakenly resolved to a language. - // For example, a directory named `cpp` would otherwise return a C++ icon. - return QString::from(FileIcon::from("dir/").to_string()); - } - let icon = FileIcon::from(str); - QString::from(icon.to_string()) + QString::from(libclide::fs::icon(path.to_string().as_str()).to_string()) } } diff --git a/src/tui/explorer.rs b/src/tui/explorer.rs index 4bb63f0..672ca4b 100644 --- a/src/tui/explorer.rs +++ b/src/tui/explorer.rs @@ -63,7 +63,7 @@ impl<'a> Explorer<'a> { } else { children.push(TreeItem::new_leaf( entry_meta.abs_path.clone(), - entry_meta.file_name.clone(), + format!("{} {}", entry_meta.icon.icon, entry_meta.file_name.as_str()), )); } } @@ -73,7 +73,7 @@ impl<'a> Explorer<'a> { // For a file tree this is fine because we shouldn't list the same object twice. TreeItem::new( path_meta.abs_path.clone(), - path_meta.file_name.clone(), + format!("{} {}", path_meta.icon.icon, path_meta.file_name.as_str()), children, ) .context(format!(