mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
146 lines
3 KiB
Rust
146 lines
3 KiB
Rust
use anyhow::{Result, bail};
|
|
use yazi_macro::{act, render, render_and, succ};
|
|
use yazi_parser::{VoidOpt, mgr::EscapeOpt};
|
|
use yazi_proxy::AppProxy;
|
|
use yazi_shared::event::Data;
|
|
|
|
use crate::{Actor, Ctx};
|
|
|
|
pub struct Escape;
|
|
|
|
impl Actor for Escape {
|
|
type Options = EscapeOpt;
|
|
|
|
const NAME: &str = "escape";
|
|
|
|
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
|
if opt.is_empty() {
|
|
_ = act!(mgr:escape_find, cx)? != false
|
|
|| act!(mgr:escape_visual, cx)? != false
|
|
|| act!(mgr:escape_filter, cx)? != false
|
|
|| act!(mgr:escape_select, cx)? != false
|
|
|| act!(mgr:escape_search, cx)? != false;
|
|
succ!();
|
|
}
|
|
|
|
if opt.contains(EscapeOpt::FIND) {
|
|
act!(mgr:escape_find, cx)?;
|
|
}
|
|
if opt.contains(EscapeOpt::VISUAL) {
|
|
act!(mgr:escape_visual, cx)?;
|
|
}
|
|
if opt.contains(EscapeOpt::FILTER) {
|
|
act!(mgr:escape_filter, cx)?;
|
|
}
|
|
if opt.contains(EscapeOpt::SELECT) {
|
|
act!(mgr:escape_select, cx)?;
|
|
}
|
|
if opt.contains(EscapeOpt::SEARCH) {
|
|
act!(mgr:escape_search, cx)?;
|
|
}
|
|
succ!();
|
|
}
|
|
}
|
|
|
|
// --- Find
|
|
pub struct EscapeFind;
|
|
|
|
impl Actor for EscapeFind {
|
|
type Options = VoidOpt;
|
|
|
|
const NAME: &str = "escape_find";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
|
succ!(render_and!(cx.tab_mut().finder.take().is_some()))
|
|
}
|
|
}
|
|
|
|
// --- Visual
|
|
pub struct EscapeVisual;
|
|
|
|
impl Actor for EscapeVisual {
|
|
type Options = VoidOpt;
|
|
|
|
const NAME: &str = "escape_visual";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
|
let tab = cx.tab_mut();
|
|
|
|
let select = tab.mode.is_select();
|
|
let Some((_, indices)) = tab.mode.take_visual() else { succ!(false) };
|
|
|
|
render!();
|
|
let urls: Vec<_> =
|
|
indices.into_iter().filter_map(|i| tab.current.files.get(i)).map(|f| &f.url).collect();
|
|
|
|
if !select {
|
|
tab.selected.remove_many(&urls);
|
|
} else if tab.selected.add_many(&urls) != urls.len() {
|
|
AppProxy::notify_warn(
|
|
"Escape visual mode",
|
|
"Some files cannot be selected, due to path nesting conflict.",
|
|
);
|
|
bail!("Some files cannot be selected, due to path nesting conflict.");
|
|
}
|
|
|
|
succ!(true)
|
|
}
|
|
}
|
|
|
|
// --- Filter
|
|
pub struct EscapeFilter;
|
|
|
|
impl Actor for EscapeFilter {
|
|
type Options = VoidOpt;
|
|
|
|
const NAME: &str = "escape_filter";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
|
if cx.current_mut().files.filter().is_none() {
|
|
succ!(false);
|
|
}
|
|
|
|
act!(mgr:filter_do, cx)?;
|
|
render!();
|
|
succ!(true);
|
|
}
|
|
}
|
|
|
|
// --- Select
|
|
pub struct EscapeSelect;
|
|
|
|
impl Actor for EscapeSelect {
|
|
type Options = VoidOpt;
|
|
|
|
const NAME: &str = "escape_select";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
|
let tab = cx.tab_mut();
|
|
if tab.selected.is_empty() {
|
|
succ!(false);
|
|
}
|
|
|
|
tab.selected.clear();
|
|
if tab.hovered().is_some_and(|h| h.is_dir()) {
|
|
act!(mgr:peek, cx, true)?;
|
|
}
|
|
|
|
render!();
|
|
succ!(true);
|
|
}
|
|
}
|
|
|
|
// --- Search
|
|
pub struct EscapeSearch;
|
|
|
|
impl Actor for EscapeSearch {
|
|
type Options = VoidOpt;
|
|
|
|
const NAME: &str = "escape_search";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Options) -> Result<Data> {
|
|
let b = cx.cwd().is_search();
|
|
act!(mgr:search_stop, cx)?;
|
|
succ!(render_and!(b));
|
|
}
|
|
}
|