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 lsp::CompletionResponse::List(mut list) => {
1851 let items = std::mem::take(&mut list.items);
1852 response_list = Some(list);
1853 items
1854 }
1855 }
1856 } else {
1857 Vec::new()
1858 };
1859
1860 let language_server_adapter = lsp_store
1861 .update(&mut cx, |lsp_store, _| {
1862 lsp_store.language_server_adapter_for_id(server_id)
1863 })?
1864 .with_context(|| format!("no language server with id {server_id}"))?;
1865
1866 let lsp_defaults = response_list
1867 .as_ref()
1868 .and_then(|list| list.item_defaults.clone())
1869 .map(Arc::new);
1870
1871 let mut completion_edits = Vec::new();
1872 buffer.update(&mut cx, |buffer, _cx| {
1873 let snapshot = buffer.snapshot();
1874 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1875
1876 let mut range_for_token = None;
1877 completions.retain(|lsp_completion| {
1878 let lsp_edit = lsp_completion.text_edit.clone().or_else(|| {
1879 let default_text_edit = lsp_defaults.as_deref()?.edit_range.as_ref()?;
1880 match default_text_edit {
1881 CompletionListItemDefaultsEditRange::Range(range) => {
1882 Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
1883 range: *range,
1884 new_text: lsp_completion.label.clone(),
1885 }))
1886 }
1887 CompletionListItemDefaultsEditRange::InsertAndReplace {
1888 insert,
1889 replace,
1890 } => Some(lsp::CompletionTextEdit::InsertAndReplace(
1891 lsp::InsertReplaceEdit {
1892 new_text: lsp_completion.label.clone(),
1893 insert: *insert,
1894 replace: *replace,
1895 },
1896 )),
1897 }
1898 });
1899
1900 let edit = match lsp_edit {
1901 // If the language server provides a range to overwrite, then
1902 // check that the range is valid.
1903 Some(completion_text_edit) => {
1904 match parse_completion_text_edit(&completion_text_edit, &snapshot) {
1905 Some(edit) => edit,
1906 None => return false,
1907 }
1908 }
1909
1910 // If the language server does not provide a range, then infer
1911 // the range based on the syntax tree.
1912 None => {
1913 if self.position != clipped_position {
1914 log::info!("completion out of expected range");
1915 return false;
1916 }
1917
1918 let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
1919 lsp_defaults
1920 .edit_range
1921 .as_ref()
1922 .and_then(|range| match range {
1923 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1924 _ => None,
1925 })
1926 });
1927
1928 let range = if let Some(range) = default_edit_range {
1929 let range = range_from_lsp(*range);
1930 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1931 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1932 if start != range.start.0 || end != range.end.0 {
1933 log::info!("completion out of expected range");
1934 return false;
1935 }
1936
1937 snapshot.anchor_before(start)..snapshot.anchor_after(end)
1938 } else {
1939 range_for_token
1940 .get_or_insert_with(|| {
1941 let offset = self.position.to_offset(&snapshot);
1942 let (range, kind) = snapshot.surrounding_word(offset);
1943 let range = if kind == Some(CharKind::Word) {
1944 range
1945 } else {
1946 offset..offset
1947 };
1948
1949 snapshot.anchor_before(range.start)
1950 ..snapshot.anchor_after(range.end)
1951 })
1952 .clone()
1953 };
1954
1955 let text = lsp_completion
1956 .insert_text
1957 .as_ref()
1958 .unwrap_or(&lsp_completion.label)
1959 .clone();
1960 (range, text)
1961 }
1962 };
1963
1964 completion_edits.push(edit);
1965 true
1966 });
1967 })?;
1968
1969 language_server_adapter
1970 .process_completions(&mut completions)
1971 .await;
1972
1973 Ok(completions
1974 .into_iter()
1975 .zip(completion_edits)
1976 .map(|(mut lsp_completion, (old_range, mut new_text))| {
1977 LineEnding::normalize(&mut new_text);
1978 if lsp_completion.data.is_none() {
1979 if let Some(default_data) = lsp_defaults
1980 .as_ref()
1981 .and_then(|item_defaults| item_defaults.data.clone())
1982 {
1983 // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
1984 // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
1985 lsp_completion.data = Some(default_data);
1986 }
1987 }
1988 CoreCompletion {
1989 old_range,
1990 new_text,
1991 source: CompletionSource::Lsp {
1992 server_id,
1993 lsp_completion: Box::new(lsp_completion),
1994 lsp_defaults: lsp_defaults.clone(),
1995 resolved: false,
1996 },
1997 }
1998 })
1999 .collect())
2000 }
2001
2002 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2003 let anchor = buffer.anchor_after(self.position);
2004 proto::GetCompletions {
2005 project_id,
2006 buffer_id: buffer.remote_id().into(),
2007 position: Some(language::proto::serialize_anchor(&anchor)),
2008 version: serialize_version(&buffer.version()),
2009 }
2010 }
2011
2012 async fn from_proto(
2013 message: proto::GetCompletions,
2014 _: Entity<LspStore>,
2015 buffer: Entity<Buffer>,
2016 mut cx: AsyncApp,
2017 ) -> Result<Self> {
2018 let version = deserialize_version(&message.version);
2019 buffer
2020 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2021 .await?;
2022 let position = message
2023 .position
2024 .and_then(language::proto::deserialize_anchor)
2025 .map(|p| {
2026 buffer.update(&mut cx, |buffer, _| {
2027 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2028 })
2029 })
2030 .ok_or_else(|| anyhow!("invalid position"))??;
2031 Ok(Self {
2032 position,
2033 context: CompletionContext {
2034 trigger_kind: CompletionTriggerKind::INVOKED,
2035 trigger_character: None,
2036 },
2037 })
2038 }
2039
2040 fn response_to_proto(
2041 completions: Vec<CoreCompletion>,
2042 _: &mut LspStore,
2043 _: PeerId,
2044 buffer_version: &clock::Global,
2045 _: &mut App,
2046 ) -> proto::GetCompletionsResponse {
2047 proto::GetCompletionsResponse {
2048 completions: completions
2049 .iter()
2050 .map(LspStore::serialize_completion)
2051 .collect(),
2052 version: serialize_version(buffer_version),
2053 }
2054 }
2055
2056 async fn response_from_proto(
2057 self,
2058 message: proto::GetCompletionsResponse,
2059 _project: Entity<LspStore>,
2060 buffer: Entity<Buffer>,
2061 mut cx: AsyncApp,
2062 ) -> Result<Self::Response> {
2063 buffer
2064 .update(&mut cx, |buffer, _| {
2065 buffer.wait_for_version(deserialize_version(&message.version))
2066 })?
2067 .await?;
2068
2069 message
2070 .completions
2071 .into_iter()
2072 .map(LspStore::deserialize_completion)
2073 .collect()
2074 }
2075
2076 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2077 BufferId::new(message.buffer_id)
2078 }
2079}
2080
2081pub(crate) fn parse_completion_text_edit(
2082 edit: &lsp::CompletionTextEdit,
2083 snapshot: &BufferSnapshot,
2084) -> Option<(Range<Anchor>, String)> {
2085 match edit {
2086 lsp::CompletionTextEdit::Edit(edit) => {
2087 let range = range_from_lsp(edit.range);
2088 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2089 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2090 if start != range.start.0 || end != range.end.0 {
2091 log::info!("completion out of expected range");
2092 None
2093 } else {
2094 Some((
2095 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2096 edit.new_text.clone(),
2097 ))
2098 }
2099 }
2100
2101 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2102 let range = range_from_lsp(edit.replace);
2103
2104 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2105 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2106 if start != range.start.0 || end != range.end.0 {
2107 log::info!("completion out of expected range");
2108 None
2109 } else {
2110 Some((
2111 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2112 edit.new_text.clone(),
2113 ))
2114 }
2115 }
2116 }
2117}
2118
2119#[async_trait(?Send)]
2120impl LspCommand for GetCodeActions {
2121 type Response = Vec<CodeAction>;
2122 type LspRequest = lsp::request::CodeActionRequest;
2123 type ProtoRequest = proto::GetCodeActions;
2124
2125 fn display_name(&self) -> &str {
2126 "Get code actions"
2127 }
2128
2129 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2130 match &capabilities.server_capabilities.code_action_provider {
2131 None => false,
2132 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2133 _ => {
2134 // If we do know that we want specific code actions AND we know that
2135 // the server only supports specific code actions, then we want to filter
2136 // down to the ones that are supported.
2137 if let Some((requested, supported)) = self
2138 .kinds
2139 .as_ref()
2140 .zip(Self::supported_code_action_kinds(capabilities))
2141 {
2142 let server_supported = supported.into_iter().collect::<HashSet<_>>();
2143 requested.iter().any(|kind| server_supported.contains(kind))
2144 } else {
2145 true
2146 }
2147 }
2148 }
2149 }
2150
2151 fn to_lsp(
2152 &self,
2153 path: &Path,
2154 buffer: &Buffer,
2155 language_server: &Arc<LanguageServer>,
2156 _: &App,
2157 ) -> Result<lsp::CodeActionParams> {
2158 let mut relevant_diagnostics = Vec::new();
2159 for entry in buffer
2160 .snapshot()
2161 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2162 {
2163 relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2164 }
2165
2166 let supported =
2167 Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2168
2169 let only = if let Some(requested) = &self.kinds {
2170 if let Some(supported_kinds) = supported {
2171 let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2172
2173 let filtered = requested
2174 .iter()
2175 .filter(|kind| server_supported.contains(kind))
2176 .cloned()
2177 .collect();
2178 Some(filtered)
2179 } else {
2180 Some(requested.clone())
2181 }
2182 } else {
2183 supported
2184 };
2185
2186 Ok(lsp::CodeActionParams {
2187 text_document: make_text_document_identifier(path)?,
2188 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2189 work_done_progress_params: Default::default(),
2190 partial_result_params: Default::default(),
2191 context: lsp::CodeActionContext {
2192 diagnostics: relevant_diagnostics,
2193 only,
2194 ..lsp::CodeActionContext::default()
2195 },
2196 })
2197 }
2198
2199 async fn response_from_lsp(
2200 self,
2201 actions: Option<lsp::CodeActionResponse>,
2202 lsp_store: Entity<LspStore>,
2203 _: Entity<Buffer>,
2204 server_id: LanguageServerId,
2205 cx: AsyncApp,
2206 ) -> Result<Vec<CodeAction>> {
2207 let requested_kinds_set = if let Some(kinds) = self.kinds {
2208 Some(kinds.into_iter().collect::<HashSet<_>>())
2209 } else {
2210 None
2211 };
2212
2213 let language_server = cx.update(|cx| {
2214 lsp_store
2215 .read(cx)
2216 .language_server_for_id(server_id)
2217 .with_context(|| {
2218 format!("Missing the language server that just returned a response {server_id}")
2219 })
2220 })??;
2221
2222 let server_capabilities = language_server.capabilities();
2223 let available_commands = server_capabilities
2224 .execute_command_provider
2225 .as_ref()
2226 .map(|options| options.commands.as_slice())
2227 .unwrap_or_default();
2228 Ok(actions
2229 .unwrap_or_default()
2230 .into_iter()
2231 .filter_map(|entry| {
2232 let lsp_action = match entry {
2233 lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2234 if let Some(command) = lsp_action.command.as_ref() {
2235 if !available_commands.contains(&command.command) {
2236 return None;
2237 }
2238 }
2239 LspAction::Action(Box::new(lsp_action))
2240 }
2241 lsp::CodeActionOrCommand::Command(command) => {
2242 if available_commands.contains(&command.command) {
2243 LspAction::Command(command)
2244 } else {
2245 return None;
2246 }
2247 }
2248 };
2249
2250 if let Some((requested_kinds, kind)) =
2251 requested_kinds_set.as_ref().zip(lsp_action.action_kind())
2252 {
2253 if !requested_kinds.contains(&kind) {
2254 return None;
2255 }
2256 }
2257
2258 Some(CodeAction {
2259 server_id,
2260 range: self.range.clone(),
2261 lsp_action,
2262 })
2263 })
2264 .collect())
2265 }
2266
2267 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2268 proto::GetCodeActions {
2269 project_id,
2270 buffer_id: buffer.remote_id().into(),
2271 start: Some(language::proto::serialize_anchor(&self.range.start)),
2272 end: Some(language::proto::serialize_anchor(&self.range.end)),
2273 version: serialize_version(&buffer.version()),
2274 }
2275 }
2276
2277 async fn from_proto(
2278 message: proto::GetCodeActions,
2279 _: Entity<LspStore>,
2280 buffer: Entity<Buffer>,
2281 mut cx: AsyncApp,
2282 ) -> Result<Self> {
2283 let start = message
2284 .start
2285 .and_then(language::proto::deserialize_anchor)
2286 .ok_or_else(|| anyhow!("invalid start"))?;
2287 let end = message
2288 .end
2289 .and_then(language::proto::deserialize_anchor)
2290 .ok_or_else(|| anyhow!("invalid end"))?;
2291 buffer
2292 .update(&mut cx, |buffer, _| {
2293 buffer.wait_for_version(deserialize_version(&message.version))
2294 })?
2295 .await?;
2296
2297 Ok(Self {
2298 range: start..end,
2299 kinds: None,
2300 })
2301 }
2302
2303 fn response_to_proto(
2304 code_actions: Vec<CodeAction>,
2305 _: &mut LspStore,
2306 _: PeerId,
2307 buffer_version: &clock::Global,
2308 _: &mut App,
2309 ) -> proto::GetCodeActionsResponse {
2310 proto::GetCodeActionsResponse {
2311 actions: code_actions
2312 .iter()
2313 .map(LspStore::serialize_code_action)
2314 .collect(),
2315 version: serialize_version(buffer_version),
2316 }
2317 }
2318
2319 async fn response_from_proto(
2320 self,
2321 message: proto::GetCodeActionsResponse,
2322 _: Entity<LspStore>,
2323 buffer: Entity<Buffer>,
2324 mut cx: AsyncApp,
2325 ) -> Result<Vec<CodeAction>> {
2326 buffer
2327 .update(&mut cx, |buffer, _| {
2328 buffer.wait_for_version(deserialize_version(&message.version))
2329 })?
2330 .await?;
2331 message
2332 .actions
2333 .into_iter()
2334 .map(LspStore::deserialize_code_action)
2335 .collect()
2336 }
2337
2338 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2339 BufferId::new(message.buffer_id)
2340 }
2341}
2342
2343impl GetCodeActions {
2344 fn supported_code_action_kinds(
2345 capabilities: AdapterServerCapabilities,
2346 ) -> Option<Vec<CodeActionKind>> {
2347 match capabilities.server_capabilities.code_action_provider {
2348 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2349 code_action_kinds: Some(supported_action_kinds),
2350 ..
2351 })) => Some(supported_action_kinds.clone()),
2352 _ => capabilities.code_action_kinds,
2353 }
2354 }
2355
2356 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2357 capabilities
2358 .code_action_provider
2359 .as_ref()
2360 .and_then(|options| match options {
2361 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2362 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2363 })
2364 .unwrap_or(false)
2365 }
2366}
2367
2368#[async_trait(?Send)]
2369impl LspCommand for OnTypeFormatting {
2370 type Response = Option<Transaction>;
2371 type LspRequest = lsp::request::OnTypeFormatting;
2372 type ProtoRequest = proto::OnTypeFormatting;
2373
2374 fn display_name(&self) -> &str {
2375 "Formatting on typing"
2376 }
2377
2378 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2379 let Some(on_type_formatting_options) = &capabilities
2380 .server_capabilities
2381 .document_on_type_formatting_provider
2382 else {
2383 return false;
2384 };
2385 on_type_formatting_options
2386 .first_trigger_character
2387 .contains(&self.trigger)
2388 || on_type_formatting_options
2389 .more_trigger_character
2390 .iter()
2391 .flatten()
2392 .any(|chars| chars.contains(&self.trigger))
2393 }
2394
2395 fn to_lsp(
2396 &self,
2397 path: &Path,
2398 _: &Buffer,
2399 _: &Arc<LanguageServer>,
2400 _: &App,
2401 ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2402 Ok(lsp::DocumentOnTypeFormattingParams {
2403 text_document_position: make_lsp_text_document_position(path, self.position)?,
2404 ch: self.trigger.clone(),
2405 options: self.options.clone(),
2406 })
2407 }
2408
2409 async fn response_from_lsp(
2410 self,
2411 message: Option<Vec<lsp::TextEdit>>,
2412 lsp_store: Entity<LspStore>,
2413 buffer: Entity<Buffer>,
2414 server_id: LanguageServerId,
2415 mut cx: AsyncApp,
2416 ) -> Result<Option<Transaction>> {
2417 if let Some(edits) = message {
2418 let (lsp_adapter, lsp_server) =
2419 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2420 LocalLspStore::deserialize_text_edits(
2421 lsp_store,
2422 buffer,
2423 edits,
2424 self.push_to_history,
2425 lsp_adapter,
2426 lsp_server,
2427 &mut cx,
2428 )
2429 .await
2430 } else {
2431 Ok(None)
2432 }
2433 }
2434
2435 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2436 proto::OnTypeFormatting {
2437 project_id,
2438 buffer_id: buffer.remote_id().into(),
2439 position: Some(language::proto::serialize_anchor(
2440 &buffer.anchor_before(self.position),
2441 )),
2442 trigger: self.trigger.clone(),
2443 version: serialize_version(&buffer.version()),
2444 }
2445 }
2446
2447 async fn from_proto(
2448 message: proto::OnTypeFormatting,
2449 _: Entity<LspStore>,
2450 buffer: Entity<Buffer>,
2451 mut cx: AsyncApp,
2452 ) -> Result<Self> {
2453 let position = message
2454 .position
2455 .and_then(deserialize_anchor)
2456 .ok_or_else(|| anyhow!("invalid position"))?;
2457 buffer
2458 .update(&mut cx, |buffer, _| {
2459 buffer.wait_for_version(deserialize_version(&message.version))
2460 })?
2461 .await?;
2462
2463 let options = buffer.update(&mut cx, |buffer, cx| {
2464 lsp_formatting_options(
2465 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2466 )
2467 })?;
2468
2469 Ok(Self {
2470 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2471 trigger: message.trigger.clone(),
2472 options,
2473 push_to_history: false,
2474 })
2475 }
2476
2477 fn response_to_proto(
2478 response: Option<Transaction>,
2479 _: &mut LspStore,
2480 _: PeerId,
2481 _: &clock::Global,
2482 _: &mut App,
2483 ) -> proto::OnTypeFormattingResponse {
2484 proto::OnTypeFormattingResponse {
2485 transaction: response
2486 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2487 }
2488 }
2489
2490 async fn response_from_proto(
2491 self,
2492 message: proto::OnTypeFormattingResponse,
2493 _: Entity<LspStore>,
2494 _: Entity<Buffer>,
2495 _: AsyncApp,
2496 ) -> Result<Option<Transaction>> {
2497 let Some(transaction) = message.transaction else {
2498 return Ok(None);
2499 };
2500 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2501 }
2502
2503 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2504 BufferId::new(message.buffer_id)
2505 }
2506}
2507
2508impl InlayHints {
2509 pub async fn lsp_to_project_hint(
2510 lsp_hint: lsp::InlayHint,
2511 buffer_handle: &Entity<Buffer>,
2512 server_id: LanguageServerId,
2513 resolve_state: ResolveState,
2514 force_no_type_left_padding: bool,
2515 cx: &mut AsyncApp,
2516 ) -> anyhow::Result<InlayHint> {
2517 let kind = lsp_hint.kind.and_then(|kind| match kind {
2518 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2519 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2520 _ => None,
2521 });
2522
2523 let position = buffer_handle.update(cx, |buffer, _| {
2524 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2525 if kind == Some(InlayHintKind::Parameter) {
2526 buffer.anchor_before(position)
2527 } else {
2528 buffer.anchor_after(position)
2529 }
2530 })?;
2531 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2532 .await
2533 .context("lsp to project inlay hint conversion")?;
2534 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2535 false
2536 } else {
2537 lsp_hint.padding_left.unwrap_or(false)
2538 };
2539
2540 Ok(InlayHint {
2541 position,
2542 padding_left,
2543 padding_right: lsp_hint.padding_right.unwrap_or(false),
2544 label,
2545 kind,
2546 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2547 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2548 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2549 InlayHintTooltip::MarkupContent(MarkupContent {
2550 kind: match markup_content.kind {
2551 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2552 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2553 },
2554 value: markup_content.value,
2555 })
2556 }
2557 }),
2558 resolve_state,
2559 })
2560 }
2561
2562 async fn lsp_inlay_label_to_project(
2563 lsp_label: lsp::InlayHintLabel,
2564 server_id: LanguageServerId,
2565 ) -> anyhow::Result<InlayHintLabel> {
2566 let label = match lsp_label {
2567 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2568 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2569 let mut parts = Vec::with_capacity(lsp_parts.len());
2570 for lsp_part in lsp_parts {
2571 parts.push(InlayHintLabelPart {
2572 value: lsp_part.value,
2573 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2574 lsp::InlayHintLabelPartTooltip::String(s) => {
2575 InlayHintLabelPartTooltip::String(s)
2576 }
2577 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2578 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2579 kind: match markup_content.kind {
2580 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2581 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2582 },
2583 value: markup_content.value,
2584 })
2585 }
2586 }),
2587 location: Some(server_id).zip(lsp_part.location),
2588 });
2589 }
2590 InlayHintLabel::LabelParts(parts)
2591 }
2592 };
2593
2594 Ok(label)
2595 }
2596
2597 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2598 let (state, lsp_resolve_state) = match response_hint.resolve_state {
2599 ResolveState::Resolved => (0, None),
2600 ResolveState::CanResolve(server_id, resolve_data) => (
2601 1,
2602 Some(proto::resolve_state::LspResolveState {
2603 server_id: server_id.0 as u64,
2604 value: resolve_data.map(|json_data| {
2605 serde_json::to_string(&json_data)
2606 .expect("failed to serialize resolve json data")
2607 }),
2608 }),
2609 ),
2610 ResolveState::Resolving => (2, None),
2611 };
2612 let resolve_state = Some(proto::ResolveState {
2613 state,
2614 lsp_resolve_state,
2615 });
2616 proto::InlayHint {
2617 position: Some(language::proto::serialize_anchor(&response_hint.position)),
2618 padding_left: response_hint.padding_left,
2619 padding_right: response_hint.padding_right,
2620 label: Some(proto::InlayHintLabel {
2621 label: Some(match response_hint.label {
2622 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2623 InlayHintLabel::LabelParts(label_parts) => {
2624 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2625 parts: label_parts.into_iter().map(|label_part| {
2626 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2627 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 });
2628 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 });
2629 proto::InlayHintLabelPart {
2630 value: label_part.value,
2631 tooltip: label_part.tooltip.map(|tooltip| {
2632 let proto_tooltip = match tooltip {
2633 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2634 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2635 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2636 value: markup_content.value,
2637 }),
2638 };
2639 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2640 }),
2641 location_url,
2642 location_range_start,
2643 location_range_end,
2644 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2645 }}).collect()
2646 })
2647 }
2648 }),
2649 }),
2650 kind: response_hint.kind.map(|kind| kind.name().to_string()),
2651 tooltip: response_hint.tooltip.map(|response_tooltip| {
2652 let proto_tooltip = match response_tooltip {
2653 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2654 InlayHintTooltip::MarkupContent(markup_content) => {
2655 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2656 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2657 value: markup_content.value,
2658 })
2659 }
2660 };
2661 proto::InlayHintTooltip {
2662 content: Some(proto_tooltip),
2663 }
2664 }),
2665 resolve_state,
2666 }
2667 }
2668
2669 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2670 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2671 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2672 });
2673 let resolve_state_data = resolve_state
2674 .lsp_resolve_state.as_ref()
2675 .map(|lsp_resolve_state| {
2676 let value = lsp_resolve_state.value.as_deref().map(|value| {
2677 serde_json::from_str::<Option<lsp::LSPAny>>(value)
2678 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2679 }).transpose()?.flatten();
2680 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2681 })
2682 .transpose()?;
2683 let resolve_state = match resolve_state.state {
2684 0 => ResolveState::Resolved,
2685 1 => {
2686 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2687 format!(
2688 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2689 )
2690 })?;
2691 ResolveState::CanResolve(server_id, lsp_resolve_state)
2692 }
2693 2 => ResolveState::Resolving,
2694 invalid => {
2695 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2696 }
2697 };
2698 Ok(InlayHint {
2699 position: message_hint
2700 .position
2701 .and_then(language::proto::deserialize_anchor)
2702 .context("invalid position")?,
2703 label: match message_hint
2704 .label
2705 .and_then(|label| label.label)
2706 .context("missing label")?
2707 {
2708 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2709 proto::inlay_hint_label::Label::LabelParts(parts) => {
2710 let mut label_parts = Vec::new();
2711 for part in parts.parts {
2712 label_parts.push(InlayHintLabelPart {
2713 value: part.value,
2714 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2715 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2716 InlayHintLabelPartTooltip::String(s)
2717 }
2718 Some(
2719 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2720 markup_content,
2721 ),
2722 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2723 kind: if markup_content.is_markdown {
2724 HoverBlockKind::Markdown
2725 } else {
2726 HoverBlockKind::PlainText
2727 },
2728 value: markup_content.value,
2729 }),
2730 None => InlayHintLabelPartTooltip::String(String::new()),
2731 }),
2732 location: {
2733 match part
2734 .location_url
2735 .zip(
2736 part.location_range_start.and_then(|start| {
2737 Some(start..part.location_range_end?)
2738 }),
2739 )
2740 .zip(part.language_server_id)
2741 {
2742 Some(((uri, range), server_id)) => Some((
2743 LanguageServerId(server_id as usize),
2744 lsp::Location {
2745 uri: lsp::Url::parse(&uri)
2746 .context("invalid uri in hint part {part:?}")?,
2747 range: lsp::Range::new(
2748 point_to_lsp(PointUtf16::new(
2749 range.start.row,
2750 range.start.column,
2751 )),
2752 point_to_lsp(PointUtf16::new(
2753 range.end.row,
2754 range.end.column,
2755 )),
2756 ),
2757 },
2758 )),
2759 None => None,
2760 }
2761 },
2762 });
2763 }
2764
2765 InlayHintLabel::LabelParts(label_parts)
2766 }
2767 },
2768 padding_left: message_hint.padding_left,
2769 padding_right: message_hint.padding_right,
2770 kind: message_hint
2771 .kind
2772 .as_deref()
2773 .and_then(InlayHintKind::from_name),
2774 tooltip: message_hint.tooltip.and_then(|tooltip| {
2775 Some(match tooltip.content? {
2776 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2777 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2778 InlayHintTooltip::MarkupContent(MarkupContent {
2779 kind: if markup_content.is_markdown {
2780 HoverBlockKind::Markdown
2781 } else {
2782 HoverBlockKind::PlainText
2783 },
2784 value: markup_content.value,
2785 })
2786 }
2787 })
2788 }),
2789 resolve_state,
2790 })
2791 }
2792
2793 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2794 lsp::InlayHint {
2795 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2796 kind: hint.kind.map(|kind| match kind {
2797 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2798 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2799 }),
2800 text_edits: None,
2801 tooltip: hint.tooltip.and_then(|tooltip| {
2802 Some(match tooltip {
2803 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2804 InlayHintTooltip::MarkupContent(markup_content) => {
2805 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2806 kind: match markup_content.kind {
2807 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2808 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2809 HoverBlockKind::Code { .. } => return None,
2810 },
2811 value: markup_content.value,
2812 })
2813 }
2814 })
2815 }),
2816 label: match hint.label {
2817 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2818 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2819 label_parts
2820 .into_iter()
2821 .map(|part| lsp::InlayHintLabelPart {
2822 value: part.value,
2823 tooltip: part.tooltip.and_then(|tooltip| {
2824 Some(match tooltip {
2825 InlayHintLabelPartTooltip::String(s) => {
2826 lsp::InlayHintLabelPartTooltip::String(s)
2827 }
2828 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2829 lsp::InlayHintLabelPartTooltip::MarkupContent(
2830 lsp::MarkupContent {
2831 kind: match markup_content.kind {
2832 HoverBlockKind::PlainText => {
2833 lsp::MarkupKind::PlainText
2834 }
2835 HoverBlockKind::Markdown => {
2836 lsp::MarkupKind::Markdown
2837 }
2838 HoverBlockKind::Code { .. } => return None,
2839 },
2840 value: markup_content.value,
2841 },
2842 )
2843 }
2844 })
2845 }),
2846 location: part.location.map(|(_, location)| location),
2847 command: None,
2848 })
2849 .collect(),
2850 ),
2851 },
2852 padding_left: Some(hint.padding_left),
2853 padding_right: Some(hint.padding_right),
2854 data: match hint.resolve_state {
2855 ResolveState::CanResolve(_, data) => data,
2856 ResolveState::Resolving | ResolveState::Resolved => None,
2857 },
2858 }
2859 }
2860
2861 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2862 capabilities
2863 .inlay_hint_provider
2864 .as_ref()
2865 .and_then(|options| match options {
2866 OneOf::Left(_is_supported) => None,
2867 OneOf::Right(capabilities) => match capabilities {
2868 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2869 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2870 o.inlay_hint_options.resolve_provider
2871 }
2872 },
2873 })
2874 .unwrap_or(false)
2875 }
2876}
2877
2878#[async_trait(?Send)]
2879impl LspCommand for InlayHints {
2880 type Response = Vec<InlayHint>;
2881 type LspRequest = lsp::InlayHintRequest;
2882 type ProtoRequest = proto::InlayHints;
2883
2884 fn display_name(&self) -> &str {
2885 "Inlay hints"
2886 }
2887
2888 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2889 let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
2890 else {
2891 return false;
2892 };
2893 match inlay_hint_provider {
2894 lsp::OneOf::Left(enabled) => *enabled,
2895 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2896 lsp::InlayHintServerCapabilities::Options(_) => true,
2897 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2898 },
2899 }
2900 }
2901
2902 fn to_lsp(
2903 &self,
2904 path: &Path,
2905 buffer: &Buffer,
2906 _: &Arc<LanguageServer>,
2907 _: &App,
2908 ) -> Result<lsp::InlayHintParams> {
2909 Ok(lsp::InlayHintParams {
2910 text_document: lsp::TextDocumentIdentifier {
2911 uri: file_path_to_lsp_url(path)?,
2912 },
2913 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2914 work_done_progress_params: Default::default(),
2915 })
2916 }
2917
2918 async fn response_from_lsp(
2919 self,
2920 message: Option<Vec<lsp::InlayHint>>,
2921 lsp_store: Entity<LspStore>,
2922 buffer: Entity<Buffer>,
2923 server_id: LanguageServerId,
2924 mut cx: AsyncApp,
2925 ) -> anyhow::Result<Vec<InlayHint>> {
2926 let (lsp_adapter, lsp_server) =
2927 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2928 // `typescript-language-server` adds padding to the left for type hints, turning
2929 // `const foo: boolean` into `const foo : boolean` which looks odd.
2930 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2931 //
2932 // We could trim the whole string, but being pessimistic on par with the situation above,
2933 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2934 // Hence let's use a heuristic first to handle the most awkward case and look for more.
2935 let force_no_type_left_padding =
2936 lsp_adapter.name.0.as_ref() == "typescript-language-server";
2937
2938 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2939 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2940 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2941 } else {
2942 ResolveState::Resolved
2943 };
2944
2945 let buffer = buffer.clone();
2946 cx.spawn(move |mut cx| async move {
2947 InlayHints::lsp_to_project_hint(
2948 lsp_hint,
2949 &buffer,
2950 server_id,
2951 resolve_state,
2952 force_no_type_left_padding,
2953 &mut cx,
2954 )
2955 .await
2956 })
2957 });
2958 future::join_all(hints)
2959 .await
2960 .into_iter()
2961 .collect::<anyhow::Result<_>>()
2962 .context("lsp to project inlay hints conversion")
2963 }
2964
2965 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2966 proto::InlayHints {
2967 project_id,
2968 buffer_id: buffer.remote_id().into(),
2969 start: Some(language::proto::serialize_anchor(&self.range.start)),
2970 end: Some(language::proto::serialize_anchor(&self.range.end)),
2971 version: serialize_version(&buffer.version()),
2972 }
2973 }
2974
2975 async fn from_proto(
2976 message: proto::InlayHints,
2977 _: Entity<LspStore>,
2978 buffer: Entity<Buffer>,
2979 mut cx: AsyncApp,
2980 ) -> Result<Self> {
2981 let start = message
2982 .start
2983 .and_then(language::proto::deserialize_anchor)
2984 .context("invalid start")?;
2985 let end = message
2986 .end
2987 .and_then(language::proto::deserialize_anchor)
2988 .context("invalid end")?;
2989 buffer
2990 .update(&mut cx, |buffer, _| {
2991 buffer.wait_for_version(deserialize_version(&message.version))
2992 })?
2993 .await?;
2994
2995 Ok(Self { range: start..end })
2996 }
2997
2998 fn response_to_proto(
2999 response: Vec<InlayHint>,
3000 _: &mut LspStore,
3001 _: PeerId,
3002 buffer_version: &clock::Global,
3003 _: &mut App,
3004 ) -> proto::InlayHintsResponse {
3005 proto::InlayHintsResponse {
3006 hints: response
3007 .into_iter()
3008 .map(InlayHints::project_to_proto_hint)
3009 .collect(),
3010 version: serialize_version(buffer_version),
3011 }
3012 }
3013
3014 async fn response_from_proto(
3015 self,
3016 message: proto::InlayHintsResponse,
3017 _: Entity<LspStore>,
3018 buffer: Entity<Buffer>,
3019 mut cx: AsyncApp,
3020 ) -> anyhow::Result<Vec<InlayHint>> {
3021 buffer
3022 .update(&mut cx, |buffer, _| {
3023 buffer.wait_for_version(deserialize_version(&message.version))
3024 })?
3025 .await?;
3026
3027 let mut hints = Vec::new();
3028 for message_hint in message.hints {
3029 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3030 }
3031
3032 Ok(hints)
3033 }
3034
3035 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3036 BufferId::new(message.buffer_id)
3037 }
3038}
3039
3040#[async_trait(?Send)]
3041impl LspCommand for LinkedEditingRange {
3042 type Response = Vec<Range<Anchor>>;
3043 type LspRequest = lsp::request::LinkedEditingRange;
3044 type ProtoRequest = proto::LinkedEditingRange;
3045
3046 fn display_name(&self) -> &str {
3047 "Linked editing range"
3048 }
3049
3050 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3051 let Some(linked_editing_options) = &capabilities
3052 .server_capabilities
3053 .linked_editing_range_provider
3054 else {
3055 return false;
3056 };
3057 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3058 return false;
3059 }
3060 true
3061 }
3062
3063 fn to_lsp(
3064 &self,
3065 path: &Path,
3066 buffer: &Buffer,
3067 _server: &Arc<LanguageServer>,
3068 _: &App,
3069 ) -> Result<lsp::LinkedEditingRangeParams> {
3070 let position = self.position.to_point_utf16(&buffer.snapshot());
3071 Ok(lsp::LinkedEditingRangeParams {
3072 text_document_position_params: make_lsp_text_document_position(path, position)?,
3073 work_done_progress_params: Default::default(),
3074 })
3075 }
3076
3077 async fn response_from_lsp(
3078 self,
3079 message: Option<lsp::LinkedEditingRanges>,
3080 _: Entity<LspStore>,
3081 buffer: Entity<Buffer>,
3082 _server_id: LanguageServerId,
3083 cx: AsyncApp,
3084 ) -> Result<Vec<Range<Anchor>>> {
3085 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3086 ranges.sort_by_key(|range| range.start);
3087
3088 buffer.read_with(&cx, |buffer, _| {
3089 ranges
3090 .into_iter()
3091 .map(|range| {
3092 let start =
3093 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3094 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3095 buffer.anchor_before(start)..buffer.anchor_after(end)
3096 })
3097 .collect()
3098 })
3099 } else {
3100 Ok(vec![])
3101 }
3102 }
3103
3104 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3105 proto::LinkedEditingRange {
3106 project_id,
3107 buffer_id: buffer.remote_id().to_proto(),
3108 position: Some(serialize_anchor(&self.position)),
3109 version: serialize_version(&buffer.version()),
3110 }
3111 }
3112
3113 async fn from_proto(
3114 message: proto::LinkedEditingRange,
3115 _: Entity<LspStore>,
3116 buffer: Entity<Buffer>,
3117 mut cx: AsyncApp,
3118 ) -> Result<Self> {
3119 let position = message
3120 .position
3121 .ok_or_else(|| anyhow!("invalid position"))?;
3122 buffer
3123 .update(&mut cx, |buffer, _| {
3124 buffer.wait_for_version(deserialize_version(&message.version))
3125 })?
3126 .await?;
3127 let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3128 buffer
3129 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3130 .await?;
3131 Ok(Self { position })
3132 }
3133
3134 fn response_to_proto(
3135 response: Vec<Range<Anchor>>,
3136 _: &mut LspStore,
3137 _: PeerId,
3138 buffer_version: &clock::Global,
3139 _: &mut App,
3140 ) -> proto::LinkedEditingRangeResponse {
3141 proto::LinkedEditingRangeResponse {
3142 items: response
3143 .into_iter()
3144 .map(|range| proto::AnchorRange {
3145 start: Some(serialize_anchor(&range.start)),
3146 end: Some(serialize_anchor(&range.end)),
3147 })
3148 .collect(),
3149 version: serialize_version(buffer_version),
3150 }
3151 }
3152
3153 async fn response_from_proto(
3154 self,
3155 message: proto::LinkedEditingRangeResponse,
3156 _: Entity<LspStore>,
3157 buffer: Entity<Buffer>,
3158 mut cx: AsyncApp,
3159 ) -> Result<Vec<Range<Anchor>>> {
3160 buffer
3161 .update(&mut cx, |buffer, _| {
3162 buffer.wait_for_version(deserialize_version(&message.version))
3163 })?
3164 .await?;
3165 let items: Vec<Range<Anchor>> = message
3166 .items
3167 .into_iter()
3168 .filter_map(|range| {
3169 let start = deserialize_anchor(range.start?)?;
3170 let end = deserialize_anchor(range.end?)?;
3171 Some(start..end)
3172 })
3173 .collect();
3174 for range in &items {
3175 buffer
3176 .update(&mut cx, |buffer, _| {
3177 buffer.wait_for_anchors([range.start, range.end])
3178 })?
3179 .await?;
3180 }
3181 Ok(items)
3182 }
3183
3184 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3185 BufferId::new(message.buffer_id)
3186 }
3187}