zed_extension_api: Add simple process
API (#25399)
This PR adds a simple API for working with processes to the extension API. The API is designed to mirror Rust's [`std::process::Command`](https://doc.rust-lang.org/std/process/struct.Command.html). Release Notes: - N/A
This commit is contained in:
parent
ec4d9ec111
commit
4d106a4b0b
6 changed files with 109 additions and 14 deletions
|
@ -1,6 +1,7 @@
|
||||||
//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
|
//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
|
||||||
|
|
||||||
pub mod http_client;
|
pub mod http_client;
|
||||||
|
pub mod process;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
44
crates/extension_api/src/process.rs
Normal file
44
crates/extension_api/src/process.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//! A module for working with processes.
|
||||||
|
|
||||||
|
use crate::wit::zed::extension::process;
|
||||||
|
pub use crate::wit::zed::extension::process::{Command, Output};
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
pub fn new(program: impl Into<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
command: program.into(),
|
||||||
|
args: Vec::new(),
|
||||||
|
env: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn arg(mut self, arg: impl Into<String>) -> Self {
|
||||||
|
self.args.push(arg.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
|
||||||
|
self.args.extend(args.into_iter().map(Into::into));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
|
||||||
|
self.env.push((key.into(), value.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn envs(
|
||||||
|
mut self,
|
||||||
|
envs: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
|
||||||
|
) -> Self {
|
||||||
|
self.env.extend(
|
||||||
|
envs.into_iter()
|
||||||
|
.map(|(key, value)| (key.into(), value.into())),
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn output(&mut self) -> Result<Output, String> {
|
||||||
|
process::run_command(self)
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,4 +6,7 @@ interface common {
|
||||||
/// The end of the range (exclusive).
|
/// The end of the range (exclusive).
|
||||||
end: u32,
|
end: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A list of environment variables.
|
||||||
|
type env-vars = list<tuple<string, string>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@ world extension {
|
||||||
import github;
|
import github;
|
||||||
import http-client;
|
import http-client;
|
||||||
import platform;
|
import platform;
|
||||||
|
import process;
|
||||||
import nodejs;
|
import nodejs;
|
||||||
|
|
||||||
use common.{range};
|
use common.{env-vars, range};
|
||||||
use lsp.{completion, symbol};
|
use lsp.{completion, symbol};
|
||||||
|
use process.{command};
|
||||||
use slash-command.{slash-command, slash-command-argument-completion, slash-command-output};
|
use slash-command.{slash-command, slash-command-argument-completion, slash-command-output};
|
||||||
|
|
||||||
/// Initializes the extension.
|
/// Initializes the extension.
|
||||||
|
@ -56,19 +58,6 @@ world extension {
|
||||||
/// Updates the installation status for the given language server.
|
/// Updates the installation status for the given language server.
|
||||||
import set-language-server-installation-status: func(language-server-name: string, status: language-server-installation-status);
|
import set-language-server-installation-status: func(language-server-name: string, status: language-server-installation-status);
|
||||||
|
|
||||||
/// A list of environment variables.
|
|
||||||
type env-vars = list<tuple<string, string>>;
|
|
||||||
|
|
||||||
/// A command.
|
|
||||||
record command {
|
|
||||||
/// The command to execute.
|
|
||||||
command: string,
|
|
||||||
/// The arguments to pass to the command.
|
|
||||||
args: list<string>,
|
|
||||||
/// The environment variables to set for the command.
|
|
||||||
env: env-vars,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Zed worktree.
|
/// A Zed worktree.
|
||||||
resource worktree {
|
resource worktree {
|
||||||
/// Returns the ID of the worktree.
|
/// Returns the ID of the worktree.
|
||||||
|
|
29
crates/extension_api/wit/since_v0.3.0/process.wit
Normal file
29
crates/extension_api/wit/since_v0.3.0/process.wit
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
interface process {
|
||||||
|
use common.{env-vars};
|
||||||
|
|
||||||
|
/// A command.
|
||||||
|
record command {
|
||||||
|
/// The command to execute.
|
||||||
|
command: string,
|
||||||
|
/// The arguments to pass to the command.
|
||||||
|
args: list<string>,
|
||||||
|
/// The environment variables to set for the command.
|
||||||
|
env: env-vars,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The output of a finished process.
|
||||||
|
record output {
|
||||||
|
/// The status (exit code) of the process.
|
||||||
|
///
|
||||||
|
/// On Unix, this will be `None` if the process was terminated by a signal.
|
||||||
|
status: option<s32>,
|
||||||
|
/// The data that the process wrote to stdout.
|
||||||
|
stdout: list<u8>,
|
||||||
|
/// The data that the process wrote to stderr.
|
||||||
|
stderr: list<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the given command as a child process, waiting for it to finish
|
||||||
|
/// and collecting all of its output.
|
||||||
|
run-command: func(command: command) -> result<output, string>;
|
||||||
|
}
|
|
@ -576,6 +576,35 @@ impl platform::Host for WasmState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<std::process::Output> for process::Output {
|
||||||
|
fn from(output: std::process::Output) -> Self {
|
||||||
|
Self {
|
||||||
|
status: output.status.code(),
|
||||||
|
stdout: output.stdout,
|
||||||
|
stderr: output.stderr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl process::Host for WasmState {
|
||||||
|
async fn run_command(
|
||||||
|
&mut self,
|
||||||
|
command: process::Command,
|
||||||
|
) -> wasmtime::Result<Result<process::Output, String>> {
|
||||||
|
maybe!(async {
|
||||||
|
let output = util::command::new_smol_command(command.command.as_str())
|
||||||
|
.args(&command.args)
|
||||||
|
.envs(command.env)
|
||||||
|
.output()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(output.into())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.to_wasmtime_result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl slash_command::Host for WasmState {}
|
impl slash_command::Host for WasmState {}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue