vue_language_server_ext.rs

  1use anyhow::Context as _;
  2use gpui::{AppContext, WeakEntity};
  3use lsp::{LanguageServer, LanguageServerName};
  4use serde_json::Value;
  5
  6use crate::LspStore;
  7
  8struct VueServerRequest;
  9struct TypescriptServerResponse;
 10
 11impl lsp::notification::Notification for VueServerRequest {
 12    type Params = Vec<(u64, String, serde_json::Value)>;
 13
 14    const METHOD: &'static str = "tsserver/request";
 15}
 16
 17impl lsp::notification::Notification for TypescriptServerResponse {
 18    type Params = Vec<(u64, serde_json::Value)>;
 19
 20    const METHOD: &'static str = "tsserver/response";
 21}
 22
 23const VUE_SERVER_NAME: LanguageServerName = LanguageServerName::new_static("vue-language-server");
 24const VTSLS: LanguageServerName = LanguageServerName::new_static("vtsls");
 25const TS_LS: LanguageServerName = LanguageServerName::new_static("typescript-language-server");
 26
 27pub fn register_requests(lsp_store: WeakEntity<LspStore>, language_server: &LanguageServer) {
 28    let language_server_name = language_server.name();
 29    if language_server_name == VUE_SERVER_NAME {
 30        let vue_server_id = language_server.server_id();
 31        language_server
 32            .on_notification::<VueServerRequest, _>({
 33                move |params, cx| {
 34                    let lsp_store = lsp_store.clone();
 35                    let Ok(Some(vue_server)) = lsp_store.read_with(cx, |this, _| {
 36                        this.language_server_for_id(vue_server_id)
 37                    }) else {
 38                        return;
 39                    };
 40
 41                    let requests = params;
 42                    let target_server = match lsp_store.read_with(cx, |this, _| {
 43                        let language_server_id = this
 44                            .as_local()
 45                            .and_then(|local| {
 46                                local.language_server_ids.iter().find_map(|(seed, v)| {
 47                                    [VTSLS, TS_LS].contains(&seed.name).then_some(v.id)
 48                                })
 49                            })
 50                            .context("Could not find language server")?;
 51
 52                        this.language_server_for_id(language_server_id)
 53                            .context("language server not found")
 54                    }) {
 55                        Ok(Ok(server)) => server,
 56                        other => {
 57                            log::warn!(
 58                                "vue-language-server forwarding skipped: {other:?}. \
 59                                 Returning null tsserver responses"
 60                            );
 61                            if !requests.is_empty() {
 62                                let null_responses = requests
 63                                    .into_iter()
 64                                    .map(|(id, _, _)| (id, Value::Null))
 65                                    .collect::<Vec<_>>();
 66                                let _ = vue_server
 67                                    .notify::<TypescriptServerResponse>(null_responses);
 68                            }
 69                            return;
 70                        }
 71                    };
 72
 73                    let cx = cx.clone();
 74                    for (request_id, command, payload) in requests.into_iter() {
 75                        let target_server = target_server.clone();
 76                        let vue_server = vue_server.clone();
 77                        cx.background_spawn(async move {
 78                            let response = target_server
 79                                .request::<lsp::request::ExecuteCommand>(
 80                                    lsp::ExecuteCommandParams {
 81                                        command: "typescript.tsserverRequest".to_owned(),
 82                                        arguments: vec![Value::String(command), payload],
 83                                        ..Default::default()
 84                                    },
 85                                )
 86                                .await;
 87
 88                            let response_body = match response {
 89                                util::ConnectionResult::Result(Ok(result)) => match result {
 90                                    Some(Value::Object(mut map)) => map
 91                                        .remove("body")
 92                                        .unwrap_or(Value::Object(map)),
 93                                    Some(other) => other,
 94                                    None => Value::Null,
 95                                },
 96                                util::ConnectionResult::Result(Err(error)) => {
 97                                    log::warn!(
 98                                        "typescript.tsserverRequest failed: {error:?} for request {request_id}"
 99                                    );
100                                    Value::Null
101                                }
102                                other => {
103                                    log::warn!(
104                                        "typescript.tsserverRequest did not return a response: {other:?} for request {request_id}"
105                                    );
106                                    Value::Null
107                                }
108                            };
109
110                            if let Err(err) = vue_server
111                                .notify::<TypescriptServerResponse>(vec![(request_id, response_body)])
112                            {
113                                log::warn!(
114                                    "Failed to notify vue-language-server of tsserver response: {err:?}"
115                                );
116                            }
117                        })
118                        .detach();
119                    }
120                }
121            })
122            .detach();
123    }
124}