feat: platform-specific key binding (#2526)

This commit is contained in:
三咲雅 · Misaki Masa 2025-03-24 19:09:37 +08:00 committed by GitHub
parent 83f4deecfe
commit e138364102
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 57 additions and 43 deletions

View file

@ -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()))
}
}

View file

@ -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<Cmd>,
pub desc: Option<String>,
#[serde(rename = "for")]
pub for_: Option<String>,
}
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<Self> {
for cmd in &mut self.run {
if cmd.layer == Default::default() {
cmd.layer = layer;
}
}
self
Ok(self)
}
}

View file

@ -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::<String>()? {
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::<String>()? {
cmds.push(Cmd::from_str(value).map_err(de::Error::custom)?);
}

View file

@ -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 {

View file

@ -1 +1 @@
yazi_macro::mod_flat!(chord cow deserializers key keymap rule);
yazi_macro::mod_flat!(chord cow deserializers key keymap rules);

View file

@ -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<Chord>,
#[serde(default)]
prepend_keymap: Vec<Chord>,
@ -17,13 +17,13 @@ pub struct KeymapRule {
append_keymap: Vec<Chord>,
}
impl Deref for KeymapRule {
impl Deref for KeymapRules {
type Target = Vec<Chord>;
fn deref(&self) -> &Self::Target { &self.keymap }
}
impl KeymapRule {
impl KeymapRules {
pub(crate) fn reshape(self, layer: Layer) -> Result<Self> {
#[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::<Result<_>>()?;
Ok(Self { keymap, ..Default::default() })
}

View file

@ -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};

View file

@ -5,6 +5,7 @@ use indexmap::IndexSet;
use serde::Deserialize;
use super::OpenerRule;
use crate::check_for;
#[derive(Debug, Deserialize)]
pub struct Opener(HashMap<String, Vec<OpenerRule>>);
@ -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::<Result<IndexSet<_>>>()?
.into_iter()

View file

@ -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,
}
}

View file

@ -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,
});
}