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