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