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