mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
e2dfa9813a
commit
ebe6714ef6
6 changed files with 149 additions and 193 deletions
|
|
@ -15,42 +15,11 @@ impl Folder {
|
|||
pub(super) fn new(kind: FolderKind) -> Self { Self { kind } }
|
||||
}
|
||||
|
||||
impl Folder {
|
||||
// let short = short_path(file.url(), &self.folder.cwd);
|
||||
}
|
||||
|
||||
impl Widget for Folder {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let x = plugin::Folder { kind: self.kind as u8 }.render(area, buf);
|
||||
if x.is_err() {
|
||||
info!("{:?}", x);
|
||||
}
|
||||
|
||||
// let items: Vec<_> = window
|
||||
// .iter()
|
||||
// .enumerate()
|
||||
// .map(|(i, f)| {
|
||||
// if let Some(idx) = active
|
||||
// .finder()
|
||||
// .filter(|&f| hovered && self.is_find && f.has_matched())
|
||||
// .and_then(|finder| finder.matched_idx(f.url()))
|
||||
// {
|
||||
// let len = active.finder().unwrap().matched().len();
|
||||
// spans.push(Span::styled(
|
||||
// format!(
|
||||
// " [{}/{}]",
|
||||
// if idx > 99 { ">99".to_string() } else { (idx + 1).to_string() },
|
||||
// if len > 99 { ">99".to_string() } else { len.to_string() }
|
||||
// ),
|
||||
// // TODO: to be configured by THEME?
|
||||
// Style::new().fg(Color::Rgb(255, 255, 50)).add_modifier(Modifier::ITALIC),
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// ListItem::new(Line::from(spans)).style(style)
|
||||
// })
|
||||
// .collect();
|
||||
|
||||
// List::new(items).render(area, buf);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl Finder {
|
|||
|
||||
/// Explode the name into three parts: head, body, tail.
|
||||
#[inline]
|
||||
pub fn highlighted(&self, name: &OsStr) -> Vec<Range<usize>> {
|
||||
pub fn highlighted(&self, name: &OsStr) -> Option<Vec<Range<usize>>> {
|
||||
#[cfg(windows)]
|
||||
let found = self.query.find(name.to_string_lossy().as_bytes()).map(|m| m.range());
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ impl Finder {
|
|||
self.query.find(name.as_bytes()).map(|m| m.range())
|
||||
};
|
||||
|
||||
found.map(|r| vec![r]).unwrap_or_default()
|
||||
found.map(|r| vec![r])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,17 +109,11 @@ impl Finder {
|
|||
#[inline]
|
||||
pub fn matched(&self) -> &BTreeMap<Url, u8> { &self.matched }
|
||||
|
||||
#[inline]
|
||||
pub fn has_matched(&self) -> bool { !self.matched.is_empty() }
|
||||
|
||||
#[inline]
|
||||
pub fn matched_idx(&self, url: &Url) -> Option<u8> {
|
||||
if let Some((_, &idx)) = self.matched.iter().find(|(u, _)| *u == url) {
|
||||
return Some(idx);
|
||||
}
|
||||
if url.file_name().map(|n| self.matches(n)) == Some(true) {
|
||||
return Some(100);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,33 @@ function Folder:markers(area, markers)
|
|||
return elements
|
||||
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 = ui.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 highlights == nil or not file:is_hovered() then
|
||||
return spans
|
||||
end
|
||||
|
||||
local found = file:found()
|
||||
if found ~= nil then
|
||||
spans[#spans + 1] = ui.Span(string.format(" [%d/%d]", found[1] + 1, found[2])):fg("#ffff32"):italic()
|
||||
end
|
||||
return spans
|
||||
end
|
||||
|
||||
function Folder:parent(area)
|
||||
local folder = self:by_kind(self.Kind.Parent)
|
||||
if folder == nil then
|
||||
|
|
@ -66,7 +93,7 @@ function Folder:parent(area)
|
|||
local items = {}
|
||||
for _, f in ipairs(folder.window) do
|
||||
local item = ui.ListItem(" " .. f:icon() .. " " .. f.name .. " ")
|
||||
if f.hovered then
|
||||
if f:is_hovered() then
|
||||
item = item:style(THEME.files.hovered)
|
||||
else
|
||||
item = item:style(f:style())
|
||||
|
|
@ -82,18 +109,11 @@ function Folder:current(area)
|
|||
local markers = {}
|
||||
local items = {}
|
||||
for i, f in ipairs(self:by_kind(self.Kind.Current).window) do
|
||||
local name = ui.highlight_ranges(f.name, f:highlights())
|
||||
|
||||
-- Show symlink target
|
||||
if MANAGER.show_symlink then
|
||||
if f.link_to ~= nil then
|
||||
name[#name + 1] = ui.Span(" -> " .. tostring(f.link_to)):italic()
|
||||
end
|
||||
end
|
||||
local name = self:highlighted_name(f)
|
||||
|
||||
-- Highlight hovered file
|
||||
local item = ui.ListItem(ui.Line { ui.Span(" " .. f:icon() .. " "), table.unpack(name) })
|
||||
if f.hovered then
|
||||
if f:is_hovered() then
|
||||
item = item:style(THEME.files.hovered)
|
||||
else
|
||||
item = item:style(f:style())
|
||||
|
|
@ -101,10 +121,10 @@ function Folder:current(area)
|
|||
items[#items + 1] = item
|
||||
|
||||
-- Mark yanked/selected files
|
||||
local yanked = f:yanked()
|
||||
local yanked = f:is_yanked()
|
||||
if yanked ~= 0 then
|
||||
markers[#markers + 1] = { i, yanked }
|
||||
elseif f:selected() then
|
||||
elseif f:is_selected() then
|
||||
markers[#markers + 1] = { i, 3 }
|
||||
end
|
||||
end
|
||||
|
|
@ -121,7 +141,7 @@ function Folder:preview(area)
|
|||
local items = {}
|
||||
for _, f in ipairs(folder.window) do
|
||||
local item = ui.ListItem(" " .. f:icon() .. " " .. f.name .. " ")
|
||||
if f.hovered then
|
||||
if f:is_hovered() then
|
||||
item = item:style(THEME.preview.hovered)
|
||||
else
|
||||
item = item:style(f:style())
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use core::Ctx;
|
||||
|
||||
use config::{MANAGER, THEME};
|
||||
use config::MANAGER;
|
||||
use mlua::{AnyUserData, MetaMethod, UserDataFields, UserDataMethods, Value};
|
||||
|
||||
use super::{Range, Url};
|
||||
use crate::{layout::Style, LUA};
|
||||
use super::Url;
|
||||
use crate::LUA;
|
||||
|
||||
pub struct Active<'a, 'b> {
|
||||
scope: &'b mlua::Scope<'a, 'a>,
|
||||
|
|
@ -99,80 +99,8 @@ impl<'a, 'b> Active<'a, 'b> {
|
|||
) -> mlua::Result<AnyUserData<'a>> {
|
||||
let ud = self.scope.create_any_userdata_ref(inner)?;
|
||||
ud.set_named_user_value("idx", idx)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"icon",
|
||||
self.scope.create_function(|_, ()| {
|
||||
Ok(
|
||||
THEME
|
||||
.icons
|
||||
.iter()
|
||||
.find(|&x| x.name.match_path(inner.url(), Some(inner.is_dir())))
|
||||
.map(|x| x.display.to_string()),
|
||||
)
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"style",
|
||||
self.scope.create_function(|_, ()| {
|
||||
let mime = self.cx.manager.mimetype.get(inner.url());
|
||||
Ok(
|
||||
THEME
|
||||
.filetypes
|
||||
.iter()
|
||||
.find(|&x| x.matches(inner.url(), mime, inner.is_dir()))
|
||||
.map(|x| Style::from(x.style)),
|
||||
)
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"hovered",
|
||||
matches!(&folder.hovered, Some(f) if f.url() == inner.url()),
|
||||
)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"yanked",
|
||||
self.scope.create_function(|_, ()| {
|
||||
let (cut, urls) = self.cx.manager.yanked();
|
||||
Ok(if !urls.contains(inner.url()) {
|
||||
0u8
|
||||
} else if *cut {
|
||||
2u8
|
||||
} else {
|
||||
1u8
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"selected",
|
||||
self.scope.create_function(|_, me: AnyUserData| {
|
||||
let is_visual = self.inner.mode.is_visual();
|
||||
let selected = folder.files.is_selected(inner.url());
|
||||
Ok(if !is_visual {
|
||||
selected
|
||||
} else {
|
||||
let idx: usize = me.named_user_value("idx")?;
|
||||
self.inner.mode.pending(folder.offset() + idx, selected)
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ud.set_named_user_value(
|
||||
"highlights",
|
||||
self.scope.create_function(|_, ()| {
|
||||
let Some(finder) = self.inner.finder() else {
|
||||
return Ok(None);
|
||||
};
|
||||
Ok(
|
||||
inner
|
||||
.name()
|
||||
.map(|n| finder.highlighted(n).into_iter().map(Range::from).collect::<Vec<_>>()),
|
||||
)
|
||||
})?,
|
||||
)?;
|
||||
ud.set_named_user_value("folder", self.scope.create_any_userdata_ref(folder)?)?;
|
||||
ud.set_named_user_value("manager", self.scope.create_any_userdata_ref(&self.cx.manager)?)?;
|
||||
|
||||
Ok(ud)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use config::THEME;
|
||||
use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef};
|
||||
|
||||
use super::Url;
|
||||
use super::{Range, Url};
|
||||
use crate::{layout::Style, LUA};
|
||||
|
||||
pub struct File(core::files::File);
|
||||
|
|
@ -46,36 +47,115 @@ impl Files {
|
|||
})?;
|
||||
|
||||
LUA.register_userdata_type::<core::files::File>(|reg| {
|
||||
reg.add_field_method_get("name", |_, me| {
|
||||
Ok(me.url().file_name().map(|n| n.to_string_lossy().to_string()))
|
||||
});
|
||||
reg.add_function("icon", |_, me: AnyUserData| {
|
||||
me.named_user_value::<Function>("icon")?.call::<_, String>(())
|
||||
});
|
||||
reg.add_function("style", |_, me: AnyUserData| {
|
||||
me.named_user_value::<Function>("style")?.call::<_, Style>(())
|
||||
});
|
||||
reg.add_field_function_get("hovered", |_, me| me.named_user_value::<bool>("hovered"));
|
||||
reg.add_function("yanked", |_, me: AnyUserData| {
|
||||
me.named_user_value::<Function>("yanked")?.call::<_, u8>(me)
|
||||
});
|
||||
reg.add_function("selected", |_, me: AnyUserData| {
|
||||
me.named_user_value::<Function>("selected")?.call::<_, bool>(me)
|
||||
});
|
||||
reg.add_function("highlights", |_, me: AnyUserData| {
|
||||
me.named_user_value::<Function>("highlights")?.call::<_, Value>(())
|
||||
});
|
||||
|
||||
reg.add_field_method_get("url", |_, me| Ok(Url::from(me.url())));
|
||||
reg.add_field_method_get("length", |_, me| Ok(me.length()));
|
||||
reg.add_field_method_get("link_to", |_, me| Ok(me.link_to().map(Url::from)));
|
||||
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
||||
|
||||
// Meta
|
||||
reg.add_field_method_get("name", |_, me| {
|
||||
Ok(me.url().file_name().map(|n| n.to_string_lossy().to_string()))
|
||||
});
|
||||
reg.add_field_method_get("permissions", |_, me| {
|
||||
Ok(shared::permissions(me.meta().permissions()))
|
||||
});
|
||||
|
||||
reg.add_function("prefix", |_, me: AnyUserData| {
|
||||
let folder = me.named_user_value::<UserDataRef<core::manager::Folder>>("folder")?;
|
||||
if !folder.cwd.is_search() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
let mut p = file.url().strip_prefix(&folder.cwd).unwrap_or(file.url()).components();
|
||||
p.next_back();
|
||||
Ok(Some(p.as_path().to_string_lossy().to_string()))
|
||||
});
|
||||
|
||||
reg.add_method("icon", |_, me, ()| {
|
||||
Ok(
|
||||
THEME
|
||||
.icons
|
||||
.iter()
|
||||
.find(|&x| x.name.match_path(me.url(), Some(me.is_dir())))
|
||||
.map(|x| x.display.to_string()),
|
||||
)
|
||||
});
|
||||
|
||||
reg.add_function("style", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<core::manager::Manager>>("manager")?;
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
let mime = manager.mimetype.get(file.url());
|
||||
Ok(
|
||||
THEME
|
||||
.filetypes
|
||||
.iter()
|
||||
.find(|&x| x.matches(file.url(), mime, file.is_dir()))
|
||||
.map(|x| Style::from(x.style)),
|
||||
)
|
||||
});
|
||||
|
||||
reg.add_function("is_hovered", |_, me: AnyUserData| {
|
||||
let folder = me.named_user_value::<UserDataRef<core::manager::Folder>>("folder")?;
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
Ok(matches!(&folder.hovered, Some(f) if f.url() == file.url()))
|
||||
});
|
||||
|
||||
reg.add_function("is_yanked", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<core::manager::Manager>>("manager")?;
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
Ok(if !manager.yanked().1.contains(file.url()) {
|
||||
0u8
|
||||
} else if manager.yanked().0 {
|
||||
2u8
|
||||
} else {
|
||||
1u8
|
||||
})
|
||||
});
|
||||
|
||||
reg.add_function("is_selected", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<core::manager::Manager>>("manager")?;
|
||||
let folder = me.named_user_value::<UserDataRef<core::manager::Folder>>("folder")?;
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
|
||||
let selected = folder.files.is_selected(file.url());
|
||||
Ok(if !manager.active().mode.is_visual() {
|
||||
selected
|
||||
} else {
|
||||
let idx: usize = me.named_user_value("idx")?;
|
||||
manager.active().mode.pending(folder.offset() + idx, selected)
|
||||
})
|
||||
});
|
||||
|
||||
reg.add_function("found", |lua, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<core::manager::Manager>>("manager")?;
|
||||
let Some(finder) = manager.active().finder() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
if let Some(idx) = finder.matched_idx(file.url()) {
|
||||
return Some(
|
||||
lua.create_sequence_from([idx.into_lua(lua)?, finder.matched().len().into_lua(lua)?]),
|
||||
)
|
||||
.transpose();
|
||||
}
|
||||
Ok(None)
|
||||
});
|
||||
|
||||
reg.add_function("highlights", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<core::manager::Manager>>("manager")?;
|
||||
let Some(finder) = manager.active().finder() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let file = me.borrow::<core::files::File>()?;
|
||||
let Some(h) = file.name().and_then(|n| finder.highlighted(n)) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
Ok(Some(h.into_iter().map(Range::from).collect::<Vec<_>>()))
|
||||
});
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, env, ffi::OsStr, fmt::Display, path::{Component, Path, PathBuf}};
|
||||
use std::{borrow::Cow, env, path::{Component, Path, PathBuf}};
|
||||
|
||||
use tokio::fs;
|
||||
|
||||
|
|
@ -43,39 +43,6 @@ pub fn expand_url(mut u: Url) -> Url {
|
|||
u
|
||||
}
|
||||
|
||||
pub struct ShortPath<'a> {
|
||||
pub prefix: &'a Path,
|
||||
pub name: &'a OsStr,
|
||||
}
|
||||
|
||||
impl Display for ShortPath<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if self.prefix == Path::new("") {
|
||||
return write!(f, "{}", self.name.to_string_lossy());
|
||||
}
|
||||
write!(f, "{}/{}", self.prefix.display(), self.name.to_string_lossy())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn short_path<'a>(p: &'a Path, base: &Path) -> ShortPath<'a> {
|
||||
let p = p.strip_prefix(base).unwrap_or(p);
|
||||
let mut parts = p.components();
|
||||
let name = parts.next_back().and_then(|p| match p {
|
||||
Component::Normal(p) => Some(p),
|
||||
_ => None,
|
||||
});
|
||||
ShortPath { prefix: parts.as_path(), name: name.unwrap_or_default() }
|
||||
}
|
||||
|
||||
pub fn readable_path(p: &Path) -> String {
|
||||
if let Some(home) = env::var_os("HOME") {
|
||||
if let Ok(p) = p.strip_prefix(home) {
|
||||
return format!("~/{}", p.display());
|
||||
}
|
||||
}
|
||||
p.display().to_string()
|
||||
}
|
||||
|
||||
pub async fn unique_path(mut p: Url) -> Url {
|
||||
let Some(name) = p.file_name().map(|n| n.to_owned()) else {
|
||||
return p;
|
||||
|
|
@ -91,7 +58,7 @@ pub async fn unique_path(mut p: Url) -> Url {
|
|||
p
|
||||
}
|
||||
|
||||
// Parmaters
|
||||
// Parameters
|
||||
// * `path`: The absolute path(contains no `/./`) to get relative path.
|
||||
// * `root`: The absolute path(contains no `/./`) to be compared.
|
||||
//
|
||||
|
|
@ -138,12 +105,10 @@ pub fn path_relative_to<'a>(path: &'a Path, root: &Path) -> Cow<'a, Path> {
|
|||
|
||||
#[inline]
|
||||
pub fn optional_bool(s: &str) -> Option<bool> {
|
||||
if s == "true" {
|
||||
Some(true)
|
||||
} else if s == "false" {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
match s {
|
||||
"true" => Some(true),
|
||||
"false" => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue