From f45af17fd473746c82df851cda8cdd6923258701 Mon Sep 17 00:00:00 2001 From: Vitor Ramos Date: Thu, 22 Aug 2024 21:31:58 +0200 Subject: [PATCH] Add option to pipe from stdin on cli (#16084) Closes #5044 Release Notes: - Linux: Added CLI pipe support. --- Cargo.lock | 1 + crates/cli/Cargo.toml | 1 + crates/cli/src/main.rs | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index eb0cd9ba78..8d1f3dcd03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2266,6 +2266,7 @@ dependencies = [ "plist", "release_channel", "serde", + "tempfile", "util", ] diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index aa64e8de8f..f0d4bb77a5 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -26,6 +26,7 @@ paths.workspace = true release_channel.workspace = true serde.workspace = true util.workspace = true +tempfile.workspace = true [target.'cfg(target_os = "linux")'.dependencies] exec.workspace = true diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 6421b0876d..b0c8fdcbf7 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -11,6 +11,7 @@ use std::{ sync::Arc, thread::{self, JoinHandle}, }; +use tempfile::NamedTempFile; use util::paths::PathWithPosition; struct Detect; @@ -22,7 +23,11 @@ trait InstalledApp { } #[derive(Parser, Debug)] -#[command(name = "zed", disable_version_flag = true)] +#[command( + name = "zed", + disable_version_flag = true, + after_help = "To read from stdin, append '-' (e.g. 'ps axf | zed -')" +)] struct Args { /// Wait for all of the given paths to be opened/closed before exiting. #[arg(short, long)] @@ -120,6 +125,7 @@ fn main() -> Result<()> { let exit_status = Arc::new(Mutex::new(None)); let mut paths = vec![]; let mut urls = vec![]; + let mut stdin_tmp_file: Option = None; for path in args.paths_with_position.iter() { if path.starts_with("zed://") || path.starts_with("http://") @@ -128,6 +134,11 @@ fn main() -> Result<()> { || path.starts_with("ssh://") { urls.push(path.to_string()); + } else if path == "-" && args.paths_with_position.len() == 1 { + let file = NamedTempFile::new()?; + paths.push(file.path().to_string_lossy().to_string()); + let (file, _) = file.keep()?; + stdin_tmp_file = Some(file); } else { paths.push(parse_path_with_position(path)?) } @@ -162,11 +173,31 @@ fn main() -> Result<()> { } }); + let pipe_handle: JoinHandle> = thread::spawn(move || { + if let Some(mut tmp_file) = stdin_tmp_file { + let mut stdin = std::io::stdin().lock(); + if io::IsTerminal::is_terminal(&stdin) { + return Ok(()); + } + let mut buffer = [0; 8 * 1024]; + loop { + let bytes_read = io::Read::read(&mut stdin, &mut buffer)?; + if bytes_read == 0 { + break; + } + io::Write::write(&mut tmp_file, &buffer[..bytes_read])?; + } + io::Write::flush(&mut tmp_file)?; + } + Ok(()) + }); + if args.foreground { app.run_foreground(url)?; } else { app.launch(url)?; sender.join().unwrap()?; + pipe_handle.join().unwrap()?; } if let Some(exit_status) = exit_status.lock().take() {