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}