feat: new ya.id("app") to get YAZI_ID in plugins (#2503)

This commit is contained in:
三咲雅 · Misaki Masa 2025-03-20 19:04:01 +08:00 committed by sxyazi
parent 570c6d308b
commit db0300c902
No known key found for this signature in database
23 changed files with 102 additions and 76 deletions

12
Cargo.lock generated
View file

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

View file

@ -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":[]}
{"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":[]}

View file

@ -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" ] }

View file

@ -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<u64>,
pub client_id: Option<Id>,
/// Report the specified local events to stdout
#[arg(long)]
pub local_events: Option<String>,

View file

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

View file

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

View file

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

View file

@ -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<u64, Peer>,
pub peers: HashMap<Id, Peer>,
pub version: Cow<'static, str>,
}
impl BodyHey {
#[inline]
pub fn owned(peers: HashMap<u64, Peer>) -> Body<'static> {
pub fn owned(peers: HashMap<Id, Peer>) -> Body<'static> {
Self { peers, version: BodyHi::version().into() }.into()
}
}

View file

@ -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<u64> = RoCell::new();
pub(super) static PEERS: RoCell<RwLock<HashMap<u64, Peer>>> = RoCell::new();
pub static ID: RoCell<Id> = RoCell::new();
pub(super) static PEERS: RoCell<RwLock<HashMap<Id, Peer>>> = RoCell::new();
pub(super) static QUEUE_TX: RoCell<mpsc::UnboundedSender<String>> = RoCell::new();
pub(super) static QUEUE_RX: RoCell<mpsc::UnboundedReceiver<String>> = RoCell::new();
#[derive(Debug)]
pub struct Client {
pub(super) id: u64,
pub(super) id: Id,
pub(super) tx: mpsc::UnboundedSender<String>,
pub(super) abilities: HashSet<String>,
}

View file

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

View file

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

View file

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

View file

@ -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<RwLock<HashMap<u64, Client>>> = RoCell::new();
pub(super) static CLIENTS: RoCell<RwLock<HashMap<Id, Client>>> = RoCell::new();
pub(super) struct Server;
@ -87,7 +87,7 @@ impl Server {
}))
}
fn handle_hi(s: String, id: &mut Option<u64>, tx: mpsc::UnboundedSender<String>) {
fn handle_hi(s: String, id: &mut Option<Id>, tx: mpsc::UnboundedSender<String>) {
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<u64, Client>) {
fn handle_hey(clients: &HashMap<Id, Client>) {
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<String>, mut writer: ClientWriter) {
async fn handle_bye(id: Id, mut rx: UnboundedReceiver<String>, 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();

View file

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

View file

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

View file

@ -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<Self> {
Ok(match value {
Value::Integer(i) => Self(i.try_into().into_lua_err()?),
Value::UserData(ud) => *ud.borrow::<Self>()?,
_ => Err("expected integer or userdata".into_lua_err())?,
})
}
}
impl UserData for Id {
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("value", |_, me: &Self| Ok(me.0.get()));
}
}

View file

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

View file

@ -8,6 +8,7 @@ impl Utils {
pub(super) fn id(lua: &Lua) -> mlua::Result<Function> {
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())?,
}))

View file

@ -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 = <usize as FromStr>::Err;
type Err = <u64 as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> { s.parse().map(Self) }
}
impl TryFrom<i64> for Id {
type Error = <usize as TryFrom<i64>>::Error;
type Error = <u64 as TryFrom<i64>>::Error;
fn try_from(value: i64) -> Result<Self, Self::Error> { usize::try_from(value).map(Self) }
fn try_from(value: i64) -> Result<Self, Self::Error> { u64::try_from(value).map(Self) }
}
impl PartialEq<u64> 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 {

View file

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

View file

@ -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::<String>() }
#[inline]
pub(super) fn window(&self, limit: usize) -> Range<usize> {
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<usize> {
pub(super) fn find_window<T>(it: T, offset: usize, limit: usize) -> Range<usize>
where
T: Iterator<Item = char>,
{
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)
}
}

View file

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

View file

@ -24,7 +24,7 @@ impl Widget for &Input {
height: area.height.min(1),
},
THEME.input.selected,
)
);
}
}
}