mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: send a foreground notification to the user when the process fails to run (#775)
This commit is contained in:
parent
b6e458f221
commit
1aed6e8b36
3 changed files with 51 additions and 33 deletions
1
yazi-plugin/src/external/shell.rs
vendored
1
yazi-plugin/src/external/shell.rs
vendored
|
|
@ -3,6 +3,7 @@ use std::{env, ffi::OsString, process::Stdio};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use tokio::process::{Child, Command};
|
use tokio::process::{Child, Command};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct ShellOpt {
|
pub struct ShellOpt {
|
||||||
pub cmd: OsString,
|
pub cmd: OsString,
|
||||||
pub args: Vec<OsString>,
|
pub args: Vec<OsString>,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{ffi::OsString, mem};
|
use std::ffi::OsString;
|
||||||
|
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use yazi_plugin::external::ShellOpt;
|
use yazi_plugin::external::ShellOpt;
|
||||||
|
|
@ -13,13 +13,8 @@ pub struct ProcessOpOpen {
|
||||||
pub cancel: oneshot::Sender<()>,
|
pub cancel: oneshot::Sender<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&mut ProcessOpOpen> for ShellOpt {
|
impl From<ProcessOpOpen> for ShellOpt {
|
||||||
fn from(op: &mut ProcessOpOpen) -> Self {
|
fn from(op: ProcessOpOpen) -> Self {
|
||||||
Self {
|
Self { cmd: op.cmd, args: op.args, piped: false, orphan: op.orphan }
|
||||||
cmd: mem::take(&mut op.cmd),
|
|
||||||
args: mem::take(&mut op.args),
|
|
||||||
piped: false,
|
|
||||||
orphan: op.orphan,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use anyhow::Result;
|
||||||
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc};
|
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc};
|
||||||
use yazi_plugin::external::{self, ShellOpt};
|
use yazi_plugin::external::{self, ShellOpt};
|
||||||
use yazi_proxy::AppProxy;
|
use yazi_proxy::AppProxy;
|
||||||
|
use yazi_shared::Defer;
|
||||||
|
|
||||||
use super::ProcessOpOpen;
|
use super::ProcessOpOpen;
|
||||||
use crate::{TaskProg, BLOCKER};
|
use crate::{TaskProg, BLOCKER};
|
||||||
|
|
@ -14,37 +15,21 @@ impl Process {
|
||||||
pub fn new(prog: mpsc::UnboundedSender<TaskProg>) -> Self { Self { prog } }
|
pub fn new(prog: mpsc::UnboundedSender<TaskProg>) -> Self { Self { prog } }
|
||||||
|
|
||||||
pub async fn open(&self, mut task: ProcessOpOpen) -> Result<()> {
|
pub async fn open(&self, mut task: ProcessOpOpen) -> Result<()> {
|
||||||
let opt = ShellOpt::from(&mut task);
|
|
||||||
if task.block {
|
if task.block {
|
||||||
let _guard = BLOCKER.acquire().await.unwrap();
|
return self.open_block(task).await;
|
||||||
AppProxy::stop().await;
|
|
||||||
|
|
||||||
match external::shell(opt) {
|
|
||||||
Ok(mut child) => {
|
|
||||||
child.wait().await.ok();
|
|
||||||
self.succ(task.id)?;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
self.prog.send(TaskProg::New(task.id, 0))?;
|
|
||||||
self.fail(task.id, format!("Failed to spawn process: {e}"))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(AppProxy::resume());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.orphan {
|
if task.orphan {
|
||||||
match external::shell(opt) {
|
return self.open_orphan(task).await;
|
||||||
Ok(_) => self.succ(task.id)?,
|
|
||||||
Err(e) => {
|
|
||||||
self.prog.send(TaskProg::New(task.id, 0))?;
|
|
||||||
self.fail(task.id, format!("Failed to spawn process: {e}"))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.prog.send(TaskProg::New(task.id, 0))?;
|
self.prog.send(TaskProg::New(task.id, 0))?;
|
||||||
let mut child = external::shell(opt.with_piped())?;
|
let mut child = external::shell(ShellOpt {
|
||||||
|
cmd: task.cmd,
|
||||||
|
args: task.args,
|
||||||
|
piped: true,
|
||||||
|
..Default::default()
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
|
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
|
||||||
let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();
|
let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();
|
||||||
|
|
@ -76,6 +61,43 @@ impl Process {
|
||||||
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
|
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
|
||||||
self.succ(task.id)
|
self.succ(task.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn open_block(&self, task: ProcessOpOpen) -> Result<()> {
|
||||||
|
let _guard = BLOCKER.acquire().await.unwrap();
|
||||||
|
let _defer = Defer::new(AppProxy::resume);
|
||||||
|
AppProxy::stop().await;
|
||||||
|
|
||||||
|
let (id, cmd) = (task.id, task.cmd.clone());
|
||||||
|
let result = external::shell(task.into());
|
||||||
|
if let Err(e) = result {
|
||||||
|
AppProxy::notify_warn(&cmd.to_string_lossy(), &format!("Failed to spawn process: {e}"));
|
||||||
|
return self.succ(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = result.unwrap().wait().await?;
|
||||||
|
if !status.success() {
|
||||||
|
let content = match status.code() {
|
||||||
|
Some(code) => format!("Process exited with status code: {code}"),
|
||||||
|
None => "Process terminated by signal".to_string(),
|
||||||
|
};
|
||||||
|
AppProxy::notify_warn(&cmd.to_string_lossy(), &content);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.succ(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn open_orphan(&self, task: ProcessOpOpen) -> Result<()> {
|
||||||
|
let id = task.id;
|
||||||
|
match external::shell(task.into()) {
|
||||||
|
Ok(_) => self.succ(id)?,
|
||||||
|
Err(e) => {
|
||||||
|
self.prog.send(TaskProg::New(id, 0))?;
|
||||||
|
self.fail(id, format!("Failed to spawn process: {e}"))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue