lsp_ext_command.rs

  1use crate::{lsp_command::LspCommand, lsp_store::LspStore};
  2use anyhow::{Context, Result};
  3use async_trait::async_trait;
  4use gpui::{AppContext, AsyncAppContext, Model};
  5use language::{point_to_lsp, proto::deserialize_anchor, Buffer};
  6use lsp::{LanguageServer, LanguageServerId};
  7use rpc::proto::{self, PeerId};
  8use serde::{Deserialize, Serialize};
  9use std::{path::Path, sync::Arc};
 10use text::{BufferId, PointUtf16, ToPointUtf16};
 11
 12pub enum LspExpandMacro {}
 13
 14impl lsp::request::Request for LspExpandMacro {
 15    type Params = ExpandMacroParams;
 16    type Result = Option<ExpandedMacro>;
 17    const METHOD: &'static str = "rust-analyzer/expandMacro";
 18}
 19
 20#[derive(Deserialize, Serialize, Debug)]
 21#[serde(rename_all = "camelCase")]
 22pub struct ExpandMacroParams {
 23    pub text_document: lsp::TextDocumentIdentifier,
 24    pub position: lsp::Position,
 25}
 26
 27#[derive(Default, Deserialize, Serialize, Debug)]
 28#[serde(rename_all = "camelCase")]
 29pub struct ExpandedMacro {
 30    pub name: String,
 31    pub expansion: String,
 32}
 33
 34impl ExpandedMacro {
 35    pub fn is_empty(&self) -> bool {
 36        self.name.is_empty() && self.expansion.is_empty()
 37    }
 38}
 39#[derive(Debug)]
 40pub struct ExpandMacro {
 41    pub position: PointUtf16,
 42}
 43
 44#[async_trait(?Send)]
 45impl LspCommand for ExpandMacro {
 46    type Response = ExpandedMacro;
 47    type LspRequest = LspExpandMacro;
 48    type ProtoRequest = proto::LspExtExpandMacro;
 49
 50    fn to_lsp(
 51        &self,
 52        path: &Path,
 53        _: &Buffer,
 54        _: &Arc<LanguageServer>,
 55        _: &AppContext,
 56    ) -> ExpandMacroParams {
 57        ExpandMacroParams {
 58            text_document: lsp::TextDocumentIdentifier {
 59                uri: lsp::Url::from_file_path(path).unwrap(),
 60            },
 61            position: point_to_lsp(self.position),
 62        }
 63    }
 64
 65    async fn response_from_lsp(
 66        self,
 67        message: Option<ExpandedMacro>,
 68        _: Model<LspStore>,
 69        _: Model<Buffer>,
 70        _: LanguageServerId,
 71        _: AsyncAppContext,
 72    ) -> anyhow::Result<ExpandedMacro> {
 73        Ok(message
 74            .map(|message| ExpandedMacro {
 75                name: message.name,
 76                expansion: message.expansion,
 77            })
 78            .unwrap_or_default())
 79    }
 80
 81    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LspExtExpandMacro {
 82        proto::LspExtExpandMacro {
 83            project_id,
 84            buffer_id: buffer.remote_id().into(),
 85            position: Some(language::proto::serialize_anchor(
 86                &buffer.anchor_before(self.position),
 87            )),
 88        }
 89    }
 90
 91    async fn from_proto(
 92        message: Self::ProtoRequest,
 93        _: Model<LspStore>,
 94        buffer: Model<Buffer>,
 95        mut cx: AsyncAppContext,
 96    ) -> anyhow::Result<Self> {
 97        let position = message
 98            .position
 99            .and_then(deserialize_anchor)
100            .context("invalid position")?;
101        Ok(Self {
102            position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
103        })
104    }
105
106    fn response_to_proto(
107        response: ExpandedMacro,
108        _: &mut LspStore,
109        _: PeerId,
110        _: &clock::Global,
111        _: &mut AppContext,
112    ) -> proto::LspExtExpandMacroResponse {
113        proto::LspExtExpandMacroResponse {
114            name: response.name,
115            expansion: response.expansion,
116        }
117    }
118
119    async fn response_from_proto(
120        self,
121        message: proto::LspExtExpandMacroResponse,
122        _: Model<LspStore>,
123        _: Model<Buffer>,
124        _: AsyncAppContext,
125    ) -> anyhow::Result<ExpandedMacro> {
126        Ok(ExpandedMacro {
127            name: message.name,
128            expansion: message.expansion,
129        })
130    }
131
132    fn buffer_id_from_proto(message: &proto::LspExtExpandMacro) -> Result<BufferId> {
133        BufferId::new(message.buffer_id)
134    }
135}
136
137pub enum LspSwitchSourceHeader {}
138
139impl lsp::request::Request for LspSwitchSourceHeader {
140    type Params = SwitchSourceHeaderParams;
141    type Result = Option<SwitchSourceHeaderResult>;
142    const METHOD: &'static str = "textDocument/switchSourceHeader";
143}
144
145#[derive(Serialize, Deserialize, Debug)]
146#[serde(rename_all = "camelCase")]
147pub struct SwitchSourceHeaderParams(lsp::TextDocumentIdentifier);
148
149#[derive(Serialize, Deserialize, Debug, Default)]
150#[serde(rename_all = "camelCase")]
151pub struct SwitchSourceHeaderResult(pub String);
152
153#[derive(Default, Deserialize, Serialize, Debug)]
154#[serde(rename_all = "camelCase")]
155pub struct SwitchSourceHeader;
156
157#[async_trait(?Send)]
158impl LspCommand for SwitchSourceHeader {
159    type Response = SwitchSourceHeaderResult;
160    type LspRequest = LspSwitchSourceHeader;
161    type ProtoRequest = proto::LspExtSwitchSourceHeader;
162
163    fn to_lsp(
164        &self,
165        path: &Path,
166        _: &Buffer,
167        _: &Arc<LanguageServer>,
168        _: &AppContext,
169    ) -> SwitchSourceHeaderParams {
170        SwitchSourceHeaderParams(lsp::TextDocumentIdentifier {
171            uri: lsp::Url::from_file_path(path).unwrap(),
172        })
173    }
174
175    async fn response_from_lsp(
176        self,
177        message: Option<SwitchSourceHeaderResult>,
178        _: Model<LspStore>,
179        _: Model<Buffer>,
180        _: LanguageServerId,
181        _: AsyncAppContext,
182    ) -> anyhow::Result<SwitchSourceHeaderResult> {
183        Ok(message
184            .map(|message| SwitchSourceHeaderResult(message.0))
185            .unwrap_or_default())
186    }
187
188    fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LspExtSwitchSourceHeader {
189        proto::LspExtSwitchSourceHeader {
190            project_id,
191            buffer_id: buffer.remote_id().into(),
192        }
193    }
194
195    async fn from_proto(
196        _: Self::ProtoRequest,
197        _: Model<LspStore>,
198        _: Model<Buffer>,
199        _: AsyncAppContext,
200    ) -> anyhow::Result<Self> {
201        Ok(Self {})
202    }
203
204    fn response_to_proto(
205        response: SwitchSourceHeaderResult,
206        _: &mut LspStore,
207        _: PeerId,
208        _: &clock::Global,
209        _: &mut AppContext,
210    ) -> proto::LspExtSwitchSourceHeaderResponse {
211        proto::LspExtSwitchSourceHeaderResponse {
212            target_file: response.0,
213        }
214    }
215
216    async fn response_from_proto(
217        self,
218        message: proto::LspExtSwitchSourceHeaderResponse,
219        _: Model<LspStore>,
220        _: Model<Buffer>,
221        _: AsyncAppContext,
222    ) -> anyhow::Result<SwitchSourceHeaderResult> {
223        Ok(SwitchSourceHeaderResult(message.target_file))
224    }
225
226    fn buffer_id_from_proto(message: &proto::LspExtSwitchSourceHeader) -> Result<BufferId> {
227        BufferId::new(message.buffer_id)
228    }
229}