diff --git a/Cargo.lock b/Cargo.lock index 68f3132b9a..89534cb02f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1950,6 +1950,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "future-wrap" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bab12b2506593396c1339caf22beeb6f5cbe95dac5e376b71a3d17cbe2c4630" +dependencies = [ + "pin-project", +] + [[package]] name = "futures" version = "0.3.21" @@ -3720,6 +3729,7 @@ dependencies = [ "pollster", "serde", "serde_json", + "smol", "wasi-common", "wasmtime", "wasmtime-wasi", @@ -7008,6 +7018,7 @@ dependencies = [ "env_logger", "file_finder", "fsevent", + "future-wrap", "futures", "fuzzy", "go_to_line", diff --git a/crates/plugin_macros/src/lib.rs b/crates/plugin_macros/src/lib.rs index 55f31b8e0c..8a008dffd0 100644 --- a/crates/plugin_macros/src/lib.rs +++ b/crates/plugin_macros/src/lib.rs @@ -6,6 +6,15 @@ use syn::{ parse_macro_input, Block, FnArg, ForeignItemFn, Ident, ItemFn, Pat, PatIdent, Type, Visibility, }; +/// Attribute macro to be used guest-side within a plugin. +/// ```ignore +/// #[export] +/// pub fn say_hello() -> String { +/// "Hello from Wasm".into() +/// } +/// ``` +/// This macro makes a function defined guest-side avaliable host-side. +/// Note that all arguments and return types must be `serde`. #[proc_macro_attribute] pub fn export(args: TokenStream, function: TokenStream) -> TokenStream { if !args.is_empty() { @@ -81,6 +90,14 @@ pub fn export(args: TokenStream, function: TokenStream) -> TokenStream { }) } +/// Attribute macro to be used guest-side within a plugin. +/// ```ignore +/// #[import] +/// pub fn operating_system_name() -> String; +/// ``` +/// This macro makes a function defined host-side avaliable guest-side. +/// Note that all arguments and return types must be `serde`. +/// All that's provided is a signature, as the function is implemented host-side. #[proc_macro_attribute] pub fn import(args: TokenStream, function: TokenStream) -> TokenStream { if !args.is_empty() { diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 433c436003..5bb441831b 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -102,6 +102,9 @@ tree-sitter-toml = { git = "https://github.com/tree-sitter/tree-sitter-toml", re tree-sitter-typescript = "0.20.1" url = "2.2" +# TODO(isaac): remove this +future-wrap = "0.1.1" + [dev-dependencies] text = { path = "../text", features = ["test-support"] } editor = { path = "../editor", features = ["test-support"] } diff --git a/crates/zed/src/languages/language_plugin.rs b/crates/zed/src/languages/language_plugin.rs index 9c7796b4b2..dbca61d7ec 100644 --- a/crates/zed/src/languages/language_plugin.rs +++ b/crates/zed/src/languages/language_plugin.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Result}; use client::http::HttpClient; use futures::lock::Mutex; +use futures::Future; use futures::{future::BoxFuture, FutureExt}; use gpui::executor::Background; use language::{LanguageServerName, LspAdapter}; @@ -8,6 +9,8 @@ use plugin_runtime::{Plugin, PluginBuilder, WasiFn}; use std::{any::Any, path::PathBuf, sync::Arc}; use util::ResultExt; +use future_wrap::*; + pub async fn new_json(executor: Arc) -> Result { let plugin = PluginBuilder::new_with_default_ctx()? .host_function_async("command", |command: String| async move { @@ -15,15 +18,20 @@ pub async fn new_json(executor: Arc) -> Result { dbg!(&command); let mut args = command.split(' '); let command = args.next().unwrap(); - smol::process::Command::new(command) - .args(args) - .output() - .await - .log_err() - .map(|output| { - dbg!("done running command"); - output.stdout - }) + dbg!("Running command"); + let future = smol::process::Command::new(command).args(args).output(); + let future = future.wrap(|fut, cx| { + dbg!("Poll command start"); + let res = fut.poll(cx); + dbg!("Poll command end"); + res + }); + dbg!("blocked on future"); + let future = smol::block_on(future); + future.log_err().map(|output| { + dbg!("done running command"); + output.stdout + }) })? .init(include_bytes!("../../../../plugins/bin/json_language.wasm")) .await?; diff --git a/plugins/test_plugin/src/lib.rs b/plugins/test_plugin/src/lib.rs index 34d7d4cb13..5ea50602f3 100644 --- a/plugins/test_plugin/src/lib.rs +++ b/plugins/test_plugin/src/lib.rs @@ -69,3 +69,15 @@ fn import_half(a: u32) -> u32; pub fn half_async(a: u32) -> u32 { import_half(a) } + +#[import] +fn command_async(command: String) -> Option>; + +#[export] +pub fn echo_async(message: String) -> String { + let command = dbg!(format!("echo {}", message)); + let result = command_async(command); + dbg!(&result); + let result = result.expect("Could not run command"); + String::from_utf8_lossy(&result).to_string() +}