Checkpoint

Isaac Clayton created

Change summary

Cargo.lock                                  | 11 +++++++++
crates/plugin_macros/src/lib.rs             | 17 +++++++++++++++
crates/zed/Cargo.toml                       |  3 ++
crates/zed/src/languages/language_plugin.rs | 26 +++++++++++++++-------
plugins/test_plugin/src/lib.rs              | 12 ++++++++++
5 files changed, 60 insertions(+), 9 deletions(-)

Detailed changes

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",

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() {

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"] }

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<Background>) -> Result<PluginLspAdapter> {
     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<Background>) -> Result<PluginLspAdapter> {
             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?;

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<Vec<u8>>;
+
+#[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()
+}