mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-22 23:31:05 +00:00
feat: allow references to the selected files during shell execution (#73)
This commit is contained in:
parent
88d67af2eb
commit
a437347306
3 changed files with 76 additions and 65 deletions
|
|
@ -106,7 +106,7 @@ impl Executor {
|
|||
}
|
||||
"create" => cx.manager.create(),
|
||||
"rename" => cx.manager.rename(),
|
||||
"copy" => cx.manager.copy(exec.args.get(0).map(|s| s.as_str()).unwrap_or("")),
|
||||
"copy" => cx.manager.active().copy(exec.args.get(0).map(|s| s.as_str()).unwrap_or("")),
|
||||
"shell" => cx.manager.active().shell(
|
||||
exec.args.get(0).map(|e| e.as_str()).unwrap_or(""),
|
||||
exec.named.contains_key("block"),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::{OsStr, OsString}, io::{stdout, BufWriter, Write}, mem, path::{Path, PathBuf}};
|
||||
use std::{collections::{BTreeMap, BTreeSet, HashMap, HashSet}, env, ffi::OsStr, io::{stdout, BufWriter, Write}, mem, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{anyhow, bail, Error, Result};
|
||||
use config::{BOOT, OPEN};
|
||||
|
|
@ -194,7 +194,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
pub fn rename(&self) -> bool {
|
||||
if self.in_selecting() {
|
||||
if self.active().in_selecting() {
|
||||
return self.bulk_rename();
|
||||
}
|
||||
|
||||
|
|
@ -319,26 +319,6 @@ impl Manager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy(&self, type_: &str) -> bool {
|
||||
let mut s = OsString::new();
|
||||
let mut it = self.selected().into_iter().peekable();
|
||||
while let Some(f) = it.next() {
|
||||
s.push(match type_ {
|
||||
"path" => f.path.as_os_str(),
|
||||
"dirname" => f.path.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
|
||||
"filename" => f.path.file_name().unwrap_or(OsStr::new("")),
|
||||
"name_without_ext" => f.path.file_stem().unwrap_or(OsStr::new("")),
|
||||
_ => return false,
|
||||
});
|
||||
if it.peek().is_some() {
|
||||
s.push("\n");
|
||||
}
|
||||
}
|
||||
|
||||
futures::executor::block_on(external::clipboard_set(s)).ok();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn update_read(&mut self, op: FilesOp) -> bool {
|
||||
let path = op.path();
|
||||
let cwd = self.cwd().to_owned();
|
||||
|
|
@ -457,28 +437,8 @@ impl Manager {
|
|||
pub fn hovered(&self) -> Option<&File> { self.tabs.active().current.hovered.as_ref() }
|
||||
|
||||
#[inline]
|
||||
pub fn yanked(&self) -> &(bool, HashSet<PathBuf>) { &self.yanked }
|
||||
|
||||
pub fn selected(&self) -> Vec<&File> {
|
||||
let mode = &self.active().mode;
|
||||
let files = &self.current().files;
|
||||
|
||||
let selected: Vec<_> = if !mode.is_visual() {
|
||||
files.iter().filter(|(_, f)| f.is_selected).map(|(_, f)| f).collect()
|
||||
} else {
|
||||
files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, (_, f))| mode.pending(*i, f.is_selected))
|
||||
.map(|(_, (_, f))| f)
|
||||
.collect()
|
||||
};
|
||||
|
||||
if selected.is_empty() { self.hovered().map(|h| vec![h]).unwrap_or_default() } else { selected }
|
||||
}
|
||||
pub fn selected(&self) -> Vec<&File> { self.tabs.active().selected() }
|
||||
|
||||
#[inline]
|
||||
pub fn in_selecting(&self) -> bool {
|
||||
self.active().mode.is_visual() || self.current().has_selected()
|
||||
}
|
||||
pub fn yanked(&self) -> &(bool, HashSet<PathBuf>) { &self.yanked }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::{BTreeMap, BTreeSet}, mem, path::{Path, PathBuf}};
|
||||
use std::{collections::{BTreeMap, BTreeSet}, ffi::{OsStr, OsString}, mem, path::{Path, PathBuf}};
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use config::open::Opener;
|
||||
|
|
@ -185,6 +185,44 @@ impl Tab {
|
|||
// TODO
|
||||
pub fn forward(&mut self) -> bool { false }
|
||||
|
||||
pub fn select(&mut self, state: Option<bool>) -> bool {
|
||||
let idx = Some(self.current.cursor());
|
||||
self.current.select(idx, state)
|
||||
}
|
||||
|
||||
pub fn select_all(&mut self, state: Option<bool>) -> bool { self.current.select(None, state) }
|
||||
|
||||
pub fn visual_mode(&mut self, unset: bool) -> bool {
|
||||
let idx = self.current.cursor();
|
||||
|
||||
if unset {
|
||||
self.mode = Mode::Unset(idx, BTreeSet::from([idx]));
|
||||
} else {
|
||||
self.mode = Mode::Select(idx, BTreeSet::from([idx]));
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
pub fn copy(&self, type_: &str) -> bool {
|
||||
let mut s = OsString::new();
|
||||
let mut it = self.selected().into_iter().peekable();
|
||||
while let Some(f) = it.next() {
|
||||
s.push(match type_ {
|
||||
"path" => f.path.as_os_str(),
|
||||
"dirname" => f.path.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
|
||||
"filename" => f.path.file_name().unwrap_or(OsStr::new("")),
|
||||
"name_without_ext" => f.path.file_stem().unwrap_or(OsStr::new("")),
|
||||
_ => return false,
|
||||
});
|
||||
if it.peek().is_some() {
|
||||
s.push("\n");
|
||||
}
|
||||
}
|
||||
|
||||
futures::executor::block_on(external::clipboard_set(s)).ok();
|
||||
false
|
||||
}
|
||||
|
||||
pub fn search(&mut self, grep: bool) -> bool {
|
||||
if let Some(handle) = self.search.take() {
|
||||
handle.abort();
|
||||
|
|
@ -249,6 +287,12 @@ impl Tab {
|
|||
}
|
||||
|
||||
pub fn shell(&self, exec: &str, block: bool, confirm: bool) -> bool {
|
||||
let selected: Vec<_> = self
|
||||
.selected()
|
||||
.into_iter()
|
||||
.map(|f| (f.path.as_os_str().to_owned(), Default::default()))
|
||||
.collect();
|
||||
|
||||
let mut exec = exec.to_owned();
|
||||
tokio::spawn(async move {
|
||||
if !confirm || exec.is_empty() {
|
||||
|
|
@ -260,31 +304,13 @@ impl Tab {
|
|||
}
|
||||
|
||||
emit!(Open(
|
||||
Default::default(),
|
||||
selected,
|
||||
Some(Opener { exec, block, display_name: Default::default(), spread: true })
|
||||
));
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn select(&mut self, state: Option<bool>) -> bool {
|
||||
let idx = Some(self.current.cursor());
|
||||
self.current.select(idx, state)
|
||||
}
|
||||
|
||||
pub fn select_all(&mut self, state: Option<bool>) -> bool { self.current.select(None, state) }
|
||||
|
||||
pub fn visual_mode(&mut self, unset: bool) -> bool {
|
||||
let idx = self.current.cursor();
|
||||
|
||||
if unset {
|
||||
self.mode = Mode::Unset(idx, BTreeSet::from([idx]));
|
||||
} else {
|
||||
self.mode = Mode::Select(idx, BTreeSet::from([idx]));
|
||||
};
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Tab {
|
||||
|
|
@ -302,6 +328,31 @@ impl Tab {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn selected(&self) -> Vec<&File> {
|
||||
let mode = self.mode();
|
||||
let files = &self.current.files;
|
||||
|
||||
let selected: Vec<_> = if !mode.is_visual() {
|
||||
files.iter().filter(|(_, f)| f.is_selected).map(|(_, f)| f).collect()
|
||||
} else {
|
||||
files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, (_, f))| mode.pending(*i, f.is_selected))
|
||||
.map(|(_, (_, f))| f)
|
||||
.collect()
|
||||
};
|
||||
|
||||
if selected.is_empty() {
|
||||
self.current.hovered.as_ref().map(|h| vec![h]).unwrap_or_default()
|
||||
} else {
|
||||
selected
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn in_selecting(&self) -> bool { self.mode().is_visual() || self.current.has_selected() }
|
||||
|
||||
#[inline]
|
||||
pub fn history(&self, path: &Path) -> Option<&Folder> { self.history.get(path) }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue