mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: better accessibility (#719)
This commit is contained in:
parent
e51e8ad789
commit
8ea7556625
10 changed files with 131 additions and 118 deletions
|
|
@ -10,12 +10,12 @@
|
||||||
cwd = { fg = "cyan" }
|
cwd = { fg = "cyan" }
|
||||||
|
|
||||||
# Hovered
|
# Hovered
|
||||||
hovered = { fg = "black", bg = "lightblue" }
|
hovered = { reversed = true }
|
||||||
preview_hovered = { underline = true }
|
preview_hovered = { underline = true }
|
||||||
|
|
||||||
# Find
|
# Find
|
||||||
find_keyword = { fg = "yellow", italic = true }
|
find_keyword = { fg = "yellow", bold = true, italic = true, underline = true }
|
||||||
find_position = { fg = "magenta", bg = "reset", italic = true }
|
find_position = { fg = "magenta", bg = "reset", bold = true, italic = true }
|
||||||
|
|
||||||
# Marker
|
# Marker
|
||||||
marker_copied = { fg = "lightgreen", bg = "lightgreen" }
|
marker_copied = { fg = "lightgreen", bg = "lightgreen" }
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,5 @@ impl Finder {
|
||||||
pub fn matched(&self) -> &BTreeMap<Url, u8> { &self.matched }
|
pub fn matched(&self) -> &BTreeMap<Url, u8> { &self.matched }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn matched_idx(&self, url: &Url) -> Option<u8> {
|
pub fn matched_idx(&self, url: &Url) -> Option<u8> { self.matched.get(url).copied() }
|
||||||
if let Some((_, &idx)) = self.matched.iter().find(|(u, _)| *u == url) {
|
|
||||||
return Some(idx);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ impl File {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
reg.add_method("is_selected", |_, me, ()| Ok(me.tab().selected.contains(&me.url)));
|
reg.add_method("is_selected", |_, me, ()| Ok(me.tab().selected.contains(&me.url)));
|
||||||
|
reg.add_method("in_current", |_, me, ()| Ok(me.folder().cwd == me.tab().current.cwd));
|
||||||
reg.add_method("found", |lua, me, ()| {
|
reg.add_method("found", |lua, me, ()| {
|
||||||
let cx = lua.named_registry_value::<CtxRef>("cx")?;
|
let cx = lua.named_registry_value::<CtxRef>("cx")?;
|
||||||
let Some(finder) = &cx.manager.active().finder else {
|
let Some(finder) = &cx.manager.active().finder else {
|
||||||
|
|
@ -113,7 +114,9 @@ impl File {
|
||||||
let Some(finder) = &cx.manager.active().finder else {
|
let Some(finder) = &cx.manager.active().finder else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
if me.folder().cwd != me.tab().current.cwd {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
let Some(h) = me.name().and_then(|n| finder.filter.highlighted(n)) else {
|
let Some(h) = me.name().and_then(|n| finder.filter.highlighted(n)) else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,12 @@ function Current:render(area)
|
||||||
|
|
||||||
local items, markers = {}, {}
|
local items, markers = {}, {}
|
||||||
for i, f in ipairs(files) do
|
for i, f in ipairs(files) do
|
||||||
local name = Folder:highlighted_name(f)
|
local style = f:style()
|
||||||
|
items[#items + 1] = ui.ListItem(ui.Line(File:full(f)))
|
||||||
-- Highlight hovered file
|
:style(f:is_hovered() and style:patch(THEME.manager.hovered) or style)
|
||||||
local item = ui.ListItem(ui.Line { Folder:icon(f), table.unpack(name) })
|
|
||||||
if f:is_hovered() then
|
|
||||||
item = item:style(THEME.manager.hovered)
|
|
||||||
else
|
|
||||||
item = item:style(f:style())
|
|
||||||
end
|
|
||||||
items[#items + 1] = item
|
|
||||||
|
|
||||||
-- Yanked/marked/selected files
|
-- Yanked/marked/selected files
|
||||||
local marker = Folder:marker(f)
|
local marker = File:marker(f)
|
||||||
if marker ~= 0 then
|
if marker ~= 0 then
|
||||||
markers[#markers + 1] = { i, marker }
|
markers[#markers + 1] = { i, marker }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
88
yazi-plugin/preset/components/file.lua
Normal file
88
yazi-plugin/preset/components/file.lua
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
File = {}
|
||||||
|
|
||||||
|
function File:icon(file)
|
||||||
|
local icon = file:icon()
|
||||||
|
if not icon then
|
||||||
|
return {}
|
||||||
|
elseif file:is_hovered() then
|
||||||
|
return { ui.Span(" " .. icon.text .. " ") }
|
||||||
|
else
|
||||||
|
return { ui.Span(" " .. icon.text .. " "):style(icon.style) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:prefix(file)
|
||||||
|
local prefix = file:prefix() or ""
|
||||||
|
return prefix == "" and {} or { ui.Span(prefix .. "/") }
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:highlights(file)
|
||||||
|
local name = file.name:gsub("\r", "?", 1)
|
||||||
|
local highlights = file:highlights()
|
||||||
|
if not highlights or #highlights == 0 then
|
||||||
|
return { ui.Span(name) }
|
||||||
|
end
|
||||||
|
|
||||||
|
local spans, last = {}, 0
|
||||||
|
for _, r in ipairs(highlights) do
|
||||||
|
if r[1] > last then
|
||||||
|
spans[#spans + 1] = ui.Span(name:sub(last + 1, r[1]))
|
||||||
|
end
|
||||||
|
spans[#spans + 1] = ui.Span(name:sub(r[1] + 1, r[2])):style(THEME.manager.find_keyword)
|
||||||
|
last = r[2]
|
||||||
|
end
|
||||||
|
if last < #name then
|
||||||
|
spans[#spans + 1] = ui.Span(name:sub(last + 1))
|
||||||
|
end
|
||||||
|
return spans
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:found(file)
|
||||||
|
if not file:is_hovered() then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local found = file:found()
|
||||||
|
if not found then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
ui.Span(" "),
|
||||||
|
ui.Span(string.format("[%d/%d]", found[1] + 1, found[2])):style(THEME.manager.find_position),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:symlink(file)
|
||||||
|
if not MANAGER.show_symlink then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local to = file.link_to
|
||||||
|
return to and { ui.Span(" -> " .. tostring(to)):italic() } or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:full(file)
|
||||||
|
return ya.flat {
|
||||||
|
self:icon(file),
|
||||||
|
self:prefix(file),
|
||||||
|
self:highlights(file),
|
||||||
|
self:found(file),
|
||||||
|
self:symlink(file),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function File:marker(file)
|
||||||
|
local yanked = file:is_yanked()
|
||||||
|
if yanked ~= 0 then
|
||||||
|
return yanked -- 1: copied, 2: cut
|
||||||
|
end
|
||||||
|
|
||||||
|
local marked = file:is_marked()
|
||||||
|
if marked == 1 then
|
||||||
|
return 3 -- 3: marked
|
||||||
|
elseif marked == 0 and file:is_selected() then
|
||||||
|
return 4 -- 4: selected
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
@ -4,69 +4,6 @@ Folder = {
|
||||||
PREVIEW = 2,
|
PREVIEW = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Folder:by_kind(kind)
|
|
||||||
if kind == self.PARENT then
|
|
||||||
return cx.active.parent
|
|
||||||
elseif kind == self.CURRENT then
|
|
||||||
return cx.active.current
|
|
||||||
elseif kind == self.PREVIEW then
|
|
||||||
return cx.active.preview.folder
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Folder:icon(file)
|
|
||||||
local icon = file:icon()
|
|
||||||
return icon and ui.Span(" " .. icon.text .. " "):style(icon.style) or ui.Span("")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Folder:highlight_ranges(s, ranges)
|
|
||||||
if not ranges or #ranges == 0 then
|
|
||||||
return { ui.Span(s) }
|
|
||||||
end
|
|
||||||
|
|
||||||
local spans = {}
|
|
||||||
local last = 0
|
|
||||||
for _, r in ipairs(ranges) do
|
|
||||||
if r[1] > last then
|
|
||||||
spans[#spans + 1] = ui.Span(s:sub(last + 1, r[1]))
|
|
||||||
end
|
|
||||||
spans[#spans + 1] = ui.Span(s:sub(r[1] + 1, r[2])):style(THEME.manager.find_keyword)
|
|
||||||
last = r[2]
|
|
||||||
end
|
|
||||||
if last < #s then
|
|
||||||
spans[#spans + 1] = ui.Span(s:sub(last + 1))
|
|
||||||
end
|
|
||||||
return spans
|
|
||||||
end
|
|
||||||
|
|
||||||
function Folder:highlighted_name(file)
|
|
||||||
-- Complete prefix when searching across directories
|
|
||||||
local prefix = file:prefix() or ""
|
|
||||||
if prefix ~= "" then
|
|
||||||
prefix = prefix .. "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Range highlighting for filenames
|
|
||||||
local highlights = file:highlights()
|
|
||||||
local spans = self:highlight_ranges(prefix .. file.name, highlights)
|
|
||||||
|
|
||||||
-- Show symlink target
|
|
||||||
if MANAGER.show_symlink and file.link_to ~= nil then
|
|
||||||
spans[#spans + 1] = ui.Span(" -> " .. tostring(file.link_to)):italic()
|
|
||||||
end
|
|
||||||
|
|
||||||
if not highlights or not file:is_hovered() then
|
|
||||||
return spans
|
|
||||||
end
|
|
||||||
|
|
||||||
local found = file:found()
|
|
||||||
if found ~= nil then
|
|
||||||
spans[#spans + 1] = ui.Span(" ")
|
|
||||||
spans[#spans + 1] = ui.Span(string.format("[%d/%d]", found[1] + 1, found[2])):style(THEME.manager.find_position)
|
|
||||||
end
|
|
||||||
return spans
|
|
||||||
end
|
|
||||||
|
|
||||||
function Folder:linemode(area, files)
|
function Folder:linemode(area, files)
|
||||||
local mode = cx.active.conf.linemode
|
local mode = cx.active.conf.linemode
|
||||||
if mode == "none" then
|
if mode == "none" then
|
||||||
|
|
@ -92,21 +29,6 @@ function Folder:linemode(area, files)
|
||||||
return ui.Paragraph(area, lines):align(ui.Paragraph.RIGHT)
|
return ui.Paragraph(area, lines):align(ui.Paragraph.RIGHT)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Folder:marker(file)
|
|
||||||
local yanked = file:is_yanked()
|
|
||||||
if yanked ~= 0 then
|
|
||||||
return yanked -- 1: copied, 2: cut
|
|
||||||
end
|
|
||||||
|
|
||||||
local marked = file:is_marked()
|
|
||||||
if marked == 1 then
|
|
||||||
return 3 -- 3: marked
|
|
||||||
elseif marked == 0 and file:is_selected() then
|
|
||||||
return 4 -- 4: selected
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Folder:markers(area, markers)
|
function Folder:markers(area, markers)
|
||||||
if #markers == 0 or area.w * area.h == 0 then
|
if #markers == 0 or area.w * area.h == 0 then
|
||||||
return {}
|
return {}
|
||||||
|
|
@ -150,3 +72,13 @@ function Folder:markers(area, markers)
|
||||||
append(last)
|
append(last)
|
||||||
return elements
|
return elements
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Folder:by_kind(kind)
|
||||||
|
if kind == self.PARENT then
|
||||||
|
return cx.active.parent
|
||||||
|
elseif kind == self.CURRENT then
|
||||||
|
return cx.active.current
|
||||||
|
elseif kind == self.PREVIEW then
|
||||||
|
return cx.active.preview.folder
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,12 @@ function Parent:render(area)
|
||||||
|
|
||||||
local items, markers = {}, {}
|
local items, markers = {}, {}
|
||||||
for i, f in ipairs(folder.window) do
|
for i, f in ipairs(folder.window) do
|
||||||
-- Highlight hovered file
|
local style = f:style()
|
||||||
local item = ui.ListItem(ui.Line { Folder:icon(f), ui.Span(f.name) })
|
items[#items + 1] = ui.ListItem(ui.Line(File:full(f)))
|
||||||
if f:is_hovered() then
|
:style(f:is_hovered() and style:patch(THEME.manager.hovered) or style)
|
||||||
item = item:style(THEME.manager.hovered)
|
|
||||||
else
|
|
||||||
item = item:style(f:style())
|
|
||||||
end
|
|
||||||
items[#items + 1] = item
|
|
||||||
|
|
||||||
-- Yanked/marked/selected files
|
-- Yanked/marked/selected files
|
||||||
local marker = Folder:marker(f)
|
local marker = File:marker(f)
|
||||||
if marker ~= 0 then
|
if marker ~= 0 then
|
||||||
markers[#markers + 1] = { i, marker }
|
markers[#markers + 1] = { i, marker }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,12 @@ function M:peek()
|
||||||
|
|
||||||
local items, markers = {}, {}
|
local items, markers = {}, {}
|
||||||
for i, f in ipairs(folder.window) do
|
for i, f in ipairs(folder.window) do
|
||||||
-- Highlight hovered file
|
local style = f:style()
|
||||||
local item = ui.ListItem(ui.Line { Folder:icon(f), ui.Span(f.name) })
|
items[#items + 1] = ui.ListItem(ui.Line(File:full(f)))
|
||||||
if f:is_hovered() then
|
:style(f:is_hovered() and style:patch(THEME.manager.preview_hovered) or style)
|
||||||
item = item:style(THEME.manager.preview_hovered)
|
|
||||||
else
|
|
||||||
item = item:style(f:style())
|
|
||||||
end
|
|
||||||
items[#items + 1] = item
|
|
||||||
|
|
||||||
-- Yanked/marked/selected files
|
-- Yanked/marked/selected files
|
||||||
local marker = Folder:marker(f)
|
local marker = File:marker(f)
|
||||||
if marker ~= 0 then
|
if marker ~= 0 then
|
||||||
markers[#markers + 1] = { i, marker }
|
markers[#markers + 1] = { i, marker }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use mlua::{AnyUserData, Lua, Table, UserData, UserDataMethods};
|
use mlua::{AnyUserData, ExternalError, Lua, Table, UserData, UserDataMethods, Value};
|
||||||
use yazi_config::theme::Color;
|
use yazi_config::theme::Color;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
|
|
@ -80,5 +80,16 @@ impl UserData for Style {
|
||||||
ud.borrow_mut::<Self>()?.0.add_modifier = ratatui::style::Modifier::empty();
|
ud.borrow_mut::<Self>()?.0.add_modifier = ratatui::style::Modifier::empty();
|
||||||
Ok(ud)
|
Ok(ud)
|
||||||
});
|
});
|
||||||
|
methods.add_function("patch", |_, (ud, value): (AnyUserData, Value)| {
|
||||||
|
{
|
||||||
|
let mut me = ud.borrow_mut::<Self>()?;
|
||||||
|
me.0 = me.0.patch(match value {
|
||||||
|
Value::Table(tb) => Style::from(tb).0,
|
||||||
|
Value::UserData(ud) => ud.borrow::<Style>()?.0,
|
||||||
|
_ => return Err("expected a Style or Table".into_lua_err()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(ud)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ pub fn init() {
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
lua.load(include_str!("../preset/components/current.lua")).exec()?;
|
lua.load(include_str!("../preset/components/current.lua")).exec()?;
|
||||||
|
lua.load(include_str!("../preset/components/file.lua")).exec()?;
|
||||||
lua.load(include_str!("../preset/components/folder.lua")).exec()?;
|
lua.load(include_str!("../preset/components/folder.lua")).exec()?;
|
||||||
lua.load(include_str!("../preset/components/header.lua")).exec()?;
|
lua.load(include_str!("../preset/components/header.lua")).exec()?;
|
||||||
lua.load(include_str!("../preset/components/manager.lua")).exec()?;
|
lua.load(include_str!("../preset/components/manager.lua")).exec()?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue