mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: enhanced execution format (#45)
This commit is contained in:
parent
a5eed70872
commit
d881614d31
16 changed files with 226 additions and 113 deletions
40
Cargo.lock
generated
40
Cargo.lock
generated
|
|
@ -34,6 +34,15 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
|
@ -341,8 +350,10 @@ dependencies = [
|
|||
"glob",
|
||||
"once_cell",
|
||||
"ratatui",
|
||||
"regex",
|
||||
"serde",
|
||||
"shared",
|
||||
"shell-words",
|
||||
"toml",
|
||||
"xdg",
|
||||
]
|
||||
|
|
@ -1384,6 +1395,29 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.4"
|
||||
|
|
@ -1497,6 +1531,12 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ impl App {
|
|||
|
||||
Event::Open(targets, opener) => {
|
||||
if let Some(opener) = opener {
|
||||
tasks.file_open_with(&opener, &targets.iter().map(|(f, _)| f).collect::<Vec<_>>());
|
||||
tasks.file_open_with(&opener, &targets.into_iter().map(|(f, _)| f).collect::<Vec<_>>());
|
||||
} else {
|
||||
tasks.file_open(&targets);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,15 @@ edition = "2021"
|
|||
shared = { path = "../shared" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = "^1"
|
||||
clap = { version = "^4", features = [ "derive" ] }
|
||||
crossterm = "^0"
|
||||
futures = "^0"
|
||||
glob = "^0"
|
||||
once_cell = "^1"
|
||||
ratatui = "^0"
|
||||
serde = { version = "^1", features = [ "derive" ] }
|
||||
toml = { version = "^0", features = [ "preserve_order" ] }
|
||||
xdg = "^2"
|
||||
anyhow = "^1"
|
||||
clap = { version = "^4", features = [ "derive" ] }
|
||||
crossterm = "^0"
|
||||
futures = "^0"
|
||||
glob = "^0"
|
||||
once_cell = "^1"
|
||||
ratatui = "^0"
|
||||
regex = "^1"
|
||||
serde = { version = "^1", features = [ "derive" ] }
|
||||
shell-words = "^1"
|
||||
toml = { version = "^0", features = [ "preserve_order" ] }
|
||||
xdg = "^2"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
- cd: Change the current directory.
|
||||
|
||||
- `path`: the path to change to.
|
||||
- `--interactive`: Use an interactive UI to input the path.
|
||||
|
||||
### Selection
|
||||
|
||||
|
|
|
|||
|
|
@ -32,21 +32,20 @@ Configure available openers, for example:
|
|||
```toml
|
||||
[opener]
|
||||
archive = [
|
||||
{ cmd = "unar", args = [ "$0" ] },
|
||||
{ exec = "unar $1" },
|
||||
]
|
||||
text = [
|
||||
{ cmd = "nvim", args = [ "$*" ], block = true },
|
||||
{ exec = "nvim $*", block = true },
|
||||
]
|
||||
# ...
|
||||
```
|
||||
|
||||
Available parameters are as follows:
|
||||
|
||||
- cmd: The program to open the selected files
|
||||
- args: Arguments to be passed
|
||||
- `"$n"`: The N-th selected file
|
||||
- `"$*"`: All selected files
|
||||
- `"foo"`: Literal string to be passed
|
||||
- exec: The command to open the selected files, with the following variables available:
|
||||
- `$n`: The N-th selected file
|
||||
- `$*`: All selected files
|
||||
- `foo`: Literal string to be passed
|
||||
- block: Open in a blocking manner. After setting this, Yazi will hide into a secondary screen and display the program on the main screen until it exits. During this time, it can receive I/O signals, which is useful for interactive programs.
|
||||
|
||||
## open
|
||||
|
|
|
|||
|
|
@ -10,30 +10,30 @@ max_height = 900
|
|||
|
||||
[opener]
|
||||
folder = [
|
||||
{ cmd = "open", args = [ "-R", "$*" ], display_name = "Reveal in Finder" },
|
||||
{ cmd = "vim", args = [ "$*" ] },
|
||||
{ exec = "open -R $*", display_name = "Reveal in Finder" },
|
||||
{ exec = "vim $*" },
|
||||
]
|
||||
archive = [
|
||||
{ cmd = "unar", args = [ "$0" ], display_name = "Extract here" },
|
||||
{ exec = "unar $1", display_name = "Extract here" },
|
||||
]
|
||||
text = [
|
||||
{ cmd = "vim", args = [ "$*" ], block = true },
|
||||
{ exec = "vim $*", block = true },
|
||||
]
|
||||
image = [
|
||||
{ cmd = "open", args = [ "$*" ], display_name = "Open" },
|
||||
{ cmd = "exiftool", args = [ "$0" ], block = true, display_name = "Show EXIF" },
|
||||
{ exec = "open $*", display_name = "Open" },
|
||||
{ exec = "exiftool $1; echo '\n\nPress enter to exit'; read", block = true, display_name = "Show EXIF" },
|
||||
]
|
||||
video = [
|
||||
{ cmd = "mpv", args = [ "$*" ] },
|
||||
{ cmd = "mediainfo", args = [ "$0" ], block = true, display_name = "Show media info" },
|
||||
{ exec = "mpv $*" },
|
||||
{ exec = "mediainfo $1; echo '\n\nPress enter to exit'; read", block = true, display_name = "Show media info" },
|
||||
]
|
||||
audio = [
|
||||
{ cmd = "mpv", args = [ "$*" ] },
|
||||
{ cmd = "mediainfo", args = [ "$0" ], block = true, display_name = "Show media info" },
|
||||
{ exec = "mpv $*" },
|
||||
{ exec = "mediainfo $1; echo '\n\nPress enter to exit'; read", block = true, display_name = "Show media info" },
|
||||
]
|
||||
fallback = [
|
||||
{ cmd = "open", args = [ "$*" ], display_name = "Open" },
|
||||
{ cmd = "open", args = [ "-R", "$*" ], display_name = "Reveal in Finder" },
|
||||
{ exec = "open $*", display_name = "Open" },
|
||||
{ exec = "open -R $*", display_name = "Reveal in Finder" },
|
||||
]
|
||||
|
||||
[open]
|
||||
|
|
|
|||
|
|
@ -1,49 +1,49 @@
|
|||
use std::{collections::BTreeMap, fmt};
|
||||
use std::{collections::BTreeMap, fmt::{self, Debug}};
|
||||
|
||||
use anyhow::bail;
|
||||
use serde::{de::{self, Visitor}, Deserializer};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Exec {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
pub named: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl From<&str> for Exec {
|
||||
fn from(value: &str) -> Self {
|
||||
let mut exec = Self::default();
|
||||
for x in value.split_whitespace() {
|
||||
if let Some(kv) = x.strip_prefix("--") {
|
||||
let mut it = kv.splitn(2, '=');
|
||||
let key = it.next().unwrap();
|
||||
let value = it.next().unwrap_or("");
|
||||
exec.named.insert(key.to_string(), value.to_string());
|
||||
} else if exec.cmd.is_empty() {
|
||||
exec.cmd = x.to_string();
|
||||
impl TryFrom<&str> for Exec {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
let s = shell_words::split(s)?;
|
||||
if s.is_empty() {
|
||||
bail!("`exec` cannot be empty");
|
||||
}
|
||||
|
||||
let mut exec = Self { cmd: s[0].clone(), args: Vec::new(), named: BTreeMap::new() };
|
||||
for arg in s.into_iter().skip(1) {
|
||||
if arg.starts_with("--") {
|
||||
let mut arg = arg.splitn(2, '=');
|
||||
let key = arg.next().unwrap().trim_start_matches('-');
|
||||
let val = arg.next().unwrap_or("").to_string();
|
||||
exec.named.insert(key.to_string(), val);
|
||||
} else {
|
||||
exec.args.push(x.to_string());
|
||||
exec.args.push(arg);
|
||||
}
|
||||
}
|
||||
exec
|
||||
Ok(exec)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Exec {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = self.cmd.clone();
|
||||
for arg in &self.args {
|
||||
s.push(' ');
|
||||
s.push_str(arg);
|
||||
let mut s = Vec::with_capacity(self.args.len() + self.named.len() + 1);
|
||||
s.push(self.cmd.clone());
|
||||
s.extend(self.args.iter().cloned());
|
||||
for (key, val) in self.named.iter() {
|
||||
s.push(format!("--{}={}", key, val));
|
||||
}
|
||||
for (name, value) in &self.named {
|
||||
s.push_str(" --");
|
||||
s.push_str(name);
|
||||
if !value.is_empty() {
|
||||
s.push('=');
|
||||
s.push_str(value);
|
||||
}
|
||||
}
|
||||
s
|
||||
|
||||
shell_words::join(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ impl Exec {
|
|||
type Value = Vec<Exec>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a command string, e.g. tab_switch 0")
|
||||
formatter.write_str("a exec string, e.g. tab_switch 0")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
|
|
@ -67,7 +67,7 @@ impl Exec {
|
|||
{
|
||||
let mut execs = Vec::new();
|
||||
while let Some(value) = &seq.next_element::<String>()? {
|
||||
execs.push(Exec::from(value.as_str()));
|
||||
execs.push(Exec::try_from(value.as_str()).map_err(de::Error::custom)?);
|
||||
}
|
||||
Ok(execs)
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ impl Exec {
|
|||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(value.split(';').map(Exec::from).collect())
|
||||
Ok(vec![Exec::try_from(value).map_err(de::Error::custom)?])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ use serde::{Deserialize, Deserializer};
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Opener {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
pub exec: String,
|
||||
pub block: bool,
|
||||
pub display_name: String,
|
||||
pub spread: bool,
|
||||
|
|
@ -16,20 +15,64 @@ impl<'de> Deserialize<'de> for Opener {
|
|||
{
|
||||
#[derive(Deserialize)]
|
||||
pub struct Shadow {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
// TODO: Deprecate this field in v0.1.5
|
||||
pub cmd: Option<String>,
|
||||
// TODO: Deprecate this field in v0.1.5
|
||||
pub args: Option<Vec<String>>,
|
||||
|
||||
pub exec: Option<String>,
|
||||
#[serde(default)]
|
||||
pub block: bool,
|
||||
pub display_name: Option<String>,
|
||||
#[serde(skip)]
|
||||
pub spread: bool,
|
||||
}
|
||||
|
||||
let shadow = Shadow::deserialize(deserializer)?;
|
||||
let mut shadow = Shadow::deserialize(deserializer)?;
|
||||
|
||||
let display_name = if let Some(s) = shadow.display_name { s } else { shadow.cmd.clone() };
|
||||
let spread = shadow.args.contains(&"$*".to_string());
|
||||
// -- TODO: Deprecate this in v0.1.5
|
||||
if shadow.exec.is_none() {
|
||||
if shadow.cmd.is_none() {
|
||||
return Err(serde::de::Error::missing_field("exec"));
|
||||
}
|
||||
if shadow.args.is_none() {
|
||||
return Err(serde::de::Error::missing_field("args"));
|
||||
}
|
||||
|
||||
Ok(Self { cmd: shadow.cmd, args: shadow.args, block: shadow.block, display_name, spread })
|
||||
println!(
|
||||
"WARNING: `cmd` and `args` are deprecated in favor of `exec` in Yazi v0.1.5, see https://github.com/sxyazi/yazi/pull/45"
|
||||
);
|
||||
|
||||
// Replace the $0 to $1, $1 to $2, and so on
|
||||
shadow.args = Some(
|
||||
shadow
|
||||
.args
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
if !s.starts_with('$') {
|
||||
return shell_words::quote(&s).into();
|
||||
}
|
||||
if let Ok(idx) = s[1..].parse::<usize>() {
|
||||
return format!("${}", idx + 1);
|
||||
}
|
||||
s
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
shadow.exec = Some(format!("{} {}", shadow.cmd.unwrap(), shadow.args.unwrap().join(" ")));
|
||||
}
|
||||
let exec = shadow.exec.unwrap();
|
||||
// TODO: Deprecate this in v0.1.5 --
|
||||
|
||||
if exec.is_empty() {
|
||||
return Err(serde::de::Error::custom("`exec` cannot be empty"));
|
||||
}
|
||||
let display_name = if let Some(s) = shadow.display_name {
|
||||
s
|
||||
} else {
|
||||
exec.split_whitespace().next().unwrap().to_string()
|
||||
};
|
||||
|
||||
let spread = exec.contains("$*") || exec.contains("$@");
|
||||
Ok(Self { exec, block: shadow.block, display_name, spread })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
core/src/external/mod.rs
vendored
2
core/src/external/mod.rs
vendored
|
|
@ -7,6 +7,7 @@ mod jq;
|
|||
mod lsar;
|
||||
mod pdftoppm;
|
||||
mod rg;
|
||||
mod shell;
|
||||
mod unar;
|
||||
mod zoxide;
|
||||
|
||||
|
|
@ -19,5 +20,6 @@ pub use jq::*;
|
|||
pub use lsar::*;
|
||||
pub use pdftoppm::*;
|
||||
pub use rg::*;
|
||||
pub use shell::*;
|
||||
pub use unar::*;
|
||||
pub use zoxide::*;
|
||||
|
|
|
|||
41
core/src/external/shell.rs
vendored
Normal file
41
core/src/external/shell.rs
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
use std::{ffi::OsString, process::Stdio};
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::process::{Child, Command};
|
||||
|
||||
pub struct ShellOpt {
|
||||
pub cmd: OsString,
|
||||
pub args: Vec<OsString>,
|
||||
pub piped: bool,
|
||||
}
|
||||
|
||||
pub fn shell(opt: ShellOpt) -> Result<Child> {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
Ok(
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(opt.cmd)
|
||||
.arg("") // $0 is the command name
|
||||
.args(opt.args)
|
||||
.stdout(if opt.piped { Stdio::piped() } else { Stdio::inherit() })
|
||||
.stderr(if opt.piped { Stdio::piped() } else { Stdio::inherit() })
|
||||
.kill_on_drop(true)
|
||||
.spawn()?,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Ok(
|
||||
Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(opt.cmd)
|
||||
.args(opt.args)
|
||||
.stdout(if opt.piped { Stdio::piped() } else { Stdio::inherit() })
|
||||
.stderr(if opt.piped { Stdio::piped() } else { Stdio::inherit() })
|
||||
.kill_on_drop(true)
|
||||
.spawn()?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -229,16 +229,10 @@ impl Manager {
|
|||
tokio::spawn(async move {
|
||||
let result = emit!(Input(InputOpt::top("Shell:").with_highlight()));
|
||||
|
||||
if let Ok(cmd) = result.await {
|
||||
if let Ok(exec) = result.await {
|
||||
emit!(Open(
|
||||
vec![(cmd.into(), "".to_string())],
|
||||
Some(Opener {
|
||||
cmd: "sh".to_string(),
|
||||
args: vec!["-c".to_string(), "$0".to_string()],
|
||||
block,
|
||||
display_name: Default::default(),
|
||||
spread: false,
|
||||
})
|
||||
Default::default(),
|
||||
Some(Opener { exec, block, display_name: Default::default(), spread: true })
|
||||
));
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{ffi::{OsStr, OsString}, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{ffi::OsStr, path::PathBuf, sync::Arc, time::Duration};
|
||||
|
||||
use async_channel::{Receiver, Sender};
|
||||
use config::open::Opener;
|
||||
|
|
@ -280,23 +280,12 @@ impl Scheduler {
|
|||
}
|
||||
|
||||
pub(super) fn process_open(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) {
|
||||
let args: Vec<OsString> = opener
|
||||
.args
|
||||
.iter()
|
||||
.map_while(|a| {
|
||||
if !a.starts_with('$') {
|
||||
return Some(vec![a.into()]);
|
||||
}
|
||||
if a == "$*" {
|
||||
return Some(args.iter().map(Into::into).collect());
|
||||
}
|
||||
a[1..].parse().ok().and_then(|n: usize| args.get(n)).map(|a| vec![a.into()])
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
let mut running = self.running.write();
|
||||
let name = format!("Exec `{} {}`", opener.cmd, args.join(" ".as_ref()).to_string_lossy());
|
||||
let name = format!(
|
||||
"Exec `{}` with `{}`",
|
||||
opener.exec,
|
||||
args.iter().map(|a| a.as_ref()).collect::<Vec<_>>().join(" ".as_ref()).to_string_lossy()
|
||||
);
|
||||
let id = running.add(name);
|
||||
|
||||
let (cancel_tx, mut cancel_rx) = oneshot::channel();
|
||||
|
|
@ -313,12 +302,19 @@ impl Scheduler {
|
|||
})
|
||||
});
|
||||
|
||||
let args = args.into_iter().map(|a| a.as_ref().to_os_string()).collect::<Vec<_>>();
|
||||
tokio::spawn({
|
||||
let process = self.process.clone();
|
||||
let opener = opener.clone();
|
||||
async move {
|
||||
process
|
||||
.open(ProcessOpOpen { id, cmd: opener.cmd, args, block: opener.block, cancel: cancel_tx })
|
||||
.open(ProcessOpOpen {
|
||||
id,
|
||||
cmd: opener.exec.into(),
|
||||
args,
|
||||
block: opener.block,
|
||||
cancel: cancel_tx,
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ impl Tasks {
|
|||
let mut openers = BTreeMap::new();
|
||||
for (path, mime) in targets {
|
||||
if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first().cloned()) {
|
||||
openers.entry(opener).or_insert_with(Vec::new).push(path.as_ref());
|
||||
openers.entry(opener).or_insert_with(Vec::new).push(path.as_ref().as_os_str());
|
||||
}
|
||||
}
|
||||
for (opener, args) in openers {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::{ffi::OsString, process::Stdio};
|
||||
use std::ffi::OsString;
|
||||
|
||||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, select, sync::{mpsc, oneshot}};
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{emit, tasks::TaskOp, BLOCKER};
|
||||
use crate::{emit, external::{self, ShellOpt}, tasks::TaskOp, BLOCKER};
|
||||
|
||||
pub(crate) struct Process {
|
||||
sch: mpsc::UnboundedSender<TaskOp>,
|
||||
|
|
@ -13,7 +13,7 @@ pub(crate) struct Process {
|
|||
#[derive(Debug)]
|
||||
pub(crate) struct ProcessOpOpen {
|
||||
pub id: usize,
|
||||
pub cmd: String,
|
||||
pub cmd: OsString,
|
||||
pub args: Vec<OsString>,
|
||||
pub block: bool,
|
||||
pub cancel: oneshot::Sender<()>,
|
||||
|
|
@ -33,12 +33,12 @@ impl Process {
|
|||
let _guard = BLOCKER.acquire().await.unwrap();
|
||||
emit!(Stop(true)).await;
|
||||
|
||||
match Command::new(&task.cmd).args(&task.args).kill_on_drop(true).spawn() {
|
||||
match external::shell(ShellOpt { cmd: task.cmd, args: task.args, piped: false }) {
|
||||
Ok(mut child) => {
|
||||
child.wait().await.ok();
|
||||
}
|
||||
Err(e) => {
|
||||
trace!("Failed to spawn {}: {e}", task.cmd);
|
||||
trace!("Failed to spawn process: {e}");
|
||||
}
|
||||
}
|
||||
emit!(Stop(false)).await;
|
||||
|
|
@ -48,12 +48,7 @@ impl Process {
|
|||
}
|
||||
|
||||
self.sch.send(TaskOp::New(task.id, 0))?;
|
||||
let mut child = Command::new(&task.cmd)
|
||||
.args(&task.args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.kill_on_drop(true)
|
||||
.spawn()?;
|
||||
let mut child = external::shell(ShellOpt { cmd: task.cmd, args: task.args, piped: true })?;
|
||||
|
||||
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
|
||||
let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp"],"version":"0.2","language":"en"}
|
||||
{"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","️ Überzug","️ Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nocapture"],"version":"0.2"}
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ crossterm = "^0"
|
|||
libc = "^0"
|
||||
parking_lot = "^0"
|
||||
ratatui = { version = "^0" }
|
||||
tokio = { version = "^1", features = [ "parking_lot" ] }
|
||||
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs" ] }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue