refactor: derive the Into<Opt> trait with procedural macros to avoid bloat (#1742)

This commit is contained in:
三咲雅 · Misaki Masa 2024-10-07 22:04:38 +08:00 committed by GitHub
parent dcbe7873cd
commit 064517665d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 360 additions and 266 deletions

10
Cargo.lock generated
View file

@ -3310,6 +3310,7 @@ dependencies = [
"yazi-config",
"yazi-dds",
"yazi-fs",
"yazi-macro",
"yazi-plugin",
"yazi-proxy",
"yazi-scheduler",
@ -3362,6 +3363,7 @@ dependencies = [
"yazi-core",
"yazi-dds",
"yazi-fs",
"yazi-macro",
"yazi-plugin",
"yazi-proxy",
"yazi-shared",
@ -3381,6 +3383,14 @@ dependencies = [
"yazi-shared",
]
[[package]]
name = "yazi-macro"
version = "0.3.3"
dependencies = [
"quote",
"syn 2.0.79",
]
[[package]]
name = "yazi-plugin"
version = "0.3.3"

View file

@ -14,6 +14,7 @@ yazi-boot = { path = "../yazi-boot", version = "0.3.3" }
yazi-config = { path = "../yazi-config", version = "0.3.3" }
yazi-dds = { path = "../yazi-dds", version = "0.3.3" }
yazi-fs = { path = "../yazi-fs", version = "0.3.3" }
yazi-macro = { path = "../yazi-macro", version = "0.3.3" }
yazi-plugin = { path = "../yazi-plugin", version = "0.3.3" }
yazi-proxy = { path = "../yazi-proxy", version = "0.3.3" }
yazi-scheduler = { path = "../yazi-scheduler", version = "0.3.3" }

View file

@ -11,6 +11,15 @@ impl From<Cmd> for Opt {
}
impl Completion {
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt) {
if opt.step > 0 {
self.next(opt.step as usize);
} else {
self.prev(opt.step.unsigned_abs());
}
}
fn next(&mut self, step: usize) {
let len = self.cands.len();
if len == 0 {
@ -38,13 +47,4 @@ impl Completion {
render!(old != self.cursor);
}
pub fn arrow(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if opt.step > 0 {
self.next(opt.step as usize);
} else {
self.prev(opt.step.unsigned_abs());
}
}
}

View file

@ -15,9 +15,8 @@ impl From<bool> for Opt {
}
impl Completion {
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn close(&mut self, opt: Opt) {
if let Some(s) = self.selected().filter(|_| opt.submit) {
InputProxy::complete(s, self.ticket);
}

View file

@ -25,6 +25,31 @@ impl From<Cmd> for Opt {
}
impl Completion {
#[yazi_macro::command]
pub fn show(&mut self, opt: Opt) {
if self.ticket != opt.ticket {
return;
}
if !opt.cache.is_empty() {
self.caches.insert(opt.cache_name.to_owned(), opt.cache);
}
let Some(cache) = self.caches.get(&opt.cache_name) else {
return;
};
self.ticket = opt.ticket;
self.cands = Self::match_candidates(&opt.word, cache);
if self.cands.is_empty() {
return render!(mem::replace(&mut self.visible, false));
}
self.offset = 0;
self.cursor = 0;
self.visible = true;
render!();
}
fn match_candidates(word: &str, cache: &[String]) -> Vec<String> {
let smart = !word.bytes().any(|c| c.is_ascii_uppercase());
@ -55,29 +80,4 @@ impl Completion {
}
prefixed.into_iter().map(ToOwned::to_owned).collect()
}
pub fn show(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if self.ticket != opt.ticket {
return;
}
if !opt.cache.is_empty() {
self.caches.insert(opt.cache_name.to_owned(), opt.cache);
}
let Some(cache) = self.caches.get(&opt.cache_name) else {
return;
};
self.ticket = opt.ticket;
self.cands = Self::match_candidates(&opt.word, cache);
if self.cands.is_empty() {
return render!(mem::replace(&mut self.visible, false));
}
self.offset = 0;
self.cursor = 0;
self.visible = true;
render!();
}
}

View file

@ -26,8 +26,8 @@ impl From<Cmd> for Opt {
}
impl Completion {
pub fn trigger(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn trigger(&mut self, opt: Opt) {
if opt.ticket < self.ticket {
return;
}

View file

@ -11,6 +11,15 @@ impl From<Cmd> for Opt {
}
impl Confirm {
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt, manager: &Manager) {
if opt.step > 0 {
self.next(opt.step as usize, manager.area(self.position).width)
} else {
self.prev(opt.step.unsigned_abs())
}
}
fn next(&mut self, step: usize, width: u16) {
let height = self.list.line_count(width);
if height == 0 {
@ -29,13 +38,4 @@ impl Confirm {
render!(old != self.offset);
}
pub fn arrow(&mut self, opt: impl Into<Opt>, manager: &Manager) {
let opt = opt.into() as Opt;
if opt.step > 0 {
self.next(opt.step as usize, manager.area(self.position).width)
} else {
self.prev(opt.step.unsigned_abs())
}
}
}

View file

@ -14,8 +14,8 @@ impl From<bool> for Opt {
}
impl Confirm {
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn close(&mut self, opt: Opt) {
if let Some(cb) = self.callback.take() {
_ = cb.send(opt.submit);
}

View file

@ -14,13 +14,12 @@ impl From<isize> for Opt {
}
impl Help {
#[inline]
pub fn arrow(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt) {
let max = self.bindings.len().saturating_sub(1);
self.offset = self.offset.min(max);
self.cursor = self.cursor.min(max);
let opt = opt.into() as Opt;
if opt.step > 0 {
self.next(opt.step as usize);
} else {

View file

@ -14,9 +14,9 @@ impl From<bool> for Opt {
}
impl Input {
pub fn backspace(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn backspace(&mut self, opt: Opt) {
let snap = self.snaps.current_mut();
let opt = opt.into() as Opt;
if !opt.under && snap.cursor < 1 {
return;
} else if opt.under && snap.cursor >= snap.value.len() {

View file

@ -15,9 +15,8 @@ impl From<bool> for Opt {
}
impl Input {
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn close(&mut self, opt: Opt) {
if self.completion {
CompletionProxy::close();
}

View file

@ -25,8 +25,8 @@ impl From<Cmd> for Opt {
}
impl Input {
pub fn complete(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn complete(&mut self, opt: Opt) {
if self.ticket != opt.ticket {
return;
}

View file

@ -12,8 +12,8 @@ impl From<Cmd> for Opt {
}
impl Input {
pub fn delete(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn delete(&mut self, opt: Opt) {
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Delete(opt.cut, opt.insert, self.snap().cursor);

View file

@ -13,7 +13,8 @@ impl From<()> for Opt {
}
impl Input {
pub fn escape(&mut self, _: impl Into<Opt>) {
#[yazi_macro::command]
pub fn escape(&mut self, _: Opt) {
let snap = self.snap_mut();
match snap.mode {
InputMode::Normal if snap.op == InputOp::None => {

View file

@ -11,8 +11,8 @@ impl From<Cmd> for Opt {
}
impl Input {
pub fn forward(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn forward(&mut self, opt: Opt) {
let snap = self.snap();
let mut it = snap.value.chars().skip(snap.cursor).enumerate();

View file

@ -14,7 +14,8 @@ impl From<bool> for Opt {
}
impl Input {
pub fn insert(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn insert(&mut self, opt: Opt) {
let snap = self.snap_mut();
if snap.mode == InputMode::Normal {
snap.op = InputOp::None;
@ -23,7 +24,6 @@ impl Input {
return;
}
let opt = opt.into() as Opt;
if opt.append {
self.move_(1);
}

View file

@ -13,6 +13,33 @@ impl From<Cmd> for Opt {
}
impl Input {
#[yazi_macro::command]
pub fn kill(&mut self, opt: Opt) {
let snap = self.snap_mut();
match opt.kind.as_str() {
"all" => self.kill_range(..),
"bol" => {
let end = snap.idx(snap.cursor).unwrap_or(snap.len());
self.kill_range(..end)
}
"eol" => {
let start = snap.idx(snap.cursor).unwrap_or(snap.len());
self.kill_range(start..)
}
"backward" => {
let end = snap.idx(snap.cursor).unwrap_or(snap.len());
let start = end - Self::find_word_boundary(snap.value[..end].chars().rev());
self.kill_range(start..end)
}
"forward" => {
let start = snap.idx(snap.cursor).unwrap_or(snap.len());
let end = start + Self::find_word_boundary(snap.value[start..].chars());
self.kill_range(start..end)
}
_ => {}
}
}
fn kill_range(&mut self, range: impl RangeBounds<usize>) {
let snap = self.snap_mut();
snap.cursor = match range.start_bound() {
@ -64,32 +91,4 @@ impl Input {
let n = n + count_characters(input.clone().skip(n));
input.take(n).fold(0, |acc, c| acc + c.len_utf8())
}
pub fn kill(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let snap = self.snap_mut();
match opt.kind.as_str() {
"all" => self.kill_range(..),
"bol" => {
let end = snap.idx(snap.cursor).unwrap_or(snap.len());
self.kill_range(..end)
}
"eol" => {
let start = snap.idx(snap.cursor).unwrap_or(snap.len());
self.kill_range(start..)
}
"backward" => {
let end = snap.idx(snap.cursor).unwrap_or(snap.len());
let start = end - Self::find_word_boundary(snap.value[..end].chars().rev());
self.kill_range(start..end)
}
"forward" => {
let start = snap.idx(snap.cursor).unwrap_or(snap.len());
let end = start + Self::find_word_boundary(snap.value[start..].chars());
self.kill_range(start..end)
}
_ => {}
}
}
}

View file

@ -21,9 +21,8 @@ impl From<isize> for Opt {
}
impl Input {
pub fn move_(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn move_(&mut self, opt: Opt) {
let snap = self.snap();
if opt.in_operating && snap.op == InputOp::None {
return;

View file

@ -12,7 +12,8 @@ impl From<Cmd> for Opt {
}
impl Input {
pub fn paste(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn paste(&mut self, opt: Opt) {
if let Some(start) = self.snap().op.start() {
self.snap_mut().op = InputOp::Delete(false, false, start);
self.handle_op(self.snap().cursor, true);
@ -23,7 +24,6 @@ impl Input {
return;
}
let opt = opt.into() as Opt;
self.insert(!opt.before);
self.type_str(&s.to_string_lossy());
self.escape(());

View file

@ -18,8 +18,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn create(&self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn create(&self, opt: Opt) {
let cwd = self.cwd().to_owned();
tokio::spawn(async move {
let mut result = InputProxy::show(InputCfg::create(opt.dir));

View file

@ -12,12 +12,12 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn hardlink(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
#[yazi_macro::command]
pub fn hardlink(&mut self, opt: Opt, tasks: &Tasks) {
if self.yanked.cut {
return;
}
let opt = opt.into() as Opt;
tasks.file_hardlink(&self.yanked, self.cwd(), opt.force, opt.follow);
}
}

View file

@ -23,8 +23,8 @@ impl From<Option<Url>> for Opt {
}
impl Manager {
pub fn hover(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn hover(&mut self, opt: Opt) {
if let Some(u) = opt.url {
self.hover_do(u, opt.tab);
} else {

View file

@ -12,12 +12,12 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn link(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
#[yazi_macro::command]
pub fn link(&mut self, opt: Opt, tasks: &Tasks) {
if self.yanked.cut {
return;
}
let opt = opt.into() as Opt;
tasks.file_link(&self.yanked, self.cwd(), opt.relative, opt.force);
}
}

View file

@ -23,7 +23,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn open(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
#[yazi_macro::command]
pub fn open(&mut self, opt: Opt, tasks: &Tasks) {
if !self.active_mut().try_escape_visual() {
return;
}
@ -31,7 +32,6 @@ impl Manager {
return;
};
let opt = opt.into() as Opt;
let selected =
if opt.hovered { vec![&hovered] } else { self.selected_or_hovered(true).collect() };
@ -72,8 +72,8 @@ impl Manager {
});
}
pub fn open_do(&mut self, opt: impl Into<OpenDoOpt>, tasks: &Tasks) {
let opt = opt.into() as OpenDoOpt;
#[yazi_macro::command]
pub fn open_do(&mut self, opt: OpenDoOpt, tasks: &Tasks) {
let targets: Vec<_> = opt
.targets
.into_iter()

View file

@ -12,8 +12,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn paste(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn paste(&mut self, opt: Opt, tasks: &Tasks) {
let (src, dest) = (self.yanked.iter().collect::<Vec<_>>(), self.cwd());
if self.yanked.cut {

View file

@ -25,7 +25,8 @@ impl From<bool> for Opt {
}
impl Manager {
pub fn peek(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn peek(&mut self, opt: Opt) {
let Some(hovered) = self.hovered().cloned() else {
return self.active_mut().preview.reset();
};
@ -40,7 +41,6 @@ impl Manager {
self.active_mut().preview.reset();
}
let opt = opt.into() as Opt;
if matches!(opt.only_if, Some(u) if u != hovered.url) {
return;
}

View file

@ -19,8 +19,9 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn quit(&self, opt: impl Into<Opt>, tasks: &Tasks) {
let opt = EventQuit { no_cwd_file: opt.into().no_cwd_file, ..Default::default() };
#[yazi_macro::command]
pub fn quit(&self, opt: Opt, tasks: &Tasks) {
let opt = EventQuit { no_cwd_file: opt.no_cwd_file, ..Default::default() };
let ongoing = tasks.ongoing().clone();
let (left, left_names) = {

View file

@ -23,7 +23,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn remove(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
#[yazi_macro::command]
pub fn remove(&mut self, mut opt: Opt, tasks: &Tasks) {
if !self.active_mut().try_escape_visual() {
return;
}
@ -31,7 +32,6 @@ impl Manager {
return;
};
let mut opt = opt.into() as Opt;
opt.targets = if opt.hovered {
vec![hovered.clone()]
} else {
@ -55,9 +55,8 @@ impl Manager {
});
}
pub fn remove_do(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn remove_do(&mut self, opt: Opt, tasks: &Tasks) {
self.tabs.iter_mut().for_each(|t| {
t.selected.remove_many(&opt.targets, false);
});

View file

@ -28,7 +28,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn rename(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn rename(&mut self, opt: Opt) {
if !self.active_mut().try_escape_visual() {
return;
}
@ -36,7 +37,6 @@ impl Manager {
return;
};
let opt = opt.into() as Opt;
if !opt.hovered && !self.active().selected.is_empty() {
return self.bulk_rename();
}

View file

@ -14,7 +14,8 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn seek(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn seek(&mut self, opt: Opt) {
let Some(hovered) = self.hovered() else {
return self.active_mut().preview.reset();
};
@ -31,7 +32,6 @@ impl Manager {
return self.active_mut().preview.reset();
};
let opt = opt.into() as Opt;
isolate::seek_sync(&previewer.run, hovered.clone(), opt.units);
}
}

View file

@ -15,9 +15,8 @@ impl From<usize> for Opt {
}
impl Tabs {
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn close(&mut self, opt: Opt) {
let len = self.items.len();
if len < 2 || opt.idx >= len {
return;

View file

@ -28,13 +28,13 @@ impl From<Cmd> for Opt {
}
impl Tabs {
pub fn create(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn create(&mut self, opt: Opt) {
if self.items.len() >= MAX_TABS {
AppProxy::notify_warn("Too many tabs", "You can only open up to 9 tabs at the same time.");
return;
}
let opt = opt.into() as Opt;
let mut tab = Tab { idx: self.cursor + 1, ..Default::default() };
if !opt.current {

View file

@ -11,8 +11,9 @@ impl From<Cmd> for Opt {
}
impl Tabs {
pub fn swap(&mut self, opt: impl Into<Opt>) {
let idx = self.absolute(opt.into().step);
#[yazi_macro::command]
pub fn swap(&mut self, opt: Opt) {
let idx = self.absolute(opt.step);
if idx == self.cursor {
return;
}

View file

@ -14,8 +14,8 @@ impl From<Cmd> for Opt {
}
impl Tabs {
pub fn switch(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn switch(&mut self, opt: Opt) {
let idx = if opt.relative {
(self.cursor as isize + opt.step).rem_euclid(self.items.len() as isize) as usize
} else {

View file

@ -12,7 +12,8 @@ impl From<()> for Opt {
}
impl Manager {
pub fn unyank(&mut self, _: impl Into<Opt>) {
#[yazi_macro::command]
pub fn unyank(&mut self, _: Opt) {
self.yanked.clear();
render!(self.yanked.catchup_revision(false));
}

View file

@ -11,12 +11,13 @@ impl From<Cmd> for Opt {
}
impl Manager {
pub fn yank(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn yank(&mut self, opt: Opt) {
if !self.active_mut().try_escape_visual() {
return;
}
self.yanked = Yanked::new(opt.into().cut, self.selected_or_hovered(false).cloned().collect());
self.yanked = Yanked::new(opt.cut, self.selected_or_hovered(false).cloned().collect());
render!(self.yanked.catchup_revision(true));
self.active_mut().escape_select();

View file

@ -11,6 +11,11 @@ impl From<Cmd> for Opt {
}
impl Select {
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt) {
if opt.step > 0 { self.next(opt.step as usize) } else { self.prev(opt.step.unsigned_abs()) }
}
fn next(&mut self, step: usize) {
let len = self.items.len();
if len == 0 {
@ -38,9 +43,4 @@ impl Select {
render!(old != self.cursor);
}
pub fn arrow(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if opt.step > 0 { self.next(opt.step as usize) } else { self.prev(opt.step.unsigned_abs()) }
}
}

View file

@ -15,8 +15,8 @@ impl From<bool> for Opt {
}
impl Select {
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn close(&mut self, opt: Opt) {
if let Some(cb) = self.callback.take() {
_ = cb.send(if opt.submit { Ok(self.cursor) } else { Err(anyhow!("canceled")) });
}

View file

@ -25,8 +25,8 @@ impl From<isize> for Opt {
}
impl Tab {
pub fn arrow(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt) {
if !self.current.arrow(opt.step) {
return;
}

View file

@ -29,12 +29,12 @@ impl From<Url> for Opt {
}
impl Tab {
pub fn cd(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn cd(&mut self, opt: Opt) {
if !self.try_escape_visual() {
return;
}
let opt = opt.into() as Opt;
if opt.interactive {
return self.cd_interactive();
}

View file

@ -14,8 +14,8 @@ impl From<Cmd> for Opt {
}
impl Tab {
pub fn copy(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn copy(&mut self, opt: Opt) {
if !self.try_escape_visual() {
return;
}

View file

@ -31,8 +31,8 @@ impl From<Cmd> for Opt {
}
impl Tab {
pub fn escape(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn escape(&mut self, opt: Opt) {
if opt.is_empty() {
_ = self.escape_find()
|| self.escape_visual()

View file

@ -3,9 +3,9 @@ use std::time::Duration;
use tokio::pin;
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
use yazi_config::popup::InputCfg;
use yazi_fs::{Filter, FilterCase};
use yazi_proxy::{InputProxy, ManagerProxy};
use yazi_shared::{Debounce, InputError, Layer, emit, event::Cmd, render};
use yazi_fs::FilterCase;
use yazi_proxy::InputProxy;
use yazi_shared::{Debounce, InputError, Layer, emit, event::Cmd};
use crate::tab::Tab;
@ -27,8 +27,8 @@ impl From<Cmd> for Opt {
}
impl Tab {
pub fn filter(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn filter(&mut self, opt: Opt) {
tokio::spawn(async move {
let rx = InputProxy::show(InputCfg::filter());
@ -49,32 +49,4 @@ impl Tab {
}
});
}
pub fn filter_do(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let filter = if opt.query.is_empty() {
None
} else if let Ok(f) = Filter::new(&opt.query, opt.case) {
Some(f)
} else {
return;
};
if opt.done {
ManagerProxy::update_paged(); // Update for paged files in next loop
}
let hovered = self.current.hovered().map(|f| f.urn_owned());
if !self.current.files.set_filter(filter) {
return;
}
self.current.repos(hovered.as_ref().map(|u| u.as_urn()));
if self.current.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) {
ManagerProxy::hover(None, self.idx);
}
render!();
}
}

View file

@ -0,0 +1,35 @@
use yazi_fs::Filter;
use yazi_proxy::ManagerProxy;
use yazi_shared::render;
use super::filter::Opt;
use crate::tab::Tab;
impl Tab {
#[yazi_macro::command]
pub fn filter_do(&mut self, opt: Opt) {
let filter = if opt.query.is_empty() {
None
} else if let Ok(f) = Filter::new(&opt.query, opt.case) {
Some(f)
} else {
return;
};
if opt.done {
ManagerProxy::update_paged(); // Update for paged files in next loop
}
let hovered = self.current.hovered().map(|f| f.urn_owned());
if !self.current.files.set_filter(filter) {
return;
}
self.current.repos(hovered.as_ref().map(|u| u.as_urn()));
if self.current.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) {
ManagerProxy::hover(None, self.idx);
}
render!();
}
}

View file

@ -5,14 +5,14 @@ use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
use yazi_config::popup::InputCfg;
use yazi_fs::FilterCase;
use yazi_proxy::InputProxy;
use yazi_shared::{Debounce, InputError, Layer, emit, event::Cmd, render};
use yazi_shared::{Debounce, InputError, Layer, emit, event::Cmd};
use crate::tab::{Finder, Tab};
use crate::tab::Tab;
pub struct Opt {
query: Option<String>,
prev: bool,
case: FilterCase,
pub(super) query: Option<String>,
pub(super) prev: bool,
pub(super) case: FilterCase,
}
impl From<Cmd> for Opt {
@ -21,17 +21,9 @@ impl From<Cmd> for Opt {
}
}
pub struct ArrowOpt {
prev: bool,
}
impl From<Cmd> for ArrowOpt {
fn from(c: Cmd) -> Self { Self { prev: c.bool("previous") } }
}
impl Tab {
pub fn find(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn find(&mut self, opt: Opt) {
tokio::spawn(async move {
let rx = InputProxy::show(InputCfg::find(opt.prev));
@ -49,48 +41,4 @@ impl Tab {
}
});
}
pub fn find_do(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let Some(query) = opt.query else {
return;
};
if query.is_empty() {
self.escape_find();
return;
}
let Ok(finder) = Finder::new(&query, opt.case) else {
return;
};
if matches!(&self.finder, Some(f) if f.filter == finder.filter) {
return;
}
let step = if opt.prev {
finder.prev(&self.current.files, self.current.cursor, true)
} else {
finder.next(&self.current.files, self.current.cursor, true)
};
if let Some(step) = step {
self.arrow(step);
}
self.finder = Some(finder);
render!();
}
pub fn find_arrow(&mut self, opt: impl Into<ArrowOpt>) {
let Some(finder) = &mut self.finder else {
return;
};
render!(finder.catchup(&self.current.files));
if opt.into().prev {
finder.prev(&self.current.files, self.current.cursor, false).map(|s| self.arrow(s));
} else {
finder.next(&self.current.files, self.current.cursor, false).map(|s| self.arrow(s));
}
}
}

View file

@ -0,0 +1,27 @@
use yazi_shared::{event::Cmd, render};
use crate::tab::Tab;
pub struct Opt {
prev: bool,
}
impl From<Cmd> for Opt {
fn from(c: Cmd) -> Self { Self { prev: c.bool("previous") } }
}
impl Tab {
#[yazi_macro::command]
pub fn find_arrow(&mut self, opt: Opt) {
let Some(finder) = &mut self.finder else {
return;
};
render!(finder.catchup(&self.current.files));
if opt.prev {
finder.prev(&self.current.files, self.current.cursor, false).map(|s| self.arrow(s));
} else {
finder.next(&self.current.files, self.current.cursor, false).map(|s| self.arrow(s));
}
}
}

View file

@ -0,0 +1,37 @@
use yazi_shared::render;
use super::find::Opt;
use crate::tab::{Finder, Tab};
impl Tab {
#[yazi_macro::command]
pub fn find_do(&mut self, opt: Opt) {
let Some(query) = opt.query else {
return;
};
if query.is_empty() {
self.escape_find();
return;
}
let Ok(finder) = Finder::new(&query, opt.case) else {
return;
};
if matches!(&self.finder, Some(f) if f.filter == finder.filter) {
return;
}
let step = if opt.prev {
finder.prev(&self.current.files, self.current.cursor, true)
} else {
finder.next(&self.current.files, self.current.cursor, true)
};
if let Some(step) = step {
self.arrow(step);
}
self.finder = Some(finder);
render!();
}
}

View file

@ -11,7 +11,8 @@ impl From<Cmd> for Opt {
}
impl Tab {
pub fn leave(&mut self, _: impl Into<Opt>) {
#[yazi_macro::command]
pub fn leave(&mut self, _: Opt) {
self
.current
.hovered()

View file

@ -5,7 +5,10 @@ mod copy;
mod enter;
mod escape;
mod filter;
mod filter_do;
mod find;
mod find_arrow;
mod find_do;
mod forward;
mod hidden;
mod leave;

View file

@ -22,9 +22,8 @@ impl From<Url> for Opt {
}
impl Tab {
pub fn reveal(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn reveal(&mut self, opt: Opt) {
let Some(parent) = opt.target.parent_url() else {
return;
};

View file

@ -24,8 +24,8 @@ impl<'a> From<Cmd> for Opt<'a> {
}
impl<'a> Tab {
pub fn select(&mut self, opt: impl Into<Opt<'a>>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn select(&mut self, opt: Opt<'a>) {
let Some(url) = opt.url.or_else(|| self.current.hovered().map(|h| Cow::Borrowed(&h.url)))
else {
return;

View file

@ -23,9 +23,10 @@ impl From<Option<bool>> for Opt {
}
impl Tab {
pub fn select_all(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn select_all(&mut self, opt: Opt) {
let iter = self.current.files.iter().map(|f| &f.url);
let (removal, addition): (Vec<_>, Vec<_>) = match opt.into().state {
let (removal, addition): (Vec<_>, Vec<_>) = match opt.state {
Some(true) => (vec![], iter.collect()),
Some(false) => (iter.collect(), vec![]),
None => iter.partition(|&u| self.selected.contains_key(u)),

View file

@ -13,10 +13,9 @@ impl From<Cmd> for Opt {
}
impl Tab {
pub fn visual_mode(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
#[yazi_macro::command]
pub fn visual_mode(&mut self, opt: Opt) {
let idx = self.current.cursor;
if opt.unset {
self.mode = Mode::Unset(idx, BTreeSet::from([idx]));
} else {

View file

@ -15,9 +15,10 @@ impl From<isize> for Opt {
}
impl Tasks {
pub fn arrow(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn arrow(&mut self, opt: Opt) {
let old = self.cursor;
if opt.into().step > 0 {
if opt.step > 0 {
self.cursor += 1;
} else {
self.cursor = self.cursor.saturating_sub(1);

View file

@ -12,7 +12,8 @@ impl From<()> for Opt {
}
impl Tasks {
pub fn toggle(&mut self, _: impl Into<Opt>) {
#[yazi_macro::command]
pub fn toggle(&mut self, _: Opt) {
self.visible = !self.visible;
if self.visible {

View file

@ -19,6 +19,7 @@ yazi-config = { path = "../yazi-config", version = "0.3.3" }
yazi-core = { path = "../yazi-core", version = "0.3.3" }
yazi-dds = { path = "../yazi-dds", version = "0.3.3" }
yazi-fs = { path = "../yazi-fs", version = "0.3.3" }
yazi-macro = { path = "../yazi-macro", version = "0.3.3" }
yazi-plugin = { path = "../yazi-plugin", version = "0.3.3" }
yazi-proxy = { path = "../yazi-proxy", version = "0.3.3" }
yazi-shared = { path = "../yazi-shared", version = "0.3.3" }

View file

@ -15,9 +15,9 @@ impl From<MouseEvent> for Opt {
}
impl App {
pub(crate) fn mouse(&mut self, opt: impl Into<Opt>) {
let event = (opt.into() as Opt).event;
#[yazi_macro::command]
pub fn mouse(&mut self, opt: Opt) {
let event = opt.event;
let Some(size) = self.term.as_ref().and_then(|t| t.size().ok()) else { return };
let Ok(evt) = yazi_plugin::bindings::MouseEvent::cast(&LUA, event) else { return };

View file

@ -13,7 +13,8 @@ impl From<()> for Opt {
}
impl App {
pub(crate) fn resize(&mut self, _: impl Into<Opt>) {
#[yazi_macro::command]
pub fn resize(&mut self, _: Opt) {
self.cx.manager.active_mut().preview.reset();
self.render();

View file

@ -12,7 +12,8 @@ impl From<Cmd> for Opt {
}
impl App {
pub(crate) fn stop(&mut self, opt: impl Into<Opt>) {
#[yazi_macro::command]
pub fn stop(&mut self, opt: Opt) {
self.cx.manager.active_mut().preview.reset_image();
// We need to destroy the `term` first before stopping the `signals`
@ -20,6 +21,6 @@ impl App {
// while the app is being suspended.
self.term = None;
self.signals.stop(opt.into().tx);
self.signals.stop(opt.tx);
}
}

17
yazi-macro/Cargo.toml Normal file
View file

@ -0,0 +1,17 @@
[package]
name = "yazi-macro"
version = "0.3.3"
edition = "2021"
license = "MIT"
authors = [ "sxyazi <sxyazi@gmail.com>" ]
description = "Yazi macros"
homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi"
[lib]
proc-macro = true
[dependencies]
# External dependencies
syn = "2.0.79"
quote = "1.0.37"

41
yazi-macro/src/lib.rs Normal file
View file

@ -0,0 +1,41 @@
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{FnArg, ItemFn};
#[proc_macro_attribute]
pub fn command(_: TokenStream, item: TokenStream) -> TokenStream {
let mut f: ItemFn = syn::parse(item).unwrap();
let mut ins = f.sig.inputs.clone();
// Turn `opt: Opt` into `opt: impl Into<Opt>`
ins[1] = {
let FnArg::Typed(opt) = &f.sig.inputs[1] else {
panic!("Cannot find the `opt` argument in the function signature.");
};
let opt_ty = &opt.ty;
syn::parse2(quote! { opt: impl Into<#opt_ty> }).unwrap()
};
// Make the original function private and add a public wrapper
assert!(matches!(f.vis, syn::Visibility::Public(_)));
f.vis = syn::Visibility::Inherited;
// Add `__` prefix to the original function name
let name_ori = f.sig.ident;
f.sig.ident = format_ident!("__{}", name_ori);
let name_new = &f.sig.ident;
// Collect the rest of the arguments
let rest_args = ins.iter().skip(2).map(|arg| match arg {
FnArg::Receiver(_) => unreachable!(),
FnArg::Typed(t) => &t.pat,
});
quote! {
#[inline]
pub fn #name_ori(#ins) { self.#name_new(opt.into(), #(#rest_args),*); }
#f
}
.into()
}