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 tokio::process::{Child, Command};
#[derive(Default)]
pub struct ShellOpt {
pub cmd: 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 yazi_plugin::external::ShellOpt;
@ -13,13 +13,8 @@ pub struct ProcessOpOpen {
pub cancel: oneshot::Sender<()>,
}
impl From<&mut ProcessOpOpen> for ShellOpt {
fn from(op: &mut ProcessOpOpen) -> Self {
Self {
cmd: mem::take(&mut op.cmd),
args: mem::take(&mut op.args),
piped: false,
orphan: op.orphan,
}
impl From<ProcessOpOpen> for ShellOpt {
fn from(op: ProcessOpOpen) -> Self {
Self { cmd: op.cmd, args: 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 yazi_plugin::external::{self, ShellOpt};
use yazi_proxy::AppProxy;
use yazi_shared::Defer;
use super::ProcessOpOpen;
use crate::{TaskProg, BLOCKER};
@ -14,37 +15,21 @@ impl Process {
pub fn new(prog: mpsc::UnboundedSender<TaskProg>) -> Self { Self { prog } }
pub async fn open(&self, mut task: ProcessOpOpen) -> Result<()> {
let opt = ShellOpt::from(&mut task);
if task.block {
let _guard = BLOCKER.acquire().await.unwrap();
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());
return self.open_block(task).await;
}
if task.orphan {
match external::shell(opt) {
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(());
return self.open_orphan(task).await;
}
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 stderr = BufReader::new(child.stderr.take().unwrap()).lines();
@ -76,6 +61,43 @@ impl Process {
self.prog.send(TaskProg::Adv(task.id, 1, 0))?;
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 {