From db0300c9029d56b5e1611839b49a50fa3f6f8b27 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: Thu, 20 Mar 2025 19:04:01 +0800 Subject: [PATCH] feat: new `ya.id("app")` to get `YAZI_ID` in plugins (#2503) --- Cargo.lock | 12 +++---- cspell.json | 2 +- yazi-boot/Cargo.toml | 5 ++- yazi-boot/src/args.rs | 3 +- yazi-cli/Cargo.toml | 2 +- yazi-config/src/popup/input.rs | 2 +- yazi-dds/src/body/body.rs | 5 +-- yazi-dds/src/body/hey.rs | 5 +-- yazi-dds/src/client.rs | 8 ++--- yazi-dds/src/lib.rs | 2 +- yazi-dds/src/payload.rs | 12 +++---- yazi-dds/src/pubsub.rs | 2 +- yazi-dds/src/server.rs | 12 +++---- yazi-plugin/Cargo.toml | 2 +- yazi-plugin/src/external/highlighter.rs | 4 +-- yazi-plugin/src/id.rs | 20 +++++++++-- yazi-plugin/src/pubsub/pubsub.rs | 6 ++-- yazi-plugin/src/utils/app.rs | 1 + yazi-shared/src/id.rs | 22 +++++++----- yazi-widgets/src/input/commands/move_.rs | 4 +-- yazi-widgets/src/input/snap.rs | 43 ++++++++++++------------ yazi-widgets/src/input/snaps.rs | 2 +- yazi-widgets/src/input/widget.rs | 2 +- 23 files changed, 102 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ae987c9..b7f9f0a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98" +checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" dependencies = [ "clap", ] @@ -3564,16 +3564,16 @@ dependencies = [ "yazi-dds", "yazi-fs", "yazi-macro", - "yazi-prebuild", + "yazi-prebuilt", "yazi-proxy", "yazi-shared", ] [[package]] -name = "yazi-prebuild" -version = "0.1.2" +name = "yazi-prebuilt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4b6c8e12e39ac0f79fa96f36e5b88e0da8d230691abd729eec709b43c74f632" +checksum = "33232d9116df6415ddfcdf72701b1b7439ce87f240a14723e8dd5d17e7ed5f98" [[package]] name = "yazi-proxy" diff --git a/cspell.json b/cspell.json index 3216a2e4..314adb1a 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition"],"flagWords":[]} \ No newline at end of file +{"version":"0.2","language":"en","words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition"],"flagWords":[]} \ No newline at end of file diff --git a/yazi-boot/Cargo.toml b/yazi-boot/Cargo.toml index da9f6b59..25c44ac7 100644 --- a/yazi-boot/Cargo.toml +++ b/yazi-boot/Cargo.toml @@ -21,8 +21,11 @@ regex = { workspace = true } serde = { workspace = true } [build-dependencies] +yazi-shared = { path = "../yazi-shared", version = "25.3.7" } + +# External dependencies clap = { workspace = true } -clap_complete = "4.5.46" +clap_complete = "4.5.47" clap_complete_fig = "4.5.2" clap_complete_nushell = "4.5.5" vergen-gitcl = { version = "1.0.5", features = [ "build", "rustc" ] } diff --git a/yazi-boot/src/args.rs b/yazi-boot/src/args.rs index 1327c9ca..ee6960d1 100644 --- a/yazi-boot/src/args.rs +++ b/yazi-boot/src/args.rs @@ -1,6 +1,7 @@ use std::path::PathBuf; use clap::{Parser, command}; +use yazi_shared::Id; #[derive(Debug, Default, Parser)] #[command(name = "yazi")] @@ -22,7 +23,7 @@ pub struct Args { /// Use the specified client ID, must be a globally unique number #[arg(long)] - pub client_id: Option, + pub client_id: Option, /// Report the specified local events to stdout #[arg(long)] pub local_events: Option, diff --git a/yazi-cli/Cargo.toml b/yazi-cli/Cargo.toml index 302801dc..a3690a53 100644 --- a/yazi-cli/Cargo.toml +++ b/yazi-cli/Cargo.toml @@ -31,7 +31,7 @@ yazi-shared = { path = "../yazi-shared", version = "25.3.7" } # External build dependencies anyhow = { workspace = true } clap = { workspace = true } -clap_complete = "4.5.46" +clap_complete = "4.5.47" clap_complete_fig = "4.5.2" clap_complete_nushell = "4.5.5" serde_json = { workspace = true } diff --git a/yazi-config/src/popup/input.rs b/yazi-config/src/popup/input.rs index 71c87ba0..f2c05c37 100644 --- a/yazi-config/src/popup/input.rs +++ b/yazi-config/src/popup/input.rs @@ -46,7 +46,7 @@ pub struct Input { } impl Input { - pub const fn border(&self) -> u16 { 1 } + pub const fn border(&self) -> u16 { 2 } } impl FromStr for Input { diff --git a/yazi-dds/src/body/body.rs b/yazi-dds/src/body/body.rs index 2081e3e0..dcb3b721 100644 --- a/yazi-dds/src/body/body.rs +++ b/yazi-dds/src/body/body.rs @@ -1,6 +1,7 @@ use anyhow::{Result, bail}; use mlua::{ExternalResult, IntoLua, Lua, Value}; use serde::Serialize; +use yazi_shared::Id; use super::{BodyBulk, BodyBye, BodyCd, BodyCustom, BodyDelete, BodyHey, BodyHi, BodyHover, BodyLoad, BodyMount, BodyMove, BodyRename, BodyTab, BodyTrash, BodyYank}; use crate::Payload; @@ -107,12 +108,12 @@ impl<'a> Body<'a> { } #[inline] - pub fn with_receiver(self, receiver: u64) -> Payload<'a> { + pub fn with_receiver(self, receiver: Id) -> Payload<'a> { Payload::new(self).with_receiver(receiver) } #[inline] - pub fn with_sender(self, sender: u64) -> Payload<'a> { Payload::new(self).with_sender(sender) } + pub fn with_sender(self, sender: Id) -> Payload<'a> { Payload::new(self).with_sender(sender) } } impl IntoLua for Body<'static> { diff --git a/yazi-dds/src/body/hey.rs b/yazi-dds/src/body/hey.rs index 18b55ee0..ca40bdb2 100644 --- a/yazi-dds/src/body/hey.rs +++ b/yazi-dds/src/body/hey.rs @@ -2,19 +2,20 @@ use std::{borrow::Cow, collections::HashMap}; use mlua::{ExternalResult, IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; +use yazi_shared::Id; use super::{Body, BodyHi}; use crate::Peer; #[derive(Debug, Serialize, Deserialize)] pub struct BodyHey { - pub peers: HashMap, + pub peers: HashMap, pub version: Cow<'static, str>, } impl BodyHey { #[inline] - pub fn owned(peers: HashMap) -> Body<'static> { + pub fn owned(peers: HashMap) -> Body<'static> { Self { peers, version: BodyHi::version().into() }.into() } } diff --git a/yazi-dds/src/client.rs b/yazi-dds/src/client.rs index 9c9d8866..10377710 100644 --- a/yazi-dds/src/client.rs +++ b/yazi-dds/src/client.rs @@ -5,19 +5,19 @@ use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use tokio::{io::AsyncWriteExt, select, sync::mpsc, task::JoinHandle, time}; use tracing::error; -use yazi_shared::RoCell; +use yazi_shared::{Id, RoCell}; use crate::{ClientReader, ClientWriter, Payload, Pubsub, Server, Stream, body::{Body, BodyBye, BodyHi}}; -pub(super) static ID: RoCell = RoCell::new(); -pub(super) static PEERS: RoCell>> = RoCell::new(); +pub static ID: RoCell = RoCell::new(); +pub(super) static PEERS: RoCell>> = RoCell::new(); pub(super) static QUEUE_TX: RoCell> = RoCell::new(); pub(super) static QUEUE_RX: RoCell> = RoCell::new(); #[derive(Debug)] pub struct Client { - pub(super) id: u64, + pub(super) id: Id, pub(super) tx: mpsc::UnboundedSender, pub(super) abilities: HashSet, } diff --git a/yazi-dds/src/lib.rs b/yazi-dds/src/lib.rs index 3f7acb1a..bc28bc6e 100644 --- a/yazi-dds/src/lib.rs +++ b/yazi-dds/src/lib.rs @@ -8,7 +8,7 @@ pub fn init() { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); // Client - ID.init(yazi_boot::ARGS.client_id.unwrap_or(yazi_shared::timestamp_us())); + ID.init(yazi_boot::ARGS.client_id.unwrap_or(yazi_shared::Id::unique())); PEERS.with(<_>::default); QUEUE_TX.init(tx); QUEUE_RX.init(rx); diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index 1175ac95..321bee61 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -3,19 +3,19 @@ use std::{fmt::Display, io::Write, str::FromStr}; use anyhow::{Result, anyhow}; use yazi_boot::BOOT; use yazi_macro::emit; -use yazi_shared::event::Cmd; +use yazi_shared::{Id, event::Cmd}; use crate::{ID, body::Body}; #[derive(Debug)] pub struct Payload<'a> { - pub receiver: u64, - pub sender: u64, + pub receiver: Id, + pub sender: Id, pub body: Body<'a>, } impl<'a> Payload<'a> { - pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: 0, sender: *ID, body } } + pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: Id(0), sender: *ID, body } } pub(super) fn flush(&self) { writeln!(std::io::stdout(), "{self}").ok(); } @@ -33,12 +33,12 @@ impl<'a> Payload<'a> { } } - pub(super) fn with_receiver(mut self, receiver: u64) -> Self { + pub(super) fn with_receiver(mut self, receiver: Id) -> Self { self.receiver = receiver; self } - pub(super) fn with_sender(mut self, sender: u64) -> Self { + pub(super) fn with_sender(mut self, sender: Id) -> Self { self.sender = sender; self } diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index 2ebf461f..49fd50f8 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -64,7 +64,7 @@ impl Pubsub { pub fn pub_(body: Body<'static>) { body.with_receiver(*ID).emit(); } - pub fn pub_to(receiver: u64, body: Body<'static>) { + pub fn pub_to(receiver: Id, body: Body<'static>) { if receiver == *ID { return Self::pub_(body); } diff --git a/yazi-dds/src/server.rs b/yazi-dds/src/server.rs index 0d0c70d4..ab6bbb9a 100644 --- a/yazi-dds/src/server.rs +++ b/yazi-dds/src/server.rs @@ -3,11 +3,11 @@ use std::{collections::HashMap, str::FromStr, time::Duration}; use anyhow::Result; use parking_lot::RwLock; use tokio::{io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, select, sync::mpsc::{self, UnboundedReceiver}, task::JoinHandle, time}; -use yazi_shared::RoCell; +use yazi_shared::{Id, RoCell}; use crate::{Client, ClientWriter, Payload, Peer, STATE, Stream, body::{Body, BodyBye, BodyHey}}; -pub(super) static CLIENTS: RoCell>> = RoCell::new(); +pub(super) static CLIENTS: RoCell>> = RoCell::new(); pub(super) struct Server; @@ -87,7 +87,7 @@ impl Server { })) } - fn handle_hi(s: String, id: &mut Option, tx: mpsc::UnboundedSender) { + fn handle_hi(s: String, id: &mut Option, tx: mpsc::UnboundedSender) { let Ok(payload) = Payload::from_str(&s) else { return }; let Body::Hi(hi) = payload.body else { return }; @@ -108,7 +108,7 @@ impl Server { Self::handle_hey(&clients); } - fn handle_hey(clients: &HashMap) { + fn handle_hey(clients: &HashMap) { let payload = format!( "{}\n", Payload::new(BodyHey::owned( @@ -118,7 +118,7 @@ impl Server { clients.values().for_each(|c| _ = c.tx.send(payload.clone())); } - async fn handle_bye(id: u64, mut rx: UnboundedReceiver, mut writer: ClientWriter) { + async fn handle_bye(id: Id, mut rx: UnboundedReceiver, mut writer: ClientWriter) { while let Ok(payload) = rx.try_recv() { if writer.write_all(payload.as_bytes()).await.is_err() { break; @@ -126,7 +126,7 @@ impl Server { } _ = writer - .write_all(BodyBye::owned().with_receiver(id).with_sender(0).to_string().as_bytes()) + .write_all(BodyBye::owned().with_receiver(id).with_sender(Id(0)).to_string().as_bytes()) .await; writer.flush().await.ok(); diff --git a/yazi-plugin/Cargo.toml b/yazi-plugin/Cargo.toml index 25eee456..137927ee 100644 --- a/yazi-plugin/Cargo.toml +++ b/yazi-plugin/Cargo.toml @@ -41,7 +41,7 @@ tokio-util = { workspace = true } tracing = { workspace = true } twox-hash = { workspace = true } unicode-width = { workspace = true } -yazi-prebuild = "0.1.2" +yazi-prebuilt = "0.1.0" [target."cfg(unix)".dependencies] uzers = { workspace = true } diff --git a/yazi-plugin/src/external/highlighter.rs b/yazi-plugin/src/external/highlighter.rs index 36b10630..b2e2995f 100644 --- a/yazi-plugin/src/external/highlighter.rs +++ b/yazi-plugin/src/external/highlighter.rs @@ -23,9 +23,9 @@ impl Highlighter { let theme = std::fs::File::open(&THEME.mgr.syntect_theme) .map_err(LoadingError::Io) .and_then(|f| ThemeSet::load_from_reader(&mut std::io::BufReader::new(f))) - .or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuild::ansi_theme()))); + .or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuilt::ansi_theme()))); - let syntaxes = dumps::from_uncompressed_data(yazi_prebuild::syntaxes()); + let syntaxes = dumps::from_uncompressed_data(yazi_prebuilt::syntaxes()); (theme.unwrap(), syntaxes.unwrap()) }; diff --git a/yazi-plugin/src/id.rs b/yazi-plugin/src/id.rs index 8f14e4d4..db0e48dd 100644 --- a/yazi-plugin/src/id.rs +++ b/yazi-plugin/src/id.rs @@ -1,8 +1,8 @@ use std::ops::Deref; -use mlua::{FromLua, UserData}; +use mlua::{ExternalError, ExternalResult, FromLua, Lua, UserData, Value}; -#[derive(Clone, Copy, FromLua)] +#[derive(Clone, Copy)] pub struct Id(pub yazi_shared::Id); impl Deref for Id { @@ -12,4 +12,18 @@ impl Deref for Id { fn deref(&self) -> &Self::Target { &self.0 } } -impl UserData for Id {} +impl FromLua for Id { + fn from_lua(value: Value, _: &Lua) -> mlua::Result { + Ok(match value { + Value::Integer(i) => Self(i.try_into().into_lua_err()?), + Value::UserData(ud) => *ud.borrow::()?, + _ => Err("expected integer or userdata".into_lua_err())?, + }) + } +} + +impl UserData for Id { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("value", |_, me: &Self| Ok(me.0.get())); + } +} diff --git a/yazi-plugin/src/pubsub/pubsub.rs b/yazi-plugin/src/pubsub/pubsub.rs index 8c6465c8..319528bd 100644 --- a/yazi-plugin/src/pubsub/pubsub.rs +++ b/yazi-plugin/src/pubsub/pubsub.rs @@ -1,7 +1,7 @@ use mlua::{ExternalResult, Function, Lua, Value}; use yazi_dds::body::Body; -use crate::runtime::RtRef; +use crate::{Id, runtime::RtRef}; pub struct Pubsub; @@ -14,8 +14,8 @@ impl Pubsub { } pub(super) fn pub_to(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (receiver, kind, value): (u64, mlua::String, Value)| { - yazi_dds::Pubsub::pub_to(receiver, Body::from_lua(&kind.to_str()?, value)?); + lua.create_function(|_, (receiver, kind, value): (Id, mlua::String, Value)| { + yazi_dds::Pubsub::pub_to(*receiver, Body::from_lua(&kind.to_str()?, value)?); Ok(()) }) } diff --git a/yazi-plugin/src/utils/app.rs b/yazi-plugin/src/utils/app.rs index dee784b8..0d8f9917 100644 --- a/yazi-plugin/src/utils/app.rs +++ b/yazi-plugin/src/utils/app.rs @@ -8,6 +8,7 @@ impl Utils { pub(super) fn id(lua: &Lua) -> mlua::Result { lua.create_function(|_, type_: mlua::String| { Ok(Id(match type_.as_bytes().as_ref() { + b"app" => *yazi_dds::ID, b"ft" => yazi_fs::FILES_TICKET.next(), _ => Err("Invalid id type".into_lua_err())?, })) diff --git a/yazi-shared/src/id.rs b/yazi-shared/src/id.rs index ab5f1523..3b68f850 100644 --- a/yazi-shared/src/id.rs +++ b/yazi-shared/src/id.rs @@ -1,13 +1,15 @@ -use std::{fmt::Display, str::FromStr, sync::atomic::{AtomicUsize, Ordering}}; +use std::{fmt::Display, str::FromStr, sync::atomic::{AtomicU64, Ordering}}; use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, Serialize, Deserialize)] -pub struct Id(usize); +pub struct Id(pub u64); impl Id { #[inline] - pub fn get(&self) -> usize { self.0 } + pub const fn get(&self) -> u64 { self.0 } + + pub fn unique() -> Self { Self(crate::timestamp_us()) } } impl Display for Id { @@ -15,25 +17,29 @@ impl Display for Id { } impl FromStr for Id { - type Err = ::Err; + type Err = ::Err; fn from_str(s: &str) -> Result { s.parse().map(Self) } } impl TryFrom for Id { - type Error = >::Error; + type Error = >::Error; - fn try_from(value: i64) -> Result { usize::try_from(value).map(Self) } + fn try_from(value: i64) -> Result { u64::try_from(value).map(Self) } +} + +impl PartialEq for Id { + fn eq(&self, other: &u64) -> bool { self.0 == *other } } // --- Ids pub struct Ids { - next: AtomicUsize, + next: AtomicU64, } impl Ids { #[inline] - pub const fn new() -> Self { Self { next: AtomicUsize::new(1) } } + pub const fn new() -> Self { Self { next: AtomicU64::new(1) } } #[inline] pub fn next(&self) -> Id { diff --git a/yazi-widgets/src/input/commands/move_.rs b/yazi-widgets/src/input/commands/move_.rs index 64ff0db2..17d00e64 100644 --- a/yazi-widgets/src/input/commands/move_.rs +++ b/yazi-widgets/src/input/commands/move_.rs @@ -42,8 +42,8 @@ impl Input { let delta = snap.mode.delta(); let s = snap.slice(snap.offset..snap.cursor + delta); if s.width() >= limit { - let s = s.chars().rev().collect::(); - snap.offset = snap.cursor - InputSnap::find_window(&s, 0, limit).end.saturating_sub(delta); + let range = InputSnap::find_window(s.chars().rev(), 0, limit); + snap.offset = snap.cursor - range.end.saturating_sub(delta); } } } diff --git a/yazi-widgets/src/input/snap.rs b/yazi-widgets/src/input/snap.rs index 6b0d09e2..11d39ba9 100644 --- a/yazi-widgets/src/input/snap.rs +++ b/yazi-widgets/src/input/snap.rs @@ -22,19 +22,19 @@ impl InputSnap { op: Default::default(), - mode: Default::default(), + mode: Default::default(), offset: usize::MAX, cursor: usize::MAX, }; - snap.reset(limit); + snap.resize(limit); snap } #[inline] - pub(super) fn reset(&mut self, limit: usize) { + pub(super) fn resize(&mut self, limit: usize) { + let range = Self::find_window(self.value.chars().rev(), 0, limit); self.cursor = self.cursor.min(self.count().saturating_sub(self.mode.delta())); - self.offset = - self.offset.min(self.cursor.saturating_sub(Self::find_window(&self.rev(), 0, limit).end)); + self.offset = self.offset.min(self.cursor.saturating_sub(range.end)); } } @@ -61,30 +61,29 @@ impl InputSnap { &self.value[s.unwrap()..e.unwrap()] } - #[inline] - pub(super) fn rev(&self) -> String { self.value.chars().rev().collect::() } - #[inline] pub(super) fn window(&self, limit: usize) -> Range { - Self::find_window(&self.value, self.offset, limit) + Self::find_window(self.value.chars(), self.offset, limit) } #[inline] - pub(super) fn find_window(s: &str, offset: usize, limit: usize) -> Range { + pub(super) fn find_window(it: T, offset: usize, limit: usize) -> Range + where + T: Iterator, + { let mut width = 0; - let v: Vec<_> = s - .chars() - .enumerate() - .skip(offset) - .map_while(|(i, c)| { - width += c.width().unwrap_or(0); - if width < limit { Some(i) } else { None } - }) - .collect(); + let mut range = None; - if v.is_empty() { - return 0..0; + for (i, c) in it.enumerate().skip(offset) { + width += c.width().unwrap_or(0); + if width > limit { + break; + } + match range { + None => range = Some(i..i + 1), + Some(ref mut r) => r.end = i + 1, + } } - *v.first().unwrap()..v.last().unwrap() + 1 + range.unwrap_or(0..0) } } diff --git a/yazi-widgets/src/input/snaps.rs b/yazi-widgets/src/input/snaps.rs index c0d6b1de..2d19078b 100644 --- a/yazi-widgets/src/input/snaps.rs +++ b/yazi-widgets/src/input/snaps.rs @@ -36,7 +36,7 @@ impl InputSnaps { let value = mem::take(&mut self.versions[self.idx].value); self.versions[self.idx] = self.current.clone(); self.versions[self.idx].value = value; - self.versions[self.idx].reset(limit); + self.versions[self.idx].resize(limit); // If the *current* value is the same as the *last* version if self.versions[self.idx].value == self.current.value { diff --git a/yazi-widgets/src/input/widget.rs b/yazi-widgets/src/input/widget.rs index 10e5ba91..43df8740 100644 --- a/yazi-widgets/src/input/widget.rs +++ b/yazi-widgets/src/input/widget.rs @@ -24,7 +24,7 @@ impl Widget for &Input { height: area.height.min(1), }, THEME.input.selected, - ) + ); } } }