mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
refactor: move several UI-related APIs from the ya namespace to ui (#2939)
This commit is contained in:
parent
4ff7dae721
commit
ffdd74b6ab
15 changed files with 205 additions and 96 deletions
2
.github/workflows/draft.yml
vendored
2
.github/workflows/draft.yml
vendored
|
|
@ -150,7 +150,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: Setup LXD
|
||||
uses: canonical/setup-lxd@v0.1.2
|
||||
uses: canonical/setup-lxd@v0.1.3
|
||||
|
||||
- name: Setup snapcraft
|
||||
run: sudo snap install --classic snapcraft
|
||||
|
|
|
|||
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -1224,6 +1224,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
|
|
@ -2666,17 +2677,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.1"
|
||||
version = "1.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.52.0",
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ scopeguard = "1.2.0"
|
|||
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||
serde_json = "1.0.140"
|
||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
tokio = { version = "1.45.1", features = [ "full" ] }
|
||||
tokio = { version = "1.46.0", features = [ "full" ] }
|
||||
tokio-stream = "0.1.17"
|
||||
tokio-util = "0.7.15"
|
||||
toml = { version = "0.8.23" }
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function Header:cwd()
|
|||
end
|
||||
|
||||
local s = ya.readable_path(tostring(self._current.cwd)) .. self:flags()
|
||||
return ui.Span(ya.truncate(s, { max = max, rtl = true })):style(th.mgr.cwd)
|
||||
return ui.Span(ui.truncate(s, { max = max, rtl = true })):style(th.mgr.cwd)
|
||||
end
|
||||
|
||||
function Header:flags()
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function Tabs:redraw()
|
|||
local pos = lines[1]:width()
|
||||
local max = math.floor(self:inner_width() / #cx.tabs)
|
||||
for i = 1, #cx.tabs do
|
||||
local name = ya.truncate(string.format(" %d %s ", i, cx.tabs[i].name), { max = max })
|
||||
local name = ui.truncate(string.format(" %d %s ", i, cx.tabs[i].name), { max = max })
|
||||
if i == cx.tabs.idx then
|
||||
lines[#lines + 1] = ui.Line {
|
||||
ui.Span(th.tabs.sep_inner.open):style(th.tabs.inactive),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ function M:peek(job)
|
|||
|
||||
left[#left] = ui.Line {
|
||||
left[#left],
|
||||
ya.truncate(f.path, {
|
||||
ui.truncate(f.path, {
|
||||
rtl = true,
|
||||
max = math.max(0, job.area.w - ui.width(left[#left]) - ui.width(right[#right])),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ end)
|
|||
function M:entry()
|
||||
ya.emit("escape", { visual = true })
|
||||
|
||||
local _permit = ya.hide()
|
||||
local _permit = ui.hide()
|
||||
local cwd, selected = state()
|
||||
|
||||
local output, err = M.run_with(cwd, selected)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ local function entry()
|
|||
return fail("No directory history found, check Zoxide's doc to set it up and restart Yazi.")
|
||||
end
|
||||
|
||||
local _permit = ya.hide()
|
||||
local _permit = ui.hide()
|
||||
local child, err1 = Command("zoxide")
|
||||
:arg({ "query", "-i", "--exclude", st.cwd })
|
||||
:env("SHELL", "sh")
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ pub fn compose(lua: &Lua) -> mlua::Result<Value> {
|
|||
b"Wrap" => super::Wrap::compose(lua)?,
|
||||
|
||||
b"area" => super::Utils::area(lua)?,
|
||||
b"hide" => super::Utils::hide(lua)?,
|
||||
b"width" => super::Utils::width(lua)?,
|
||||
b"redraw" => super::Utils::redraw(lua)?,
|
||||
b"render" => super::Utils::render(lua)?,
|
||||
b"truncate" => super::Utils::truncate(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use mlua::{ExternalError, IntoLua, Lua, ObjectLike, Table, Value};
|
||||
use mlua::{AnyUserData, ExternalError, IntoLua, Lua, ObjectLike, Table, Value};
|
||||
use tracing::error;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_macro::render;
|
||||
use yazi_proxy::{AppProxy, HIDER};
|
||||
|
||||
use super::{Line, Rect, Span};
|
||||
use crate::bindings::{Permit, PermitRef};
|
||||
|
||||
pub(super) struct Utils;
|
||||
|
||||
|
|
@ -22,6 +25,22 @@ impl Utils {
|
|||
f.into_lua(lua)
|
||||
}
|
||||
|
||||
pub(super) fn hide(lua: &Lua) -> mlua::Result<Value> {
|
||||
let f = lua.create_async_function(|lua, ()| async move {
|
||||
if lua.named_registry_value::<PermitRef<fn()>>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) {
|
||||
return Err("Cannot hide while already hidden".into_lua_err());
|
||||
}
|
||||
|
||||
let permit = HIDER.acquire().await.unwrap();
|
||||
AppProxy::stop().await;
|
||||
|
||||
lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume as fn()))?;
|
||||
lua.named_registry_value::<AnyUserData>("HIDE_PERMIT")
|
||||
})?;
|
||||
|
||||
f.into_lua(lua)
|
||||
}
|
||||
|
||||
pub(super) fn width(lua: &Lua) -> mlua::Result<Value> {
|
||||
let f = lua.create_function(|_, v: Value| match v {
|
||||
Value::String(s) => {
|
||||
|
|
@ -77,4 +96,149 @@ impl Utils {
|
|||
|
||||
f.into_lua(lua)
|
||||
}
|
||||
|
||||
pub(super) fn render(lua: &Lua) -> mlua::Result<Value> {
|
||||
let f = lua.create_function(|_, ()| {
|
||||
render!();
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
f.into_lua(lua)
|
||||
}
|
||||
|
||||
pub(super) fn truncate(lua: &Lua) -> mlua::Result<Value> {
|
||||
fn traverse(
|
||||
it: impl Iterator<Item = (usize, char)>,
|
||||
max: usize,
|
||||
) -> (Option<usize>, usize, bool) {
|
||||
let (mut adv, mut last) = (0, 0);
|
||||
let idx = it
|
||||
.take_while(|&(_, c)| {
|
||||
(last, adv) = (adv, adv + c.width().unwrap_or(0));
|
||||
adv <= max
|
||||
})
|
||||
.map(|(i, _)| i)
|
||||
.last();
|
||||
(idx, last, adv > max)
|
||||
}
|
||||
|
||||
let f = lua.create_function(|lua, (s, t): (mlua::String, Table)| {
|
||||
let b = s.as_bytes();
|
||||
if b.is_empty() {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let max = t.raw_get("max")?;
|
||||
if b.len() <= max {
|
||||
return Ok(s);
|
||||
} else if max < 1 {
|
||||
return lua.create_string("");
|
||||
}
|
||||
|
||||
let lossy = String::from_utf8_lossy(&b);
|
||||
let rtl = t.raw_get("rtl").unwrap_or(false);
|
||||
let (idx, width, remain) = if rtl {
|
||||
traverse(lossy.char_indices().rev(), max)
|
||||
} else {
|
||||
traverse(lossy.char_indices(), max)
|
||||
};
|
||||
|
||||
let Some(idx) = idx else { return lua.create_string("…") };
|
||||
if !remain {
|
||||
return Ok(s);
|
||||
}
|
||||
|
||||
let result: Vec<_> = match (rtl, width == max) {
|
||||
(false, false) => {
|
||||
let len = lossy[idx..].chars().next().map_or(0, |c| c.len_utf8());
|
||||
lossy[..idx + len].bytes().chain("…".bytes()).collect()
|
||||
}
|
||||
(false, true) => lossy[..idx].bytes().chain("…".bytes()).collect(),
|
||||
(true, false) => "…".bytes().chain(lossy[idx..].bytes()).collect(),
|
||||
(true, true) => {
|
||||
let len = lossy[idx..].chars().next().map_or(0, |c| c.len_utf8());
|
||||
"…".bytes().chain(lossy[idx + len..].bytes()).collect()
|
||||
}
|
||||
};
|
||||
lua.create_string(result)
|
||||
})?;
|
||||
|
||||
f.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mlua::chunk;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn truncate(s: &str, max: usize, rtl: bool) -> String {
|
||||
let lua = Lua::new();
|
||||
let f = Utils::truncate(&lua).unwrap();
|
||||
|
||||
lua
|
||||
.load(chunk! {
|
||||
return $f($s, { max = $max, rtl = $rtl })
|
||||
})
|
||||
.call(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
assert_eq!(truncate("你好,world", 0, false), "");
|
||||
assert_eq!(truncate("你好,world", 1, false), "…");
|
||||
assert_eq!(truncate("你好,world", 2, false), "…");
|
||||
|
||||
assert_eq!(truncate("你好,世界", 3, false), "你…");
|
||||
assert_eq!(truncate("你好,世界", 4, false), "你…");
|
||||
assert_eq!(truncate("你好,世界", 5, false), "你好…");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 5, false), "Hell…");
|
||||
assert_eq!(truncate("Ni好,世界", 3, false), "Ni…");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_rtl() {
|
||||
assert_eq!(truncate("world,你好", 0, true), "");
|
||||
assert_eq!(truncate("world,你好", 1, true), "…");
|
||||
assert_eq!(truncate("world,你好", 2, true), "…");
|
||||
|
||||
assert_eq!(truncate("你好,世界", 3, true), "…界");
|
||||
assert_eq!(truncate("你好,世界", 4, true), "…界");
|
||||
assert_eq!(truncate("你好,世界", 5, true), "…世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 5, true), "…orld");
|
||||
assert_eq!(truncate("你好,Shi界", 3, true), "…界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_oboe() {
|
||||
assert_eq!(truncate("Hello, world", 11, false), "Hello, wor…");
|
||||
assert_eq!(truncate("你好,世界", 9, false), "你好,世…");
|
||||
assert_eq!(truncate("你好,世Jie", 9, false), "你好,世…");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 11, true), "…llo, world");
|
||||
assert_eq!(truncate("你好,世界", 9, true), "…好,世界");
|
||||
assert_eq!(truncate("Ni好,世界", 9, true), "…好,世界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_exact() {
|
||||
assert_eq!(truncate("Hello, world", 12, false), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 10, false), "你好,世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 12, true), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 10, true), "你好,世界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_overflow() {
|
||||
assert_eq!(truncate("Hello, world", 13, false), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 11, false), "你好,世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 13, true), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 11, true), "你好,世界");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use yazi_binding::Id;
|
|||
use yazi_proxy::{AppProxy, HIDER};
|
||||
|
||||
use super::Utils;
|
||||
use crate::bindings::{Permit, PermitRef};
|
||||
use crate::{bindings::{Permit, PermitRef}, deprecate};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn id(lua: &Lua) -> mlua::Result<Function> {
|
||||
|
|
@ -18,6 +18,8 @@ impl Utils {
|
|||
|
||||
pub(super) fn hide(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, ()| async move {
|
||||
deprecate!(lua, "`ya.hide()` is deprecated, use `ui.hide()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
|
||||
|
||||
if lua.named_registry_value::<PermitRef<fn()>>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) {
|
||||
return Err("Cannot hide while already hidden".into_lua_err());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ use yazi_macro::{emit, render};
|
|||
use yazi_shared::{Layer, event::Cmd};
|
||||
|
||||
use super::Utils;
|
||||
use crate::deprecate;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn render(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| {
|
||||
lua.create_function(|lua, ()| {
|
||||
deprecate!(lua, "`ya.render()` is deprecated, use `ui.render()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
|
||||
|
||||
render!();
|
||||
Ok(())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -44,10 +44,7 @@ impl Utils {
|
|||
if pos.is_nil() {
|
||||
pos = t.raw_get("position")?;
|
||||
if !pos.is_nil() {
|
||||
deprecate!(
|
||||
lua,
|
||||
"The `position` property of `ya.input()` is deprecated, use `pos` instead in your {}\nSee #2921 for more details: https://github.com/sxyazi/yazi/pull/2921"
|
||||
);
|
||||
deprecate!(lua, "The `position` property of `ya.input()` is deprecated, use `pos` instead in your {}\nSee #2921 for more details: https://github.com/sxyazi/yazi/pull/2921");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use twox_hash::XxHash3_128;
|
|||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use super::Utils;
|
||||
use crate::CLIPBOARD;
|
||||
use crate::{CLIPBOARD, deprecate};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn hash(lua: &Lua) -> mlua::Result<Function> {
|
||||
|
|
@ -41,6 +41,8 @@ impl Utils {
|
|||
}
|
||||
|
||||
lua.create_function(|lua, (s, t): (mlua::String, Table)| {
|
||||
deprecate!(lua, "`ya.truncate()` is deprecated, use `ui.truncate()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
|
||||
|
||||
let b = s.as_bytes();
|
||||
if b.is_empty() {
|
||||
return Ok(s);
|
||||
|
|
@ -93,79 +95,3 @@ impl Utils {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mlua::chunk;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn truncate(s: &str, max: usize, rtl: bool) -> String {
|
||||
let lua = Lua::new();
|
||||
let f = Utils::truncate(&lua).unwrap();
|
||||
|
||||
lua
|
||||
.load(chunk! {
|
||||
return $f($s, { max = $max, rtl = $rtl })
|
||||
})
|
||||
.call(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate() {
|
||||
assert_eq!(truncate("你好,world", 0, false), "");
|
||||
assert_eq!(truncate("你好,world", 1, false), "…");
|
||||
assert_eq!(truncate("你好,world", 2, false), "…");
|
||||
|
||||
assert_eq!(truncate("你好,世界", 3, false), "你…");
|
||||
assert_eq!(truncate("你好,世界", 4, false), "你…");
|
||||
assert_eq!(truncate("你好,世界", 5, false), "你好…");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 5, false), "Hell…");
|
||||
assert_eq!(truncate("Ni好,世界", 3, false), "Ni…");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_rtl() {
|
||||
assert_eq!(truncate("world,你好", 0, true), "");
|
||||
assert_eq!(truncate("world,你好", 1, true), "…");
|
||||
assert_eq!(truncate("world,你好", 2, true), "…");
|
||||
|
||||
assert_eq!(truncate("你好,世界", 3, true), "…界");
|
||||
assert_eq!(truncate("你好,世界", 4, true), "…界");
|
||||
assert_eq!(truncate("你好,世界", 5, true), "…世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 5, true), "…orld");
|
||||
assert_eq!(truncate("你好,Shi界", 3, true), "…界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_oboe() {
|
||||
assert_eq!(truncate("Hello, world", 11, false), "Hello, wor…");
|
||||
assert_eq!(truncate("你好,世界", 9, false), "你好,世…");
|
||||
assert_eq!(truncate("你好,世Jie", 9, false), "你好,世…");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 11, true), "…llo, world");
|
||||
assert_eq!(truncate("你好,世界", 9, true), "…好,世界");
|
||||
assert_eq!(truncate("Ni好,世界", 9, true), "…好,世界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_exact() {
|
||||
assert_eq!(truncate("Hello, world", 12, false), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 10, false), "你好,世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 12, true), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 10, true), "你好,世界");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_truncate_overflow() {
|
||||
assert_eq!(truncate("Hello, world", 13, false), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 11, false), "你好,世界");
|
||||
|
||||
assert_eq!(truncate("Hello, world", 13, true), "Hello, world");
|
||||
assert_eq!(truncate("你好,世界", 11, true), "你好,世界");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ impl Input {
|
|||
return;
|
||||
}
|
||||
|
||||
let (o_cur, n_cur) = (snap.cursor, opt.step.cursor(snap));
|
||||
render!(self.handle_op(n_cur, false));
|
||||
let o_cur = snap.cursor;
|
||||
render!(self.handle_op(opt.step.cursor(snap), false));
|
||||
let n_cur = self.snap().cursor;
|
||||
|
||||
let (limit, snap) = (self.limit, self.snap_mut());
|
||||
if snap.value.is_empty() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue