mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
refactor: tab-specific selection (#653)
This commit is contained in:
parent
84616bd15f
commit
a764e42098
13 changed files with 167 additions and 168 deletions
|
|
@ -15,7 +15,6 @@ pub struct Files {
|
|||
pub(crate) revision: u64,
|
||||
|
||||
pub sizes: BTreeMap<Url, u64>,
|
||||
selected: BTreeSet<Url>,
|
||||
|
||||
sorter: FilesSorter,
|
||||
filter: Option<Filter>,
|
||||
|
|
@ -31,8 +30,7 @@ impl Default for Files {
|
|||
version: Default::default(),
|
||||
revision: Default::default(),
|
||||
|
||||
sizes: Default::default(),
|
||||
selected: Default::default(),
|
||||
sizes: Default::default(),
|
||||
|
||||
sorter: Default::default(),
|
||||
filter: Default::default(),
|
||||
|
|
@ -97,67 +95,6 @@ impl Files {
|
|||
}
|
||||
|
||||
impl Files {
|
||||
#[inline]
|
||||
pub fn select(&mut self, url: &Url, state: Option<bool>) -> bool {
|
||||
let old = self.selected.contains(url);
|
||||
let new = state.unwrap_or(!old);
|
||||
|
||||
if new == old {
|
||||
return false;
|
||||
}
|
||||
|
||||
if new {
|
||||
self.selected.insert(url.to_owned());
|
||||
} else {
|
||||
self.selected.remove(url);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn select_all(&mut self, state: Option<bool>) -> bool {
|
||||
match state {
|
||||
Some(true) => {
|
||||
let b = if self.selected.len() < self.items.len() {
|
||||
true
|
||||
} else {
|
||||
self.items.iter().any(|f| !self.selected.contains(&f.url))
|
||||
};
|
||||
|
||||
self.selected = self.iter().map(|f| f.url()).collect();
|
||||
b
|
||||
}
|
||||
Some(false) => {
|
||||
if self.selected.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let b = self.items.iter().any(|f| self.selected.contains(&f.url));
|
||||
self.selected.clear();
|
||||
b
|
||||
}
|
||||
None => {
|
||||
for item in &self.items {
|
||||
if self.selected.contains(&item.url) {
|
||||
self.selected.remove(&item.url);
|
||||
} else {
|
||||
self.selected.insert(item.url());
|
||||
}
|
||||
}
|
||||
!self.items.is_empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_index(&mut self, indices: &BTreeSet<usize>, state: Option<bool>) -> bool {
|
||||
let mut applied = false;
|
||||
let paths: Vec<_> = self.pick(indices).iter().map(|f| f.url()).collect();
|
||||
|
||||
for path in paths {
|
||||
applied |= self.select(&path, state);
|
||||
}
|
||||
applied
|
||||
}
|
||||
|
||||
pub fn update_full(&mut self, files: Vec<File>) {
|
||||
self.ticket = FILES_TICKET.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
|
|
@ -379,16 +316,6 @@ impl Files {
|
|||
|
||||
impl Files {
|
||||
// --- Items
|
||||
pub fn pick(&self, indices: &BTreeSet<usize>) -> Vec<&File> {
|
||||
let mut items = Vec::with_capacity(indices.len());
|
||||
for (i, item) in self.iter().enumerate() {
|
||||
if indices.contains(&i) {
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
items
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn position(&self, url: &Url) -> Option<usize> { self.iter().position(|f| &f.url == url) }
|
||||
|
||||
|
|
@ -396,45 +323,6 @@ impl Files {
|
|||
#[inline]
|
||||
pub fn ticket(&self) -> u64 { self.ticket }
|
||||
|
||||
// --- Selected
|
||||
pub fn selected(&self, pending: &BTreeSet<usize>, unset: bool) -> Vec<&File> {
|
||||
if self.selected.is_empty() && (unset || pending.is_empty()) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let selected: BTreeSet<_> = self.selected.iter().collect();
|
||||
let pending: BTreeSet<_> =
|
||||
pending.iter().filter_map(|&i| self.items.get(i)).map(|f| &f.url).collect();
|
||||
|
||||
let selected: BTreeSet<_> = if unset {
|
||||
selected.difference(&pending).cloned().collect()
|
||||
} else {
|
||||
selected.union(&pending).cloned().collect()
|
||||
};
|
||||
|
||||
let mut items = Vec::with_capacity(selected.len());
|
||||
for item in &self.items {
|
||||
if selected.contains(&item.url) {
|
||||
items.push(item);
|
||||
}
|
||||
if items.len() == selected.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
items
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_selected(&self, url: &Url) -> bool { self.selected.contains(url) }
|
||||
|
||||
#[inline]
|
||||
pub fn has_selected(&self) -> bool {
|
||||
if self.selected.is_empty() {
|
||||
return false;
|
||||
}
|
||||
self.iter().any(|f| self.selected.contains(&f.url))
|
||||
}
|
||||
|
||||
// --- Sorter
|
||||
#[inline]
|
||||
pub fn sorter(&self) -> &FilesSorter { &self.sorter }
|
||||
|
|
|
|||
|
|
@ -33,16 +33,30 @@ impl Tab {
|
|||
|
||||
#[inline]
|
||||
fn escape_visual(&mut self) -> bool {
|
||||
if let Some((_, indices)) = self.mode.visual() {
|
||||
self.current.files.select_index(indices, Some(self.mode.is_select()));
|
||||
self.mode = Mode::Normal;
|
||||
return true;
|
||||
let Some((_, indices)) = self.mode.visual() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let state = self.mode.is_select();
|
||||
for f in indices.iter().filter_map(|i| self.current.files.get(*i)) {
|
||||
if state {
|
||||
self.selected.insert(f.url());
|
||||
} else {
|
||||
self.selected.remove(&f.url);
|
||||
}
|
||||
}
|
||||
false
|
||||
|
||||
self.mode = Mode::Normal;
|
||||
render!();
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn escape_select(&mut self) -> bool { self.current.files.select_all(Some(false)) }
|
||||
fn escape_select(&mut self) -> bool {
|
||||
let old = self.selected.len();
|
||||
self.select_all(Some(false));
|
||||
old != self.selected.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn escape_filter(&mut self) -> bool {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ mod preview;
|
|||
mod reveal;
|
||||
mod search;
|
||||
mod select;
|
||||
mod select_all;
|
||||
mod shell;
|
||||
mod sort;
|
||||
mod visual_mode;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
use yazi_shared::{event::Cmd, render};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use yazi_shared::{event::Cmd, fs::Url, render};
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt {
|
||||
pub struct Opt<'a> {
|
||||
url: Option<Cow<'a, Url>>,
|
||||
state: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<Cmd> for Opt {
|
||||
fn from(c: Cmd) -> Self {
|
||||
impl<'a> From<Cmd> for Opt<'a> {
|
||||
fn from(mut c: Cmd) -> Self {
|
||||
Self {
|
||||
url: c.take_name("url").map(|s| Cow::Owned(Url::from(s))),
|
||||
state: match c.named.get("state").map(|s| s.as_str()) {
|
||||
Some("true") => Some(true),
|
||||
Some("false") => Some(false),
|
||||
|
|
@ -17,18 +21,19 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<Option<bool>> for Opt {
|
||||
fn from(state: Option<bool>) -> Self { Self { state } }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn select(&mut self, opt: impl Into<Opt>) {
|
||||
if let Some(u) = self.current.hovered().map(|h| h.url()) {
|
||||
render!(self.current.files.select(&u, opt.into().state));
|
||||
}
|
||||
}
|
||||
impl<'a> Tab {
|
||||
pub fn select(&mut self, opt: impl Into<Opt<'a>>) {
|
||||
let opt = opt.into() as Opt;
|
||||
let Some(url) = opt.url.or_else(|| self.current.hovered().map(|h| Cow::Borrowed(&h.url)))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
pub fn select_all(&mut self, opt: impl Into<Opt>) {
|
||||
render!(self.current.files.select_all(opt.into().state));
|
||||
render!(match opt.state {
|
||||
Some(true) => self.selected.insert(url.into_owned()),
|
||||
Some(false) => self.selected.remove(&url),
|
||||
None => self.selected.remove(&url) || self.selected.insert(url.into_owned()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
46
yazi-core/src/tab/commands/select_all.rs
Normal file
46
yazi-core/src/tab/commands/select_all.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use yazi_shared::{event::Cmd, render};
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt {
|
||||
state: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<Cmd> for Opt {
|
||||
fn from(c: Cmd) -> Self {
|
||||
Self {
|
||||
state: match c.named.get("state").map(|s| s.as_str()) {
|
||||
Some("true") => Some(true),
|
||||
Some("false") => Some(false),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<Option<bool>> for Opt {
|
||||
fn from(state: Option<bool>) -> Self { Self { state } }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn select_all(&mut self, opt: impl Into<Opt>) {
|
||||
let mut b = false;
|
||||
match opt.into().state {
|
||||
Some(true) => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.insert(f.url());
|
||||
}
|
||||
}
|
||||
Some(false) => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.remove(&f.url);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for f in self.current.files.iter() {
|
||||
b |= self.selected.remove(&f.url) || self.selected.insert(f.url());
|
||||
}
|
||||
}
|
||||
}
|
||||
render!(b);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{borrow::Cow, collections::BTreeMap};
|
||||
use std::{borrow::Cow, collections::{BTreeMap, BTreeSet}};
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::task::JoinHandle;
|
||||
|
|
@ -15,6 +15,7 @@ pub struct Tab {
|
|||
|
||||
pub backstack: Backstack<Url>,
|
||||
pub history: BTreeMap<Url, Folder>,
|
||||
pub selected: BTreeSet<Url>,
|
||||
|
||||
pub preview: Preview,
|
||||
pub finder: Option<Finder>,
|
||||
|
|
@ -32,6 +33,7 @@ impl From<Url> for Tab {
|
|||
|
||||
backstack: Backstack::new(url),
|
||||
history: Default::default(),
|
||||
selected: Default::default(),
|
||||
|
||||
preview: Default::default(),
|
||||
finder: None,
|
||||
|
|
@ -47,26 +49,45 @@ impl From<&Url> for Tab {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
// --- Mode
|
||||
#[inline]
|
||||
pub fn in_selecting(&self) -> bool { self.mode.is_visual() || self.current.files.has_selected() }
|
||||
|
||||
// --- Current
|
||||
#[inline]
|
||||
pub fn in_selecting(&self) -> bool {
|
||||
!self.selected.is_empty() || self.mode.visual().is_some_and(|(_, indices)| !indices.is_empty())
|
||||
}
|
||||
|
||||
pub fn selected(&self) -> Vec<&File> {
|
||||
let pending = self.mode.visual().map(|(_, p)| Cow::Borrowed(p)).unwrap_or_default();
|
||||
let selected = self.current.files.selected(&pending, self.mode.is_unset());
|
||||
|
||||
if selected.is_empty() {
|
||||
self.current.hovered().map(|h| vec![h]).unwrap_or_default()
|
||||
} else {
|
||||
selected
|
||||
let is_unset = self.mode.is_unset();
|
||||
if self.selected.is_empty() && (is_unset || pending.is_empty()) {
|
||||
return self.current.hovered().map(|h| vec![h]).unwrap_or_default();
|
||||
}
|
||||
|
||||
let selected: BTreeSet<_> = self.selected.iter().collect();
|
||||
let pending: BTreeSet<_> =
|
||||
pending.iter().filter_map(|&i| self.current.files.get(i)).map(|f| &f.url).collect();
|
||||
|
||||
let urls: BTreeSet<_> = if is_unset {
|
||||
selected.difference(&pending).copied().collect()
|
||||
} else {
|
||||
selected.union(&pending).copied().collect()
|
||||
};
|
||||
|
||||
let mut items = Vec::with_capacity(urls.len());
|
||||
for item in self.current.files.iter() {
|
||||
if urls.contains(&item.url) {
|
||||
items.push(item);
|
||||
if items.len() == urls.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(items)
|
||||
.filter(|v| !v.is_empty())
|
||||
.or_else(|| self.current.hovered().map(|h| vec![h]))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// --- History
|
||||
#[inline]
|
||||
pub fn history(&self, url: &Url) -> Option<&Folder> { self.history.get(url) }
|
||||
|
||||
#[inline]
|
||||
pub fn history_new(&mut self, url: &Url) -> Folder {
|
||||
self.history.remove(url).unwrap_or_else(|| Folder::from(url))
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use super::{CtxRef, SCOPE};
|
|||
pub(super) struct File {
|
||||
idx: usize,
|
||||
folder: *const yazi_core::folder::Folder,
|
||||
tab: *const yazi_core::tab::Tab,
|
||||
}
|
||||
|
||||
impl Deref for File {
|
||||
|
|
@ -23,8 +24,9 @@ impl File {
|
|||
pub(super) fn make(
|
||||
idx: usize,
|
||||
folder: &yazi_core::folder::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData<'static>> {
|
||||
SCOPE.create_any_userdata(Self { idx, folder })
|
||||
SCOPE.create_any_userdata(Self { idx, folder, tab })
|
||||
}
|
||||
|
||||
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
|
|
@ -84,7 +86,7 @@ impl File {
|
|||
});
|
||||
reg.add_method("is_selected", |lua, me, ()| {
|
||||
let cx = lua.named_registry_value::<CtxRef>("cx")?;
|
||||
let selected = me.folder().files.is_selected(&me.url);
|
||||
let selected = me.tab().selected.contains(&me.url);
|
||||
|
||||
Ok(if !cx.manager.active().mode.is_visual() {
|
||||
selected
|
||||
|
|
@ -124,4 +126,7 @@ impl File {
|
|||
|
||||
#[inline]
|
||||
fn folder(&self) -> &yazi_core::folder::Folder { unsafe { &*self.folder } }
|
||||
|
||||
#[inline]
|
||||
fn tab(&self) -> &yazi_core::tab::Tab { unsafe { &*self.tab } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ use mlua::{AnyUserData, Lua, MetaMethod, UserDataMethods};
|
|||
use super::{File, SCOPE};
|
||||
|
||||
pub(super) struct Files {
|
||||
folder: *const yazi_core::folder::Folder,
|
||||
window: Range<usize>,
|
||||
folder: *const yazi_core::folder::Folder,
|
||||
tab: *const yazi_core::tab::Tab,
|
||||
}
|
||||
|
||||
impl Deref for Files {
|
||||
|
|
@ -18,10 +19,11 @@ impl Deref for Files {
|
|||
impl Files {
|
||||
#[inline]
|
||||
pub(super) fn make(
|
||||
folder: &yazi_core::folder::Folder,
|
||||
window: Range<usize>,
|
||||
folder: &yazi_core::folder::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData<'static>> {
|
||||
SCOPE.create_any_userdata(Self { folder, window })
|
||||
SCOPE.create_any_userdata(Self { window, folder, tab })
|
||||
}
|
||||
|
||||
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
|
|
@ -33,7 +35,7 @@ impl Files {
|
|||
if idx > me.window.end || idx == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(File::make(idx - 1, me.folder())).transpose()
|
||||
Some(File::make(idx - 1, me.folder(), me.tab())).transpose()
|
||||
}
|
||||
});
|
||||
})?;
|
||||
|
|
@ -43,4 +45,7 @@ impl Files {
|
|||
|
||||
#[inline]
|
||||
fn folder(&self) -> &yazi_core::folder::Folder { unsafe { &*self.folder } }
|
||||
|
||||
#[inline]
|
||||
fn tab(&self) -> &yazi_core::tab::Tab { unsafe { &*self.tab } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ use yazi_plugin::{bindings::Cast, url::Url};
|
|||
use super::{File, Files, SCOPE};
|
||||
|
||||
pub(super) struct Folder {
|
||||
inner: *const yazi_core::folder::Folder,
|
||||
window: Range<usize>,
|
||||
inner: *const yazi_core::folder::Folder,
|
||||
tab: *const yazi_core::tab::Tab,
|
||||
}
|
||||
|
||||
impl Deref for Folder {
|
||||
|
|
@ -20,8 +21,9 @@ impl Deref for Folder {
|
|||
impl Folder {
|
||||
#[inline]
|
||||
pub(super) fn make(
|
||||
inner: &yazi_core::folder::Folder,
|
||||
window: Option<Range<usize>>,
|
||||
inner: &yazi_core::folder::Folder,
|
||||
tab: &yazi_core::tab::Tab,
|
||||
) -> mlua::Result<AnyUserData<'static>> {
|
||||
let window = match window {
|
||||
Some(w) => w,
|
||||
|
|
@ -31,20 +33,20 @@ impl Folder {
|
|||
}
|
||||
};
|
||||
|
||||
SCOPE.create_any_userdata(Self { inner, window })
|
||||
SCOPE.create_any_userdata(Self { window, inner, tab })
|
||||
}
|
||||
|
||||
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<Self>(|reg| {
|
||||
reg.add_field_method_get("cwd", |lua, me| Url::cast(lua, me.cwd.clone()));
|
||||
reg.add_field_method_get("files", |_, me| Files::make(me, 0..me.files.len()));
|
||||
reg.add_field_method_get("files", |_, me| Files::make(0..me.files.len(), me, me.tab()));
|
||||
reg.add_field_method_get("stage", |lua, me| lua.create_any_userdata(me.stage));
|
||||
reg.add_field_method_get("window", |_, me| Files::make(me, me.window.clone()));
|
||||
reg.add_field_method_get("window", |_, me| Files::make(me.window.clone(), me, me.tab()));
|
||||
|
||||
reg.add_field_method_get("offset", |_, me| Ok(me.offset));
|
||||
reg.add_field_method_get("cursor", |_, me| Ok(me.cursor));
|
||||
reg.add_field_method_get("hovered", |_, me| {
|
||||
me.hovered().map(|_| File::make(me.cursor, me)).transpose()
|
||||
me.hovered().map(|_| File::make(me.cursor, me, me.tab())).transpose()
|
||||
});
|
||||
})?;
|
||||
|
||||
|
|
@ -61,4 +63,7 @@ impl Folder {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn tab(&self) -> &yazi_core::tab::Tab { unsafe { &*self.tab } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ impl Preview {
|
|||
.current
|
||||
.hovered()
|
||||
.filter(|&f| f.is_dir())
|
||||
.and_then(|f| me.tab().history(&f.url))
|
||||
.and_then(|f| me.tab().history.get(&f.url))
|
||||
.map(|f| {
|
||||
let limit = LAYOUT.load().preview.height as usize;
|
||||
Folder::make(f, Some(me.skip..f.files.len().min(me.skip + limit)))
|
||||
Folder::make(Some(me.skip..f.files.len().min(me.skip + limit)), f, me.tab())
|
||||
})
|
||||
.transpose()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ impl Tab {
|
|||
reg.add_field_method_get("mode", |_, me| Mode::make(&me.mode));
|
||||
reg.add_field_method_get("conf", |_, me| Config::make(&me.conf));
|
||||
reg.add_field_method_get("parent", |_, me| {
|
||||
me.parent.as_ref().map(|f| Folder::make(f, None)).transpose()
|
||||
me.parent.as_ref().map(|f| Folder::make(None, f, me)).transpose()
|
||||
});
|
||||
reg.add_field_method_get("current", |_, me| Folder::make(&me.current, None));
|
||||
reg.add_field_method_get("current", |_, me| Folder::make(None, &me.current, me));
|
||||
reg.add_field_method_get("preview", |_, me| Preview::make(me));
|
||||
})?;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ function Header:cwd()
|
|||
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))
|
||||
span = ui.Span(string.format("%s (search: %s)", ya.readable_path(tostring(cwd)), cwd:frag()))
|
||||
end
|
||||
return span:style(THEME.manager.cwd)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,17 +9,26 @@ pub struct Url;
|
|||
impl Url {
|
||||
pub fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<yazi_shared::fs::Url>(|reg| {
|
||||
reg.add_field_method_get("frag", |lua, me| lua.create_string(me.frag()));
|
||||
reg.add_method("frag", |lua, me, ()| lua.create_string(me.frag()));
|
||||
reg.add_field_method_get("is_regular", |_, me| Ok(me.is_regular()));
|
||||
reg.add_field_method_get("is_search", |_, me| Ok(me.is_search()));
|
||||
reg.add_field_method_get("is_archive", |_, me| Ok(me.is_archive()));
|
||||
|
||||
reg.add_meta_method(MetaMethod::Eq, |_, me, other: UrlRef| Ok(me == &*other));
|
||||
reg.add_method("name", |lua, me, ()| {
|
||||
me.file_name().map(|s| lua.create_string(s.as_encoded_bytes())).transpose()
|
||||
});
|
||||
reg.add_method("stem", |lua, me, ()| {
|
||||
me.file_stem().map(|s| lua.create_string(s.as_encoded_bytes())).transpose()
|
||||
});
|
||||
reg.add_method("join", |lua, me, other: UrlRef| Self::cast(lua, me.join(&*other)));
|
||||
reg.add_method("parent", |lua, me, ()| {
|
||||
me.parent_url().map(|u| Self::cast(lua, u)).transpose()
|
||||
});
|
||||
|
||||
reg.add_meta_method(MetaMethod::Eq, |_, me, other: UrlRef| Ok(me == &*other));
|
||||
reg.add_meta_method(MetaMethod::ToString, |lua, me, ()| {
|
||||
lua.create_string(me.as_os_str().as_encoded_bytes())
|
||||
});
|
||||
|
||||
reg.add_meta_method(MetaMethod::Concat, |lua, me, other: mlua::String| {
|
||||
let me = me.as_os_str().as_encoded_bytes();
|
||||
let other = other.as_bytes();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue