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
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Setup LXD
|
- name: Setup LXD
|
||||||
uses: canonical/setup-lxd@v0.1.2
|
uses: canonical/setup-lxd@v0.1.3
|
||||||
|
|
||||||
- name: Setup snapcraft
|
- name: Setup snapcraft
|
||||||
run: sudo snap install --classic snapcraft
|
run: sudo snap install --classic snapcraft
|
||||||
|
|
|
||||||
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -1224,6 +1224,17 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
|
|
@ -2666,17 +2677,19 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.45.1"
|
version = "1.46.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"io-uring",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
"slab",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ scopeguard = "1.2.0"
|
||||||
serde = { version = "1.0.219", features = [ "derive" ] }
|
serde = { version = "1.0.219", features = [ "derive" ] }
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
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-stream = "0.1.17"
|
||||||
tokio-util = "0.7.15"
|
tokio-util = "0.7.15"
|
||||||
toml = { version = "0.8.23" }
|
toml = { version = "0.8.23" }
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ function Header:cwd()
|
||||||
end
|
end
|
||||||
|
|
||||||
local s = ya.readable_path(tostring(self._current.cwd)) .. self:flags()
|
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
|
end
|
||||||
|
|
||||||
function Header:flags()
|
function Header:flags()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ function Tabs:redraw()
|
||||||
local pos = lines[1]:width()
|
local pos = lines[1]:width()
|
||||||
local max = math.floor(self:inner_width() / #cx.tabs)
|
local max = math.floor(self:inner_width() / #cx.tabs)
|
||||||
for i = 1, #cx.tabs do
|
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
|
if i == cx.tabs.idx then
|
||||||
lines[#lines + 1] = ui.Line {
|
lines[#lines + 1] = ui.Line {
|
||||||
ui.Span(th.tabs.sep_inner.open):style(th.tabs.inactive),
|
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] = ui.Line {
|
||||||
left[#left],
|
left[#left],
|
||||||
ya.truncate(f.path, {
|
ui.truncate(f.path, {
|
||||||
rtl = true,
|
rtl = true,
|
||||||
max = math.max(0, job.area.w - ui.width(left[#left]) - ui.width(right[#right])),
|
max = math.max(0, job.area.w - ui.width(left[#left]) - ui.width(right[#right])),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ end)
|
||||||
function M:entry()
|
function M:entry()
|
||||||
ya.emit("escape", { visual = true })
|
ya.emit("escape", { visual = true })
|
||||||
|
|
||||||
local _permit = ya.hide()
|
local _permit = ui.hide()
|
||||||
local cwd, selected = state()
|
local cwd, selected = state()
|
||||||
|
|
||||||
local output, err = M.run_with(cwd, selected)
|
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.")
|
return fail("No directory history found, check Zoxide's doc to set it up and restart Yazi.")
|
||||||
end
|
end
|
||||||
|
|
||||||
local _permit = ya.hide()
|
local _permit = ui.hide()
|
||||||
local child, err1 = Command("zoxide")
|
local child, err1 = Command("zoxide")
|
||||||
:arg({ "query", "-i", "--exclude", st.cwd })
|
:arg({ "query", "-i", "--exclude", st.cwd })
|
||||||
:env("SHELL", "sh")
|
:env("SHELL", "sh")
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,11 @@ pub fn compose(lua: &Lua) -> mlua::Result<Value> {
|
||||||
b"Wrap" => super::Wrap::compose(lua)?,
|
b"Wrap" => super::Wrap::compose(lua)?,
|
||||||
|
|
||||||
b"area" => super::Utils::area(lua)?,
|
b"area" => super::Utils::area(lua)?,
|
||||||
|
b"hide" => super::Utils::hide(lua)?,
|
||||||
b"width" => super::Utils::width(lua)?,
|
b"width" => super::Utils::width(lua)?,
|
||||||
b"redraw" => super::Utils::redraw(lua)?,
|
b"redraw" => super::Utils::redraw(lua)?,
|
||||||
|
b"render" => super::Utils::render(lua)?,
|
||||||
|
b"truncate" => super::Utils::truncate(lua)?,
|
||||||
_ => return Ok(Value::Nil),
|
_ => return Ok(Value::Nil),
|
||||||
}
|
}
|
||||||
.into_lua(lua)
|
.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 tracing::error;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
|
||||||
use yazi_config::LAYOUT;
|
use yazi_config::LAYOUT;
|
||||||
|
use yazi_macro::render;
|
||||||
|
use yazi_proxy::{AppProxy, HIDER};
|
||||||
|
|
||||||
use super::{Line, Rect, Span};
|
use super::{Line, Rect, Span};
|
||||||
|
use crate::bindings::{Permit, PermitRef};
|
||||||
|
|
||||||
pub(super) struct Utils;
|
pub(super) struct Utils;
|
||||||
|
|
||||||
|
|
@ -22,6 +25,22 @@ impl Utils {
|
||||||
f.into_lua(lua)
|
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> {
|
pub(super) fn width(lua: &Lua) -> mlua::Result<Value> {
|
||||||
let f = lua.create_function(|_, v: Value| match v {
|
let f = lua.create_function(|_, v: Value| match v {
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
|
|
@ -77,4 +96,149 @@ impl Utils {
|
||||||
|
|
||||||
f.into_lua(lua)
|
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 yazi_proxy::{AppProxy, HIDER};
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
use crate::bindings::{Permit, PermitRef};
|
use crate::{bindings::{Permit, PermitRef}, deprecate};
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
pub(super) fn id(lua: &Lua) -> mlua::Result<Function> {
|
pub(super) fn id(lua: &Lua) -> mlua::Result<Function> {
|
||||||
|
|
@ -18,6 +18,8 @@ impl Utils {
|
||||||
|
|
||||||
pub(super) fn hide(lua: &Lua) -> mlua::Result<Function> {
|
pub(super) fn hide(lua: &Lua) -> mlua::Result<Function> {
|
||||||
lua.create_async_function(|lua, ()| async move {
|
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()) {
|
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());
|
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 yazi_shared::{Layer, event::Cmd};
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
|
use crate::deprecate;
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
pub(super) fn render(lua: &Lua) -> mlua::Result<Function> {
|
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!();
|
render!();
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,7 @@ impl Utils {
|
||||||
if pos.is_nil() {
|
if pos.is_nil() {
|
||||||
pos = t.raw_get("position")?;
|
pos = t.raw_get("position")?;
|
||||||
if !pos.is_nil() {
|
if !pos.is_nil() {
|
||||||
deprecate!(
|
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");
|
||||||
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 unicode_width::UnicodeWidthChar;
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
use crate::CLIPBOARD;
|
use crate::{CLIPBOARD, deprecate};
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
pub(super) fn hash(lua: &Lua) -> mlua::Result<Function> {
|
pub(super) fn hash(lua: &Lua) -> mlua::Result<Function> {
|
||||||
|
|
@ -41,6 +41,8 @@ impl Utils {
|
||||||
}
|
}
|
||||||
|
|
||||||
lua.create_function(|lua, (s, t): (mlua::String, Table)| {
|
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();
|
let b = s.as_bytes();
|
||||||
if b.is_empty() {
|
if b.is_empty() {
|
||||||
return Ok(s);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (o_cur, n_cur) = (snap.cursor, opt.step.cursor(snap));
|
let o_cur = snap.cursor;
|
||||||
render!(self.handle_op(n_cur, false));
|
render!(self.handle_op(opt.step.cursor(snap), false));
|
||||||
|
let n_cur = self.snap().cursor;
|
||||||
|
|
||||||
let (limit, snap) = (self.limit, self.snap_mut());
|
let (limit, snap) = (self.limit, self.snap_mut());
|
||||||
if snap.value.is_empty() {
|
if snap.value.is_empty() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue