1use anyhow::{anyhow, Result};
2use async_trait::async_trait;
3use client::http::HttpClient;
4use futures::lock::Mutex;
5use gpui::executor::Background;
6use language::{LanguageServerName, LspAdapter};
7use plugin_runtime::{Plugin, PluginBuilder, WasiFn};
8use std::{any::Any, path::PathBuf, sync::Arc};
9use util::ResultExt;
10
11pub async fn new_json(executor: Arc<Background>) -> Result<PluginLspAdapter> {
12 let plugin = PluginBuilder::new_with_default_ctx()?
13 .host_function_async("command", |command: String| async move {
14 let mut args = command.split(' ');
15 let command = args.next().unwrap();
16 smol::process::Command::new(command)
17 .args(args)
18 .output()
19 .await
20 .log_err()
21 .map(|output| output.stdout)
22 })?
23 .init(
24 true,
25 include_bytes!("../../../../plugins/bin/json_language.wasm.pre"),
26 )
27 .await?;
28
29 PluginLspAdapter::new(plugin, executor).await
30}
31
32pub struct PluginLspAdapter {
33 name: WasiFn<(), String>,
34 server_args: WasiFn<(), Vec<String>>,
35 fetch_latest_server_version: WasiFn<(), Option<String>>,
36 fetch_server_binary: WasiFn<(PathBuf, String), Result<PathBuf, String>>,
37 cached_server_binary: WasiFn<PathBuf, Option<PathBuf>>,
38 initialization_options: WasiFn<(), String>,
39 executor: Arc<Background>,
40 runtime: Arc<Mutex<Plugin>>,
41}
42
43impl PluginLspAdapter {
44 pub async fn new(mut plugin: Plugin, executor: Arc<Background>) -> Result<Self> {
45 Ok(Self {
46 name: plugin.function("name")?,
47 server_args: plugin.function("server_args")?,
48 fetch_latest_server_version: plugin.function("fetch_latest_server_version")?,
49 fetch_server_binary: plugin.function("fetch_server_binary")?,
50 cached_server_binary: plugin.function("cached_server_binary")?,
51 initialization_options: plugin.function("initialization_options")?,
52 executor,
53 runtime: Arc::new(Mutex::new(plugin)),
54 })
55 }
56}
57
58#[async_trait]
59impl LspAdapter for PluginLspAdapter {
60 async fn name(&self) -> LanguageServerName {
61 let name: String = self
62 .runtime
63 .lock()
64 .await
65 .call(&self.name, ())
66 .await
67 .unwrap();
68 LanguageServerName(name.into())
69 }
70
71 async fn server_args<'a>(&'a self) -> Vec<String> {
72 self.runtime
73 .lock()
74 .await
75 .call(&self.server_args, ())
76 .await
77 .unwrap()
78 }
79
80 async fn fetch_latest_server_version(
81 &self,
82 _: Arc<dyn HttpClient>,
83 ) -> Result<Box<dyn 'static + Send + Any>> {
84 let runtime = self.runtime.clone();
85 let function = self.fetch_latest_server_version;
86 self.executor
87 .spawn(async move {
88 let mut runtime = runtime.lock().await;
89 let versions: Result<Option<String>> =
90 runtime.call::<_, Option<String>>(&function, ()).await;
91 versions
92 .map_err(|e| anyhow!("{}", e))?
93 .ok_or_else(|| anyhow!("Could not fetch latest server version"))
94 .map(|v| Box::new(v) as Box<_>)
95 })
96 .await
97 }
98
99 async fn fetch_server_binary(
100 &self,
101 version: Box<dyn 'static + Send + Any>,
102 _: Arc<dyn HttpClient>,
103 container_dir: PathBuf,
104 ) -> Result<PathBuf> {
105 let version = *version.downcast::<String>().unwrap();
106 let runtime = self.runtime.clone();
107 let function = self.fetch_server_binary;
108 self.executor
109 .spawn(async move {
110 let mut runtime = runtime.lock().await;
111 let handle = runtime.attach_path(&container_dir)?;
112 let result: Result<PathBuf, String> =
113 runtime.call(&function, (container_dir, version)).await?;
114 runtime.remove_resource(handle)?;
115 result.map_err(|e| anyhow!("{}", e))
116 })
117 .await
118 }
119
120 async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
121 let runtime = self.runtime.clone();
122 let function = self.cached_server_binary;
123
124 self.executor
125 .spawn(async move {
126 let mut runtime = runtime.lock().await;
127 let handle = runtime.attach_path(&container_dir).ok()?;
128 let result: Option<PathBuf> = runtime.call(&function, container_dir).await.ok()?;
129 runtime.remove_resource(handle).ok()?;
130 result
131 })
132 .await
133 }
134
135 async fn initialization_options(&self) -> Option<serde_json::Value> {
136 let string: String = self
137 .runtime
138 .lock()
139 .await
140 .call(&self.initialization_options, ())
141 .await
142 .log_err()?;
143
144 serde_json::from_str(&string).ok()
145 }
146}