diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6ab86f..8264a615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,19 +19,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Shell formatting ([#3232]) - Multi-entry support for plugin system ([#3154]) - Zoom in or out of the preview image ([#2864]) -- Improve the UX of the pick and input component ([#2906], [#2935]) +- Improve the UX of the pick and input components ([#2906], [#2935]) - Show progress of each task in task manager ([#3121], [#3131], [#3134]) - New `bulk_rename` command always renames files with the editor ([#2984]) - `key-*` DDS events to allow changing or canceling user key events ([#3005], [#3037]) -- New `--bg` specifying image background color for the preset `svg` and `magick` previewers ([#3189]) +- New `--bg` specifying image background color in the preset SVG and ImageMagick previewers ([#3189]) - `filter` by full path (prefix + filename) in search view instead of just filename ([#2915]) - New `casefy` command for case conversion of the input content ([#3235]) - Allow dynamic adjustment of layout ratio via `rt.mgr.ratio` ([#2964]) - Support `.deb` packages ([#2807], [#3128], [#3209]) - Port several widespread GUI keys to the input component ([#2849]) -- Support invalid UTF-8 paths throughout the codebase ([#2884], [#2889], [#2890], [#2895], [#3023]) +- Support invalid UTF-8 paths throughout the codebase ([#2884], [#2889], [#2890], [#2895], [#3023], [#3290]) - Allow upgrading only specific packages with `ya pkg` ([#2841]) -- Respect the user's `image_filter` setting for the preset `magick` previewer ([#3286]) +- Respect the user's `image_filter` setting in the preset ImageMagick previewer ([#3286]) - Allow custom mouse click behavior for individual files ([#2925]) - Display newlines in input as spaces to improve readability ([#2932]) - Fill in error messages if preview fails ([#2917]) @@ -49,7 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): ### Deprecated -- Deprecate `$n`, `$@` (Unix-like) and `%n`, `%*` (Windows) in `shell` command and opener rules in favor of new shell formatting ([#3232]) +- Deprecate `$n`, `$@` (\*nix) and `%n`, `%*` (Windows) in `shell` command and opener rules in favor of new shell formatting ([#3232]) - Deprecate `ya.hide`, `ya.render`, and `ya.truncate` in favor of `ui.hide`, `ui.render`, and `ui.truncate` ([#2939]) - Deprecate `position` property of `ya.input()` in favor of `pos` to align with `ya.confirm()` and its type `ui.Pos` ([#2921]) - Deprecate `cx.tasks.progress` in favor of `cx.tasks.summary` ([#3131]) @@ -84,7 +84,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Zero-copy `UrlBuf` to `Url` conversion ([#3117]) - String interning to reduce memory usage of mimetype and URL domain ([#3084], [#3091]) - Do not pre-allocate memory for Lua tables ([#2879]) -- Copy-on-write on command data & avoid converting primitive types to strings thereby allocating memory ([#2862]) +- Copy-on-write on command data, and avoid converting primitive types to strings thereby allocating memory ([#2862]) - Use `AnyUserData::type_id()` to reduce stack pushes ([#2834]) - App data instead of Lua registry to reduce stack pushes ([#2880]) @@ -140,7 +140,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): ### Fixed -- Respect the user's `max_width` setting for the built-in video previewer ([#2560]) +- Respect the user's `max_width` setting in the preset video previewer ([#2560]) - Reverse the mixing order of theme and flavor configuration ([#2594]) - No title is set when starts the first time ([#2700]) - `ya pub-to 0` checks if any peer is able to receive the message ([#2697]) @@ -227,9 +227,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - New `tbl_col` and `tbl_cell` in theme system for spotter table styling ([#2391]) - Allow different separators to be applied individually to the left and right sides of the status bar ([#2313]) - `ripgrep-all` support for the `search` command ([#2383]) -- Respect the user's `max_width` setting for the built-in PDF preloader ([#2331]) -- Respect the user's `wrap` setting for the built-in JSON previewer ([#2337]) -- Respect the user's `image_alloc` setting for the built-in ImageMagick previewer ([#2403]) +- Respect the user's `max_width` setting in the preset PDF preloader ([#2331]) +- Respect the user's `wrap` setting in the preset JSON previewer ([#2337]) +- Respect the user's `image_alloc` setting in the preset ImageMagick previewer ([#2403]) - New `external` and `removable` fields in the `fs.partitions()` API ([#2343]) - CSI-based Vim and Neovim built-in terminal detection for better accuracy ([#2327]) @@ -1532,3 +1532,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3268]: https://github.com/sxyazi/yazi/pull/3268 [#3271]: https://github.com/sxyazi/yazi/pull/3271 [#3286]: https://github.com/sxyazi/yazi/pull/3286 +[#3290]: https://github.com/sxyazi/yazi/pull/3290 diff --git a/yazi-cli/src/args.rs b/yazi-cli/src/args.rs index f28730f2..273a4447 100644 --- a/yazi-cli/src/args.rs +++ b/yazi-cli/src/args.rs @@ -1,8 +1,8 @@ -use std::borrow::Cow; +use std::{borrow::Cow, ffi::OsString}; use anyhow::{Result, bail}; use clap::{Parser, Subcommand}; -use yazi_shared::{Id, event::Cmd}; +use yazi_shared::{Either, Id}; #[derive(Parser)] #[command(name = "Ya", about, long_about = None)] @@ -38,7 +38,7 @@ pub(super) struct CommandEmit { pub(super) name: String, /// Arguments of the command. #[arg(allow_hyphen_values = true, trailing_var_arg = true)] - pub(super) args: Vec, + pub(super) args: Vec, } #[derive(clap::Args)] @@ -49,7 +49,7 @@ pub(super) struct CommandEmitTo { pub(super) name: String, /// Arguments of the command. #[arg(allow_hyphen_values = true, trailing_var_arg = true)] - pub(super) args: Vec, + pub(super) args: Vec, } #[derive(Subcommand)] @@ -139,10 +139,11 @@ macro_rules! impl_emit_body { impl $name { #[allow(dead_code)] pub(super) fn body(self) -> Result { - Ok(serde_json::to_string(&( - self.name, - Cmd::parse_args(self.args.into_iter(), None, false)?, - ))?) + let cmd: Vec<_> = [Either::Left(self.name)] + .into_iter() + .chain(self.args.into_iter().map(|s| Either::Right(s.into_encoded_bytes()))) + .collect(); + Ok(serde_json::to_string(&cmd)?) } } }; diff --git a/yazi-parser/src/app/plugin.rs b/yazi-parser/src/app/plugin.rs index 4b7114bf..2413a573 100644 --- a/yazi-parser/src/app/plugin.rs +++ b/yazi-parser/src/app/plugin.rs @@ -30,7 +30,7 @@ impl TryFrom for PluginOpt { let args = if let Ok(s) = c.second() { let (words, last) = yazi_shared::shell::split_unix(s, true)?; - Cmd::parse_args(words.into_iter(), last, true)? + Cmd::parse_args(words, last)? } else { Default::default() }; diff --git a/yazi-plugin/preset/plugins/dds.lua b/yazi-plugin/preset/plugins/dds.lua index 4f63f9b0..b6e403ac 100644 --- a/yazi-plugin/preset/plugins/dds.lua +++ b/yazi-plugin/preset/plugins/dds.lua @@ -1,7 +1,21 @@ local M = {} function M:setup() - ps.sub_remote("dds-emit", function(cmd) ya.emit(cmd[1], cmd[2]) end) + ps.sub_remote("dds-emit", function(cmd) + local i, args = 1, {} + for j = 2, #cmd do + local word = string.char(table.unpack(cmd[j])) + local key = word:match("^%-%-([^=]+)") + if not key then + i, args[i] = i + 1, word + elseif #key + 2 == #word then + args[key] = true + else + args[key] = word:sub(#key + 4) + end + end + ya.emit(cmd[1], args) + end) end return M diff --git a/yazi-shared/src/either.rs b/yazi-shared/src/either.rs index 8f2c1eca..edc2c7d8 100644 --- a/yazi-shared/src/either.rs +++ b/yazi-shared/src/either.rs @@ -1,3 +1,5 @@ +use serde::Serialize; + #[derive(Clone, Copy, Debug)] pub enum Either { Left(L), @@ -69,3 +71,19 @@ impl Either { } } } + +impl Serialize for Either +where + L: Serialize, + R: Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Left(l) => l.serialize(serializer), + Self::Right(r) => r.serialize(serializer), + } + } +} diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index 9bc9c08f..352765c1 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -178,34 +178,26 @@ impl Cmd { } // Parse - pub fn parse_args( - words: impl Iterator, - last: Option, - obase: bool, - ) -> Result> { + pub fn parse_args(words: I, last: Option) -> Result> + where + I: IntoIterator, + { let mut i = 0i64; words .into_iter() .map(|s| (s, true)) .chain(last.into_iter().map(|s| (s, false))) .map(|(word, normal)| { - let Some(arg) = word.strip_prefix("--").filter(|_| normal) else { + let Some(arg) = word.strip_prefix("--").filter(|&s| normal && !s.is_empty()) else { i += 1; - return Ok((DataKey::Integer(i - obase as i64), Data::String(word.into()))); + return Ok((DataKey::Integer(i - 1), word.into())); }; let mut parts = arg.splitn(2, '='); - let Some(key) = parts.next().map(|s| s.to_owned()) else { - bail!("invalid argument: {arg}"); - }; + let key = parts.next().expect("at least one part"); + let val = parts.next().map_or(Data::Boolean(true), Data::from); - let val = if let Some(val) = parts.next() { - Data::String(val.to_owned().into()) - } else { - Data::Boolean(true) - }; - - Ok((DataKey::String(Cow::Owned(key)), val)) + Ok((DataKey::from(key.to_owned()), val)) }) .collect() } @@ -245,7 +237,7 @@ impl FromStr for Cmd { } let mut me = Self::new(mem::take(&mut words[0]), Default::default(), Some(Default::default()))?; - me.args = Self::parse_args(words.into_iter().skip(1), last, true)?; + me.args = Self::parse_args(words.into_iter().skip(1), last)?; Ok(me) } }