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.
|
||||
|
||||
pub mod http_client;
|
||||
pub mod process;
|
||||
pub mod settings;
|
||||
|
||||
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).
|
||||
end: u32,
|
||||
}
|
||||
|
||||
/// A list of environment variables.
|
||||
type env-vars = list<tuple<string, string>>;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ world extension {
|
|||
import github;
|
||||
import http-client;
|
||||
import platform;
|
||||
import process;
|
||||
import nodejs;
|
||||
|
||||
use common.{range};
|
||||
use common.{env-vars, range};
|
||||
use lsp.{completion, symbol};
|
||||
use process.{command};
|
||||
use slash-command.{slash-command, slash-command-argument-completion, slash-command-output};
|
||||
|
||||
/// Initializes the extension.
|
||||
|
@ -56,19 +58,6 @@ world extension {
|
|||
/// 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);
|
||||
|
||||
/// 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.
|
||||
resource 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]
|
||||
impl slash_command::Host for WasmState {}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue