1mod signature_help;
2
3use crate::{
4 lsp_store::LspStore, CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock,
5 HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip,
6 InlayHintTooltip, Location, LocationLink, MarkupContent, ProjectTransaction, ResolveState,
7};
8use anyhow::{anyhow, Context, Result};
9use async_trait::async_trait;
10use client::proto::{self, PeerId};
11use clock::Global;
12use collections::HashSet;
13use futures::future;
14use gpui::{AppContext, AsyncAppContext, Entity, Model};
15use language::{
16 language_settings::{language_settings, InlayHintKind, LanguageSettings},
17 point_from_lsp, point_to_lsp,
18 proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
19 range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind,
20 OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
21};
22use lsp::{
23 AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CompletionContext,
24 CompletionListItemDefaultsEditRange, CompletionTriggerKind, DocumentHighlightKind,
25 LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities, OneOf,
26 ServerCapabilities,
27};
28use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
29use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
30use text::{BufferId, LineEnding};
31
32pub use signature_help::{
33 SignatureHelp, SIGNATURE_HELP_HIGHLIGHT_CURRENT, SIGNATURE_HELP_HIGHLIGHT_OVERLOAD,
34};
35
36pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions {
37 lsp::FormattingOptions {
38 tab_size: settings.tab_size.into(),
39 insert_spaces: !settings.hard_tabs,
40 trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save),
41 trim_final_newlines: Some(settings.ensure_final_newline_on_save),
42 insert_final_newline: Some(settings.ensure_final_newline_on_save),
43 ..lsp::FormattingOptions::default()
44 }
45}
46
47#[async_trait(?Send)]
48pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {
49 type Response: 'static + Default + Send + std::fmt::Debug;
50 type LspRequest: 'static + Send + lsp::request::Request;
51 type ProtoRequest: 'static + Send + proto::RequestMessage;
52
53 fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
54 true
55 }
56
57 fn status(&self) -> Option<String> {
58 None
59 }
60
61 fn to_lsp(
62 &self,
63 path: &Path,
64 buffer: &Buffer,
65 language_server: &Arc<LanguageServer>,
66 cx: &AppContext,
67 ) -> <Self::LspRequest as lsp::request::Request>::Params;
68
69 async fn response_from_lsp(
70 self,
71 message: <Self::LspRequest as lsp::request::Request>::Result,
72 lsp_store: Model<LspStore>,
73 buffer: Model<Buffer>,
74 server_id: LanguageServerId,
75 cx: AsyncAppContext,
76 ) -> Result<Self::Response>;
77
78 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
79
80 async fn from_proto(
81 message: Self::ProtoRequest,
82 lsp_store: Model<LspStore>,
83 buffer: Model<Buffer>,
84 cx: AsyncAppContext,
85 ) -> Result<Self>;
86
87 fn response_to_proto(
88 response: Self::Response,
89 lsp_store: &mut LspStore,
90 peer_id: PeerId,
91 buffer_version: &clock::Global,
92 cx: &mut AppContext,
93 ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
94
95 async fn response_from_proto(
96 self,
97 message: <Self::ProtoRequest as proto::RequestMessage>::Response,
98 lsp_store: Model<LspStore>,
99 buffer: Model<Buffer>,
100 cx: AsyncAppContext,
101 ) -> Result<Self::Response>;
102
103 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
104}
105
106#[derive(Debug)]
107pub(crate) struct PrepareRename {
108 pub position: PointUtf16,
109}
110
111#[derive(Debug)]
112pub(crate) struct PerformRename {
113 pub position: PointUtf16,
114 pub new_name: String,
115 pub push_to_history: bool,
116}
117
118#[derive(Debug)]
119pub struct GetDefinition {
120 pub position: PointUtf16,
121}
122
123#[derive(Debug)]
124pub(crate) struct GetDeclaration {
125 pub position: PointUtf16,
126}
127
128#[derive(Debug)]
129pub(crate) struct GetTypeDefinition {
130 pub position: PointUtf16,
131}
132
133#[derive(Debug)]
134pub(crate) struct GetImplementation {
135 pub position: PointUtf16,
136}
137#[derive(Debug)]
138pub(crate) struct GetReferences {
139 pub position: PointUtf16,
140}
141
142#[derive(Debug)]
143pub(crate) struct GetDocumentHighlights {
144 pub position: PointUtf16,
145}
146
147#[derive(Clone, Debug)]
148pub(crate) struct GetSignatureHelp {
149 pub position: PointUtf16,
150}
151
152#[derive(Clone, Debug)]
153pub(crate) struct GetHover {
154 pub position: PointUtf16,
155}
156
157#[derive(Debug)]
158pub(crate) struct GetCompletions {
159 pub position: PointUtf16,
160 pub context: CompletionContext,
161}
162
163#[derive(Clone, Debug)]
164pub(crate) struct GetCodeActions {
165 pub range: Range<Anchor>,
166 pub kinds: Option<Vec<lsp::CodeActionKind>>,
167}
168#[derive(Debug)]
169pub(crate) struct OnTypeFormatting {
170 pub position: PointUtf16,
171 pub trigger: String,
172 pub options: lsp::FormattingOptions,
173 pub push_to_history: bool,
174}
175#[derive(Debug)]
176pub(crate) struct InlayHints {
177 pub range: Range<Anchor>,
178}
179#[derive(Debug)]
180pub(crate) struct LinkedEditingRange {
181 pub position: Anchor,
182}
183
184#[async_trait(?Send)]
185impl LspCommand for PrepareRename {
186 type Response = Option<Range<Anchor>>;
187 type LspRequest = lsp::request::PrepareRenameRequest;
188 type ProtoRequest = proto::PrepareRename;
189
190 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
191 if let Some(lsp::OneOf::Right(rename)) = &capabilities.server_capabilities.rename_provider {
192 rename.prepare_provider == Some(true)
193 } else {
194 false
195 }
196 }
197
198 fn to_lsp(
199 &self,
200 path: &Path,
201 _: &Buffer,
202 _: &Arc<LanguageServer>,
203 _: &AppContext,
204 ) -> lsp::TextDocumentPositionParams {
205 lsp::TextDocumentPositionParams {
206 text_document: lsp::TextDocumentIdentifier {
207 uri: lsp::Url::from_file_path(path).unwrap(),
208 },
209 position: point_to_lsp(self.position),
210 }
211 }
212
213 async fn response_from_lsp(
214 self,
215 message: Option<lsp::PrepareRenameResponse>,
216 _: Model<LspStore>,
217 buffer: Model<Buffer>,
218 _: LanguageServerId,
219 mut cx: AsyncAppContext,
220 ) -> Result<Option<Range<Anchor>>> {
221 buffer.update(&mut cx, |buffer, _| {
222 if let Some(
223 lsp::PrepareRenameResponse::Range(range)
224 | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
225 ) = message
226 {
227 let Range { start, end } = range_from_lsp(range);
228 if buffer.clip_point_utf16(start, Bias::Left) == start.0
229 && buffer.clip_point_utf16(end, Bias::Left) == end.0
230 {
231 return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
232 }
233 }
234 Ok(None)
235 })?
236 }
237
238 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
239 proto::PrepareRename {
240 project_id,
241 buffer_id: buffer.remote_id().into(),
242 position: Some(language::proto::serialize_anchor(
243 &buffer.anchor_before(self.position),
244 )),
245 version: serialize_version(&buffer.version()),
246 }
247 }
248
249 async fn from_proto(
250 message: proto::PrepareRename,
251 _: Model<LspStore>,
252 buffer: Model<Buffer>,
253 mut cx: AsyncAppContext,
254 ) -> Result<Self> {
255 let position = message
256 .position
257 .and_then(deserialize_anchor)
258 .ok_or_else(|| anyhow!("invalid position"))?;
259 buffer
260 .update(&mut cx, |buffer, _| {
261 buffer.wait_for_version(deserialize_version(&message.version))
262 })?
263 .await?;
264
265 Ok(Self {
266 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
267 })
268 }
269
270 fn response_to_proto(
271 range: Option<Range<Anchor>>,
272 _: &mut LspStore,
273 _: PeerId,
274 buffer_version: &clock::Global,
275 _: &mut AppContext,
276 ) -> proto::PrepareRenameResponse {
277 proto::PrepareRenameResponse {
278 can_rename: range.is_some(),
279 start: range
280 .as_ref()
281 .map(|range| language::proto::serialize_anchor(&range.start)),
282 end: range
283 .as_ref()
284 .map(|range| language::proto::serialize_anchor(&range.end)),
285 version: serialize_version(buffer_version),
286 }
287 }
288
289 async fn response_from_proto(
290 self,
291 message: proto::PrepareRenameResponse,
292 _: Model<LspStore>,
293 buffer: Model<Buffer>,
294 mut cx: AsyncAppContext,
295 ) -> Result<Option<Range<Anchor>>> {
296 if message.can_rename {
297 buffer
298 .update(&mut cx, |buffer, _| {
299 buffer.wait_for_version(deserialize_version(&message.version))
300 })?
301 .await?;
302 let start = message.start.and_then(deserialize_anchor);
303 let end = message.end.and_then(deserialize_anchor);
304 Ok(start.zip(end).map(|(start, end)| start..end))
305 } else {
306 Ok(None)
307 }
308 }
309
310 fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {
311 BufferId::new(message.buffer_id)
312 }
313}
314
315#[async_trait(?Send)]
316impl LspCommand for PerformRename {
317 type Response = ProjectTransaction;
318 type LspRequest = lsp::request::Rename;
319 type ProtoRequest = proto::PerformRename;
320
321 fn to_lsp(
322 &self,
323 path: &Path,
324 _: &Buffer,
325 _: &Arc<LanguageServer>,
326 _: &AppContext,
327 ) -> lsp::RenameParams {
328 lsp::RenameParams {
329 text_document_position: lsp::TextDocumentPositionParams {
330 text_document: lsp::TextDocumentIdentifier {
331 uri: lsp::Url::from_file_path(path).unwrap(),
332 },
333 position: point_to_lsp(self.position),
334 },
335 new_name: self.new_name.clone(),
336 work_done_progress_params: Default::default(),
337 }
338 }
339
340 async fn response_from_lsp(
341 self,
342 message: Option<lsp::WorkspaceEdit>,
343 lsp_store: Model<LspStore>,
344 buffer: Model<Buffer>,
345 server_id: LanguageServerId,
346 mut cx: AsyncAppContext,
347 ) -> Result<ProjectTransaction> {
348 if let Some(edit) = message {
349 let (lsp_adapter, lsp_server) =
350 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
351 LspStore::deserialize_workspace_edit(
352 lsp_store,
353 edit,
354 self.push_to_history,
355 lsp_adapter,
356 lsp_server,
357 &mut cx,
358 )
359 .await
360 } else {
361 Ok(ProjectTransaction::default())
362 }
363 }
364
365 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
366 proto::PerformRename {
367 project_id,
368 buffer_id: buffer.remote_id().into(),
369 position: Some(language::proto::serialize_anchor(
370 &buffer.anchor_before(self.position),
371 )),
372 new_name: self.new_name.clone(),
373 version: serialize_version(&buffer.version()),
374 }
375 }
376
377 async fn from_proto(
378 message: proto::PerformRename,
379 _: Model<LspStore>,
380 buffer: Model<Buffer>,
381 mut cx: AsyncAppContext,
382 ) -> Result<Self> {
383 let position = message
384 .position
385 .and_then(deserialize_anchor)
386 .ok_or_else(|| anyhow!("invalid position"))?;
387 buffer
388 .update(&mut cx, |buffer, _| {
389 buffer.wait_for_version(deserialize_version(&message.version))
390 })?
391 .await?;
392 Ok(Self {
393 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
394 new_name: message.new_name,
395 push_to_history: false,
396 })
397 }
398
399 fn response_to_proto(
400 response: ProjectTransaction,
401 lsp_store: &mut LspStore,
402 peer_id: PeerId,
403 _: &clock::Global,
404 cx: &mut AppContext,
405 ) -> proto::PerformRenameResponse {
406 let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| {
407 buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx)
408 });
409 proto::PerformRenameResponse {
410 transaction: Some(transaction),
411 }
412 }
413
414 async fn response_from_proto(
415 self,
416 message: proto::PerformRenameResponse,
417 lsp_store: Model<LspStore>,
418 _: Model<Buffer>,
419 mut cx: AsyncAppContext,
420 ) -> Result<ProjectTransaction> {
421 let message = message
422 .transaction
423 .ok_or_else(|| anyhow!("missing transaction"))?;
424 lsp_store
425 .update(&mut cx, |lsp_store, cx| {
426 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
427 buffer_store.deserialize_project_transaction(message, self.push_to_history, cx)
428 })
429 })?
430 .await
431 }
432
433 fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {
434 BufferId::new(message.buffer_id)
435 }
436}
437
438#[async_trait(?Send)]
439impl LspCommand for GetDefinition {
440 type Response = Vec<LocationLink>;
441 type LspRequest = lsp::request::GotoDefinition;
442 type ProtoRequest = proto::GetDefinition;
443
444 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
445 capabilities
446 .server_capabilities
447 .definition_provider
448 .is_some()
449 }
450
451 fn to_lsp(
452 &self,
453 path: &Path,
454 _: &Buffer,
455 _: &Arc<LanguageServer>,
456 _: &AppContext,
457 ) -> lsp::GotoDefinitionParams {
458 lsp::GotoDefinitionParams {
459 text_document_position_params: lsp::TextDocumentPositionParams {
460 text_document: lsp::TextDocumentIdentifier {
461 uri: lsp::Url::from_file_path(path).unwrap(),
462 },
463 position: point_to_lsp(self.position),
464 },
465 work_done_progress_params: Default::default(),
466 partial_result_params: Default::default(),
467 }
468 }
469
470 async fn response_from_lsp(
471 self,
472 message: Option<lsp::GotoDefinitionResponse>,
473 lsp_store: Model<LspStore>,
474 buffer: Model<Buffer>,
475 server_id: LanguageServerId,
476 cx: AsyncAppContext,
477 ) -> Result<Vec<LocationLink>> {
478 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
479 }
480
481 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
482 proto::GetDefinition {
483 project_id,
484 buffer_id: buffer.remote_id().into(),
485 position: Some(language::proto::serialize_anchor(
486 &buffer.anchor_before(self.position),
487 )),
488 version: serialize_version(&buffer.version()),
489 }
490 }
491
492 async fn from_proto(
493 message: proto::GetDefinition,
494 _: Model<LspStore>,
495 buffer: Model<Buffer>,
496 mut cx: AsyncAppContext,
497 ) -> Result<Self> {
498 let position = message
499 .position
500 .and_then(deserialize_anchor)
501 .ok_or_else(|| anyhow!("invalid position"))?;
502 buffer
503 .update(&mut cx, |buffer, _| {
504 buffer.wait_for_version(deserialize_version(&message.version))
505 })?
506 .await?;
507 Ok(Self {
508 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
509 })
510 }
511
512 fn response_to_proto(
513 response: Vec<LocationLink>,
514 lsp_store: &mut LspStore,
515 peer_id: PeerId,
516 _: &clock::Global,
517 cx: &mut AppContext,
518 ) -> proto::GetDefinitionResponse {
519 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
520 proto::GetDefinitionResponse { links }
521 }
522
523 async fn response_from_proto(
524 self,
525 message: proto::GetDefinitionResponse,
526 lsp_store: Model<LspStore>,
527 _: Model<Buffer>,
528 cx: AsyncAppContext,
529 ) -> Result<Vec<LocationLink>> {
530 location_links_from_proto(message.links, lsp_store, cx).await
531 }
532
533 fn buffer_id_from_proto(message: &proto::GetDefinition) -> Result<BufferId> {
534 BufferId::new(message.buffer_id)
535 }
536}
537
538#[async_trait(?Send)]
539impl LspCommand for GetDeclaration {
540 type Response = Vec<LocationLink>;
541 type LspRequest = lsp::request::GotoDeclaration;
542 type ProtoRequest = proto::GetDeclaration;
543
544 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
545 capabilities
546 .server_capabilities
547 .declaration_provider
548 .is_some()
549 }
550
551 fn to_lsp(
552 &self,
553 path: &Path,
554 _: &Buffer,
555 _: &Arc<LanguageServer>,
556 _: &AppContext,
557 ) -> lsp::GotoDeclarationParams {
558 lsp::GotoDeclarationParams {
559 text_document_position_params: lsp::TextDocumentPositionParams {
560 text_document: lsp::TextDocumentIdentifier {
561 uri: lsp::Url::from_file_path(path).unwrap(),
562 },
563 position: point_to_lsp(self.position),
564 },
565 work_done_progress_params: Default::default(),
566 partial_result_params: Default::default(),
567 }
568 }
569
570 async fn response_from_lsp(
571 self,
572 message: Option<lsp::GotoDeclarationResponse>,
573 lsp_store: Model<LspStore>,
574 buffer: Model<Buffer>,
575 server_id: LanguageServerId,
576 cx: AsyncAppContext,
577 ) -> Result<Vec<LocationLink>> {
578 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
579 }
580
581 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDeclaration {
582 proto::GetDeclaration {
583 project_id,
584 buffer_id: buffer.remote_id().into(),
585 position: Some(language::proto::serialize_anchor(
586 &buffer.anchor_before(self.position),
587 )),
588 version: serialize_version(&buffer.version()),
589 }
590 }
591
592 async fn from_proto(
593 message: proto::GetDeclaration,
594 _: Model<LspStore>,
595 buffer: Model<Buffer>,
596 mut cx: AsyncAppContext,
597 ) -> Result<Self> {
598 let position = message
599 .position
600 .and_then(deserialize_anchor)
601 .ok_or_else(|| anyhow!("invalid position"))?;
602 buffer
603 .update(&mut cx, |buffer, _| {
604 buffer.wait_for_version(deserialize_version(&message.version))
605 })?
606 .await?;
607 Ok(Self {
608 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
609 })
610 }
611
612 fn response_to_proto(
613 response: Vec<LocationLink>,
614 lsp_store: &mut LspStore,
615 peer_id: PeerId,
616 _: &clock::Global,
617 cx: &mut AppContext,
618 ) -> proto::GetDeclarationResponse {
619 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
620 proto::GetDeclarationResponse { links }
621 }
622
623 async fn response_from_proto(
624 self,
625 message: proto::GetDeclarationResponse,
626 lsp_store: Model<LspStore>,
627 _: Model<Buffer>,
628 cx: AsyncAppContext,
629 ) -> Result<Vec<LocationLink>> {
630 location_links_from_proto(message.links, lsp_store, cx).await
631 }
632
633 fn buffer_id_from_proto(message: &proto::GetDeclaration) -> Result<BufferId> {
634 BufferId::new(message.buffer_id)
635 }
636}
637
638#[async_trait(?Send)]
639impl LspCommand for GetImplementation {
640 type Response = Vec<LocationLink>;
641 type LspRequest = lsp::request::GotoImplementation;
642 type ProtoRequest = proto::GetImplementation;
643
644 fn to_lsp(
645 &self,
646 path: &Path,
647 _: &Buffer,
648 _: &Arc<LanguageServer>,
649 _: &AppContext,
650 ) -> lsp::GotoImplementationParams {
651 lsp::GotoImplementationParams {
652 text_document_position_params: lsp::TextDocumentPositionParams {
653 text_document: lsp::TextDocumentIdentifier {
654 uri: lsp::Url::from_file_path(path).unwrap(),
655 },
656 position: point_to_lsp(self.position),
657 },
658 work_done_progress_params: Default::default(),
659 partial_result_params: Default::default(),
660 }
661 }
662
663 async fn response_from_lsp(
664 self,
665 message: Option<lsp::GotoImplementationResponse>,
666 lsp_store: Model<LspStore>,
667 buffer: Model<Buffer>,
668 server_id: LanguageServerId,
669 cx: AsyncAppContext,
670 ) -> Result<Vec<LocationLink>> {
671 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
672 }
673
674 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetImplementation {
675 proto::GetImplementation {
676 project_id,
677 buffer_id: buffer.remote_id().into(),
678 position: Some(language::proto::serialize_anchor(
679 &buffer.anchor_before(self.position),
680 )),
681 version: serialize_version(&buffer.version()),
682 }
683 }
684
685 async fn from_proto(
686 message: proto::GetImplementation,
687 _: Model<LspStore>,
688 buffer: Model<Buffer>,
689 mut cx: AsyncAppContext,
690 ) -> Result<Self> {
691 let position = message
692 .position
693 .and_then(deserialize_anchor)
694 .ok_or_else(|| anyhow!("invalid position"))?;
695 buffer
696 .update(&mut cx, |buffer, _| {
697 buffer.wait_for_version(deserialize_version(&message.version))
698 })?
699 .await?;
700 Ok(Self {
701 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
702 })
703 }
704
705 fn response_to_proto(
706 response: Vec<LocationLink>,
707 lsp_store: &mut LspStore,
708 peer_id: PeerId,
709 _: &clock::Global,
710 cx: &mut AppContext,
711 ) -> proto::GetImplementationResponse {
712 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
713 proto::GetImplementationResponse { links }
714 }
715
716 async fn response_from_proto(
717 self,
718 message: proto::GetImplementationResponse,
719 project: Model<LspStore>,
720 _: Model<Buffer>,
721 cx: AsyncAppContext,
722 ) -> Result<Vec<LocationLink>> {
723 location_links_from_proto(message.links, project, cx).await
724 }
725
726 fn buffer_id_from_proto(message: &proto::GetImplementation) -> Result<BufferId> {
727 BufferId::new(message.buffer_id)
728 }
729}
730
731#[async_trait(?Send)]
732impl LspCommand for GetTypeDefinition {
733 type Response = Vec<LocationLink>;
734 type LspRequest = lsp::request::GotoTypeDefinition;
735 type ProtoRequest = proto::GetTypeDefinition;
736
737 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
738 !matches!(
739 &capabilities.server_capabilities.type_definition_provider,
740 None | Some(lsp::TypeDefinitionProviderCapability::Simple(false))
741 )
742 }
743
744 fn to_lsp(
745 &self,
746 path: &Path,
747 _: &Buffer,
748 _: &Arc<LanguageServer>,
749 _: &AppContext,
750 ) -> lsp::GotoTypeDefinitionParams {
751 lsp::GotoTypeDefinitionParams {
752 text_document_position_params: lsp::TextDocumentPositionParams {
753 text_document: lsp::TextDocumentIdentifier {
754 uri: lsp::Url::from_file_path(path).unwrap(),
755 },
756 position: point_to_lsp(self.position),
757 },
758 work_done_progress_params: Default::default(),
759 partial_result_params: Default::default(),
760 }
761 }
762
763 async fn response_from_lsp(
764 self,
765 message: Option<lsp::GotoTypeDefinitionResponse>,
766 project: Model<LspStore>,
767 buffer: Model<Buffer>,
768 server_id: LanguageServerId,
769 cx: AsyncAppContext,
770 ) -> Result<Vec<LocationLink>> {
771 location_links_from_lsp(message, project, buffer, server_id, cx).await
772 }
773
774 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
775 proto::GetTypeDefinition {
776 project_id,
777 buffer_id: buffer.remote_id().into(),
778 position: Some(language::proto::serialize_anchor(
779 &buffer.anchor_before(self.position),
780 )),
781 version: serialize_version(&buffer.version()),
782 }
783 }
784
785 async fn from_proto(
786 message: proto::GetTypeDefinition,
787 _: Model<LspStore>,
788 buffer: Model<Buffer>,
789 mut cx: AsyncAppContext,
790 ) -> Result<Self> {
791 let position = message
792 .position
793 .and_then(deserialize_anchor)
794 .ok_or_else(|| anyhow!("invalid position"))?;
795 buffer
796 .update(&mut cx, |buffer, _| {
797 buffer.wait_for_version(deserialize_version(&message.version))
798 })?
799 .await?;
800 Ok(Self {
801 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
802 })
803 }
804
805 fn response_to_proto(
806 response: Vec<LocationLink>,
807 lsp_store: &mut LspStore,
808 peer_id: PeerId,
809 _: &clock::Global,
810 cx: &mut AppContext,
811 ) -> proto::GetTypeDefinitionResponse {
812 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
813 proto::GetTypeDefinitionResponse { links }
814 }
815
816 async fn response_from_proto(
817 self,
818 message: proto::GetTypeDefinitionResponse,
819 project: Model<LspStore>,
820 _: Model<Buffer>,
821 cx: AsyncAppContext,
822 ) -> Result<Vec<LocationLink>> {
823 location_links_from_proto(message.links, project, cx).await
824 }
825
826 fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> Result<BufferId> {
827 BufferId::new(message.buffer_id)
828 }
829}
830
831fn language_server_for_buffer(
832 lsp_store: &Model<LspStore>,
833 buffer: &Model<Buffer>,
834 server_id: LanguageServerId,
835 cx: &mut AsyncAppContext,
836) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
837 lsp_store
838 .update(cx, |lsp_store, cx| {
839 lsp_store
840 .language_server_for_buffer(buffer.read(cx), server_id, cx)
841 .map(|(adapter, server)| (adapter.clone(), server.clone()))
842 })?
843 .ok_or_else(|| anyhow!("no language server found for buffer"))
844}
845
846async fn location_links_from_proto(
847 proto_links: Vec<proto::LocationLink>,
848 lsp_store: Model<LspStore>,
849 mut cx: AsyncAppContext,
850) -> Result<Vec<LocationLink>> {
851 let mut links = Vec::new();
852
853 for link in proto_links {
854 let origin = match link.origin {
855 Some(origin) => {
856 let buffer_id = BufferId::new(origin.buffer_id)?;
857 let buffer = lsp_store
858 .update(&mut cx, |lsp_store, cx| {
859 lsp_store.wait_for_remote_buffer(buffer_id, cx)
860 })?
861 .await?;
862 let start = origin
863 .start
864 .and_then(deserialize_anchor)
865 .ok_or_else(|| anyhow!("missing origin start"))?;
866 let end = origin
867 .end
868 .and_then(deserialize_anchor)
869 .ok_or_else(|| anyhow!("missing origin end"))?;
870 buffer
871 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
872 .await?;
873 Some(Location {
874 buffer,
875 range: start..end,
876 })
877 }
878 None => None,
879 };
880
881 let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
882 let buffer_id = BufferId::new(target.buffer_id)?;
883 let buffer = lsp_store
884 .update(&mut cx, |lsp_store, cx| {
885 lsp_store.wait_for_remote_buffer(buffer_id, cx)
886 })?
887 .await?;
888 let start = target
889 .start
890 .and_then(deserialize_anchor)
891 .ok_or_else(|| anyhow!("missing target start"))?;
892 let end = target
893 .end
894 .and_then(deserialize_anchor)
895 .ok_or_else(|| anyhow!("missing target end"))?;
896 buffer
897 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
898 .await?;
899 let target = Location {
900 buffer,
901 range: start..end,
902 };
903
904 links.push(LocationLink { origin, target })
905 }
906
907 Ok(links)
908}
909
910async fn location_links_from_lsp(
911 message: Option<lsp::GotoDefinitionResponse>,
912 lsp_store: Model<LspStore>,
913 buffer: Model<Buffer>,
914 server_id: LanguageServerId,
915 mut cx: AsyncAppContext,
916) -> Result<Vec<LocationLink>> {
917 let message = match message {
918 Some(message) => message,
919 None => return Ok(Vec::new()),
920 };
921
922 let mut unresolved_links = Vec::new();
923 match message {
924 lsp::GotoDefinitionResponse::Scalar(loc) => {
925 unresolved_links.push((None, loc.uri, loc.range));
926 }
927
928 lsp::GotoDefinitionResponse::Array(locs) => {
929 unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
930 }
931
932 lsp::GotoDefinitionResponse::Link(links) => {
933 unresolved_links.extend(links.into_iter().map(|l| {
934 (
935 l.origin_selection_range,
936 l.target_uri,
937 l.target_selection_range,
938 )
939 }));
940 }
941 }
942
943 let (lsp_adapter, language_server) =
944 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
945 let mut definitions = Vec::new();
946 for (origin_range, target_uri, target_range) in unresolved_links {
947 let target_buffer_handle = lsp_store
948 .update(&mut cx, |this, cx| {
949 this.open_local_buffer_via_lsp(
950 target_uri,
951 language_server.server_id(),
952 lsp_adapter.name.clone(),
953 cx,
954 )
955 })?
956 .await?;
957
958 cx.update(|cx| {
959 let origin_location = origin_range.map(|origin_range| {
960 let origin_buffer = buffer.read(cx);
961 let origin_start =
962 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
963 let origin_end =
964 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
965 Location {
966 buffer: buffer.clone(),
967 range: origin_buffer.anchor_after(origin_start)
968 ..origin_buffer.anchor_before(origin_end),
969 }
970 });
971
972 let target_buffer = target_buffer_handle.read(cx);
973 let target_start =
974 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
975 let target_end =
976 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
977 let target_location = Location {
978 buffer: target_buffer_handle,
979 range: target_buffer.anchor_after(target_start)
980 ..target_buffer.anchor_before(target_end),
981 };
982
983 definitions.push(LocationLink {
984 origin: origin_location,
985 target: target_location,
986 })
987 })?;
988 }
989 Ok(definitions)
990}
991
992fn location_links_to_proto(
993 links: Vec<LocationLink>,
994 lsp_store: &mut LspStore,
995 peer_id: PeerId,
996 cx: &mut AppContext,
997) -> Vec<proto::LocationLink> {
998 links
999 .into_iter()
1000 .map(|definition| {
1001 let origin = definition.origin.map(|origin| {
1002 lsp_store
1003 .buffer_store()
1004 .update(cx, |buffer_store, cx| {
1005 buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1006 })
1007 .detach_and_log_err(cx);
1008
1009 let buffer_id = origin.buffer.read(cx).remote_id().into();
1010 proto::Location {
1011 start: Some(serialize_anchor(&origin.range.start)),
1012 end: Some(serialize_anchor(&origin.range.end)),
1013 buffer_id,
1014 }
1015 });
1016
1017 lsp_store
1018 .buffer_store()
1019 .update(cx, |buffer_store, cx| {
1020 buffer_store.create_buffer_for_peer(&definition.target.buffer, peer_id, cx)
1021 })
1022 .detach_and_log_err(cx);
1023
1024 let buffer_id = definition.target.buffer.read(cx).remote_id().into();
1025 let target = proto::Location {
1026 start: Some(serialize_anchor(&definition.target.range.start)),
1027 end: Some(serialize_anchor(&definition.target.range.end)),
1028 buffer_id,
1029 };
1030
1031 proto::LocationLink {
1032 origin,
1033 target: Some(target),
1034 }
1035 })
1036 .collect()
1037}
1038
1039#[async_trait(?Send)]
1040impl LspCommand for GetReferences {
1041 type Response = Vec<Location>;
1042 type LspRequest = lsp::request::References;
1043 type ProtoRequest = proto::GetReferences;
1044
1045 fn status(&self) -> Option<String> {
1046 Some("Finding references...".to_owned())
1047 }
1048
1049 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1050 match &capabilities.server_capabilities.references_provider {
1051 Some(OneOf::Left(has_support)) => *has_support,
1052 Some(OneOf::Right(_)) => true,
1053 None => false,
1054 }
1055 }
1056
1057 fn to_lsp(
1058 &self,
1059 path: &Path,
1060 _: &Buffer,
1061 _: &Arc<LanguageServer>,
1062 _: &AppContext,
1063 ) -> lsp::ReferenceParams {
1064 lsp::ReferenceParams {
1065 text_document_position: lsp::TextDocumentPositionParams {
1066 text_document: lsp::TextDocumentIdentifier {
1067 uri: lsp::Url::from_file_path(path).unwrap(),
1068 },
1069 position: point_to_lsp(self.position),
1070 },
1071 work_done_progress_params: Default::default(),
1072 partial_result_params: Default::default(),
1073 context: lsp::ReferenceContext {
1074 include_declaration: true,
1075 },
1076 }
1077 }
1078
1079 async fn response_from_lsp(
1080 self,
1081 locations: Option<Vec<lsp::Location>>,
1082 lsp_store: Model<LspStore>,
1083 buffer: Model<Buffer>,
1084 server_id: LanguageServerId,
1085 mut cx: AsyncAppContext,
1086 ) -> Result<Vec<Location>> {
1087 let mut references = Vec::new();
1088 let (lsp_adapter, language_server) =
1089 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1090
1091 if let Some(locations) = locations {
1092 for lsp_location in locations {
1093 let target_buffer_handle = lsp_store
1094 .update(&mut cx, |lsp_store, cx| {
1095 lsp_store.open_local_buffer_via_lsp(
1096 lsp_location.uri,
1097 language_server.server_id(),
1098 lsp_adapter.name.clone(),
1099 cx,
1100 )
1101 })?
1102 .await?;
1103
1104 target_buffer_handle
1105 .clone()
1106 .update(&mut cx, |target_buffer, _| {
1107 let target_start = target_buffer
1108 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1109 let target_end = target_buffer
1110 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1111 references.push(Location {
1112 buffer: target_buffer_handle,
1113 range: target_buffer.anchor_after(target_start)
1114 ..target_buffer.anchor_before(target_end),
1115 });
1116 })?;
1117 }
1118 }
1119
1120 Ok(references)
1121 }
1122
1123 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1124 proto::GetReferences {
1125 project_id,
1126 buffer_id: buffer.remote_id().into(),
1127 position: Some(language::proto::serialize_anchor(
1128 &buffer.anchor_before(self.position),
1129 )),
1130 version: serialize_version(&buffer.version()),
1131 }
1132 }
1133
1134 async fn from_proto(
1135 message: proto::GetReferences,
1136 _: Model<LspStore>,
1137 buffer: Model<Buffer>,
1138 mut cx: AsyncAppContext,
1139 ) -> Result<Self> {
1140 let position = message
1141 .position
1142 .and_then(deserialize_anchor)
1143 .ok_or_else(|| anyhow!("invalid position"))?;
1144 buffer
1145 .update(&mut cx, |buffer, _| {
1146 buffer.wait_for_version(deserialize_version(&message.version))
1147 })?
1148 .await?;
1149 Ok(Self {
1150 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1151 })
1152 }
1153
1154 fn response_to_proto(
1155 response: Vec<Location>,
1156 lsp_store: &mut LspStore,
1157 peer_id: PeerId,
1158 _: &clock::Global,
1159 cx: &mut AppContext,
1160 ) -> proto::GetReferencesResponse {
1161 let locations = response
1162 .into_iter()
1163 .map(|definition| {
1164 lsp_store
1165 .buffer_store()
1166 .update(cx, |buffer_store, cx| {
1167 buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1168 })
1169 .detach_and_log_err(cx);
1170 let buffer_id = definition.buffer.read(cx).remote_id();
1171 proto::Location {
1172 start: Some(serialize_anchor(&definition.range.start)),
1173 end: Some(serialize_anchor(&definition.range.end)),
1174 buffer_id: buffer_id.into(),
1175 }
1176 })
1177 .collect();
1178 proto::GetReferencesResponse { locations }
1179 }
1180
1181 async fn response_from_proto(
1182 self,
1183 message: proto::GetReferencesResponse,
1184 project: Model<LspStore>,
1185 _: Model<Buffer>,
1186 mut cx: AsyncAppContext,
1187 ) -> Result<Vec<Location>> {
1188 let mut locations = Vec::new();
1189 for location in message.locations {
1190 let buffer_id = BufferId::new(location.buffer_id)?;
1191 let target_buffer = project
1192 .update(&mut cx, |this, cx| {
1193 this.wait_for_remote_buffer(buffer_id, cx)
1194 })?
1195 .await?;
1196 let start = location
1197 .start
1198 .and_then(deserialize_anchor)
1199 .ok_or_else(|| anyhow!("missing target start"))?;
1200 let end = location
1201 .end
1202 .and_then(deserialize_anchor)
1203 .ok_or_else(|| anyhow!("missing target end"))?;
1204 target_buffer
1205 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1206 .await?;
1207 locations.push(Location {
1208 buffer: target_buffer,
1209 range: start..end,
1210 })
1211 }
1212 Ok(locations)
1213 }
1214
1215 fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1216 BufferId::new(message.buffer_id)
1217 }
1218}
1219
1220#[async_trait(?Send)]
1221impl LspCommand for GetDocumentHighlights {
1222 type Response = Vec<DocumentHighlight>;
1223 type LspRequest = lsp::request::DocumentHighlightRequest;
1224 type ProtoRequest = proto::GetDocumentHighlights;
1225
1226 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1227 capabilities
1228 .server_capabilities
1229 .document_highlight_provider
1230 .is_some()
1231 }
1232
1233 fn to_lsp(
1234 &self,
1235 path: &Path,
1236 _: &Buffer,
1237 _: &Arc<LanguageServer>,
1238 _: &AppContext,
1239 ) -> lsp::DocumentHighlightParams {
1240 lsp::DocumentHighlightParams {
1241 text_document_position_params: lsp::TextDocumentPositionParams {
1242 text_document: lsp::TextDocumentIdentifier {
1243 uri: lsp::Url::from_file_path(path).unwrap(),
1244 },
1245 position: point_to_lsp(self.position),
1246 },
1247 work_done_progress_params: Default::default(),
1248 partial_result_params: Default::default(),
1249 }
1250 }
1251
1252 async fn response_from_lsp(
1253 self,
1254 lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1255 _: Model<LspStore>,
1256 buffer: Model<Buffer>,
1257 _: LanguageServerId,
1258 mut cx: AsyncAppContext,
1259 ) -> Result<Vec<DocumentHighlight>> {
1260 buffer.update(&mut cx, |buffer, _| {
1261 let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1262 lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1263 lsp_highlights
1264 .into_iter()
1265 .map(|lsp_highlight| {
1266 let start = buffer
1267 .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1268 let end = buffer
1269 .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1270 DocumentHighlight {
1271 range: buffer.anchor_after(start)..buffer.anchor_before(end),
1272 kind: lsp_highlight
1273 .kind
1274 .unwrap_or(lsp::DocumentHighlightKind::READ),
1275 }
1276 })
1277 .collect()
1278 })
1279 }
1280
1281 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1282 proto::GetDocumentHighlights {
1283 project_id,
1284 buffer_id: buffer.remote_id().into(),
1285 position: Some(language::proto::serialize_anchor(
1286 &buffer.anchor_before(self.position),
1287 )),
1288 version: serialize_version(&buffer.version()),
1289 }
1290 }
1291
1292 async fn from_proto(
1293 message: proto::GetDocumentHighlights,
1294 _: Model<LspStore>,
1295 buffer: Model<Buffer>,
1296 mut cx: AsyncAppContext,
1297 ) -> Result<Self> {
1298 let position = message
1299 .position
1300 .and_then(deserialize_anchor)
1301 .ok_or_else(|| anyhow!("invalid position"))?;
1302 buffer
1303 .update(&mut cx, |buffer, _| {
1304 buffer.wait_for_version(deserialize_version(&message.version))
1305 })?
1306 .await?;
1307 Ok(Self {
1308 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1309 })
1310 }
1311
1312 fn response_to_proto(
1313 response: Vec<DocumentHighlight>,
1314 _: &mut LspStore,
1315 _: PeerId,
1316 _: &clock::Global,
1317 _: &mut AppContext,
1318 ) -> proto::GetDocumentHighlightsResponse {
1319 let highlights = response
1320 .into_iter()
1321 .map(|highlight| proto::DocumentHighlight {
1322 start: Some(serialize_anchor(&highlight.range.start)),
1323 end: Some(serialize_anchor(&highlight.range.end)),
1324 kind: match highlight.kind {
1325 DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1326 DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1327 DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1328 _ => proto::document_highlight::Kind::Text.into(),
1329 },
1330 })
1331 .collect();
1332 proto::GetDocumentHighlightsResponse { highlights }
1333 }
1334
1335 async fn response_from_proto(
1336 self,
1337 message: proto::GetDocumentHighlightsResponse,
1338 _: Model<LspStore>,
1339 buffer: Model<Buffer>,
1340 mut cx: AsyncAppContext,
1341 ) -> Result<Vec<DocumentHighlight>> {
1342 let mut highlights = Vec::new();
1343 for highlight in message.highlights {
1344 let start = highlight
1345 .start
1346 .and_then(deserialize_anchor)
1347 .ok_or_else(|| anyhow!("missing target start"))?;
1348 let end = highlight
1349 .end
1350 .and_then(deserialize_anchor)
1351 .ok_or_else(|| anyhow!("missing target end"))?;
1352 buffer
1353 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1354 .await?;
1355 let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1356 Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1357 Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1358 Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1359 None => DocumentHighlightKind::TEXT,
1360 };
1361 highlights.push(DocumentHighlight {
1362 range: start..end,
1363 kind,
1364 });
1365 }
1366 Ok(highlights)
1367 }
1368
1369 fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1370 BufferId::new(message.buffer_id)
1371 }
1372}
1373
1374#[async_trait(?Send)]
1375impl LspCommand for GetSignatureHelp {
1376 type Response = Option<SignatureHelp>;
1377 type LspRequest = lsp::SignatureHelpRequest;
1378 type ProtoRequest = proto::GetSignatureHelp;
1379
1380 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1381 capabilities
1382 .server_capabilities
1383 .signature_help_provider
1384 .is_some()
1385 }
1386
1387 fn to_lsp(
1388 &self,
1389 path: &Path,
1390 _: &Buffer,
1391 _: &Arc<LanguageServer>,
1392 _cx: &AppContext,
1393 ) -> lsp::SignatureHelpParams {
1394 let url_result = lsp::Url::from_file_path(path);
1395 if url_result.is_err() {
1396 log::error!("an invalid file path has been specified");
1397 }
1398
1399 lsp::SignatureHelpParams {
1400 text_document_position_params: lsp::TextDocumentPositionParams {
1401 text_document: lsp::TextDocumentIdentifier {
1402 uri: url_result.expect("invalid file path"),
1403 },
1404 position: point_to_lsp(self.position),
1405 },
1406 context: None,
1407 work_done_progress_params: Default::default(),
1408 }
1409 }
1410
1411 async fn response_from_lsp(
1412 self,
1413 message: Option<lsp::SignatureHelp>,
1414 _: Model<LspStore>,
1415 buffer: Model<Buffer>,
1416 _: LanguageServerId,
1417 mut cx: AsyncAppContext,
1418 ) -> Result<Self::Response> {
1419 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1420 Ok(message.and_then(|message| SignatureHelp::new(message, language)))
1421 }
1422
1423 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1424 let offset = buffer.point_utf16_to_offset(self.position);
1425 proto::GetSignatureHelp {
1426 project_id,
1427 buffer_id: buffer.remote_id().to_proto(),
1428 position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1429 version: serialize_version(&buffer.version()),
1430 }
1431 }
1432
1433 async fn from_proto(
1434 payload: Self::ProtoRequest,
1435 _: Model<LspStore>,
1436 buffer: Model<Buffer>,
1437 mut cx: AsyncAppContext,
1438 ) -> Result<Self> {
1439 buffer
1440 .update(&mut cx, |buffer, _| {
1441 buffer.wait_for_version(deserialize_version(&payload.version))
1442 })?
1443 .await
1444 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1445 let buffer_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
1446 Ok(Self {
1447 position: payload
1448 .position
1449 .and_then(deserialize_anchor)
1450 .context("invalid position")?
1451 .to_point_utf16(&buffer_snapshot),
1452 })
1453 }
1454
1455 fn response_to_proto(
1456 response: Self::Response,
1457 _: &mut LspStore,
1458 _: PeerId,
1459 _: &Global,
1460 _: &mut AppContext,
1461 ) -> proto::GetSignatureHelpResponse {
1462 proto::GetSignatureHelpResponse {
1463 signature_help: response
1464 .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1465 }
1466 }
1467
1468 async fn response_from_proto(
1469 self,
1470 response: proto::GetSignatureHelpResponse,
1471 _: Model<LspStore>,
1472 buffer: Model<Buffer>,
1473 mut cx: AsyncAppContext,
1474 ) -> Result<Self::Response> {
1475 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1476 Ok(response
1477 .signature_help
1478 .map(proto_to_lsp_signature)
1479 .and_then(|lsp_help| SignatureHelp::new(lsp_help, language)))
1480 }
1481
1482 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1483 BufferId::new(message.buffer_id)
1484 }
1485}
1486
1487#[async_trait(?Send)]
1488impl LspCommand for GetHover {
1489 type Response = Option<Hover>;
1490 type LspRequest = lsp::request::HoverRequest;
1491 type ProtoRequest = proto::GetHover;
1492
1493 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1494 match capabilities.server_capabilities.hover_provider {
1495 Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1496 Some(lsp::HoverProviderCapability::Options(_)) => true,
1497 None => false,
1498 }
1499 }
1500
1501 fn to_lsp(
1502 &self,
1503 path: &Path,
1504 _: &Buffer,
1505 _: &Arc<LanguageServer>,
1506 _: &AppContext,
1507 ) -> lsp::HoverParams {
1508 lsp::HoverParams {
1509 text_document_position_params: lsp::TextDocumentPositionParams {
1510 text_document: lsp::TextDocumentIdentifier {
1511 uri: lsp::Url::from_file_path(path).unwrap(),
1512 },
1513 position: point_to_lsp(self.position),
1514 },
1515 work_done_progress_params: Default::default(),
1516 }
1517 }
1518
1519 async fn response_from_lsp(
1520 self,
1521 message: Option<lsp::Hover>,
1522 _: Model<LspStore>,
1523 buffer: Model<Buffer>,
1524 _: LanguageServerId,
1525 mut cx: AsyncAppContext,
1526 ) -> Result<Self::Response> {
1527 let Some(hover) = message else {
1528 return Ok(None);
1529 };
1530
1531 let (language, range) = buffer.update(&mut cx, |buffer, _| {
1532 (
1533 buffer.language().cloned(),
1534 hover.range.map(|range| {
1535 let token_start =
1536 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1537 let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1538 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1539 }),
1540 )
1541 })?;
1542
1543 fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1544 let block = match marked_string {
1545 lsp::MarkedString::String(content) => HoverBlock {
1546 text: content,
1547 kind: HoverBlockKind::Markdown,
1548 },
1549 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1550 HoverBlock {
1551 text: value,
1552 kind: HoverBlockKind::Code { language },
1553 }
1554 }
1555 };
1556 if block.text.is_empty() {
1557 None
1558 } else {
1559 Some(block)
1560 }
1561 }
1562
1563 let contents = match hover.contents {
1564 lsp::HoverContents::Scalar(marked_string) => {
1565 hover_blocks_from_marked_string(marked_string)
1566 .into_iter()
1567 .collect()
1568 }
1569 lsp::HoverContents::Array(marked_strings) => marked_strings
1570 .into_iter()
1571 .filter_map(hover_blocks_from_marked_string)
1572 .collect(),
1573 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1574 text: markup_content.value,
1575 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1576 HoverBlockKind::Markdown
1577 } else {
1578 HoverBlockKind::PlainText
1579 },
1580 }],
1581 };
1582
1583 Ok(Some(Hover {
1584 contents,
1585 range,
1586 language,
1587 }))
1588 }
1589
1590 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1591 proto::GetHover {
1592 project_id,
1593 buffer_id: buffer.remote_id().into(),
1594 position: Some(language::proto::serialize_anchor(
1595 &buffer.anchor_before(self.position),
1596 )),
1597 version: serialize_version(&buffer.version),
1598 }
1599 }
1600
1601 async fn from_proto(
1602 message: Self::ProtoRequest,
1603 _: Model<LspStore>,
1604 buffer: Model<Buffer>,
1605 mut cx: AsyncAppContext,
1606 ) -> Result<Self> {
1607 let position = message
1608 .position
1609 .and_then(deserialize_anchor)
1610 .ok_or_else(|| anyhow!("invalid position"))?;
1611 buffer
1612 .update(&mut cx, |buffer, _| {
1613 buffer.wait_for_version(deserialize_version(&message.version))
1614 })?
1615 .await?;
1616 Ok(Self {
1617 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1618 })
1619 }
1620
1621 fn response_to_proto(
1622 response: Self::Response,
1623 _: &mut LspStore,
1624 _: PeerId,
1625 _: &clock::Global,
1626 _: &mut AppContext,
1627 ) -> proto::GetHoverResponse {
1628 if let Some(response) = response {
1629 let (start, end) = if let Some(range) = response.range {
1630 (
1631 Some(language::proto::serialize_anchor(&range.start)),
1632 Some(language::proto::serialize_anchor(&range.end)),
1633 )
1634 } else {
1635 (None, None)
1636 };
1637
1638 let contents = response
1639 .contents
1640 .into_iter()
1641 .map(|block| proto::HoverBlock {
1642 text: block.text,
1643 is_markdown: block.kind == HoverBlockKind::Markdown,
1644 language: if let HoverBlockKind::Code { language } = block.kind {
1645 Some(language)
1646 } else {
1647 None
1648 },
1649 })
1650 .collect();
1651
1652 proto::GetHoverResponse {
1653 start,
1654 end,
1655 contents,
1656 }
1657 } else {
1658 proto::GetHoverResponse {
1659 start: None,
1660 end: None,
1661 contents: Vec::new(),
1662 }
1663 }
1664 }
1665
1666 async fn response_from_proto(
1667 self,
1668 message: proto::GetHoverResponse,
1669 _: Model<LspStore>,
1670 buffer: Model<Buffer>,
1671 mut cx: AsyncAppContext,
1672 ) -> Result<Self::Response> {
1673 let contents: Vec<_> = message
1674 .contents
1675 .into_iter()
1676 .map(|block| HoverBlock {
1677 text: block.text,
1678 kind: if let Some(language) = block.language {
1679 HoverBlockKind::Code { language }
1680 } else if block.is_markdown {
1681 HoverBlockKind::Markdown
1682 } else {
1683 HoverBlockKind::PlainText
1684 },
1685 })
1686 .collect();
1687 if contents.is_empty() {
1688 return Ok(None);
1689 }
1690
1691 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1692 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1693 language::proto::deserialize_anchor(start)
1694 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1695 } else {
1696 None
1697 };
1698 if let Some(range) = range.as_ref() {
1699 buffer
1700 .update(&mut cx, |buffer, _| {
1701 buffer.wait_for_anchors([range.start, range.end])
1702 })?
1703 .await?;
1704 }
1705
1706 Ok(Some(Hover {
1707 contents,
1708 range,
1709 language,
1710 }))
1711 }
1712
1713 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1714 BufferId::new(message.buffer_id)
1715 }
1716}
1717
1718#[async_trait(?Send)]
1719impl LspCommand for GetCompletions {
1720 type Response = Vec<CoreCompletion>;
1721 type LspRequest = lsp::request::Completion;
1722 type ProtoRequest = proto::GetCompletions;
1723
1724 fn to_lsp(
1725 &self,
1726 path: &Path,
1727 _: &Buffer,
1728 _: &Arc<LanguageServer>,
1729 _: &AppContext,
1730 ) -> lsp::CompletionParams {
1731 lsp::CompletionParams {
1732 text_document_position: lsp::TextDocumentPositionParams::new(
1733 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1734 point_to_lsp(self.position),
1735 ),
1736 context: Some(self.context.clone()),
1737 work_done_progress_params: Default::default(),
1738 partial_result_params: Default::default(),
1739 }
1740 }
1741
1742 async fn response_from_lsp(
1743 self,
1744 completions: Option<lsp::CompletionResponse>,
1745 lsp_store: Model<LspStore>,
1746 buffer: Model<Buffer>,
1747 server_id: LanguageServerId,
1748 mut cx: AsyncAppContext,
1749 ) -> Result<Self::Response> {
1750 let mut response_list = None;
1751 let mut completions = if let Some(completions) = completions {
1752 match completions {
1753 lsp::CompletionResponse::Array(completions) => completions,
1754
1755 lsp::CompletionResponse::List(mut list) => {
1756 let items = std::mem::take(&mut list.items);
1757 response_list = Some(list);
1758 items
1759 }
1760 }
1761 } else {
1762 Default::default()
1763 };
1764
1765 let language_server_adapter = lsp_store
1766 .update(&mut cx, |lsp_store, _| {
1767 lsp_store.language_server_adapter_for_id(server_id)
1768 })?
1769 .ok_or_else(|| anyhow!("no such language server"))?;
1770
1771 let item_defaults = response_list
1772 .as_ref()
1773 .and_then(|list| list.item_defaults.as_ref());
1774
1775 if let Some(item_defaults) = item_defaults {
1776 let default_data = item_defaults.data.as_ref();
1777 let default_commit_characters = item_defaults.commit_characters.as_ref();
1778 let default_insert_text_mode = item_defaults.insert_text_mode.as_ref();
1779
1780 if default_data.is_some()
1781 || default_commit_characters.is_some()
1782 || default_insert_text_mode.is_some()
1783 {
1784 for item in completions.iter_mut() {
1785 if let Some(data) = default_data {
1786 item.data = Some(data.clone())
1787 }
1788 if let Some(characters) = default_commit_characters {
1789 item.commit_characters = Some(characters.clone())
1790 }
1791 if let Some(text_mode) = default_insert_text_mode {
1792 item.insert_text_mode = Some(*text_mode)
1793 }
1794 }
1795 }
1796 }
1797
1798 let mut completion_edits = Vec::new();
1799 buffer.update(&mut cx, |buffer, _cx| {
1800 let snapshot = buffer.snapshot();
1801 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1802
1803 let mut range_for_token = None;
1804 completions.retain_mut(|lsp_completion| {
1805 let edit = match lsp_completion.text_edit.as_ref() {
1806 // If the language server provides a range to overwrite, then
1807 // check that the range is valid.
1808 Some(completion_text_edit) => {
1809 match parse_completion_text_edit(completion_text_edit, &snapshot) {
1810 Some(edit) => edit,
1811 None => return false,
1812 }
1813 }
1814
1815 // If the language server does not provide a range, then infer
1816 // the range based on the syntax tree.
1817 None => {
1818 if self.position != clipped_position {
1819 log::info!("completion out of expected range");
1820 return false;
1821 }
1822
1823 let default_edit_range = response_list
1824 .as_ref()
1825 .and_then(|list| list.item_defaults.as_ref())
1826 .and_then(|defaults| defaults.edit_range.as_ref())
1827 .and_then(|range| match range {
1828 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1829 _ => None,
1830 });
1831
1832 let range = if let Some(range) = default_edit_range {
1833 let range = range_from_lsp(*range);
1834 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1835 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1836 if start != range.start.0 || end != range.end.0 {
1837 log::info!("completion out of expected range");
1838 return false;
1839 }
1840
1841 snapshot.anchor_before(start)..snapshot.anchor_after(end)
1842 } else {
1843 range_for_token
1844 .get_or_insert_with(|| {
1845 let offset = self.position.to_offset(&snapshot);
1846 let (range, kind) = snapshot.surrounding_word(offset);
1847 let range = if kind == Some(CharKind::Word) {
1848 range
1849 } else {
1850 offset..offset
1851 };
1852
1853 snapshot.anchor_before(range.start)
1854 ..snapshot.anchor_after(range.end)
1855 })
1856 .clone()
1857 };
1858
1859 let text = lsp_completion
1860 .insert_text
1861 .as_ref()
1862 .unwrap_or(&lsp_completion.label)
1863 .clone();
1864 (range, text)
1865 }
1866 };
1867
1868 completion_edits.push(edit);
1869 true
1870 });
1871 })?;
1872
1873 language_server_adapter
1874 .process_completions(&mut completions)
1875 .await;
1876
1877 Ok(completions
1878 .into_iter()
1879 .zip(completion_edits)
1880 .map(|(lsp_completion, (old_range, mut new_text))| {
1881 LineEnding::normalize(&mut new_text);
1882 CoreCompletion {
1883 old_range,
1884 new_text,
1885 server_id,
1886 lsp_completion,
1887 }
1888 })
1889 .collect())
1890 }
1891
1892 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1893 let anchor = buffer.anchor_after(self.position);
1894 proto::GetCompletions {
1895 project_id,
1896 buffer_id: buffer.remote_id().into(),
1897 position: Some(language::proto::serialize_anchor(&anchor)),
1898 version: serialize_version(&buffer.version()),
1899 }
1900 }
1901
1902 async fn from_proto(
1903 message: proto::GetCompletions,
1904 _: Model<LspStore>,
1905 buffer: Model<Buffer>,
1906 mut cx: AsyncAppContext,
1907 ) -> Result<Self> {
1908 let version = deserialize_version(&message.version);
1909 buffer
1910 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
1911 .await?;
1912 let position = message
1913 .position
1914 .and_then(language::proto::deserialize_anchor)
1915 .map(|p| {
1916 buffer.update(&mut cx, |buffer, _| {
1917 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1918 })
1919 })
1920 .ok_or_else(|| anyhow!("invalid position"))??;
1921 Ok(Self {
1922 position,
1923 context: CompletionContext {
1924 trigger_kind: CompletionTriggerKind::INVOKED,
1925 trigger_character: None,
1926 },
1927 })
1928 }
1929
1930 fn response_to_proto(
1931 completions: Vec<CoreCompletion>,
1932 _: &mut LspStore,
1933 _: PeerId,
1934 buffer_version: &clock::Global,
1935 _: &mut AppContext,
1936 ) -> proto::GetCompletionsResponse {
1937 proto::GetCompletionsResponse {
1938 completions: completions
1939 .iter()
1940 .map(LspStore::serialize_completion)
1941 .collect(),
1942 version: serialize_version(buffer_version),
1943 }
1944 }
1945
1946 async fn response_from_proto(
1947 self,
1948 message: proto::GetCompletionsResponse,
1949 _project: Model<LspStore>,
1950 buffer: Model<Buffer>,
1951 mut cx: AsyncAppContext,
1952 ) -> Result<Self::Response> {
1953 buffer
1954 .update(&mut cx, |buffer, _| {
1955 buffer.wait_for_version(deserialize_version(&message.version))
1956 })?
1957 .await?;
1958
1959 message
1960 .completions
1961 .into_iter()
1962 .map(LspStore::deserialize_completion)
1963 .collect()
1964 }
1965
1966 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
1967 BufferId::new(message.buffer_id)
1968 }
1969}
1970
1971pub(crate) fn parse_completion_text_edit(
1972 edit: &lsp::CompletionTextEdit,
1973 snapshot: &BufferSnapshot,
1974) -> Option<(Range<Anchor>, String)> {
1975 match edit {
1976 lsp::CompletionTextEdit::Edit(edit) => {
1977 let range = range_from_lsp(edit.range);
1978 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1979 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1980 if start != range.start.0 || end != range.end.0 {
1981 log::info!("completion out of expected range");
1982 None
1983 } else {
1984 Some((
1985 snapshot.anchor_before(start)..snapshot.anchor_after(end),
1986 edit.new_text.clone(),
1987 ))
1988 }
1989 }
1990
1991 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
1992 let range = range_from_lsp(edit.insert);
1993
1994 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1995 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1996 if start != range.start.0 || end != range.end.0 {
1997 log::info!("completion out of expected range");
1998 None
1999 } else {
2000 Some((
2001 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2002 edit.new_text.clone(),
2003 ))
2004 }
2005 }
2006 }
2007}
2008
2009#[async_trait(?Send)]
2010impl LspCommand for GetCodeActions {
2011 type Response = Vec<CodeAction>;
2012 type LspRequest = lsp::request::CodeActionRequest;
2013 type ProtoRequest = proto::GetCodeActions;
2014
2015 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2016 match &capabilities.server_capabilities.code_action_provider {
2017 None => false,
2018 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2019 _ => {
2020 // If we do know that we want specific code actions AND we know that
2021 // the server only supports specific code actions, then we want to filter
2022 // down to the ones that are supported.
2023 if let Some((requested, supported)) = self
2024 .kinds
2025 .as_ref()
2026 .zip(Self::supported_code_action_kinds(capabilities))
2027 {
2028 let server_supported = supported.into_iter().collect::<HashSet<_>>();
2029 requested.iter().any(|kind| server_supported.contains(kind))
2030 } else {
2031 true
2032 }
2033 }
2034 }
2035 }
2036
2037 fn to_lsp(
2038 &self,
2039 path: &Path,
2040 buffer: &Buffer,
2041 language_server: &Arc<LanguageServer>,
2042 _: &AppContext,
2043 ) -> lsp::CodeActionParams {
2044 let relevant_diagnostics = buffer
2045 .snapshot()
2046 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2047 .map(|entry| entry.to_lsp_diagnostic_stub())
2048 .collect::<Vec<_>>();
2049
2050 let supported =
2051 Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2052
2053 let only = if let Some(requested) = &self.kinds {
2054 if let Some(supported_kinds) = supported {
2055 let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2056
2057 let filtered = requested
2058 .iter()
2059 .filter(|kind| server_supported.contains(kind))
2060 .cloned()
2061 .collect();
2062 Some(filtered)
2063 } else {
2064 Some(requested.clone())
2065 }
2066 } else {
2067 supported
2068 };
2069
2070 lsp::CodeActionParams {
2071 text_document: lsp::TextDocumentIdentifier::new(
2072 lsp::Url::from_file_path(path).unwrap(),
2073 ),
2074 range: range_to_lsp(self.range.to_point_utf16(buffer)),
2075 work_done_progress_params: Default::default(),
2076 partial_result_params: Default::default(),
2077 context: lsp::CodeActionContext {
2078 diagnostics: relevant_diagnostics,
2079 only,
2080 ..lsp::CodeActionContext::default()
2081 },
2082 }
2083 }
2084
2085 async fn response_from_lsp(
2086 self,
2087 actions: Option<lsp::CodeActionResponse>,
2088 _: Model<LspStore>,
2089 _: Model<Buffer>,
2090 server_id: LanguageServerId,
2091 _: AsyncAppContext,
2092 ) -> Result<Vec<CodeAction>> {
2093 let requested_kinds_set = if let Some(kinds) = self.kinds {
2094 Some(kinds.into_iter().collect::<HashSet<_>>())
2095 } else {
2096 None
2097 };
2098
2099 Ok(actions
2100 .unwrap_or_default()
2101 .into_iter()
2102 .filter_map(|entry| {
2103 let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry else {
2104 return None;
2105 };
2106
2107 if let Some((requested_kinds, kind)) =
2108 requested_kinds_set.as_ref().zip(lsp_action.kind.as_ref())
2109 {
2110 if !requested_kinds.contains(kind) {
2111 return None;
2112 }
2113 }
2114
2115 Some(CodeAction {
2116 server_id,
2117 range: self.range.clone(),
2118 lsp_action,
2119 })
2120 })
2121 .collect())
2122 }
2123
2124 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2125 proto::GetCodeActions {
2126 project_id,
2127 buffer_id: buffer.remote_id().into(),
2128 start: Some(language::proto::serialize_anchor(&self.range.start)),
2129 end: Some(language::proto::serialize_anchor(&self.range.end)),
2130 version: serialize_version(&buffer.version()),
2131 }
2132 }
2133
2134 async fn from_proto(
2135 message: proto::GetCodeActions,
2136 _: Model<LspStore>,
2137 buffer: Model<Buffer>,
2138 mut cx: AsyncAppContext,
2139 ) -> Result<Self> {
2140 let start = message
2141 .start
2142 .and_then(language::proto::deserialize_anchor)
2143 .ok_or_else(|| anyhow!("invalid start"))?;
2144 let end = message
2145 .end
2146 .and_then(language::proto::deserialize_anchor)
2147 .ok_or_else(|| anyhow!("invalid end"))?;
2148 buffer
2149 .update(&mut cx, |buffer, _| {
2150 buffer.wait_for_version(deserialize_version(&message.version))
2151 })?
2152 .await?;
2153
2154 Ok(Self {
2155 range: start..end,
2156 kinds: None,
2157 })
2158 }
2159
2160 fn response_to_proto(
2161 code_actions: Vec<CodeAction>,
2162 _: &mut LspStore,
2163 _: PeerId,
2164 buffer_version: &clock::Global,
2165 _: &mut AppContext,
2166 ) -> proto::GetCodeActionsResponse {
2167 proto::GetCodeActionsResponse {
2168 actions: code_actions
2169 .iter()
2170 .map(LspStore::serialize_code_action)
2171 .collect(),
2172 version: serialize_version(buffer_version),
2173 }
2174 }
2175
2176 async fn response_from_proto(
2177 self,
2178 message: proto::GetCodeActionsResponse,
2179 _: Model<LspStore>,
2180 buffer: Model<Buffer>,
2181 mut cx: AsyncAppContext,
2182 ) -> Result<Vec<CodeAction>> {
2183 buffer
2184 .update(&mut cx, |buffer, _| {
2185 buffer.wait_for_version(deserialize_version(&message.version))
2186 })?
2187 .await?;
2188 message
2189 .actions
2190 .into_iter()
2191 .map(LspStore::deserialize_code_action)
2192 .collect()
2193 }
2194
2195 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2196 BufferId::new(message.buffer_id)
2197 }
2198}
2199
2200impl GetCodeActions {
2201 fn supported_code_action_kinds(
2202 capabilities: AdapterServerCapabilities,
2203 ) -> Option<Vec<CodeActionKind>> {
2204 match capabilities.server_capabilities.code_action_provider {
2205 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2206 code_action_kinds: Some(supported_action_kinds),
2207 ..
2208 })) => Some(supported_action_kinds.clone()),
2209 _ => capabilities.code_action_kinds,
2210 }
2211 }
2212
2213 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2214 capabilities
2215 .code_action_provider
2216 .as_ref()
2217 .and_then(|options| match options {
2218 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2219 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2220 })
2221 .unwrap_or(false)
2222 }
2223}
2224
2225#[async_trait(?Send)]
2226impl LspCommand for OnTypeFormatting {
2227 type Response = Option<Transaction>;
2228 type LspRequest = lsp::request::OnTypeFormatting;
2229 type ProtoRequest = proto::OnTypeFormatting;
2230
2231 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2232 let Some(on_type_formatting_options) = &capabilities
2233 .server_capabilities
2234 .document_on_type_formatting_provider
2235 else {
2236 return false;
2237 };
2238 on_type_formatting_options
2239 .first_trigger_character
2240 .contains(&self.trigger)
2241 || on_type_formatting_options
2242 .more_trigger_character
2243 .iter()
2244 .flatten()
2245 .any(|chars| chars.contains(&self.trigger))
2246 }
2247
2248 fn to_lsp(
2249 &self,
2250 path: &Path,
2251 _: &Buffer,
2252 _: &Arc<LanguageServer>,
2253 _: &AppContext,
2254 ) -> lsp::DocumentOnTypeFormattingParams {
2255 lsp::DocumentOnTypeFormattingParams {
2256 text_document_position: lsp::TextDocumentPositionParams::new(
2257 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2258 point_to_lsp(self.position),
2259 ),
2260 ch: self.trigger.clone(),
2261 options: self.options.clone(),
2262 }
2263 }
2264
2265 async fn response_from_lsp(
2266 self,
2267 message: Option<Vec<lsp::TextEdit>>,
2268 lsp_store: Model<LspStore>,
2269 buffer: Model<Buffer>,
2270 server_id: LanguageServerId,
2271 mut cx: AsyncAppContext,
2272 ) -> Result<Option<Transaction>> {
2273 if let Some(edits) = message {
2274 let (lsp_adapter, lsp_server) =
2275 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2276 LspStore::deserialize_text_edits(
2277 lsp_store,
2278 buffer,
2279 edits,
2280 self.push_to_history,
2281 lsp_adapter,
2282 lsp_server,
2283 &mut cx,
2284 )
2285 .await
2286 } else {
2287 Ok(None)
2288 }
2289 }
2290
2291 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2292 proto::OnTypeFormatting {
2293 project_id,
2294 buffer_id: buffer.remote_id().into(),
2295 position: Some(language::proto::serialize_anchor(
2296 &buffer.anchor_before(self.position),
2297 )),
2298 trigger: self.trigger.clone(),
2299 version: serialize_version(&buffer.version()),
2300 }
2301 }
2302
2303 async fn from_proto(
2304 message: proto::OnTypeFormatting,
2305 _: Model<LspStore>,
2306 buffer: Model<Buffer>,
2307 mut cx: AsyncAppContext,
2308 ) -> Result<Self> {
2309 let position = message
2310 .position
2311 .and_then(deserialize_anchor)
2312 .ok_or_else(|| anyhow!("invalid position"))?;
2313 buffer
2314 .update(&mut cx, |buffer, _| {
2315 buffer.wait_for_version(deserialize_version(&message.version))
2316 })?
2317 .await?;
2318
2319 let options = buffer.update(&mut cx, |buffer, cx| {
2320 lsp_formatting_options(
2321 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2322 )
2323 })?;
2324
2325 Ok(Self {
2326 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2327 trigger: message.trigger.clone(),
2328 options,
2329 push_to_history: false,
2330 })
2331 }
2332
2333 fn response_to_proto(
2334 response: Option<Transaction>,
2335 _: &mut LspStore,
2336 _: PeerId,
2337 _: &clock::Global,
2338 _: &mut AppContext,
2339 ) -> proto::OnTypeFormattingResponse {
2340 proto::OnTypeFormattingResponse {
2341 transaction: response
2342 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2343 }
2344 }
2345
2346 async fn response_from_proto(
2347 self,
2348 message: proto::OnTypeFormattingResponse,
2349 _: Model<LspStore>,
2350 _: Model<Buffer>,
2351 _: AsyncAppContext,
2352 ) -> Result<Option<Transaction>> {
2353 let Some(transaction) = message.transaction else {
2354 return Ok(None);
2355 };
2356 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2357 }
2358
2359 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2360 BufferId::new(message.buffer_id)
2361 }
2362}
2363
2364impl InlayHints {
2365 pub async fn lsp_to_project_hint(
2366 lsp_hint: lsp::InlayHint,
2367 buffer_handle: &Model<Buffer>,
2368 server_id: LanguageServerId,
2369 resolve_state: ResolveState,
2370 force_no_type_left_padding: bool,
2371 cx: &mut AsyncAppContext,
2372 ) -> anyhow::Result<InlayHint> {
2373 let kind = lsp_hint.kind.and_then(|kind| match kind {
2374 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2375 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2376 _ => None,
2377 });
2378
2379 let position = buffer_handle.update(cx, |buffer, _| {
2380 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2381 if kind == Some(InlayHintKind::Parameter) {
2382 buffer.anchor_before(position)
2383 } else {
2384 buffer.anchor_after(position)
2385 }
2386 })?;
2387 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2388 .await
2389 .context("lsp to project inlay hint conversion")?;
2390 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2391 false
2392 } else {
2393 lsp_hint.padding_left.unwrap_or(false)
2394 };
2395
2396 Ok(InlayHint {
2397 position,
2398 padding_left,
2399 padding_right: lsp_hint.padding_right.unwrap_or(false),
2400 label,
2401 kind,
2402 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2403 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2404 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2405 InlayHintTooltip::MarkupContent(MarkupContent {
2406 kind: match markup_content.kind {
2407 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2408 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2409 },
2410 value: markup_content.value,
2411 })
2412 }
2413 }),
2414 resolve_state,
2415 })
2416 }
2417
2418 async fn lsp_inlay_label_to_project(
2419 lsp_label: lsp::InlayHintLabel,
2420 server_id: LanguageServerId,
2421 ) -> anyhow::Result<InlayHintLabel> {
2422 let label = match lsp_label {
2423 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2424 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2425 let mut parts = Vec::with_capacity(lsp_parts.len());
2426 for lsp_part in lsp_parts {
2427 parts.push(InlayHintLabelPart {
2428 value: lsp_part.value,
2429 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2430 lsp::InlayHintLabelPartTooltip::String(s) => {
2431 InlayHintLabelPartTooltip::String(s)
2432 }
2433 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2434 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2435 kind: match markup_content.kind {
2436 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2437 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2438 },
2439 value: markup_content.value,
2440 })
2441 }
2442 }),
2443 location: Some(server_id).zip(lsp_part.location),
2444 });
2445 }
2446 InlayHintLabel::LabelParts(parts)
2447 }
2448 };
2449
2450 Ok(label)
2451 }
2452
2453 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2454 let (state, lsp_resolve_state) = match response_hint.resolve_state {
2455 ResolveState::Resolved => (0, None),
2456 ResolveState::CanResolve(server_id, resolve_data) => (
2457 1,
2458 Some(proto::resolve_state::LspResolveState {
2459 server_id: server_id.0 as u64,
2460 value: resolve_data.map(|json_data| {
2461 serde_json::to_string(&json_data)
2462 .expect("failed to serialize resolve json data")
2463 }),
2464 }),
2465 ),
2466 ResolveState::Resolving => (2, None),
2467 };
2468 let resolve_state = Some(proto::ResolveState {
2469 state,
2470 lsp_resolve_state,
2471 });
2472 proto::InlayHint {
2473 position: Some(language::proto::serialize_anchor(&response_hint.position)),
2474 padding_left: response_hint.padding_left,
2475 padding_right: response_hint.padding_right,
2476 label: Some(proto::InlayHintLabel {
2477 label: Some(match response_hint.label {
2478 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2479 InlayHintLabel::LabelParts(label_parts) => {
2480 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2481 parts: label_parts.into_iter().map(|label_part| {
2482 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2483 let location_range_start = label_part.location.as_ref().map(|(_, location)| point_from_lsp(location.range.start).0).map(|point| proto::PointUtf16 { row: point.row, column: point.column });
2484 let location_range_end = label_part.location.as_ref().map(|(_, location)| point_from_lsp(location.range.end).0).map(|point| proto::PointUtf16 { row: point.row, column: point.column });
2485 proto::InlayHintLabelPart {
2486 value: label_part.value,
2487 tooltip: label_part.tooltip.map(|tooltip| {
2488 let proto_tooltip = match tooltip {
2489 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2490 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2491 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2492 value: markup_content.value,
2493 }),
2494 };
2495 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2496 }),
2497 location_url,
2498 location_range_start,
2499 location_range_end,
2500 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2501 }}).collect()
2502 })
2503 }
2504 }),
2505 }),
2506 kind: response_hint.kind.map(|kind| kind.name().to_string()),
2507 tooltip: response_hint.tooltip.map(|response_tooltip| {
2508 let proto_tooltip = match response_tooltip {
2509 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2510 InlayHintTooltip::MarkupContent(markup_content) => {
2511 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2512 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2513 value: markup_content.value,
2514 })
2515 }
2516 };
2517 proto::InlayHintTooltip {
2518 content: Some(proto_tooltip),
2519 }
2520 }),
2521 resolve_state,
2522 }
2523 }
2524
2525 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2526 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2527 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2528 });
2529 let resolve_state_data = resolve_state
2530 .lsp_resolve_state.as_ref()
2531 .map(|lsp_resolve_state| {
2532 let value = lsp_resolve_state.value.as_deref().map(|value| {
2533 serde_json::from_str::<Option<lsp::LSPAny>>(value)
2534 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2535 }).transpose()?.flatten();
2536 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2537 })
2538 .transpose()?;
2539 let resolve_state = match resolve_state.state {
2540 0 => ResolveState::Resolved,
2541 1 => {
2542 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2543 format!(
2544 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2545 )
2546 })?;
2547 ResolveState::CanResolve(server_id, lsp_resolve_state)
2548 }
2549 2 => ResolveState::Resolving,
2550 invalid => {
2551 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2552 }
2553 };
2554 Ok(InlayHint {
2555 position: message_hint
2556 .position
2557 .and_then(language::proto::deserialize_anchor)
2558 .context("invalid position")?,
2559 label: match message_hint
2560 .label
2561 .and_then(|label| label.label)
2562 .context("missing label")?
2563 {
2564 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2565 proto::inlay_hint_label::Label::LabelParts(parts) => {
2566 let mut label_parts = Vec::new();
2567 for part in parts.parts {
2568 label_parts.push(InlayHintLabelPart {
2569 value: part.value,
2570 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2571 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2572 InlayHintLabelPartTooltip::String(s)
2573 }
2574 Some(
2575 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2576 markup_content,
2577 ),
2578 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2579 kind: if markup_content.is_markdown {
2580 HoverBlockKind::Markdown
2581 } else {
2582 HoverBlockKind::PlainText
2583 },
2584 value: markup_content.value,
2585 }),
2586 None => InlayHintLabelPartTooltip::String(String::new()),
2587 }),
2588 location: {
2589 match part
2590 .location_url
2591 .zip(
2592 part.location_range_start.and_then(|start| {
2593 Some(start..part.location_range_end?)
2594 }),
2595 )
2596 .zip(part.language_server_id)
2597 {
2598 Some(((uri, range), server_id)) => Some((
2599 LanguageServerId(server_id as usize),
2600 lsp::Location {
2601 uri: lsp::Url::parse(&uri)
2602 .context("invalid uri in hint part {part:?}")?,
2603 range: lsp::Range::new(
2604 point_to_lsp(PointUtf16::new(
2605 range.start.row,
2606 range.start.column,
2607 )),
2608 point_to_lsp(PointUtf16::new(
2609 range.end.row,
2610 range.end.column,
2611 )),
2612 ),
2613 },
2614 )),
2615 None => None,
2616 }
2617 },
2618 });
2619 }
2620
2621 InlayHintLabel::LabelParts(label_parts)
2622 }
2623 },
2624 padding_left: message_hint.padding_left,
2625 padding_right: message_hint.padding_right,
2626 kind: message_hint
2627 .kind
2628 .as_deref()
2629 .and_then(InlayHintKind::from_name),
2630 tooltip: message_hint.tooltip.and_then(|tooltip| {
2631 Some(match tooltip.content? {
2632 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2633 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2634 InlayHintTooltip::MarkupContent(MarkupContent {
2635 kind: if markup_content.is_markdown {
2636 HoverBlockKind::Markdown
2637 } else {
2638 HoverBlockKind::PlainText
2639 },
2640 value: markup_content.value,
2641 })
2642 }
2643 })
2644 }),
2645 resolve_state,
2646 })
2647 }
2648
2649 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2650 lsp::InlayHint {
2651 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2652 kind: hint.kind.map(|kind| match kind {
2653 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2654 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2655 }),
2656 text_edits: None,
2657 tooltip: hint.tooltip.and_then(|tooltip| {
2658 Some(match tooltip {
2659 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2660 InlayHintTooltip::MarkupContent(markup_content) => {
2661 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2662 kind: match markup_content.kind {
2663 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2664 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2665 HoverBlockKind::Code { .. } => return None,
2666 },
2667 value: markup_content.value,
2668 })
2669 }
2670 })
2671 }),
2672 label: match hint.label {
2673 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2674 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2675 label_parts
2676 .into_iter()
2677 .map(|part| lsp::InlayHintLabelPart {
2678 value: part.value,
2679 tooltip: part.tooltip.and_then(|tooltip| {
2680 Some(match tooltip {
2681 InlayHintLabelPartTooltip::String(s) => {
2682 lsp::InlayHintLabelPartTooltip::String(s)
2683 }
2684 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2685 lsp::InlayHintLabelPartTooltip::MarkupContent(
2686 lsp::MarkupContent {
2687 kind: match markup_content.kind {
2688 HoverBlockKind::PlainText => {
2689 lsp::MarkupKind::PlainText
2690 }
2691 HoverBlockKind::Markdown => {
2692 lsp::MarkupKind::Markdown
2693 }
2694 HoverBlockKind::Code { .. } => return None,
2695 },
2696 value: markup_content.value,
2697 },
2698 )
2699 }
2700 })
2701 }),
2702 location: part.location.map(|(_, location)| location),
2703 command: None,
2704 })
2705 .collect(),
2706 ),
2707 },
2708 padding_left: Some(hint.padding_left),
2709 padding_right: Some(hint.padding_right),
2710 data: match hint.resolve_state {
2711 ResolveState::CanResolve(_, data) => data,
2712 ResolveState::Resolving | ResolveState::Resolved => None,
2713 },
2714 }
2715 }
2716
2717 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2718 capabilities
2719 .inlay_hint_provider
2720 .as_ref()
2721 .and_then(|options| match options {
2722 OneOf::Left(_is_supported) => None,
2723 OneOf::Right(capabilities) => match capabilities {
2724 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2725 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2726 o.inlay_hint_options.resolve_provider
2727 }
2728 },
2729 })
2730 .unwrap_or(false)
2731 }
2732}
2733
2734#[async_trait(?Send)]
2735impl LspCommand for InlayHints {
2736 type Response = Vec<InlayHint>;
2737 type LspRequest = lsp::InlayHintRequest;
2738 type ProtoRequest = proto::InlayHints;
2739
2740 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2741 let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
2742 else {
2743 return false;
2744 };
2745 match inlay_hint_provider {
2746 lsp::OneOf::Left(enabled) => *enabled,
2747 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2748 lsp::InlayHintServerCapabilities::Options(_) => true,
2749 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2750 },
2751 }
2752 }
2753
2754 fn to_lsp(
2755 &self,
2756 path: &Path,
2757 buffer: &Buffer,
2758 _: &Arc<LanguageServer>,
2759 _: &AppContext,
2760 ) -> lsp::InlayHintParams {
2761 lsp::InlayHintParams {
2762 text_document: lsp::TextDocumentIdentifier {
2763 uri: lsp::Url::from_file_path(path).unwrap(),
2764 },
2765 range: range_to_lsp(self.range.to_point_utf16(buffer)),
2766 work_done_progress_params: Default::default(),
2767 }
2768 }
2769
2770 async fn response_from_lsp(
2771 self,
2772 message: Option<Vec<lsp::InlayHint>>,
2773 lsp_store: Model<LspStore>,
2774 buffer: Model<Buffer>,
2775 server_id: LanguageServerId,
2776 mut cx: AsyncAppContext,
2777 ) -> anyhow::Result<Vec<InlayHint>> {
2778 let (lsp_adapter, lsp_server) =
2779 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2780 // `typescript-language-server` adds padding to the left for type hints, turning
2781 // `const foo: boolean` into `const foo : boolean` which looks odd.
2782 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2783 //
2784 // We could trim the whole string, but being pessimistic on par with the situation above,
2785 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2786 // Hence let's use a heuristic first to handle the most awkward case and look for more.
2787 let force_no_type_left_padding =
2788 lsp_adapter.name.0.as_ref() == "typescript-language-server";
2789
2790 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2791 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2792 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2793 } else {
2794 ResolveState::Resolved
2795 };
2796
2797 let buffer = buffer.clone();
2798 cx.spawn(move |mut cx| async move {
2799 InlayHints::lsp_to_project_hint(
2800 lsp_hint,
2801 &buffer,
2802 server_id,
2803 resolve_state,
2804 force_no_type_left_padding,
2805 &mut cx,
2806 )
2807 .await
2808 })
2809 });
2810 future::join_all(hints)
2811 .await
2812 .into_iter()
2813 .collect::<anyhow::Result<_>>()
2814 .context("lsp to project inlay hints conversion")
2815 }
2816
2817 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2818 proto::InlayHints {
2819 project_id,
2820 buffer_id: buffer.remote_id().into(),
2821 start: Some(language::proto::serialize_anchor(&self.range.start)),
2822 end: Some(language::proto::serialize_anchor(&self.range.end)),
2823 version: serialize_version(&buffer.version()),
2824 }
2825 }
2826
2827 async fn from_proto(
2828 message: proto::InlayHints,
2829 _: Model<LspStore>,
2830 buffer: Model<Buffer>,
2831 mut cx: AsyncAppContext,
2832 ) -> Result<Self> {
2833 let start = message
2834 .start
2835 .and_then(language::proto::deserialize_anchor)
2836 .context("invalid start")?;
2837 let end = message
2838 .end
2839 .and_then(language::proto::deserialize_anchor)
2840 .context("invalid end")?;
2841 buffer
2842 .update(&mut cx, |buffer, _| {
2843 buffer.wait_for_version(deserialize_version(&message.version))
2844 })?
2845 .await?;
2846
2847 Ok(Self { range: start..end })
2848 }
2849
2850 fn response_to_proto(
2851 response: Vec<InlayHint>,
2852 _: &mut LspStore,
2853 _: PeerId,
2854 buffer_version: &clock::Global,
2855 _: &mut AppContext,
2856 ) -> proto::InlayHintsResponse {
2857 proto::InlayHintsResponse {
2858 hints: response
2859 .into_iter()
2860 .map(InlayHints::project_to_proto_hint)
2861 .collect(),
2862 version: serialize_version(buffer_version),
2863 }
2864 }
2865
2866 async fn response_from_proto(
2867 self,
2868 message: proto::InlayHintsResponse,
2869 _: Model<LspStore>,
2870 buffer: Model<Buffer>,
2871 mut cx: AsyncAppContext,
2872 ) -> anyhow::Result<Vec<InlayHint>> {
2873 buffer
2874 .update(&mut cx, |buffer, _| {
2875 buffer.wait_for_version(deserialize_version(&message.version))
2876 })?
2877 .await?;
2878
2879 let mut hints = Vec::new();
2880 for message_hint in message.hints {
2881 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
2882 }
2883
2884 Ok(hints)
2885 }
2886
2887 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
2888 BufferId::new(message.buffer_id)
2889 }
2890}
2891
2892#[async_trait(?Send)]
2893impl LspCommand for LinkedEditingRange {
2894 type Response = Vec<Range<Anchor>>;
2895 type LspRequest = lsp::request::LinkedEditingRange;
2896 type ProtoRequest = proto::LinkedEditingRange;
2897
2898 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2899 let Some(linked_editing_options) = &capabilities
2900 .server_capabilities
2901 .linked_editing_range_provider
2902 else {
2903 return false;
2904 };
2905 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
2906 return false;
2907 }
2908 true
2909 }
2910
2911 fn to_lsp(
2912 &self,
2913 path: &Path,
2914 buffer: &Buffer,
2915 _server: &Arc<LanguageServer>,
2916 _: &AppContext,
2917 ) -> lsp::LinkedEditingRangeParams {
2918 let position = self.position.to_point_utf16(&buffer.snapshot());
2919 lsp::LinkedEditingRangeParams {
2920 text_document_position_params: lsp::TextDocumentPositionParams::new(
2921 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
2922 point_to_lsp(position),
2923 ),
2924 work_done_progress_params: Default::default(),
2925 }
2926 }
2927
2928 async fn response_from_lsp(
2929 self,
2930 message: Option<lsp::LinkedEditingRanges>,
2931 _: Model<LspStore>,
2932 buffer: Model<Buffer>,
2933 _server_id: LanguageServerId,
2934 cx: AsyncAppContext,
2935 ) -> Result<Vec<Range<Anchor>>> {
2936 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
2937 ranges.sort_by_key(|range| range.start);
2938
2939 buffer.read_with(&cx, |buffer, _| {
2940 ranges
2941 .into_iter()
2942 .map(|range| {
2943 let start =
2944 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
2945 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
2946 buffer.anchor_before(start)..buffer.anchor_after(end)
2947 })
2948 .collect()
2949 })
2950 } else {
2951 Ok(vec![])
2952 }
2953 }
2954
2955 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
2956 proto::LinkedEditingRange {
2957 project_id,
2958 buffer_id: buffer.remote_id().to_proto(),
2959 position: Some(serialize_anchor(&self.position)),
2960 version: serialize_version(&buffer.version()),
2961 }
2962 }
2963
2964 async fn from_proto(
2965 message: proto::LinkedEditingRange,
2966 _: Model<LspStore>,
2967 buffer: Model<Buffer>,
2968 mut cx: AsyncAppContext,
2969 ) -> Result<Self> {
2970 let position = message
2971 .position
2972 .ok_or_else(|| anyhow!("invalid position"))?;
2973 buffer
2974 .update(&mut cx, |buffer, _| {
2975 buffer.wait_for_version(deserialize_version(&message.version))
2976 })?
2977 .await?;
2978 let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
2979 buffer
2980 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
2981 .await?;
2982 Ok(Self { position })
2983 }
2984
2985 fn response_to_proto(
2986 response: Vec<Range<Anchor>>,
2987 _: &mut LspStore,
2988 _: PeerId,
2989 buffer_version: &clock::Global,
2990 _: &mut AppContext,
2991 ) -> proto::LinkedEditingRangeResponse {
2992 proto::LinkedEditingRangeResponse {
2993 items: response
2994 .into_iter()
2995 .map(|range| proto::AnchorRange {
2996 start: Some(serialize_anchor(&range.start)),
2997 end: Some(serialize_anchor(&range.end)),
2998 })
2999 .collect(),
3000 version: serialize_version(buffer_version),
3001 }
3002 }
3003
3004 async fn response_from_proto(
3005 self,
3006 message: proto::LinkedEditingRangeResponse,
3007 _: Model<LspStore>,
3008 buffer: Model<Buffer>,
3009 mut cx: AsyncAppContext,
3010 ) -> Result<Vec<Range<Anchor>>> {
3011 buffer
3012 .update(&mut cx, |buffer, _| {
3013 buffer.wait_for_version(deserialize_version(&message.version))
3014 })?
3015 .await?;
3016 let items: Vec<Range<Anchor>> = message
3017 .items
3018 .into_iter()
3019 .filter_map(|range| {
3020 let start = deserialize_anchor(range.start?)?;
3021 let end = deserialize_anchor(range.end?)?;
3022 Some(start..end)
3023 })
3024 .collect();
3025 for range in &items {
3026 buffer
3027 .update(&mut cx, |buffer, _| {
3028 buffer.wait_for_anchors([range.start, range.end])
3029 })?
3030 .await?;
3031 }
3032 Ok(items)
3033 }
3034
3035 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3036 BufferId::new(message.buffer_id)
3037 }
3038}