From 3f80bc56a6cf331558ffbe8d83de51206ae87b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=8A=E5=B0=8F=E4=B9=85?= Date: Fri, 8 Mar 2024 17:54:29 +0800 Subject: [PATCH] feat: truncate path for deeply nested directories (#787) --- yazi-plugin/preset/components/header.lua | 33 +++++++++++-------- yazi-plugin/src/utils/text.rs | 41 +++++++++++++++--------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/yazi-plugin/preset/components/header.lua b/yazi-plugin/preset/components/header.lua index 8f02c035..72cffa03 100644 --- a/yazi-plugin/preset/components/header.lua +++ b/yazi-plugin/preset/components/header.lua @@ -2,16 +2,12 @@ Header = { area = ui.Rect.default, } -function Header:cwd() +function Header:cwd(max) local cwd = cx.active.current.cwd + local readable = ya.readable_path(tostring(cwd)) - local span - if not cwd.is_search then - span = ui.Span(ya.readable_path(tostring(cwd))) - else - span = ui.Span(string.format("%s (search: %s)", ya.readable_path(tostring(cwd)), cwd:frag())) - end - return span:style(THEME.manager.cwd) + local text = cwd.is_search and string.format("%s (search: %s)", readable, cwd:frag()) or readable + return ui.Span(ya.truncate(text, { max = max, rtl = true })):style(THEME.manager.cwd) end function Header:count() @@ -49,7 +45,7 @@ function Header:tabs() for i = 1, tabs do local text = i if THEME.manager.tab_width > 2 then - text = ya.truncate(text .. " " .. cx.tabs[i]:name(), THEME.manager.tab_width) + text = ya.truncate(text .. " " .. cx.tabs[i]:name(), { max = THEME.manager.tab_width }) end if i == cx.tabs.idx then spans[#spans + 1] = ui.Span(" " .. text .. " "):style(THEME.manager.tab_active) @@ -60,7 +56,18 @@ function Header:tabs() return ui.Line(spans) end +-- TODO: remove this function after v0.2.5 release function Header:layout(area) + if not ya.deprecated_header_layout then + ya.deprecated_header_layout = true + ya.notify { + title = "Deprecated API", + content = "`Header:layout()` is deprecated, please apply the latest `Header:render()` in your `init.lua`", + timeout = 5, + level = "warn", + } + end + self.area = area return ui.Layout() @@ -70,12 +77,12 @@ function Header:layout(area) end function Header:render(area) - local chunks = self:layout(area) + self.area = area - local left = ui.Line { self:cwd() } local right = ui.Line { self:count(), self:tabs() } + local left = ui.Line { self:cwd(math.max(0, area.w - right:width())) } return { - ui.Paragraph(chunks[1], { left }), - ui.Paragraph(chunks[2], { right }):align(ui.Paragraph.RIGHT), + ui.Paragraph(area, { left }), + ui.Paragraph(area, { right }):align(ui.Paragraph.RIGHT), } end diff --git a/yazi-plugin/src/utils/text.rs b/yazi-plugin/src/utils/text.rs index 401084a7..92044180 100644 --- a/yazi-plugin/src/utils/text.rs +++ b/yazi-plugin/src/utils/text.rs @@ -1,7 +1,7 @@ use std::ops::ControlFlow; use mlua::{Lua, Table}; -use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; +use unicode_width::UnicodeWidthChar; use super::Utils; @@ -20,26 +20,35 @@ impl Utils { ya.raw_set( "truncate", - lua.create_function(|_, (text, max): (mlua::String, usize)| { - let mut width = 0; - let flow = - text.to_string_lossy().chars().try_fold(String::with_capacity(max), |mut s, c| { - width += c.width().unwrap_or(0); - if s.width() < max { - s.push(c); - ControlFlow::Continue(s) - } else { - ControlFlow::Break(s) - } - }); + lua.create_function(|_, (text, t): (mlua::String, Table)| { + let (max, text) = (t.raw_get("max")?, text.to_string_lossy()); - Ok(match flow { - ControlFlow::Break(s) => s, - ControlFlow::Continue(s) => s, + Ok(if t.raw_get("rtl").unwrap_or(false) { + Self::truncate(text.chars().rev(), max).into_iter().rev().collect() + } else { + Self::truncate(text.chars(), max).into_iter().collect::() }) })?, )?; Ok(()) } + + fn truncate(mut chars: impl Iterator, max: usize) -> Vec { + let mut width = 0; + let flow = chars.try_fold(Vec::with_capacity(max), |mut v, c| { + width += c.width().unwrap_or(0); + if width < max { + v.push(c); + ControlFlow::Continue(v) + } else { + ControlFlow::Break(v) + } + }); + + match flow { + ControlFlow::Break(v) => v, + ControlFlow::Continue(v) => v, + } + } }