extension_lsp_adapter.rs

  1use crate::wasm_host::{wit::LanguageServerConfig, WasmExtension, WasmHost};
  2use anyhow::{anyhow, Context, Result};
  3use async_trait::async_trait;
  4use futures::{Future, FutureExt};
  5use gpui::AsyncAppContext;
  6use language::{Language, LanguageServerName, LspAdapter, LspAdapterDelegate};
  7use lsp::LanguageServerBinary;
  8use std::{
  9    any::Any,
 10    path::{Path, PathBuf},
 11    pin::Pin,
 12    sync::Arc,
 13};
 14use wasmtime_wasi::WasiView as _;
 15
 16pub struct ExtensionLspAdapter {
 17    pub(crate) extension: WasmExtension,
 18    pub(crate) config: LanguageServerConfig,
 19    pub(crate) host: Arc<WasmHost>,
 20}
 21
 22#[async_trait(?Send)]
 23impl LspAdapter for ExtensionLspAdapter {
 24    fn name(&self) -> LanguageServerName {
 25        LanguageServerName(self.config.name.clone().into())
 26    }
 27
 28    fn get_language_server_command<'a>(
 29        self: Arc<Self>,
 30        _: Arc<Language>,
 31        _: Arc<Path>,
 32        delegate: Arc<dyn LspAdapterDelegate>,
 33        _: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
 34        _: &'a mut AsyncAppContext,
 35    ) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
 36        async move {
 37            let command = self
 38                .extension
 39                .call({
 40                    let this = self.clone();
 41                    |extension, store| {
 42                        async move {
 43                            let resource = store.data_mut().table().push(delegate)?;
 44                            let command = extension
 45                                .call_language_server_command(store, &this.config, resource)
 46                                .await?
 47                                .map_err(|e| anyhow!("{}", e))?;
 48                            anyhow::Ok(command)
 49                        }
 50                        .boxed()
 51                    }
 52                })
 53                .await?;
 54
 55            let path = self
 56                .host
 57                .path_from_extension(&self.extension.manifest.id, command.command.as_ref());
 58
 59            Ok(LanguageServerBinary {
 60                path,
 61                arguments: command.args.into_iter().map(|arg| arg.into()).collect(),
 62                env: Some(command.env.into_iter().collect()),
 63            })
 64        }
 65        .boxed_local()
 66    }
 67
 68    async fn fetch_latest_server_version(
 69        &self,
 70        _: &dyn LspAdapterDelegate,
 71    ) -> Result<Box<dyn 'static + Send + Any>> {
 72        unreachable!("get_language_server_command is overridden")
 73    }
 74
 75    async fn fetch_server_binary(
 76        &self,
 77        _: Box<dyn 'static + Send + Any>,
 78        _: PathBuf,
 79        _: &dyn LspAdapterDelegate,
 80    ) -> Result<LanguageServerBinary> {
 81        unreachable!("get_language_server_command is overridden")
 82    }
 83
 84    async fn cached_server_binary(
 85        &self,
 86        _: PathBuf,
 87        _: &dyn LspAdapterDelegate,
 88    ) -> Option<LanguageServerBinary> {
 89        unreachable!("get_language_server_command is overridden")
 90    }
 91
 92    async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
 93        None
 94    }
 95
 96    async fn initialization_options(
 97        self: Arc<Self>,
 98        delegate: &Arc<dyn LspAdapterDelegate>,
 99    ) -> Result<Option<serde_json::Value>> {
100        let delegate = delegate.clone();
101        let json_options = self
102            .extension
103            .call({
104                let this = self.clone();
105                |extension, store| {
106                    async move {
107                        let resource = store.data_mut().table().push(delegate)?;
108                        let options = extension
109                            .call_language_server_initialization_options(
110                                store,
111                                &this.config,
112                                resource,
113                            )
114                            .await?
115                            .map_err(|e| anyhow!("{}", e))?;
116                        anyhow::Ok(options)
117                    }
118                    .boxed()
119                }
120            })
121            .await?;
122        Ok(if let Some(json_options) = json_options {
123            serde_json::from_str(&json_options).with_context(|| {
124                format!("failed to parse initialization_options from extension: {json_options}")
125            })?
126        } else {
127            None
128        })
129    }
130}