mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
refactor: extracting commands into separate files to make them easier to maintain
This commit is contained in:
parent
1bbb323509
commit
1e283682ce
31 changed files with 658 additions and 312 deletions
|
|
@ -1,10 +1,18 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt;
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(_: &Exec) -> Self { Self }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn close(&mut self, tasks: &Tasks) -> bool {
|
||||
pub fn close(&mut self, _: impl Into<Opt>, tasks: &Tasks) -> bool {
|
||||
if self.tabs.len() > 1 {
|
||||
return self.tabs.close(self.tabs.idx);
|
||||
}
|
||||
self.quit(tasks, false)
|
||||
self.quit((), tasks)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,22 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use tokio::fs::{self};
|
||||
use yazi_config::keymap::Exec;
|
||||
use yazi_shared::Url;
|
||||
|
||||
use crate::{emit, files::{File, FilesOp}, input::InputOpt, manager::Manager};
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn create(&self, force: bool) -> bool {
|
||||
pub fn create(&self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
let cwd = self.cwd().to_owned();
|
||||
tokio::spawn(async move {
|
||||
let mut result = emit!(Input(InputOpt::top("Create:")));
|
||||
|
|
@ -15,7 +25,7 @@ impl Manager {
|
|||
};
|
||||
|
||||
let path = cwd.join(&name);
|
||||
if !force && fs::symlink_metadata(&path).await.is_ok() {
|
||||
if !opt.force && fs::symlink_metadata(&path).await.is_ok() {
|
||||
match emit!(Input(InputOpt::top("Overwrite an existing file? (y/N)"))).recv().await {
|
||||
Some(Ok(c)) if c == "y" || c == "Y" => (),
|
||||
_ => return Ok(()),
|
||||
|
|
|
|||
22
yazi-core/src/manager/commands/link.rs
Normal file
22
yazi-core/src/manager/commands/link.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
relative: bool,
|
||||
force: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self { relative: e.named.contains_key("relative"), force: e.named.contains_key("force") }
|
||||
}
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn link(&mut self, opt: impl Into<Opt>, tasks: &Tasks) -> bool {
|
||||
let opt = opt.into();
|
||||
let (cut, ref src) = self.yanked;
|
||||
!cut && tasks.file_link(src, self.cwd(), opt.relative, opt.force)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,16 @@
|
|||
mod close;
|
||||
mod create;
|
||||
mod link;
|
||||
mod open;
|
||||
mod paste;
|
||||
mod peek;
|
||||
mod quit;
|
||||
mod refresh;
|
||||
mod remove;
|
||||
mod rename;
|
||||
mod suspend;
|
||||
mod tab_close;
|
||||
mod tab_create;
|
||||
mod tab_swap;
|
||||
mod tab_switch;
|
||||
mod yank;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,36 @@
|
|||
use yazi_config::OPEN;
|
||||
use std::ffi::OsString;
|
||||
|
||||
use yazi_config::{keymap::Exec, OPEN};
|
||||
use yazi_shared::MIME_DIR;
|
||||
|
||||
use crate::{emit, external, manager::Manager, select::SelectOpt};
|
||||
|
||||
pub struct Opt {
|
||||
interactive: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { interactive: e.named.contains_key("interactive") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn open(&mut self, interactive: bool) -> bool {
|
||||
async fn open_interactive(files: Vec<(OsString, String)>) {
|
||||
let openers = OPEN.common_openers(&files);
|
||||
if openers.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = emit!(Select(SelectOpt::hovered(
|
||||
"Open with:",
|
||||
openers.iter().map(|o| o.desc.clone()).collect()
|
||||
)));
|
||||
|
||||
if let Ok(choice) = result.await {
|
||||
emit!(Open(files, Some(openers[choice].clone())));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let mut files: Vec<_> = self
|
||||
.selected()
|
||||
.into_iter()
|
||||
|
|
@ -20,6 +46,7 @@ impl Manager {
|
|||
return false;
|
||||
}
|
||||
|
||||
let opt = opt.into();
|
||||
tokio::spawn(async move {
|
||||
let todo: Vec<_> = files.iter().filter(|(_, m)| m.is_none()).map(|(u, _)| u).collect();
|
||||
if let Ok(mut mimes) = external::file(&todo).await {
|
||||
|
|
@ -35,23 +62,12 @@ impl Manager {
|
|||
let files: Vec<_> =
|
||||
files.into_iter().filter_map(|(u, m)| m.map(|m| (u.into_os_string(), m))).collect();
|
||||
|
||||
if !interactive {
|
||||
if opt.interactive {
|
||||
Self::open_interactive(files).await;
|
||||
return;
|
||||
}
|
||||
|
||||
emit!(Open(files, None));
|
||||
return;
|
||||
}
|
||||
|
||||
let openers = OPEN.common_openers(&files);
|
||||
if openers.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = emit!(Select(SelectOpt::hovered(
|
||||
"Open with:",
|
||||
openers.iter().map(|o| o.desc.clone()).collect()
|
||||
)));
|
||||
if let Ok(choice) = result.await {
|
||||
emit!(Open(files, Some(openers[choice].clone())));
|
||||
}
|
||||
});
|
||||
false
|
||||
}
|
||||
|
|
|
|||
21
yazi-core/src/manager/commands/paste.rs
Normal file
21
yazi-core/src/manager/commands/paste.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn paste(&mut self, opt: impl Into<Opt>, tasks: &Tasks) -> bool {
|
||||
let dest = self.cwd();
|
||||
let (cut, ref src) = self.yanked;
|
||||
|
||||
let opt = opt.into();
|
||||
if cut { tasks.file_cut(src, dest, opt.force) } else { tasks.file_copy(src, dest, opt.force) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,25 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{emit, input::InputOpt, manager::Manager, tasks::Tasks};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Opt {
|
||||
no_cwd_file: bool,
|
||||
}
|
||||
impl From<()> for Opt {
|
||||
fn from(_: ()) -> Self { Self::default() }
|
||||
}
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { no_cwd_file: e.named.contains_key("no-cwd-file") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn quit(&self, tasks: &Tasks, no_cwd_file: bool) -> bool {
|
||||
pub fn quit(&self, opt: impl Into<Opt>, tasks: &Tasks) -> bool {
|
||||
let opt = opt.into();
|
||||
|
||||
let tasks = tasks.len();
|
||||
if tasks == 0 {
|
||||
emit!(Quit(no_cwd_file));
|
||||
emit!(Quit(opt.no_cwd_file));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +30,7 @@ impl Manager {
|
|||
|
||||
if let Some(Ok(choice)) = result.recv().await {
|
||||
if choice == "y" || choice == "Y" {
|
||||
emit!(Quit(no_cwd_file));
|
||||
emit!(Quit(opt.no_cwd_file));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
25
yazi-core/src/manager/commands/remove.rs
Normal file
25
yazi-core/src/manager/commands/remove.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
permanently: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self {
|
||||
force: e.named.contains_key("force"),
|
||||
permanently: e.named.contains_key("permanently"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn remove(&mut self, opt: impl Into<Opt>, tasks: &Tasks) -> bool {
|
||||
let opt = opt.into();
|
||||
let targets = self.selected().into_iter().map(|f| f.url()).collect();
|
||||
tasks.file_remove(targets, opt.force, opt.permanently)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,21 +2,20 @@ use std::{collections::BTreeSet, ffi::OsStr, io::{stdout, BufWriter, Write}, pat
|
|||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
|
||||
use yazi_config::{OPEN, PREVIEW};
|
||||
use yazi_config::{keymap::Exec, OPEN, PREVIEW};
|
||||
use yazi_shared::{max_common_root, Defer, Term, Url};
|
||||
|
||||
use crate::{emit, external::{self, ShellOpt}, files::{File, FilesOp}, input::InputOpt, manager::Manager, Event, BLOCKER};
|
||||
|
||||
impl Manager {
|
||||
pub fn rename(&self, force: bool) -> bool {
|
||||
if self.active().in_selecting() {
|
||||
return self.bulk_rename();
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
}
|
||||
|
||||
let Some(hovered) = self.hovered().map(|h| h.url()) else {
|
||||
return false;
|
||||
};
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
async fn rename_and_hover(old: Url, new: Url) -> Result<()> {
|
||||
fs::rename(&old, &new).await?;
|
||||
if old.parent() != new.parent() {
|
||||
|
|
@ -32,6 +31,16 @@ impl Manager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rename(&self, opt: impl Into<Opt>) -> bool {
|
||||
if self.active().in_selecting() {
|
||||
return self.bulk_rename();
|
||||
}
|
||||
|
||||
let Some(hovered) = self.hovered().map(|h| h.url()) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let opt = opt.into();
|
||||
tokio::spawn(async move {
|
||||
let mut result = emit!(Input(
|
||||
InputOpt::hovered("Rename:").with_value(hovered.file_name().unwrap().to_string_lossy())
|
||||
|
|
@ -42,15 +51,15 @@ impl Manager {
|
|||
};
|
||||
|
||||
let new = hovered.parent().unwrap().join(name);
|
||||
if force || fs::symlink_metadata(&new).await.is_err() {
|
||||
rename_and_hover(hovered, Url::from(new)).await.ok();
|
||||
if opt.force || fs::symlink_metadata(&new).await.is_err() {
|
||||
Self::rename_and_hover(hovered, Url::from(new)).await.ok();
|
||||
return;
|
||||
}
|
||||
|
||||
let mut result = emit!(Input(InputOpt::hovered("Overwrite an existing file? (y/N)")));
|
||||
if let Some(Ok(choice)) = result.recv().await {
|
||||
if choice == "y" || choice == "Y" {
|
||||
rename_and_hover(hovered, Url::from(new)).await.ok();
|
||||
Self::rename_and_hover(hovered, Url::from(new)).await.ok();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
||||
pub struct Opt;
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(_: &Exec) -> Self { Self }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn suspend(&mut self) -> bool {
|
||||
pub fn suspend(&mut self, _: impl Into<Opt>) -> bool {
|
||||
#[cfg(unix)]
|
||||
tokio::spawn(async move {
|
||||
crate::emit!(Stop(true)).await;
|
||||
|
|
|
|||
35
yazi-core/src/manager/commands/tab_close.rs
Normal file
35
yazi-core/src/manager/commands/tab_close.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::manager::Tabs;
|
||||
|
||||
pub struct Opt {
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self { idx: e.args.first().and_then(|i| i.parse().ok()).unwrap_or(0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Opt {
|
||||
fn from(idx: usize) -> Self { Self { idx } }
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
pub fn close(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
|
||||
let len = self.items.len();
|
||||
if len < 2 || opt.idx >= len {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.items.remove(opt.idx);
|
||||
if opt.idx <= self.idx {
|
||||
self.set_idx(self.absolute(1));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
41
yazi-core/src/manager/commands/tab_create.rs
Normal file
41
yazi-core/src/manager/commands/tab_create.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
use yazi_shared::Url;
|
||||
|
||||
use crate::{manager::Tabs, tab::Tab};
|
||||
|
||||
const MAX_TABS: usize = 9;
|
||||
|
||||
pub struct Opt {
|
||||
url: Option<Url>,
|
||||
current: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
let mut opt = Self { url: None, current: e.named.contains_key("current") };
|
||||
|
||||
if !opt.current {
|
||||
opt.url = Some(e.args.first().map_or_else(|| Url::from("."), Url::from));
|
||||
}
|
||||
opt
|
||||
}
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
pub fn create(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
if self.items.len() >= MAX_TABS {
|
||||
return false;
|
||||
}
|
||||
|
||||
let opt = opt.into();
|
||||
let url = if opt.current { self.active().current.cwd.to_owned() } else { opt.url.unwrap() };
|
||||
|
||||
let mut tab = Tab::from(url);
|
||||
tab.conf = self.active().conf.clone();
|
||||
tab.apply_files_attrs(false);
|
||||
|
||||
self.items.insert(self.idx + 1, tab);
|
||||
self.set_idx(self.idx + 1);
|
||||
true
|
||||
}
|
||||
}
|
||||
26
yazi-core/src/manager/commands/tab_swap.rs
Normal file
26
yazi-core/src/manager/commands/tab_swap.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::manager::Tabs;
|
||||
|
||||
pub struct Opt {
|
||||
idx: isize,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self { idx: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
pub fn swap(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let idx = self.absolute(opt.into().idx);
|
||||
if idx == self.idx {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.items.swap(self.idx, idx);
|
||||
self.set_idx(idx);
|
||||
true
|
||||
}
|
||||
}
|
||||
35
yazi-core/src/manager/commands/tab_switch.rs
Normal file
35
yazi-core/src/manager/commands/tab_switch.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::manager::Tabs;
|
||||
|
||||
pub struct Opt {
|
||||
idx: isize,
|
||||
rel: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self {
|
||||
idx: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0),
|
||||
rel: e.named.contains_key("relative"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
pub fn switch(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
let idx = if opt.rel {
|
||||
(self.idx as isize + opt.idx).rem_euclid(self.items.len() as isize) as usize
|
||||
} else {
|
||||
opt.idx as usize
|
||||
};
|
||||
|
||||
if idx == self.idx || idx >= self.items.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.set_idx(idx);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,20 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::manager::Manager;
|
||||
|
||||
pub struct Opt {
|
||||
cut: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { cut: e.named.contains_key("cut") } }
|
||||
}
|
||||
|
||||
impl Manager {
|
||||
pub fn yank(&mut self, cut: bool) -> bool {
|
||||
self.yanked.0 = cut;
|
||||
pub fn yank(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
|
||||
self.yanked.0 = opt.cut;
|
||||
self.yanked.1 = self.selected().into_iter().map(|f| f.url()).collect();
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ impl Manager {
|
|||
|
||||
if url == self.cwd() {
|
||||
self.current_mut().update(op);
|
||||
self.active_mut().leave();
|
||||
self.active_mut().leave(());
|
||||
true
|
||||
} else if matches!(self.parent(), Some(p) if &p.cwd == url) {
|
||||
self.active_mut().parent.as_mut().unwrap().update(op)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ use yazi_shared::Url;
|
|||
|
||||
use crate::{emit, tab::Tab};
|
||||
|
||||
const MAX_TABS: usize = 9;
|
||||
|
||||
pub struct Tabs {
|
||||
pub idx: usize,
|
||||
items: Vec<Tab>,
|
||||
pub(super) items: Vec<Tab>,
|
||||
}
|
||||
|
||||
impl Tabs {
|
||||
|
|
@ -17,62 +15,8 @@ impl Tabs {
|
|||
tabs
|
||||
}
|
||||
|
||||
pub fn create(&mut self, url: &Url) -> bool {
|
||||
if self.items.len() >= MAX_TABS {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut tab = Tab::from(url);
|
||||
tab.conf = self.active().conf.clone();
|
||||
tab.apply_files_attrs(false);
|
||||
|
||||
self.items.insert(self.idx + 1, tab);
|
||||
self.set_idx(self.idx + 1);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn switch(&mut self, idx: isize, rel: bool) -> bool {
|
||||
let idx = if rel {
|
||||
(self.idx as isize + idx).rem_euclid(self.items.len() as isize) as usize
|
||||
} else {
|
||||
idx as usize
|
||||
};
|
||||
|
||||
if idx == self.idx || idx >= self.items.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.set_idx(idx);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn swap(&mut self, rel: isize) -> bool {
|
||||
let idx = self.absolute(rel);
|
||||
if idx == self.idx {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.items.swap(self.idx, idx);
|
||||
self.set_idx(idx);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn close(&mut self, idx: usize) -> bool {
|
||||
let len = self.items.len();
|
||||
if len < 2 || idx >= len {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.items.remove(idx);
|
||||
if idx <= self.idx {
|
||||
self.set_idx(self.absolute(1));
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn absolute(&self, rel: isize) -> usize {
|
||||
pub(super) fn absolute(&self, rel: isize) -> usize {
|
||||
if rel > 0 {
|
||||
(self.idx + rel as usize).min(self.items.len() - 1)
|
||||
} else {
|
||||
|
|
@ -81,7 +25,7 @@ impl Tabs {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn set_idx(&mut self, idx: usize) {
|
||||
pub(super) fn set_idx(&mut self, idx: usize) {
|
||||
self.idx = idx;
|
||||
self.active_mut().preview.reset(|l| l.is_image());
|
||||
emit!(Refresh);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,25 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{emit, tab::Tab, Step};
|
||||
|
||||
pub struct Opt(Step);
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self(e.args.first().and_then(|s| s.parse().ok()).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Opt
|
||||
where
|
||||
T: Into<Step>,
|
||||
{
|
||||
fn from(t: T) -> Self { Self(t.into()) }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn arrow(&mut self, step: Step) -> bool {
|
||||
pub fn arrow(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let step = opt.into().0;
|
||||
let ok = if step.is_positive() { self.current.next(step) } else { self.current.prev(step) };
|
||||
if !ok {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,24 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt;
|
||||
impl From<()> for Opt {
|
||||
fn from(_: ()) -> Self { Self }
|
||||
}
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(_: &Exec) -> Self { Self }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn back(&mut self) -> bool {
|
||||
pub fn back(&mut self, _: impl Into<Opt>) -> bool {
|
||||
if let Some(url) = self.backstack.shift_backward().cloned() {
|
||||
self.cd(url);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn forward(&mut self) -> bool {
|
||||
pub fn forward(&mut self, _: impl Into<Opt>) -> bool {
|
||||
if let Some(url) = self.backstack.shift_forward().cloned() {
|
||||
self.cd(url);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,25 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{external, tab::Tab};
|
||||
|
||||
pub struct Opt<'a> {
|
||||
type_: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Exec> for Opt<'a> {
|
||||
fn from(e: &'a Exec) -> Self { Self { type_: e.args.first().map(|s| s.as_str()).unwrap_or("") } }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn copy(&self, type_: &str) -> bool {
|
||||
pub fn copy<'a>(&self, opt: impl Into<Opt<'a>>) -> bool {
|
||||
let opt = opt.into();
|
||||
|
||||
let mut s = OsString::new();
|
||||
let mut it = self.selected().into_iter().peekable();
|
||||
while let Some(f) = it.next() {
|
||||
s.push(match type_ {
|
||||
s.push(match opt.type_ {
|
||||
"path" => f.url.as_os_str(),
|
||||
"dirname" => f.url.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
|
||||
"filename" => f.name().unwrap_or(OsStr::new("")),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
use std::mem;
|
||||
|
||||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{emit, tab::Tab};
|
||||
|
||||
pub struct Opt;
|
||||
impl From<()> for Opt {
|
||||
fn from(_: ()) -> Self { Self }
|
||||
}
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(_: &Exec) -> Self { Self }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn enter(&mut self) -> bool {
|
||||
pub fn enter(&mut self, _: impl Into<Opt>) -> bool {
|
||||
let Some(hovered) = self.current.hovered().filter(|h| h.is_dir()).map(|h| h.url()) else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,30 +7,40 @@ use yazi_shared::{Debounce, InputError};
|
|||
|
||||
use crate::{emit, input::InputOpt, tab::{Finder, FinderCase, Tab}};
|
||||
|
||||
pub struct Opt<'a> {
|
||||
query: Option<&'a str>,
|
||||
prev: bool,
|
||||
case: FinderCase,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Exec> for Opt<'a> {
|
||||
fn from(e: &'a Exec) -> Self {
|
||||
Self {
|
||||
query: e.args.first().map(|s| s.as_str()),
|
||||
prev: e.named.contains_key("previous"),
|
||||
case: match (e.named.contains_key("smart"), e.named.contains_key("insensitive")) {
|
||||
(true, _) => FinderCase::Smart,
|
||||
(_, false) => FinderCase::Sensitive,
|
||||
(_, true) => FinderCase::Insensitive,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ArrowOpt {
|
||||
prev: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for ArrowOpt {
|
||||
fn from(e: &Exec) -> Self { Self { prev: e.named.contains_key("previous") } }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn find(&mut self, query: Option<&str>, prev: bool, case: FinderCase) -> bool {
|
||||
if let Some(query) = query {
|
||||
let Ok(finder) = Finder::new(query, case) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let step = if 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.into());
|
||||
}
|
||||
|
||||
self.finder = Some(finder);
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn find<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
|
||||
let opt = opt.into();
|
||||
tokio::spawn(async move {
|
||||
let rx = emit!(Input(
|
||||
InputOpt::top(if prev { "Find previous:" } else { "Find next:" }).with_realtime()
|
||||
InputOpt::top(if opt.prev { "Find previous:" } else { "Find next:" }).with_realtime()
|
||||
));
|
||||
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
|
||||
|
|
@ -38,10 +48,10 @@ impl Tab {
|
|||
|
||||
while let Some(Ok(s)) | Some(Err(InputError::Typed(s))) = rx.next().await {
|
||||
emit!(Call(
|
||||
Exec::call("find", vec![s])
|
||||
.with_bool("previous", prev)
|
||||
.with_bool("smart", case == FinderCase::Smart)
|
||||
.with_bool("insensitive", case == FinderCase::Insensitive)
|
||||
Exec::call("find_do", vec![s])
|
||||
.with_bool("previous", opt.prev)
|
||||
.with_bool("smart", opt.case == FinderCase::Smart)
|
||||
.with_bool("insensitive", opt.case == FinderCase::Insensitive)
|
||||
.vec(),
|
||||
KeymapLayer::Manager
|
||||
));
|
||||
|
|
@ -50,18 +60,42 @@ impl Tab {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn find_arrow(&mut self, prev: bool) -> bool {
|
||||
pub fn find_do<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
|
||||
let opt = opt.into();
|
||||
let Some(query) = opt.query else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Ok(finder) = Finder::new(query, opt.case) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
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);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn find_arrow(&mut self, opt: impl Into<ArrowOpt>) -> bool {
|
||||
let Some(finder) = &mut self.finder else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let b = finder.catchup(&self.current.files);
|
||||
let step = if prev {
|
||||
let step = if opt.into().prev {
|
||||
finder.prev(&self.current.files, self.current.cursor, false)
|
||||
} else {
|
||||
finder.next(&self.current.files, self.current.cursor, false)
|
||||
};
|
||||
|
||||
b | step.is_some_and(|s| self.arrow(s.into()))
|
||||
b | step.is_some_and(|s| self.arrow(s))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,46 @@ use yazi_shared::{ends_with_slash, Defer};
|
|||
|
||||
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Event, BLOCKER};
|
||||
|
||||
impl Tab {
|
||||
pub fn jump(&self, global: bool) -> bool {
|
||||
let cwd = self.current.cwd.clone();
|
||||
pub struct Opt {
|
||||
type_: OptType,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum OptType {
|
||||
None,
|
||||
Fzf,
|
||||
Zoxide,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self {
|
||||
type_: match e.args.first().map(|s| s.as_str()) {
|
||||
Some("fzf") => OptType::Fzf,
|
||||
Some("zoxide") => OptType::Zoxide,
|
||||
_ => OptType::None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn jump(&self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
if opt.type_ == OptType::None {
|
||||
return false;
|
||||
}
|
||||
|
||||
let cwd = self.current.cwd.clone();
|
||||
tokio::spawn(async move {
|
||||
let _guard = BLOCKER.acquire().await.unwrap();
|
||||
let _defer = Defer::new(|| Event::Stop(false, None).emit());
|
||||
emit!(Stop(true)).await;
|
||||
|
||||
let url = if global {
|
||||
external::fzf(FzfOpt { cwd }).await
|
||||
let rx = if opt.type_ == OptType::Fzf {
|
||||
external::fzf(FzfOpt { cwd })
|
||||
} else {
|
||||
external::zoxide(ZoxideOpt { cwd }).await
|
||||
external::zoxide(ZoxideOpt { cwd })
|
||||
}?;
|
||||
|
||||
let op = if global && !ends_with_slash(&url) { "reveal" } else { "cd" };
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
use std::mem;
|
||||
|
||||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::{emit, tab::Tab};
|
||||
|
||||
pub struct Opt;
|
||||
impl From<()> for Opt {
|
||||
fn from(_: ()) -> Self { Self }
|
||||
}
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(_: &Exec) -> Self { Self }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn leave(&mut self) -> bool {
|
||||
pub fn leave(&mut self, _: impl Into<Opt>) -> bool {
|
||||
let current = self
|
||||
.current
|
||||
.hovered()
|
||||
|
|
|
|||
|
|
@ -7,8 +7,36 @@ use yazi_config::keymap::{Exec, KeymapLayer};
|
|||
|
||||
use crate::{emit, external, files::FilesOp, input::InputOpt, tab::Tab};
|
||||
|
||||
pub struct Opt {
|
||||
pub type_: OptType,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum OptType {
|
||||
None,
|
||||
Rg,
|
||||
Fd,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self {
|
||||
type_: match e.args.first().map(|s| s.as_str()) {
|
||||
Some("fd") => OptType::Fd,
|
||||
Some("rg") => OptType::Rg,
|
||||
_ => OptType::None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn search(&mut self, grep: bool) -> bool {
|
||||
pub fn search(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
if opt.type_ == OptType::None {
|
||||
return self.search_stop();
|
||||
}
|
||||
|
||||
if let Some(handle) = self.search.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
|
@ -22,7 +50,7 @@ impl Tab {
|
|||
};
|
||||
|
||||
cwd = cwd.into_search(subject.clone());
|
||||
let rx = if grep {
|
||||
let rx = if opt.type_ == OptType::Rg {
|
||||
external::rg(external::RgOpt { cwd: cwd.clone(), hidden, subject })
|
||||
} else {
|
||||
external::fd(external::FdOpt { cwd: cwd.clone(), hidden, glob: false, subject })
|
||||
|
|
@ -45,7 +73,7 @@ impl Tab {
|
|||
true
|
||||
}
|
||||
|
||||
pub fn search_stop(&mut self) -> bool {
|
||||
pub(super) fn search_stop(&mut self) -> bool {
|
||||
if let Some(handle) = self.search.take() {
|
||||
handle.abort();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,32 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt(Option<bool>);
|
||||
|
||||
impl From<Option<bool>> for Opt {
|
||||
fn from(b: Option<bool>) -> Self { Self(b) }
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self {
|
||||
Self(match e.named.get("state").map(|s| s.as_bytes()) {
|
||||
Some(b"true") => Some(true),
|
||||
Some(b"false") => Some(false),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn select(&mut self, state: Option<bool>) -> bool {
|
||||
pub fn select(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
if let Some(u) = self.current.hovered().map(|h| h.url()) {
|
||||
return self.current.files.select(&u, state);
|
||||
return self.current.files.select(&u, opt.into().0);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn select_all(&mut self, state: Option<bool>) -> bool { self.current.files.select_all(state) }
|
||||
pub fn select_all(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
self.current.files.select_all(opt.into().0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,41 @@
|
|||
use yazi_config::open::Opener;
|
||||
use yazi_config::{keymap::Exec, open::Opener};
|
||||
|
||||
use crate::{emit, input::InputOpt, tab::Tab};
|
||||
|
||||
pub struct Opt {
|
||||
cmd: String,
|
||||
block: bool,
|
||||
confirm: bool,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Exec> for Opt {
|
||||
fn from(e: &'a Exec) -> Self {
|
||||
Self {
|
||||
cmd: e.args.first().map(|e| e.to_owned()).unwrap_or_default(),
|
||||
block: e.named.contains_key("block"),
|
||||
confirm: e.named.contains_key("confirm"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn shell(&self, exec: &str, block: bool, confirm: bool) -> bool {
|
||||
pub fn shell(&self, opt: impl Into<Opt>) -> bool {
|
||||
let selected: Vec<_> = self
|
||||
.selected()
|
||||
.into_iter()
|
||||
.map(|f| (f.url.as_os_str().to_owned(), Default::default()))
|
||||
.collect();
|
||||
|
||||
let mut exec = exec.to_owned();
|
||||
let mut opt = opt.into();
|
||||
tokio::spawn(async move {
|
||||
if !confirm || exec.is_empty() {
|
||||
if !opt.confirm || opt.cmd.is_empty() {
|
||||
let mut result = emit!(Input(
|
||||
InputOpt::top(if block { "Shell (block):" } else { "Shell:" })
|
||||
.with_value(&exec)
|
||||
InputOpt::top(if opt.block { "Shell (block):" } else { "Shell:" })
|
||||
.with_value(opt.cmd)
|
||||
.with_highlight()
|
||||
));
|
||||
match result.recv().await {
|
||||
Some(Ok(e)) => exec = e,
|
||||
Some(Ok(e)) => opt.cmd = e,
|
||||
_ => return,
|
||||
}
|
||||
}
|
||||
|
|
@ -27,12 +43,12 @@ impl Tab {
|
|||
emit!(Open(
|
||||
selected,
|
||||
Some(Opener {
|
||||
exec,
|
||||
block,
|
||||
exec: opt.cmd,
|
||||
block: opt.block,
|
||||
orphan: false,
|
||||
desc: Default::default(),
|
||||
for_: None,
|
||||
spread: true
|
||||
spread: true,
|
||||
})
|
||||
));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,12 +1,23 @@
|
|||
use std::collections::BTreeSet;
|
||||
|
||||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::tab::{Mode, Tab};
|
||||
|
||||
pub struct Opt {
|
||||
unset: bool,
|
||||
}
|
||||
|
||||
impl From<&Exec> for Opt {
|
||||
fn from(e: &Exec) -> Self { Self { unset: e.named.contains_key("unset") } }
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn visual_mode(&mut self, unset: bool) -> bool {
|
||||
pub fn visual_mode(&mut self, opt: impl Into<Opt>) -> bool {
|
||||
let opt = opt.into();
|
||||
let idx = self.current.cursor;
|
||||
|
||||
if unset {
|
||||
if opt.unset {
|
||||
self.mode = Mode::Unset(idx, BTreeSet::from([idx]));
|
||||
} else {
|
||||
self.mode = Mode::Select(idx, BTreeSet::from([idx]));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use yazi_config::{keymap::{Control, Exec, Key, KeymapLayer}, KEYMAP};
|
||||
use yazi_core::{input::InputMode, tab::FinderCase, Ctx};
|
||||
use yazi_shared::{expand_url, optional_bool, Url};
|
||||
use yazi_core::{input::InputMode, Ctx};
|
||||
|
||||
pub(super) struct Executor<'a> {
|
||||
cx: &'a mut Ctx,
|
||||
|
|
@ -71,148 +70,76 @@ impl<'a> Executor<'a> {
|
|||
}
|
||||
|
||||
fn manager(&mut self, exec: &Exec) -> bool {
|
||||
match exec.cmd.as_str() {
|
||||
"escape" => self.cx.manager.active_mut().escape(exec),
|
||||
"quit" => self.cx.manager.quit(&self.cx.tasks, exec.named.contains_key("no-cwd-file")),
|
||||
"close" => self.cx.manager.close(&self.cx.tasks),
|
||||
"suspend" => self.cx.manager.suspend(),
|
||||
macro_rules! on {
|
||||
(MANAGER, $name:ident $(,$args:expr)*) => {
|
||||
if exec.cmd == stringify!($name) {
|
||||
return self.cx.manager.$name(exec, $($args),*);
|
||||
}
|
||||
};
|
||||
(ACTIVE, $name:ident) => {
|
||||
if exec.cmd == stringify!($name) {
|
||||
return self.cx.manager.active_mut().$name(exec);
|
||||
}
|
||||
};
|
||||
(TABS, $name:ident) => {
|
||||
if exec.cmd == concat!("tab_", stringify!($name)) {
|
||||
return self.cx.manager.tabs.$name(exec);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
on!(ACTIVE, escape);
|
||||
on!(MANAGER, quit, &self.cx.tasks);
|
||||
on!(MANAGER, close, &self.cx.tasks);
|
||||
on!(MANAGER, suspend);
|
||||
|
||||
// Navigation
|
||||
"arrow" => {
|
||||
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or_default();
|
||||
self.cx.manager.active_mut().arrow(step)
|
||||
}
|
||||
"peek" => {
|
||||
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
self.cx.manager.active_mut().preview.arrow(step);
|
||||
self.cx.manager.peek(true, self.cx.image_layer())
|
||||
}
|
||||
"leave" => self.cx.manager.active_mut().leave(),
|
||||
"enter" => self.cx.manager.active_mut().enter(),
|
||||
"back" => self.cx.manager.active_mut().back(),
|
||||
"forward" => self.cx.manager.active_mut().forward(),
|
||||
"cd" => {
|
||||
let url = exec.args.first().map(Url::from).unwrap_or_default();
|
||||
if exec.named.contains_key("interactive") {
|
||||
self.cx.manager.active_mut().cd_interactive(url)
|
||||
} else {
|
||||
self.cx.manager.active_mut().cd(expand_url(url))
|
||||
}
|
||||
}
|
||||
"reveal" => self.cx.manager.active_mut().reveal(exec),
|
||||
on!(ACTIVE, arrow);
|
||||
// on!(T, peek);
|
||||
on!(ACTIVE, leave);
|
||||
on!(ACTIVE, enter);
|
||||
on!(ACTIVE, back);
|
||||
on!(ACTIVE, forward);
|
||||
// on!(A, cd);
|
||||
|
||||
// Selection
|
||||
"select" => {
|
||||
let state = exec.named.get("state").cloned().unwrap_or("none".to_string());
|
||||
self.cx.manager.active_mut().select(optional_bool(&state))
|
||||
}
|
||||
"select_all" => {
|
||||
let state = exec.named.get("state").cloned().unwrap_or("none".to_string());
|
||||
self.cx.manager.active_mut().select_all(optional_bool(&state))
|
||||
}
|
||||
"visual_mode" => self.cx.manager.active_mut().visual_mode(exec.named.contains_key("unset")),
|
||||
on!(ACTIVE, select);
|
||||
on!(ACTIVE, select_all);
|
||||
on!(ACTIVE, visual_mode);
|
||||
|
||||
// Operation
|
||||
"open" => self.cx.manager.open(exec.named.contains_key("interactive")),
|
||||
"yank" => self.cx.manager.yank(exec.named.contains_key("cut")),
|
||||
"paste" => {
|
||||
let dest = self.cx.manager.cwd();
|
||||
let (cut, ref src) = self.cx.manager.yanked;
|
||||
|
||||
let force = exec.named.contains_key("force");
|
||||
if cut {
|
||||
self.cx.tasks.file_cut(src, dest, force)
|
||||
} else {
|
||||
self.cx.tasks.file_copy(src, dest, force)
|
||||
}
|
||||
}
|
||||
"link" => {
|
||||
let (cut, ref src) = self.cx.manager.yanked;
|
||||
!cut
|
||||
&& self.cx.tasks.file_link(
|
||||
src,
|
||||
self.cx.manager.cwd(),
|
||||
exec.named.contains_key("relative"),
|
||||
exec.named.contains_key("force"),
|
||||
)
|
||||
}
|
||||
"remove" => {
|
||||
let targets = self.cx.manager.selected().into_iter().map(|f| f.url()).collect();
|
||||
let force = exec.named.contains_key("force");
|
||||
let permanently = exec.named.contains_key("permanently");
|
||||
self.cx.tasks.file_remove(targets, force, permanently)
|
||||
}
|
||||
"create" => self.cx.manager.create(exec.named.contains_key("force")),
|
||||
"rename" => self.cx.manager.rename(exec.named.contains_key("force")),
|
||||
"copy" => self.cx.manager.active().copy(exec.args.first().map(|s| s.as_str()).unwrap_or("")),
|
||||
"shell" => self.cx.manager.active().shell(
|
||||
exec.args.first().map(|e| e.as_str()).unwrap_or(""),
|
||||
exec.named.contains_key("block"),
|
||||
exec.named.contains_key("confirm"),
|
||||
),
|
||||
"hidden" => self.cx.manager.active_mut().hidden(exec),
|
||||
"linemode" => self.cx.manager.active_mut().linemode(exec),
|
||||
"search" => match exec.args.first().map(|s| s.as_str()).unwrap_or("") {
|
||||
"rg" => self.cx.manager.active_mut().search(true),
|
||||
"fd" => self.cx.manager.active_mut().search(false),
|
||||
_ => self.cx.manager.active_mut().search_stop(),
|
||||
},
|
||||
"jump" => match exec.args.first().map(|s| s.as_str()).unwrap_or("") {
|
||||
"fzf" => self.cx.manager.active_mut().jump(true),
|
||||
"zoxide" => self.cx.manager.active_mut().jump(false),
|
||||
_ => false,
|
||||
},
|
||||
on!(MANAGER, open);
|
||||
on!(MANAGER, yank);
|
||||
on!(MANAGER, paste, &self.cx.tasks);
|
||||
on!(MANAGER, link, &self.cx.tasks);
|
||||
on!(MANAGER, remove, &self.cx.tasks);
|
||||
on!(MANAGER, create);
|
||||
on!(MANAGER, rename);
|
||||
on!(ACTIVE, copy);
|
||||
on!(ACTIVE, shell);
|
||||
on!(ACTIVE, hidden);
|
||||
on!(ACTIVE, linemode);
|
||||
on!(ACTIVE, search);
|
||||
on!(ACTIVE, jump);
|
||||
|
||||
// Find
|
||||
"find" => {
|
||||
let query = exec.args.first().map(|s| s.as_str());
|
||||
let prev = exec.named.contains_key("previous");
|
||||
let case = match (exec.named.contains_key("smart"), exec.named.contains_key("insensitive"))
|
||||
{
|
||||
(true, _) => FinderCase::Smart,
|
||||
(_, false) => FinderCase::Sensitive,
|
||||
(_, true) => FinderCase::Insensitive,
|
||||
};
|
||||
self.cx.manager.active_mut().find(query, prev, case)
|
||||
}
|
||||
"find_arrow" => self.cx.manager.active_mut().find_arrow(exec.named.contains_key("previous")),
|
||||
on!(ACTIVE, find);
|
||||
on!(ACTIVE, find_arrow);
|
||||
|
||||
// Sorting
|
||||
"sort" => {
|
||||
let b = self.cx.manager.active_mut().sort(exec);
|
||||
self.cx.tasks.precache_size(&self.cx.manager.current().files);
|
||||
b
|
||||
}
|
||||
on!(ACTIVE, sort);
|
||||
|
||||
// Tabs
|
||||
"tab_create" => {
|
||||
let path = if exec.named.contains_key("current") {
|
||||
self.cx.manager.cwd().to_owned()
|
||||
} else {
|
||||
exec.args.first().map(Url::from).unwrap_or_else(|| Url::from("/"))
|
||||
};
|
||||
self.cx.manager.tabs.create(&path)
|
||||
}
|
||||
"tab_close" => {
|
||||
let idx = exec.args.first().and_then(|i| i.parse().ok()).unwrap_or(0);
|
||||
self.cx.manager.tabs.close(idx)
|
||||
}
|
||||
"tab_switch" => {
|
||||
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
let rel = exec.named.contains_key("relative");
|
||||
self.cx.manager.tabs.switch(step, rel)
|
||||
}
|
||||
"tab_swap" => {
|
||||
let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||
self.cx.manager.tabs.swap(step)
|
||||
}
|
||||
on!(TABS, create);
|
||||
on!(TABS, close);
|
||||
on!(TABS, switch);
|
||||
on!(TABS, swap);
|
||||
|
||||
match exec.cmd.as_bytes() {
|
||||
// Tasks
|
||||
"tasks_show" => self.cx.tasks.toggle(),
|
||||
|
||||
b"tasks_show" => self.cx.tasks.toggle(),
|
||||
// Help
|
||||
"help" => self.cx.help.toggle(KeymapLayer::Manager),
|
||||
|
||||
b"help" => self.cx.help.toggle(KeymapLayer::Manager),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ function ui.highlight_ranges(s, ranges)
|
|||
if r[1] > last then
|
||||
spans[#spans + 1] = ui.Span(s:sub(last + 1, r[1]))
|
||||
end
|
||||
-- TODO: use a customable style
|
||||
spans[#spans + 1] = ui.Span(s:sub(r[1] + 1, r[2])):style(THEME.manager.find_keyword)
|
||||
last = r[2]
|
||||
end
|
||||
|
|
|
|||
|
|
@ -141,15 +141,6 @@ pub fn path_relative_to<'a>(path: &'a Path, root: &Path) -> Cow<'a, Path> {
|
|||
Cow::from(buf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn optional_bool(s: &str) -> Option<bool> {
|
||||
match s {
|
||||
"true" => Some(true),
|
||||
"false" => Some(false),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{borrow::Cow, path::Path};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue