feat: icon color and ordered icon rules support (#503)

This commit is contained in:
三咲雅 · Misaki Masa 2024-01-10 23:24:36 +08:00 committed by GitHub
parent cd84386ead
commit 560a1bf3f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 201 additions and 170 deletions

View File

@ -164,145 +164,149 @@ rules = [
{ name = "*/", fg = "blue" }
]
[icons]
[icon]
"Desktop/" = ""
"Documents/" = ""
"Downloads/" = ""
"Pictures/" = ""
"Music/" = ""
"Movies/" = ""
"Videos/" = ""
"Public/" = ""
"Library/" = ""
"Development/" = ""
".config/" = ""
rules = [
# Programming
{ name = "*.c" , text = "" },
{ name = "*.cpp" , text = "" },
{ name = "*.css" , text = "" },
{ name = "*.fish" , text = "" },
{ name = "*.go" , text = "" },
{ name = "*.h" , text = "" },
{ name = "*.hpp" , text = "" },
{ name = "*.html" , text = "" },
{ name = "*.java" , text = "" },
{ name = "*.js" , text = "" },
{ name = "*.jsx" , text = "" },
{ name = "*.lua" , text = "" },
{ name = "*.nix" , text = "" },
{ name = "*.php" , text = "" },
{ name = "*.py" , text = "" },
{ name = "*.rb" , text = "" },
{ name = "*.rs" , text = "" },
{ name = "*.scss" , text = "" },
{ name = "*.sh" , text = "" },
{ name = "*.swift", text = "" },
{ name = "*.ts" , text = "" },
{ name = "*.tsx" , text = "" },
{ name = "*.vim" , text = "" },
{ name = "*.vue" , text = "󰡄" },
# Git
".git/" = ""
".gitignore" = ""
".gitmodules" = ""
".gitattributes" = ""
# Text
{ name = "*.conf", text = "" },
{ name = "*.ini" , text = "" },
{ name = "*.json", text = "" },
{ name = "*.md" , text = "" },
{ name = "*.toml", text = "" },
{ name = "*.txt", text = "" },
{ name = "*.yaml", text = "" },
{ name = "*.yml" , text = "" },
# Dotfiles
".DS_Store" = ""
".bashrc" = ""
".bashprofile" = ""
".zshrc" = ""
".zshenv" = ""
".zprofile" = ""
".vimrc" = ""
# Archives
{ name = "*.7z" , text = "" },
{ name = "*.bz2", text = "" },
{ name = "*.gz" , text = "" },
{ name = "*.rar", text = "" },
{ name = "*.tar", text = "" },
{ name = "*.xz" , text = "" },
{ name = "*.zip", text = "" },
# Text
"*.txt" = ""
"*.md" = ""
"*.rst" = ""
COPYING = "󰿃"
LICENSE = "󰿃"
# Images
{ name = "*.HEIC", text = "" },
{ name = "*.avif", text = "" },
{ name = "*.bmp" , text = "" },
{ name = "*.gif" , text = "" },
{ name = "*.ico" , text = "" },
{ name = "*.jpeg", text = "" },
{ name = "*.jpg" , text = "" },
{ name = "*.png" , text = "" },
{ name = "*.svg" , text = "" },
{ name = "*.webp", text = "" },
# Archives
"*.zip" = ""
"*.tar" = ""
"*.gz" = ""
"*.7z" = ""
"*.bz2" = ""
"*.xz" = ""
# Movies
{ name = "*.avi" , text = "" },
{ name = "*.mkv" , text = "" },
{ name = "*.mov" , text = "" },
{ name = "*.mp4" , text = "" },
{ name = "*.webm", text = "" },
# Documents
"*.csv" = ""
"*.doc" = ""
"*.doct" = ""
"*.docx" = ""
"*.dot" = ""
"*.ods" = ""
"*.ots" = ""
"*.pdf" = ""
"*.pom" = ""
"*.pot" = ""
"*.ppm" = ""
"*.pps" = ""
"*.ppt" = ""
"*.potx" = ""
"*.ppmx" = ""
"*.ppsx" = ""
"*.pptx" = ""
"*.xlc" = ""
"*.xlm" = ""
"*.xls" = ""
"*.xlt" = ""
"*.xlsm" = ""
"*.xlsx" = ""
# Audio
{ name = "*.aac" , text = "" },
{ name = "*.flac", text = "" },
{ name = "*.m4a" , text = "" },
{ name = "*.mp3" , text = "" },
{ name = "*.ogg" , text = "" },
{ name = "*.wav" , text = "" },
# Audio
"*.mp3" = ""
"*.flac" = ""
"*.wav" = ""
"*.aac" = ""
"*.ogg" = ""
"*.m4a" = ""
"*.mp2" = ""
# Documents
{ name = "*.csv" , text = "" },
{ name = "*.doc" , text = "" },
{ name = "*.doct", text = "" },
{ name = "*.docx", text = "" },
{ name = "*.dot" , text = "" },
{ name = "*.ods" , text = "" },
{ name = "*.ots" , text = "" },
{ name = "*.pdf" , text = "" },
{ name = "*.pom" , text = "" },
{ name = "*.pot" , text = "" },
{ name = "*.potx", text = "" },
{ name = "*.ppm" , text = "" },
{ name = "*.ppmx", text = "" },
{ name = "*.pps" , text = "" },
{ name = "*.ppsx", text = "" },
{ name = "*.ppt" , text = "" },
{ name = "*.pptx", text = "" },
{ name = "*.xlc" , text = "" },
{ name = "*.xlm" , text = "" },
{ name = "*.xls" , text = "" },
{ name = "*.xlsm", text = "" },
{ name = "*.xlsx", text = "" },
{ name = "*.xlt" , text = "" },
# Movies
"*.mp4" = ""
"*.mkv" = ""
"*.avi" = ""
"*.mov" = ""
"*.webm" = ""
# Lockfiles
{ name = "*.lock", text = "" },
# Images
"*.jpg" = ""
"*.jpeg" = ""
"*.png" = ""
"*.gif" = ""
"*.webp" = ""
"*.avif" = ""
"*.bmp" = ""
"*.ico" = ""
"*.svg" = ""
"*.xcf" = ""
"*.HEIC" = ""
# Misc
{ name = "*.bin", text = "" },
{ name = "*.exe", text = "" },
{ name = "*.pkg", text = "" },
# Programming
"*.c" = ""
"*.cpp" = ""
"*.h" = ""
"*.hpp" = ""
"*.rs" = ""
"*.go" = ""
"*.py" = ""
"*.js" = ""
"*.ts" = ""
"*.tsx" = ""
"*.jsx" = ""
"*.rb" = ""
"*.php" = ""
"*.java" = ""
"*.sh" = ""
"*.fish" = ""
"*.swift" = ""
"*.vim" = ""
"*.lua" = ""
"*.html" = ""
"*.css" = ""
"*.scss" = ""
"*.json" = ""
"*.toml" = ""
"*.yml" = ""
"*.yaml" = ""
"*.ini" = ""
"*.conf" = ""
"*.lock" = ""
"*.nix" = ""
Containerfile = "󰡨"
Dockerfile = "󰡨"
# Dotfiles
{ name = ".DS_Store" , text = "" },
{ name = ".bashprofile" , text = "" },
{ name = ".bashrc" , text = "" },
{ name = ".gitattributes", text = "" },
{ name = ".gitignore" , text = "" },
{ name = ".gitmodules" , text = "" },
{ name = ".vimrc" , text = "" },
{ name = ".zprofile" , text = "" },
{ name = ".zshenv" , text = "" },
{ name = ".zshrc" , text = "" },
# Misc
"*.bin" = ""
"*.exe" = ""
"*.pkg" = ""
# Named files
{ name = "COPYING" , text = "󰿃" },
{ name = "Containerfile", text = "󰡨" },
{ name = "Dockerfile" , text = "󰡨" },
{ name = "LICENSE" , text = "󰿃" },
# Default
"*" = ""
"*/" = ""
# Directories
{ name = ".config/" , text = "" },
{ name = ".git/" , text = "" },
{ name = "Desktop/" , text = "" },
{ name = "Development/", text = "" },
{ name = "Documents/" , text = "" },
{ name = "Downloads/" , text = "" },
{ name = "Library/" , text = "" },
{ name = "Movies/" , text = "" },
{ name = "Music/" , text = "" },
{ name = "Pictures/" , text = "" },
{ name = "Public/" , text = "" },
{ name = "Videos/" , text = "" },
# Default
{ name = "*" , text = "" },
{ name = "*/", text = "" },
]
# : }}}

View File

@ -1,13 +1,12 @@
use std::fmt;
use serde::{Deserialize, Deserializer};
use serde::{de::{self, Visitor}, Deserializer};
use super::Style;
use crate::{theme::{Color, StyleShadow}, Pattern};
use crate::Pattern;
#[derive(Debug)]
pub struct Icon {
pub name: Pattern,
pub display: String,
pub name: Pattern,
pub text: String,
pub style: Style,
}
impl Icon {
@ -15,31 +14,28 @@ impl Icon {
where
D: Deserializer<'de>,
{
struct IconVisitor;
#[derive(Deserialize)]
struct IconOuter {
rules: Vec<IconRule>,
}
#[derive(Deserialize)]
struct IconRule {
name: Pattern,
text: String,
impl<'de> Visitor<'de> for IconVisitor {
type Value = Vec<Icon>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a icon rule, e.g. \"*.md\" = \"\"")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
let mut icons = vec![];
while let Some((key, value)) = &map.next_entry::<String, String>()? {
icons.push(Icon {
name: Pattern::try_from(key.clone())
.map_err(|e| de::Error::custom(e.to_string()))?,
display: value.clone(),
});
}
Ok(icons)
}
fg: Option<Color>,
}
deserializer.deserialize_map(IconVisitor)
Ok(
IconOuter::deserialize(deserializer)?
.rules
.into_iter()
.map(|r| Icon {
name: r.name,
text: r.text,
style: StyleShadow { fg: r.fg, ..Default::default() }.into(),
})
.collect::<Vec<_>>(),
)
}
}

View File

@ -36,7 +36,7 @@ impl From<Style> for ratatui::style::Style {
}
}
#[derive(Deserialize)]
#[derive(Default, Deserialize)]
pub(super) struct StyleShadow {
#[serde(default)]
pub(super) fg: Option<Color>,

View File

@ -130,7 +130,7 @@ pub struct Theme {
// File-specific styles
#[serde(rename = "filetype", deserialize_with = "Filetype::deserialize", skip_serializing)]
pub filetypes: Vec<Filetype>,
#[serde(deserialize_with = "Icon::deserialize", skip_serializing)]
#[serde(rename = "icon", deserialize_with = "Icon::deserialize", skip_serializing)]
pub icons: Vec<Icon>,
}

View File

@ -1,6 +1,6 @@
use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, UserDataFields, UserDataMethods, Value};
use yazi_config::{LAYOUT, THEME};
use yazi_plugin::{bindings::{Cast, File, Range, Url}, elements::Style};
use yazi_plugin::{bindings::{Cast, File, Icon, Range, Url}, elements::Style};
use yazi_shared::MIME_DIR;
use super::{CtxRef, FolderRef};
@ -69,14 +69,13 @@ impl<'a, 'b> Folder<'a, 'b> {
p.next_back();
Some(lua.create_string(p.as_path().as_os_str().as_encoded_bytes())).transpose()
});
reg.add_method("icon", |_, me, ()| {
Ok(
THEME
.icons
.iter()
.find(|&x| x.name.match_path(&me.url, me.is_dir()))
.map(|x| x.display.to_string()),
)
reg.add_method("icon", |lua, me, ()| {
THEME
.icons
.iter()
.find(|&x| x.name.match_path(&me.url, me.is_dir()))
.map(|x| Icon::cast(lua, x))
.transpose()
});
reg.add_function("style", |lua, me: AnyUserData| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;

View File

@ -12,6 +12,7 @@ pub(crate) struct Lives;
impl Lives {
pub(crate) fn register() -> mlua::Result<()> {
yazi_plugin::bindings::Cha::register(&LUA)?;
yazi_plugin::bindings::Icon::register(&LUA)?;
yazi_plugin::bindings::Url::register(&LUA)?;
super::Active::register(&LUA)?;

View File

@ -14,7 +14,10 @@ function Folder:by_kind(kind)
end
end
function Folder:icon(file) return ui.Span(" " .. file:icon() .. " ") end
function Folder:icon(file)
local icon = file:icon()
return icon and ui.Span(" " .. icon.text .. " "):style(icon.style) or ui.Span("")
end
function Folder:highlighted_name(file)
-- Complete prefix when searching across directories

View File

@ -0,0 +1,26 @@
use mlua::{AnyUserData, Lua, UserDataFields};
use super::Cast;
use crate::elements::Style;
pub struct Icon;
impl Icon {
pub fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<&yazi_config::theme::Icon>(|reg| {
reg.add_field_method_get("text", |lua, me| lua.create_string(&me.text));
reg.add_field_method_get("style", |_, me| Ok(Style::from(me.style)));
})?;
Ok(())
}
}
impl Cast<&'static yazi_config::theme::Icon> for Icon {
fn cast<'lua>(
lua: &'lua Lua,
data: &'static yazi_config::theme::Icon,
) -> mlua::Result<AnyUserData<'lua>> {
lua.create_any_userdata(data)
}
}

View File

@ -3,6 +3,7 @@
mod bindings;
mod cha;
mod file;
mod icon;
mod range;
mod url;
mod window;
@ -10,6 +11,7 @@ mod window;
pub use bindings::*;
pub use cha::*;
pub use file::*;
pub use icon::*;
pub use range::*;
pub use url::*;
pub use window::*;