From e13836410285528b26eb0f52dab7c2ad8a78e4de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Mon, 24 Mar 2025 19:09:37 +0800 Subject: [PATCH] feat: platform-specific key binding (#2526) --- yazi-cli/src/package/hash.rs | 25 +++++++++++--------- yazi-config/src/keymap/chord.rs | 16 ++++++++----- yazi-config/src/keymap/deserializers.rs | 4 ++-- yazi-config/src/keymap/keymap.rs | 18 +++++++------- yazi-config/src/keymap/mod.rs | 2 +- yazi-config/src/keymap/{rule.rs => rules.rs} | 15 ++++++------ yazi-config/src/lib.rs | 2 +- yazi-config/src/opener/opener.rs | 8 ++----- yazi-config/src/platform.rs | 9 +++++++ yazi-plugin/src/utils/layer.rs | 1 + 10 files changed, 57 insertions(+), 43 deletions(-) rename yazi-config/src/keymap/{rule.rs => rules.rs} (76%) create mode 100644 yazi-config/src/platform.rs diff --git a/yazi-cli/src/package/hash.rs b/yazi-cli/src/package/hash.rs index 761b72b2..42e83ba6 100644 --- a/yazi-cli/src/package/hash.rs +++ b/yazi-cli/src/package/hash.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use tokio::fs; use twox_hash::XxHash3_128; use yazi_fs::ok_or_not_found; @@ -22,18 +22,21 @@ impl Dependency { &["LICENSE", "README.md", "main.lua"][..] }; - let mut hasher = XxHash3_128::new(); - for file in files { - hasher.write(file.as_bytes()); - hasher.write(b"VpvFw9Atb7cWGOdqhZCra634CcJJRlsRl72RbZeV0vpG1\0"); - hasher.write(&ok_or_not_found(fs::read(dir.join(file)).await)?); + let mut h = XxHash3_128::new(); + for &file in files { + h.write(file.as_bytes()); + h.write(b"VpvFw9Atb7cWGOdqhZCra634CcJJRlsRl72RbZeV0vpG1\0"); + h.write(&ok_or_not_found(fs::read(dir.join(file)).await)?); } let mut assets = vec![]; match fs::read_dir(dir.join("assets")).await { Ok(mut it) => { while let Some(entry) = it.next_entry().await? { - assets.push((entry.file_name(), fs::read(entry.path()).await?)); + let Ok(name) = entry.file_name().into_string() else { + bail!("asset path is not valid UTF-8: {}", entry.path().display()); + }; + assets.push((name, fs::read(entry.path()).await?)); } } Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} @@ -42,11 +45,11 @@ impl Dependency { assets.sort_unstable_by(|(a, _), (b, _)| a.cmp(b)); for (name, data) in assets { - hasher.write(name.as_encoded_bytes()); - hasher.write(b"pQU2in0xcsu97Y77Nuq2LnT8mczMlFj22idcYRmMrglqU\0"); - hasher.write(&data); + h.write(name.as_bytes()); + h.write(b"pQU2in0xcsu97Y77Nuq2LnT8mczMlFj22idcYRmMrglqU\0"); + h.write(&data); } - Ok(format!("{:x}", hasher.finish_128())) + Ok(format!("{:x}", h.finish_128())) } } diff --git a/yazi-config/src/keymap/chord.rs b/yazi-config/src/keymap/chord.rs index 045aa15f..67ae555f 100644 --- a/yazi-config/src/keymap/chord.rs +++ b/yazi-config/src/keymap/chord.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, hash::{Hash, Hasher}, sync::OnceLock}; +use anyhow::Result; use regex::Regex; use serde::Deserialize; use yazi_shared::{Layer, event::Cmd}; @@ -15,6 +16,8 @@ pub struct Chord { #[serde(deserialize_with = "super::deserialize_run")] pub run: Vec, pub desc: Option, + #[serde(rename = "for")] + pub for_: Option, } impl PartialEq for Chord { @@ -53,14 +56,15 @@ impl Chord { pub(super) fn noop(&self) -> bool { self.run.len() == 1 && self.run[0].name == "noop" && self.run[0].args.is_empty() } +} - #[inline] - pub(super) fn with_layer(mut self, layer: Layer) -> Self { - for c in &mut self.run { - if c.layer == Default::default() { - c.layer = layer; +impl Chord { + pub(super) fn reshape(mut self, layer: Layer) -> Result { + for cmd in &mut self.run { + if cmd.layer == Default::default() { + cmd.layer = layer; } } - self + Ok(self) } } diff --git a/yazi-config/src/keymap/deserializers.rs b/yazi-config/src/keymap/deserializers.rs index 66287891..462325c1 100644 --- a/yazi-config/src/keymap/deserializers.rs +++ b/yazi-config/src/keymap/deserializers.rs @@ -23,7 +23,7 @@ where where A: de::SeqAccess<'de>, { - let mut cmds = vec![]; + let mut cmds = Vec::with_capacity(seq.size_hint().unwrap_or(0)); while let Some(value) = &seq.next_element::()? { cmds.push(Key::from_str(value).map_err(de::Error::custom)?); } @@ -61,7 +61,7 @@ where where A: de::SeqAccess<'de>, { - let mut cmds = vec![]; + let mut cmds = Vec::with_capacity(seq.size_hint().unwrap_or(0)); while let Some(value) = &seq.next_element::()? { cmds.push(Cmd::from_str(value).map_err(de::Error::custom)?); } diff --git a/yazi-config/src/keymap/keymap.rs b/yazi-config/src/keymap/keymap.rs index 980d43c0..ce34689f 100644 --- a/yazi-config/src/keymap/keymap.rs +++ b/yazi-config/src/keymap/keymap.rs @@ -3,19 +3,19 @@ use serde::Deserialize; use yazi_codegen::DeserializeOver1; use yazi_shared::Layer; -use super::{Chord, KeymapRule}; +use super::{Chord, KeymapRules}; #[derive(Deserialize, DeserializeOver1)] pub struct Keymap { #[serde(rename = "manager")] - pub mgr: KeymapRule, - pub tasks: KeymapRule, - pub spot: KeymapRule, - pub pick: KeymapRule, - pub input: KeymapRule, - pub confirm: KeymapRule, - pub help: KeymapRule, - pub cmp: KeymapRule, + pub mgr: KeymapRules, + pub tasks: KeymapRules, + pub spot: KeymapRules, + pub pick: KeymapRules, + pub input: KeymapRules, + pub confirm: KeymapRules, + pub help: KeymapRules, + pub cmp: KeymapRules, } impl Keymap { diff --git a/yazi-config/src/keymap/mod.rs b/yazi-config/src/keymap/mod.rs index 3c8bab95..45921949 100644 --- a/yazi-config/src/keymap/mod.rs +++ b/yazi-config/src/keymap/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(chord cow deserializers key keymap rule); +yazi_macro::mod_flat!(chord cow deserializers key keymap rules); diff --git a/yazi-config/src/keymap/rule.rs b/yazi-config/src/keymap/rules.rs similarity index 76% rename from yazi-config/src/keymap/rule.rs rename to yazi-config/src/keymap/rules.rs index 80cd8e2b..d392da11 100644 --- a/yazi-config/src/keymap/rule.rs +++ b/yazi-config/src/keymap/rules.rs @@ -6,10 +6,10 @@ use yazi_codegen::DeserializeOver2; use yazi_shared::Layer; use super::Chord; -use crate::{Preset, keymap::Key}; +use crate::{Preset, check_for, keymap::Key}; #[derive(Default, Deserialize, DeserializeOver2)] -pub struct KeymapRule { +pub struct KeymapRules { pub keymap: Vec, #[serde(default)] prepend_keymap: Vec, @@ -17,13 +17,13 @@ pub struct KeymapRule { append_keymap: Vec, } -impl Deref for KeymapRule { +impl Deref for KeymapRules { type Target = Vec; fn deref(&self) -> &Self::Target { &self.keymap } } -impl KeymapRule { +impl KeymapRules { pub(crate) fn reshape(self, layer: Layer) -> Result { #[inline] fn on(Chord { on, .. }: &Chord) -> [Key; 2] { @@ -38,9 +38,10 @@ impl KeymapRule { self.keymap.into_iter().filter(|v| !a_seen.contains(&on(v))), self.append_keymap.into_iter().filter(|v| !b_seen.contains(&on(v))), ) - .filter(|chord| !chord.noop()) - .map(|chord| chord.with_layer(layer)) - .collect(); + .map(|mut chord| (chord.for_.take(), chord)) + .filter(|(for_, chord)| !chord.noop() && check_for(for_.as_deref())) + .map(|(_, chord)| chord.reshape(layer)) + .collect::>()?; Ok(Self { keymap, ..Default::default() }) } diff --git a/yazi-config/src/lib.rs b/yazi-config/src/lib.rs index 5493d58c..6493f9ee 100644 --- a/yazi-config/src/lib.rs +++ b/yazi-config/src/lib.rs @@ -2,7 +2,7 @@ yazi_macro::mod_pub!(keymap mgr open opener plugin popup preview tasks theme which); -yazi_macro::mod_flat!(layout pattern preset priority yazi); +yazi_macro::mod_flat!(layout pattern platform preset priority yazi); use std::io::{Read, Write}; diff --git a/yazi-config/src/opener/opener.rs b/yazi-config/src/opener/opener.rs index 13bc8db1..525b0a96 100644 --- a/yazi-config/src/opener/opener.rs +++ b/yazi-config/src/opener/opener.rs @@ -5,6 +5,7 @@ use indexmap::IndexSet; use serde::Deserialize; use super::OpenerRule; +use crate::check_for; #[derive(Debug, Deserialize)] pub struct Opener(HashMap>); @@ -44,12 +45,7 @@ impl Opener { *rules = mem::take(rules) .into_iter() .map(|mut r| (r.for_.take(), r)) - .filter(|(for_, _)| match for_.as_ref().map(|s| s.as_str()) { - Some("unix") if cfg!(unix) => true, - Some(os) if os == std::env::consts::OS => true, - Some(_) => false, - None => true, - }) + .filter(|(for_, _)| check_for(for_.as_deref())) .map(|(_, r)| r.reshape()) .collect::>>()? .into_iter() diff --git a/yazi-config/src/platform.rs b/yazi-config/src/platform.rs new file mode 100644 index 00000000..a12884f3 --- /dev/null +++ b/yazi-config/src/platform.rs @@ -0,0 +1,9 @@ +#[inline] +pub(crate) fn check_for(for_: Option<&str>) -> bool { + match for_.as_ref().map(|s| s.as_ref()) { + Some("unix") if cfg!(unix) => true, + Some(os) if os == std::env::consts::OS => true, + Some(_) => false, + None => true, + } +} diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index 8f4cf515..f33fff6c 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -23,6 +23,7 @@ impl Utils { on: Self::parse_keys(cand.raw_get("on")?)?, run: vec![Cmd::args("which:callback", &[i]).with_any("tx", tx.clone())], desc: cand.raw_get("desc").ok(), + for_: None, }); }