feat: send a foreground notification to the user when the process fails to run (#775)

This commit is contained in:
Prajna 2024-03-06 23:43:39 +08:00 committed by GitHub
parent b6e458f221
commit 1aed6e8b36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 33 deletions

View file

@ -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>,

View file

@ -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,
}
} }
} }

View file

@ -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 {