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 lsp_store
946 .language_server_for_local_buffer(buffer.read(cx), server_id, cx)
947 .map(|(adapter, server)| (adapter.clone(), server.clone()))
948 })?
949 .ok_or_else(|| anyhow!("no language server found for buffer"))
950}
951
952async fn location_links_from_proto(
953 proto_links: Vec<proto::LocationLink>,
954 lsp_store: Entity<LspStore>,
955 mut cx: AsyncApp,
956) -> Result<Vec<LocationLink>> {
957 let mut links = Vec::new();
958
959 for link in proto_links {
960 let origin = match link.origin {
961 Some(origin) => {
962 let buffer_id = BufferId::new(origin.buffer_id)?;
963 let buffer = lsp_store
964 .update(&mut cx, |lsp_store, cx| {
965 lsp_store.wait_for_remote_buffer(buffer_id, cx)
966 })?
967 .await?;
968 let start = origin
969 .start
970 .and_then(deserialize_anchor)
971 .ok_or_else(|| anyhow!("missing origin start"))?;
972 let end = origin
973 .end
974 .and_then(deserialize_anchor)
975 .ok_or_else(|| anyhow!("missing origin end"))?;
976 buffer
977 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
978 .await?;
979 Some(Location {
980 buffer,
981 range: start..end,
982 })
983 }
984 None => None,
985 };
986
987 let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
988 let buffer_id = BufferId::new(target.buffer_id)?;
989 let buffer = lsp_store
990 .update(&mut cx, |lsp_store, cx| {
991 lsp_store.wait_for_remote_buffer(buffer_id, cx)
992 })?
993 .await?;
994 let start = target
995 .start
996 .and_then(deserialize_anchor)
997 .ok_or_else(|| anyhow!("missing target start"))?;
998 let end = target
999 .end
1000 .and_then(deserialize_anchor)
1001 .ok_or_else(|| anyhow!("missing target end"))?;
1002 buffer
1003 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1004 .await?;
1005 let target = Location {
1006 buffer,
1007 range: start..end,
1008 };
1009
1010 links.push(LocationLink { origin, target })
1011 }
1012
1013 Ok(links)
1014}
1015
1016async fn location_links_from_lsp(
1017 message: Option<lsp::GotoDefinitionResponse>,
1018 lsp_store: Entity<LspStore>,
1019 buffer: Entity<Buffer>,
1020 server_id: LanguageServerId,
1021 mut cx: AsyncApp,
1022) -> Result<Vec<LocationLink>> {
1023 let message = match message {
1024 Some(message) => message,
1025 None => return Ok(Vec::new()),
1026 };
1027
1028 let mut unresolved_links = Vec::new();
1029 match message {
1030 lsp::GotoDefinitionResponse::Scalar(loc) => {
1031 unresolved_links.push((None, loc.uri, loc.range));
1032 }
1033
1034 lsp::GotoDefinitionResponse::Array(locs) => {
1035 unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
1036 }
1037
1038 lsp::GotoDefinitionResponse::Link(links) => {
1039 unresolved_links.extend(links.into_iter().map(|l| {
1040 (
1041 l.origin_selection_range,
1042 l.target_uri,
1043 l.target_selection_range,
1044 )
1045 }));
1046 }
1047 }
1048
1049 let (lsp_adapter, language_server) =
1050 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1051 let mut definitions = Vec::new();
1052 for (origin_range, target_uri, target_range) in unresolved_links {
1053 let target_buffer_handle = lsp_store
1054 .update(&mut cx, |this, cx| {
1055 this.open_local_buffer_via_lsp(
1056 target_uri,
1057 language_server.server_id(),
1058 lsp_adapter.name.clone(),
1059 cx,
1060 )
1061 })?
1062 .await?;
1063
1064 cx.update(|cx| {
1065 let origin_location = origin_range.map(|origin_range| {
1066 let origin_buffer = buffer.read(cx);
1067 let origin_start =
1068 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1069 let origin_end =
1070 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1071 Location {
1072 buffer: buffer.clone(),
1073 range: origin_buffer.anchor_after(origin_start)
1074 ..origin_buffer.anchor_before(origin_end),
1075 }
1076 });
1077
1078 let target_buffer = target_buffer_handle.read(cx);
1079 let target_start =
1080 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1081 let target_end =
1082 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1083 let target_location = Location {
1084 buffer: target_buffer_handle,
1085 range: target_buffer.anchor_after(target_start)
1086 ..target_buffer.anchor_before(target_end),
1087 };
1088
1089 definitions.push(LocationLink {
1090 origin: origin_location,
1091 target: target_location,
1092 })
1093 })?;
1094 }
1095 Ok(definitions)
1096}
1097
1098fn location_links_to_proto(
1099 links: Vec<LocationLink>,
1100 lsp_store: &mut LspStore,
1101 peer_id: PeerId,
1102 cx: &mut App,
1103) -> Vec<proto::LocationLink> {
1104 links
1105 .into_iter()
1106 .map(|definition| {
1107 let origin = definition.origin.map(|origin| {
1108 lsp_store
1109 .buffer_store()
1110 .update(cx, |buffer_store, cx| {
1111 buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1112 })
1113 .detach_and_log_err(cx);
1114
1115 let buffer_id = origin.buffer.read(cx).remote_id().into();
1116 proto::Location {
1117 start: Some(serialize_anchor(&origin.range.start)),
1118 end: Some(serialize_anchor(&origin.range.end)),
1119 buffer_id,
1120 }
1121 });
1122
1123 lsp_store
1124 .buffer_store()
1125 .update(cx, |buffer_store, cx| {
1126 buffer_store.create_buffer_for_peer(&definition.target.buffer, peer_id, cx)
1127 })
1128 .detach_and_log_err(cx);
1129
1130 let buffer_id = definition.target.buffer.read(cx).remote_id().into();
1131 let target = proto::Location {
1132 start: Some(serialize_anchor(&definition.target.range.start)),
1133 end: Some(serialize_anchor(&definition.target.range.end)),
1134 buffer_id,
1135 };
1136
1137 proto::LocationLink {
1138 origin,
1139 target: Some(target),
1140 }
1141 })
1142 .collect()
1143}
1144
1145#[async_trait(?Send)]
1146impl LspCommand for GetReferences {
1147 type Response = Vec<Location>;
1148 type LspRequest = lsp::request::References;
1149 type ProtoRequest = proto::GetReferences;
1150
1151 fn display_name(&self) -> &str {
1152 "Find all references"
1153 }
1154
1155 fn status(&self) -> Option<String> {
1156 Some("Finding references...".to_owned())
1157 }
1158
1159 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1160 match &capabilities.server_capabilities.references_provider {
1161 Some(OneOf::Left(has_support)) => *has_support,
1162 Some(OneOf::Right(_)) => true,
1163 None => false,
1164 }
1165 }
1166
1167 fn to_lsp(
1168 &self,
1169 path: &Path,
1170 _: &Buffer,
1171 _: &Arc<LanguageServer>,
1172 _: &App,
1173 ) -> Result<lsp::ReferenceParams> {
1174 Ok(lsp::ReferenceParams {
1175 text_document_position: make_lsp_text_document_position(path, self.position)?,
1176 work_done_progress_params: Default::default(),
1177 partial_result_params: Default::default(),
1178 context: lsp::ReferenceContext {
1179 include_declaration: true,
1180 },
1181 })
1182 }
1183
1184 async fn response_from_lsp(
1185 self,
1186 locations: Option<Vec<lsp::Location>>,
1187 lsp_store: Entity<LspStore>,
1188 buffer: Entity<Buffer>,
1189 server_id: LanguageServerId,
1190 mut cx: AsyncApp,
1191 ) -> Result<Vec<Location>> {
1192 let mut references = Vec::new();
1193 let (lsp_adapter, language_server) =
1194 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1195
1196 if let Some(locations) = locations {
1197 for lsp_location in locations {
1198 let target_buffer_handle = lsp_store
1199 .update(&mut cx, |lsp_store, cx| {
1200 lsp_store.open_local_buffer_via_lsp(
1201 lsp_location.uri,
1202 language_server.server_id(),
1203 lsp_adapter.name.clone(),
1204 cx,
1205 )
1206 })?
1207 .await?;
1208
1209 target_buffer_handle
1210 .clone()
1211 .update(&mut cx, |target_buffer, _| {
1212 let target_start = target_buffer
1213 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1214 let target_end = target_buffer
1215 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1216 references.push(Location {
1217 buffer: target_buffer_handle,
1218 range: target_buffer.anchor_after(target_start)
1219 ..target_buffer.anchor_before(target_end),
1220 });
1221 })?;
1222 }
1223 }
1224
1225 Ok(references)
1226 }
1227
1228 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1229 proto::GetReferences {
1230 project_id,
1231 buffer_id: buffer.remote_id().into(),
1232 position: Some(language::proto::serialize_anchor(
1233 &buffer.anchor_before(self.position),
1234 )),
1235 version: serialize_version(&buffer.version()),
1236 }
1237 }
1238
1239 async fn from_proto(
1240 message: proto::GetReferences,
1241 _: Entity<LspStore>,
1242 buffer: Entity<Buffer>,
1243 mut cx: AsyncApp,
1244 ) -> Result<Self> {
1245 let position = message
1246 .position
1247 .and_then(deserialize_anchor)
1248 .ok_or_else(|| anyhow!("invalid position"))?;
1249 buffer
1250 .update(&mut cx, |buffer, _| {
1251 buffer.wait_for_version(deserialize_version(&message.version))
1252 })?
1253 .await?;
1254 Ok(Self {
1255 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1256 })
1257 }
1258
1259 fn response_to_proto(
1260 response: Vec<Location>,
1261 lsp_store: &mut LspStore,
1262 peer_id: PeerId,
1263 _: &clock::Global,
1264 cx: &mut App,
1265 ) -> proto::GetReferencesResponse {
1266 let locations = response
1267 .into_iter()
1268 .map(|definition| {
1269 lsp_store
1270 .buffer_store()
1271 .update(cx, |buffer_store, cx| {
1272 buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1273 })
1274 .detach_and_log_err(cx);
1275 let buffer_id = definition.buffer.read(cx).remote_id();
1276 proto::Location {
1277 start: Some(serialize_anchor(&definition.range.start)),
1278 end: Some(serialize_anchor(&definition.range.end)),
1279 buffer_id: buffer_id.into(),
1280 }
1281 })
1282 .collect();
1283 proto::GetReferencesResponse { locations }
1284 }
1285
1286 async fn response_from_proto(
1287 self,
1288 message: proto::GetReferencesResponse,
1289 project: Entity<LspStore>,
1290 _: Entity<Buffer>,
1291 mut cx: AsyncApp,
1292 ) -> Result<Vec<Location>> {
1293 let mut locations = Vec::new();
1294 for location in message.locations {
1295 let buffer_id = BufferId::new(location.buffer_id)?;
1296 let target_buffer = project
1297 .update(&mut cx, |this, cx| {
1298 this.wait_for_remote_buffer(buffer_id, cx)
1299 })?
1300 .await?;
1301 let start = location
1302 .start
1303 .and_then(deserialize_anchor)
1304 .ok_or_else(|| anyhow!("missing target start"))?;
1305 let end = location
1306 .end
1307 .and_then(deserialize_anchor)
1308 .ok_or_else(|| anyhow!("missing target end"))?;
1309 target_buffer
1310 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1311 .await?;
1312 locations.push(Location {
1313 buffer: target_buffer,
1314 range: start..end,
1315 })
1316 }
1317 Ok(locations)
1318 }
1319
1320 fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1321 BufferId::new(message.buffer_id)
1322 }
1323}
1324
1325#[async_trait(?Send)]
1326impl LspCommand for GetDocumentHighlights {
1327 type Response = Vec<DocumentHighlight>;
1328 type LspRequest = lsp::request::DocumentHighlightRequest;
1329 type ProtoRequest = proto::GetDocumentHighlights;
1330
1331 fn display_name(&self) -> &str {
1332 "Get document highlights"
1333 }
1334
1335 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1336 capabilities
1337 .server_capabilities
1338 .document_highlight_provider
1339 .is_some()
1340 }
1341
1342 fn to_lsp(
1343 &self,
1344 path: &Path,
1345 _: &Buffer,
1346 _: &Arc<LanguageServer>,
1347 _: &App,
1348 ) -> Result<lsp::DocumentHighlightParams> {
1349 Ok(lsp::DocumentHighlightParams {
1350 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1351 work_done_progress_params: Default::default(),
1352 partial_result_params: Default::default(),
1353 })
1354 }
1355
1356 async fn response_from_lsp(
1357 self,
1358 lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1359 _: Entity<LspStore>,
1360 buffer: Entity<Buffer>,
1361 _: LanguageServerId,
1362 mut cx: AsyncApp,
1363 ) -> Result<Vec<DocumentHighlight>> {
1364 buffer.update(&mut cx, |buffer, _| {
1365 let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1366 lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1367 lsp_highlights
1368 .into_iter()
1369 .map(|lsp_highlight| {
1370 let start = buffer
1371 .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1372 let end = buffer
1373 .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1374 DocumentHighlight {
1375 range: buffer.anchor_after(start)..buffer.anchor_before(end),
1376 kind: lsp_highlight
1377 .kind
1378 .unwrap_or(lsp::DocumentHighlightKind::READ),
1379 }
1380 })
1381 .collect()
1382 })
1383 }
1384
1385 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1386 proto::GetDocumentHighlights {
1387 project_id,
1388 buffer_id: buffer.remote_id().into(),
1389 position: Some(language::proto::serialize_anchor(
1390 &buffer.anchor_before(self.position),
1391 )),
1392 version: serialize_version(&buffer.version()),
1393 }
1394 }
1395
1396 async fn from_proto(
1397 message: proto::GetDocumentHighlights,
1398 _: Entity<LspStore>,
1399 buffer: Entity<Buffer>,
1400 mut cx: AsyncApp,
1401 ) -> Result<Self> {
1402 let position = message
1403 .position
1404 .and_then(deserialize_anchor)
1405 .ok_or_else(|| anyhow!("invalid position"))?;
1406 buffer
1407 .update(&mut cx, |buffer, _| {
1408 buffer.wait_for_version(deserialize_version(&message.version))
1409 })?
1410 .await?;
1411 Ok(Self {
1412 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1413 })
1414 }
1415
1416 fn response_to_proto(
1417 response: Vec<DocumentHighlight>,
1418 _: &mut LspStore,
1419 _: PeerId,
1420 _: &clock::Global,
1421 _: &mut App,
1422 ) -> proto::GetDocumentHighlightsResponse {
1423 let highlights = response
1424 .into_iter()
1425 .map(|highlight| proto::DocumentHighlight {
1426 start: Some(serialize_anchor(&highlight.range.start)),
1427 end: Some(serialize_anchor(&highlight.range.end)),
1428 kind: match highlight.kind {
1429 DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1430 DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1431 DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1432 _ => proto::document_highlight::Kind::Text.into(),
1433 },
1434 })
1435 .collect();
1436 proto::GetDocumentHighlightsResponse { highlights }
1437 }
1438
1439 async fn response_from_proto(
1440 self,
1441 message: proto::GetDocumentHighlightsResponse,
1442 _: Entity<LspStore>,
1443 buffer: Entity<Buffer>,
1444 mut cx: AsyncApp,
1445 ) -> Result<Vec<DocumentHighlight>> {
1446 let mut highlights = Vec::new();
1447 for highlight in message.highlights {
1448 let start = highlight
1449 .start
1450 .and_then(deserialize_anchor)
1451 .ok_or_else(|| anyhow!("missing target start"))?;
1452 let end = highlight
1453 .end
1454 .and_then(deserialize_anchor)
1455 .ok_or_else(|| anyhow!("missing target end"))?;
1456 buffer
1457 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1458 .await?;
1459 let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1460 Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1461 Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1462 Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1463 None => DocumentHighlightKind::TEXT,
1464 };
1465 highlights.push(DocumentHighlight {
1466 range: start..end,
1467 kind,
1468 });
1469 }
1470 Ok(highlights)
1471 }
1472
1473 fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1474 BufferId::new(message.buffer_id)
1475 }
1476}
1477
1478#[async_trait(?Send)]
1479impl LspCommand for GetSignatureHelp {
1480 type Response = Option<SignatureHelp>;
1481 type LspRequest = lsp::SignatureHelpRequest;
1482 type ProtoRequest = proto::GetSignatureHelp;
1483
1484 fn display_name(&self) -> &str {
1485 "Get signature help"
1486 }
1487
1488 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1489 capabilities
1490 .server_capabilities
1491 .signature_help_provider
1492 .is_some()
1493 }
1494
1495 fn to_lsp(
1496 &self,
1497 path: &Path,
1498 _: &Buffer,
1499 _: &Arc<LanguageServer>,
1500 _cx: &App,
1501 ) -> Result<lsp::SignatureHelpParams> {
1502 Ok(lsp::SignatureHelpParams {
1503 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1504 context: None,
1505 work_done_progress_params: Default::default(),
1506 })
1507 }
1508
1509 async fn response_from_lsp(
1510 self,
1511 message: Option<lsp::SignatureHelp>,
1512 _: Entity<LspStore>,
1513 buffer: Entity<Buffer>,
1514 _: LanguageServerId,
1515 mut cx: AsyncApp,
1516 ) -> Result<Self::Response> {
1517 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1518 Ok(message.and_then(|message| SignatureHelp::new(message, language)))
1519 }
1520
1521 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1522 let offset = buffer.point_utf16_to_offset(self.position);
1523 proto::GetSignatureHelp {
1524 project_id,
1525 buffer_id: buffer.remote_id().to_proto(),
1526 position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1527 version: serialize_version(&buffer.version()),
1528 }
1529 }
1530
1531 async fn from_proto(
1532 payload: Self::ProtoRequest,
1533 _: Entity<LspStore>,
1534 buffer: Entity<Buffer>,
1535 mut cx: AsyncApp,
1536 ) -> Result<Self> {
1537 buffer
1538 .update(&mut cx, |buffer, _| {
1539 buffer.wait_for_version(deserialize_version(&payload.version))
1540 })?
1541 .await
1542 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1543 let buffer_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
1544 Ok(Self {
1545 position: payload
1546 .position
1547 .and_then(deserialize_anchor)
1548 .context("invalid position")?
1549 .to_point_utf16(&buffer_snapshot),
1550 })
1551 }
1552
1553 fn response_to_proto(
1554 response: Self::Response,
1555 _: &mut LspStore,
1556 _: PeerId,
1557 _: &Global,
1558 _: &mut App,
1559 ) -> proto::GetSignatureHelpResponse {
1560 proto::GetSignatureHelpResponse {
1561 signature_help: response
1562 .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1563 }
1564 }
1565
1566 async fn response_from_proto(
1567 self,
1568 response: proto::GetSignatureHelpResponse,
1569 _: Entity<LspStore>,
1570 buffer: Entity<Buffer>,
1571 mut cx: AsyncApp,
1572 ) -> Result<Self::Response> {
1573 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1574 Ok(response
1575 .signature_help
1576 .map(proto_to_lsp_signature)
1577 .and_then(|lsp_help| SignatureHelp::new(lsp_help, language)))
1578 }
1579
1580 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1581 BufferId::new(message.buffer_id)
1582 }
1583}
1584
1585#[async_trait(?Send)]
1586impl LspCommand for GetHover {
1587 type Response = Option<Hover>;
1588 type LspRequest = lsp::request::HoverRequest;
1589 type ProtoRequest = proto::GetHover;
1590
1591 fn display_name(&self) -> &str {
1592 "Get hover"
1593 }
1594
1595 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1596 match capabilities.server_capabilities.hover_provider {
1597 Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1598 Some(lsp::HoverProviderCapability::Options(_)) => true,
1599 None => false,
1600 }
1601 }
1602
1603 fn to_lsp(
1604 &self,
1605 path: &Path,
1606 _: &Buffer,
1607 _: &Arc<LanguageServer>,
1608 _: &App,
1609 ) -> Result<lsp::HoverParams> {
1610 Ok(lsp::HoverParams {
1611 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1612 work_done_progress_params: Default::default(),
1613 })
1614 }
1615
1616 async fn response_from_lsp(
1617 self,
1618 message: Option<lsp::Hover>,
1619 _: Entity<LspStore>,
1620 buffer: Entity<Buffer>,
1621 _: LanguageServerId,
1622 mut cx: AsyncApp,
1623 ) -> Result<Self::Response> {
1624 let Some(hover) = message else {
1625 return Ok(None);
1626 };
1627
1628 let (language, range) = buffer.update(&mut cx, |buffer, _| {
1629 (
1630 buffer.language().cloned(),
1631 hover.range.map(|range| {
1632 let token_start =
1633 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1634 let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1635 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1636 }),
1637 )
1638 })?;
1639
1640 fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1641 let block = match marked_string {
1642 lsp::MarkedString::String(content) => HoverBlock {
1643 text: content,
1644 kind: HoverBlockKind::Markdown,
1645 },
1646 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1647 HoverBlock {
1648 text: value,
1649 kind: HoverBlockKind::Code { language },
1650 }
1651 }
1652 };
1653 if block.text.is_empty() {
1654 None
1655 } else {
1656 Some(block)
1657 }
1658 }
1659
1660 let contents = match hover.contents {
1661 lsp::HoverContents::Scalar(marked_string) => {
1662 hover_blocks_from_marked_string(marked_string)
1663 .into_iter()
1664 .collect()
1665 }
1666 lsp::HoverContents::Array(marked_strings) => marked_strings
1667 .into_iter()
1668 .filter_map(hover_blocks_from_marked_string)
1669 .collect(),
1670 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1671 text: markup_content.value,
1672 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1673 HoverBlockKind::Markdown
1674 } else {
1675 HoverBlockKind::PlainText
1676 },
1677 }],
1678 };
1679
1680 Ok(Some(Hover {
1681 contents,
1682 range,
1683 language,
1684 }))
1685 }
1686
1687 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1688 proto::GetHover {
1689 project_id,
1690 buffer_id: buffer.remote_id().into(),
1691 position: Some(language::proto::serialize_anchor(
1692 &buffer.anchor_before(self.position),
1693 )),
1694 version: serialize_version(&buffer.version),
1695 }
1696 }
1697
1698 async fn from_proto(
1699 message: Self::ProtoRequest,
1700 _: Entity<LspStore>,
1701 buffer: Entity<Buffer>,
1702 mut cx: AsyncApp,
1703 ) -> Result<Self> {
1704 let position = message
1705 .position
1706 .and_then(deserialize_anchor)
1707 .ok_or_else(|| anyhow!("invalid position"))?;
1708 buffer
1709 .update(&mut cx, |buffer, _| {
1710 buffer.wait_for_version(deserialize_version(&message.version))
1711 })?
1712 .await?;
1713 Ok(Self {
1714 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1715 })
1716 }
1717
1718 fn response_to_proto(
1719 response: Self::Response,
1720 _: &mut LspStore,
1721 _: PeerId,
1722 _: &clock::Global,
1723 _: &mut App,
1724 ) -> proto::GetHoverResponse {
1725 if let Some(response) = response {
1726 let (start, end) = if let Some(range) = response.range {
1727 (
1728 Some(language::proto::serialize_anchor(&range.start)),
1729 Some(language::proto::serialize_anchor(&range.end)),
1730 )
1731 } else {
1732 (None, None)
1733 };
1734
1735 let contents = response
1736 .contents
1737 .into_iter()
1738 .map(|block| proto::HoverBlock {
1739 text: block.text,
1740 is_markdown: block.kind == HoverBlockKind::Markdown,
1741 language: if let HoverBlockKind::Code { language } = block.kind {
1742 Some(language)
1743 } else {
1744 None
1745 },
1746 })
1747 .collect();
1748
1749 proto::GetHoverResponse {
1750 start,
1751 end,
1752 contents,
1753 }
1754 } else {
1755 proto::GetHoverResponse {
1756 start: None,
1757 end: None,
1758 contents: Vec::new(),
1759 }
1760 }
1761 }
1762
1763 async fn response_from_proto(
1764 self,
1765 message: proto::GetHoverResponse,
1766 _: Entity<LspStore>,
1767 buffer: Entity<Buffer>,
1768 mut cx: AsyncApp,
1769 ) -> Result<Self::Response> {
1770 let contents: Vec<_> = message
1771 .contents
1772 .into_iter()
1773 .map(|block| HoverBlock {
1774 text: block.text,
1775 kind: if let Some(language) = block.language {
1776 HoverBlockKind::Code { language }
1777 } else if block.is_markdown {
1778 HoverBlockKind::Markdown
1779 } else {
1780 HoverBlockKind::PlainText
1781 },
1782 })
1783 .collect();
1784 if contents.is_empty() {
1785 return Ok(None);
1786 }
1787
1788 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
1789 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1790 language::proto::deserialize_anchor(start)
1791 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1792 } else {
1793 None
1794 };
1795 if let Some(range) = range.as_ref() {
1796 buffer
1797 .update(&mut cx, |buffer, _| {
1798 buffer.wait_for_anchors([range.start, range.end])
1799 })?
1800 .await?;
1801 }
1802
1803 Ok(Some(Hover {
1804 contents,
1805 range,
1806 language,
1807 }))
1808 }
1809
1810 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1811 BufferId::new(message.buffer_id)
1812 }
1813}
1814
1815#[async_trait(?Send)]
1816impl LspCommand for GetCompletions {
1817 type Response = Vec<CoreCompletion>;
1818 type LspRequest = lsp::request::Completion;
1819 type ProtoRequest = proto::GetCompletions;
1820
1821 fn display_name(&self) -> &str {
1822 "Get completion"
1823 }
1824
1825 fn to_lsp(
1826 &self,
1827 path: &Path,
1828 _: &Buffer,
1829 _: &Arc<LanguageServer>,
1830 _: &App,
1831 ) -> Result<lsp::CompletionParams> {
1832 Ok(lsp::CompletionParams {
1833 text_document_position: make_lsp_text_document_position(path, self.position)?,
1834 context: Some(self.context.clone()),
1835 work_done_progress_params: Default::default(),
1836 partial_result_params: Default::default(),
1837 })
1838 }
1839
1840 async fn response_from_lsp(
1841 self,
1842 completions: Option<lsp::CompletionResponse>,
1843 lsp_store: Entity<LspStore>,
1844 buffer: Entity<Buffer>,
1845 server_id: LanguageServerId,
1846 mut cx: AsyncApp,
1847 ) -> Result<Self::Response> {
1848 let mut response_list = None;
1849 let mut completions = if let Some(completions) = completions {
1850 match completions {
1851 lsp::CompletionResponse::Array(completions) => completions,
1852
1853 lsp::CompletionResponse::List(mut list) => {
1854 let items = std::mem::take(&mut list.items);
1855 response_list = Some(list);
1856 items
1857 }
1858 }
1859 } else {
1860 Default::default()
1861 };
1862
1863 let language_server_adapter = lsp_store
1864 .update(&mut cx, |lsp_store, _| {
1865 lsp_store.language_server_adapter_for_id(server_id)
1866 })?
1867 .ok_or_else(|| anyhow!("no such language server"))?;
1868
1869 let item_defaults = response_list
1870 .as_ref()
1871 .and_then(|list| list.item_defaults.as_ref());
1872
1873 if let Some(item_defaults) = item_defaults {
1874 let default_data = item_defaults.data.as_ref();
1875 let default_commit_characters = item_defaults.commit_characters.as_ref();
1876 let default_edit_range = item_defaults.edit_range.as_ref();
1877 let default_insert_text_format = item_defaults.insert_text_format.as_ref();
1878 let default_insert_text_mode = item_defaults.insert_text_mode.as_ref();
1879
1880 if default_data.is_some()
1881 || default_commit_characters.is_some()
1882 || default_edit_range.is_some()
1883 || default_insert_text_format.is_some()
1884 || default_insert_text_mode.is_some()
1885 {
1886 for item in completions.iter_mut() {
1887 if item.data.is_none() && default_data.is_some() {
1888 item.data = default_data.cloned()
1889 }
1890 if item.commit_characters.is_none() && default_commit_characters.is_some() {
1891 item.commit_characters = default_commit_characters.cloned()
1892 }
1893 if item.text_edit.is_none() {
1894 if let Some(default_edit_range) = default_edit_range {
1895 match default_edit_range {
1896 CompletionListItemDefaultsEditRange::Range(range) => {
1897 item.text_edit =
1898 Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
1899 range: *range,
1900 new_text: item.label.clone(),
1901 }))
1902 }
1903 CompletionListItemDefaultsEditRange::InsertAndReplace {
1904 insert,
1905 replace,
1906 } => {
1907 item.text_edit =
1908 Some(lsp::CompletionTextEdit::InsertAndReplace(
1909 lsp::InsertReplaceEdit {
1910 new_text: item.label.clone(),
1911 insert: *insert,
1912 replace: *replace,
1913 },
1914 ))
1915 }
1916 }
1917 }
1918 }
1919 if item.insert_text_format.is_none() && default_insert_text_format.is_some() {
1920 item.insert_text_format = default_insert_text_format.cloned()
1921 }
1922 if item.insert_text_mode.is_none() && default_insert_text_mode.is_some() {
1923 item.insert_text_mode = default_insert_text_mode.cloned()
1924 }
1925 }
1926 }
1927 }
1928
1929 let mut completion_edits = Vec::new();
1930 buffer.update(&mut cx, |buffer, _cx| {
1931 let snapshot = buffer.snapshot();
1932 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1933
1934 let mut range_for_token = None;
1935 completions.retain_mut(|lsp_completion| {
1936 let edit = match lsp_completion.text_edit.as_ref() {
1937 // If the language server provides a range to overwrite, then
1938 // check that the range is valid.
1939 Some(completion_text_edit) => {
1940 match parse_completion_text_edit(completion_text_edit, &snapshot) {
1941 Some(edit) => edit,
1942 None => return false,
1943 }
1944 }
1945
1946 // If the language server does not provide a range, then infer
1947 // the range based on the syntax tree.
1948 None => {
1949 if self.position != clipped_position {
1950 log::info!("completion out of expected range");
1951 return false;
1952 }
1953
1954 let default_edit_range = response_list
1955 .as_ref()
1956 .and_then(|list| list.item_defaults.as_ref())
1957 .and_then(|defaults| defaults.edit_range.as_ref())
1958 .and_then(|range| match range {
1959 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
1960 _ => None,
1961 });
1962
1963 let range = if let Some(range) = default_edit_range {
1964 let range = range_from_lsp(*range);
1965 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1966 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1967 if start != range.start.0 || end != range.end.0 {
1968 log::info!("completion out of expected range");
1969 return false;
1970 }
1971
1972 snapshot.anchor_before(start)..snapshot.anchor_after(end)
1973 } else {
1974 range_for_token
1975 .get_or_insert_with(|| {
1976 let offset = self.position.to_offset(&snapshot);
1977 let (range, kind) = snapshot.surrounding_word(offset);
1978 let range = if kind == Some(CharKind::Word) {
1979 range
1980 } else {
1981 offset..offset
1982 };
1983
1984 snapshot.anchor_before(range.start)
1985 ..snapshot.anchor_after(range.end)
1986 })
1987 .clone()
1988 };
1989
1990 let text = lsp_completion
1991 .insert_text
1992 .as_ref()
1993 .unwrap_or(&lsp_completion.label)
1994 .clone();
1995 (range, text)
1996 }
1997 };
1998
1999 completion_edits.push(edit);
2000 true
2001 });
2002 })?;
2003
2004 language_server_adapter
2005 .process_completions(&mut completions)
2006 .await;
2007
2008 Ok(completions
2009 .into_iter()
2010 .zip(completion_edits)
2011 .map(|(lsp_completion, (old_range, mut new_text))| {
2012 LineEnding::normalize(&mut new_text);
2013 CoreCompletion {
2014 old_range,
2015 new_text,
2016 server_id,
2017 lsp_completion,
2018 resolved: false,
2019 }
2020 })
2021 .collect())
2022 }
2023
2024 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2025 let anchor = buffer.anchor_after(self.position);
2026 proto::GetCompletions {
2027 project_id,
2028 buffer_id: buffer.remote_id().into(),
2029 position: Some(language::proto::serialize_anchor(&anchor)),
2030 version: serialize_version(&buffer.version()),
2031 }
2032 }
2033
2034 async fn from_proto(
2035 message: proto::GetCompletions,
2036 _: Entity<LspStore>,
2037 buffer: Entity<Buffer>,
2038 mut cx: AsyncApp,
2039 ) -> Result<Self> {
2040 let version = deserialize_version(&message.version);
2041 buffer
2042 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2043 .await?;
2044 let position = message
2045 .position
2046 .and_then(language::proto::deserialize_anchor)
2047 .map(|p| {
2048 buffer.update(&mut cx, |buffer, _| {
2049 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2050 })
2051 })
2052 .ok_or_else(|| anyhow!("invalid position"))??;
2053 Ok(Self {
2054 position,
2055 context: CompletionContext {
2056 trigger_kind: CompletionTriggerKind::INVOKED,
2057 trigger_character: None,
2058 },
2059 })
2060 }
2061
2062 fn response_to_proto(
2063 completions: Vec<CoreCompletion>,
2064 _: &mut LspStore,
2065 _: PeerId,
2066 buffer_version: &clock::Global,
2067 _: &mut App,
2068 ) -> proto::GetCompletionsResponse {
2069 proto::GetCompletionsResponse {
2070 completions: completions
2071 .iter()
2072 .map(LspStore::serialize_completion)
2073 .collect(),
2074 version: serialize_version(buffer_version),
2075 }
2076 }
2077
2078 async fn response_from_proto(
2079 self,
2080 message: proto::GetCompletionsResponse,
2081 _project: Entity<LspStore>,
2082 buffer: Entity<Buffer>,
2083 mut cx: AsyncApp,
2084 ) -> Result<Self::Response> {
2085 buffer
2086 .update(&mut cx, |buffer, _| {
2087 buffer.wait_for_version(deserialize_version(&message.version))
2088 })?
2089 .await?;
2090
2091 message
2092 .completions
2093 .into_iter()
2094 .map(LspStore::deserialize_completion)
2095 .collect()
2096 }
2097
2098 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2099 BufferId::new(message.buffer_id)
2100 }
2101}
2102
2103pub(crate) fn parse_completion_text_edit(
2104 edit: &lsp::CompletionTextEdit,
2105 snapshot: &BufferSnapshot,
2106) -> Option<(Range<Anchor>, String)> {
2107 match edit {
2108 lsp::CompletionTextEdit::Edit(edit) => {
2109 let range = range_from_lsp(edit.range);
2110 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2111 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2112 if start != range.start.0 || end != range.end.0 {
2113 log::info!("completion out of expected range");
2114 None
2115 } else {
2116 Some((
2117 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2118 edit.new_text.clone(),
2119 ))
2120 }
2121 }
2122
2123 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2124 let range = range_from_lsp(edit.replace);
2125
2126 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2127 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2128 if start != range.start.0 || end != range.end.0 {
2129 log::info!("completion out of expected range");
2130 None
2131 } else {
2132 Some((
2133 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2134 edit.new_text.clone(),
2135 ))
2136 }
2137 }
2138 }
2139}
2140
2141#[async_trait(?Send)]
2142impl LspCommand for GetCodeActions {
2143 type Response = Vec<CodeAction>;
2144 type LspRequest = lsp::request::CodeActionRequest;
2145 type ProtoRequest = proto::GetCodeActions;
2146
2147 fn display_name(&self) -> &str {
2148 "Get code actions"
2149 }
2150
2151 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2152 match &capabilities.server_capabilities.code_action_provider {
2153 None => false,
2154 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2155 _ => {
2156 // If we do know that we want specific code actions AND we know that
2157 // the server only supports specific code actions, then we want to filter
2158 // down to the ones that are supported.
2159 if let Some((requested, supported)) = self
2160 .kinds
2161 .as_ref()
2162 .zip(Self::supported_code_action_kinds(capabilities))
2163 {
2164 let server_supported = supported.into_iter().collect::<HashSet<_>>();
2165 requested.iter().any(|kind| server_supported.contains(kind))
2166 } else {
2167 true
2168 }
2169 }
2170 }
2171 }
2172
2173 fn to_lsp(
2174 &self,
2175 path: &Path,
2176 buffer: &Buffer,
2177 language_server: &Arc<LanguageServer>,
2178 _: &App,
2179 ) -> Result<lsp::CodeActionParams> {
2180 let mut relevant_diagnostics = Vec::new();
2181 for entry in buffer
2182 .snapshot()
2183 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2184 {
2185 relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2186 }
2187
2188 let supported =
2189 Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2190
2191 let only = if let Some(requested) = &self.kinds {
2192 if let Some(supported_kinds) = supported {
2193 let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2194
2195 let filtered = requested
2196 .iter()
2197 .filter(|kind| server_supported.contains(kind))
2198 .cloned()
2199 .collect();
2200 Some(filtered)
2201 } else {
2202 Some(requested.clone())
2203 }
2204 } else {
2205 supported
2206 };
2207
2208 Ok(lsp::CodeActionParams {
2209 text_document: make_text_document_identifier(path)?,
2210 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2211 work_done_progress_params: Default::default(),
2212 partial_result_params: Default::default(),
2213 context: lsp::CodeActionContext {
2214 diagnostics: relevant_diagnostics,
2215 only,
2216 ..lsp::CodeActionContext::default()
2217 },
2218 })
2219 }
2220
2221 async fn response_from_lsp(
2222 self,
2223 actions: Option<lsp::CodeActionResponse>,
2224 _: Entity<LspStore>,
2225 _: Entity<Buffer>,
2226 server_id: LanguageServerId,
2227 _: AsyncApp,
2228 ) -> Result<Vec<CodeAction>> {
2229 let requested_kinds_set = if let Some(kinds) = self.kinds {
2230 Some(kinds.into_iter().collect::<HashSet<_>>())
2231 } else {
2232 None
2233 };
2234
2235 Ok(actions
2236 .unwrap_or_default()
2237 .into_iter()
2238 .filter_map(|entry| {
2239 let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry else {
2240 return None;
2241 };
2242
2243 if let Some((requested_kinds, kind)) =
2244 requested_kinds_set.as_ref().zip(lsp_action.kind.as_ref())
2245 {
2246 if !requested_kinds.contains(kind) {
2247 return None;
2248 }
2249 }
2250
2251 Some(CodeAction {
2252 server_id,
2253 range: self.range.clone(),
2254 lsp_action,
2255 })
2256 })
2257 .collect())
2258 }
2259
2260 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2261 proto::GetCodeActions {
2262 project_id,
2263 buffer_id: buffer.remote_id().into(),
2264 start: Some(language::proto::serialize_anchor(&self.range.start)),
2265 end: Some(language::proto::serialize_anchor(&self.range.end)),
2266 version: serialize_version(&buffer.version()),
2267 }
2268 }
2269
2270 async fn from_proto(
2271 message: proto::GetCodeActions,
2272 _: Entity<LspStore>,
2273 buffer: Entity<Buffer>,
2274 mut cx: AsyncApp,
2275 ) -> Result<Self> {
2276 let start = message
2277 .start
2278 .and_then(language::proto::deserialize_anchor)
2279 .ok_or_else(|| anyhow!("invalid start"))?;
2280 let end = message
2281 .end
2282 .and_then(language::proto::deserialize_anchor)
2283 .ok_or_else(|| anyhow!("invalid end"))?;
2284 buffer
2285 .update(&mut cx, |buffer, _| {
2286 buffer.wait_for_version(deserialize_version(&message.version))
2287 })?
2288 .await?;
2289
2290 Ok(Self {
2291 range: start..end,
2292 kinds: None,
2293 })
2294 }
2295
2296 fn response_to_proto(
2297 code_actions: Vec<CodeAction>,
2298 _: &mut LspStore,
2299 _: PeerId,
2300 buffer_version: &clock::Global,
2301 _: &mut App,
2302 ) -> proto::GetCodeActionsResponse {
2303 proto::GetCodeActionsResponse {
2304 actions: code_actions
2305 .iter()
2306 .map(LspStore::serialize_code_action)
2307 .collect(),
2308 version: serialize_version(buffer_version),
2309 }
2310 }
2311
2312 async fn response_from_proto(
2313 self,
2314 message: proto::GetCodeActionsResponse,
2315 _: Entity<LspStore>,
2316 buffer: Entity<Buffer>,
2317 mut cx: AsyncApp,
2318 ) -> Result<Vec<CodeAction>> {
2319 buffer
2320 .update(&mut cx, |buffer, _| {
2321 buffer.wait_for_version(deserialize_version(&message.version))
2322 })?
2323 .await?;
2324 message
2325 .actions
2326 .into_iter()
2327 .map(LspStore::deserialize_code_action)
2328 .collect()
2329 }
2330
2331 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2332 BufferId::new(message.buffer_id)
2333 }
2334}
2335
2336impl GetCodeActions {
2337 fn supported_code_action_kinds(
2338 capabilities: AdapterServerCapabilities,
2339 ) -> Option<Vec<CodeActionKind>> {
2340 match capabilities.server_capabilities.code_action_provider {
2341 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2342 code_action_kinds: Some(supported_action_kinds),
2343 ..
2344 })) => Some(supported_action_kinds.clone()),
2345 _ => capabilities.code_action_kinds,
2346 }
2347 }
2348
2349 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2350 capabilities
2351 .code_action_provider
2352 .as_ref()
2353 .and_then(|options| match options {
2354 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2355 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2356 })
2357 .unwrap_or(false)
2358 }
2359}
2360
2361#[async_trait(?Send)]
2362impl LspCommand for OnTypeFormatting {
2363 type Response = Option<Transaction>;
2364 type LspRequest = lsp::request::OnTypeFormatting;
2365 type ProtoRequest = proto::OnTypeFormatting;
2366
2367 fn display_name(&self) -> &str {
2368 "Formatting on typing"
2369 }
2370
2371 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2372 let Some(on_type_formatting_options) = &capabilities
2373 .server_capabilities
2374 .document_on_type_formatting_provider
2375 else {
2376 return false;
2377 };
2378 on_type_formatting_options
2379 .first_trigger_character
2380 .contains(&self.trigger)
2381 || on_type_formatting_options
2382 .more_trigger_character
2383 .iter()
2384 .flatten()
2385 .any(|chars| chars.contains(&self.trigger))
2386 }
2387
2388 fn to_lsp(
2389 &self,
2390 path: &Path,
2391 _: &Buffer,
2392 _: &Arc<LanguageServer>,
2393 _: &App,
2394 ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2395 Ok(lsp::DocumentOnTypeFormattingParams {
2396 text_document_position: make_lsp_text_document_position(path, self.position)?,
2397 ch: self.trigger.clone(),
2398 options: self.options.clone(),
2399 })
2400 }
2401
2402 async fn response_from_lsp(
2403 self,
2404 message: Option<Vec<lsp::TextEdit>>,
2405 lsp_store: Entity<LspStore>,
2406 buffer: Entity<Buffer>,
2407 server_id: LanguageServerId,
2408 mut cx: AsyncApp,
2409 ) -> Result<Option<Transaction>> {
2410 if let Some(edits) = message {
2411 let (lsp_adapter, lsp_server) =
2412 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2413 LocalLspStore::deserialize_text_edits(
2414 lsp_store,
2415 buffer,
2416 edits,
2417 self.push_to_history,
2418 lsp_adapter,
2419 lsp_server,
2420 &mut cx,
2421 )
2422 .await
2423 } else {
2424 Ok(None)
2425 }
2426 }
2427
2428 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2429 proto::OnTypeFormatting {
2430 project_id,
2431 buffer_id: buffer.remote_id().into(),
2432 position: Some(language::proto::serialize_anchor(
2433 &buffer.anchor_before(self.position),
2434 )),
2435 trigger: self.trigger.clone(),
2436 version: serialize_version(&buffer.version()),
2437 }
2438 }
2439
2440 async fn from_proto(
2441 message: proto::OnTypeFormatting,
2442 _: Entity<LspStore>,
2443 buffer: Entity<Buffer>,
2444 mut cx: AsyncApp,
2445 ) -> Result<Self> {
2446 let position = message
2447 .position
2448 .and_then(deserialize_anchor)
2449 .ok_or_else(|| anyhow!("invalid position"))?;
2450 buffer
2451 .update(&mut cx, |buffer, _| {
2452 buffer.wait_for_version(deserialize_version(&message.version))
2453 })?
2454 .await?;
2455
2456 let options = buffer.update(&mut cx, |buffer, cx| {
2457 lsp_formatting_options(
2458 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2459 )
2460 })?;
2461
2462 Ok(Self {
2463 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2464 trigger: message.trigger.clone(),
2465 options,
2466 push_to_history: false,
2467 })
2468 }
2469
2470 fn response_to_proto(
2471 response: Option<Transaction>,
2472 _: &mut LspStore,
2473 _: PeerId,
2474 _: &clock::Global,
2475 _: &mut App,
2476 ) -> proto::OnTypeFormattingResponse {
2477 proto::OnTypeFormattingResponse {
2478 transaction: response
2479 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2480 }
2481 }
2482
2483 async fn response_from_proto(
2484 self,
2485 message: proto::OnTypeFormattingResponse,
2486 _: Entity<LspStore>,
2487 _: Entity<Buffer>,
2488 _: AsyncApp,
2489 ) -> Result<Option<Transaction>> {
2490 let Some(transaction) = message.transaction else {
2491 return Ok(None);
2492 };
2493 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2494 }
2495
2496 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2497 BufferId::new(message.buffer_id)
2498 }
2499}
2500
2501impl InlayHints {
2502 pub async fn lsp_to_project_hint(
2503 lsp_hint: lsp::InlayHint,
2504 buffer_handle: &Entity<Buffer>,
2505 server_id: LanguageServerId,
2506 resolve_state: ResolveState,
2507 force_no_type_left_padding: bool,
2508 cx: &mut AsyncApp,
2509 ) -> anyhow::Result<InlayHint> {
2510 let kind = lsp_hint.kind.and_then(|kind| match kind {
2511 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2512 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2513 _ => None,
2514 });
2515
2516 let position = buffer_handle.update(cx, |buffer, _| {
2517 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2518 if kind == Some(InlayHintKind::Parameter) {
2519 buffer.anchor_before(position)
2520 } else {
2521 buffer.anchor_after(position)
2522 }
2523 })?;
2524 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2525 .await
2526 .context("lsp to project inlay hint conversion")?;
2527 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2528 false
2529 } else {
2530 lsp_hint.padding_left.unwrap_or(false)
2531 };
2532
2533 Ok(InlayHint {
2534 position,
2535 padding_left,
2536 padding_right: lsp_hint.padding_right.unwrap_or(false),
2537 label,
2538 kind,
2539 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2540 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2541 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2542 InlayHintTooltip::MarkupContent(MarkupContent {
2543 kind: match markup_content.kind {
2544 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2545 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2546 },
2547 value: markup_content.value,
2548 })
2549 }
2550 }),
2551 resolve_state,
2552 })
2553 }
2554
2555 async fn lsp_inlay_label_to_project(
2556 lsp_label: lsp::InlayHintLabel,
2557 server_id: LanguageServerId,
2558 ) -> anyhow::Result<InlayHintLabel> {
2559 let label = match lsp_label {
2560 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2561 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2562 let mut parts = Vec::with_capacity(lsp_parts.len());
2563 for lsp_part in lsp_parts {
2564 parts.push(InlayHintLabelPart {
2565 value: lsp_part.value,
2566 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2567 lsp::InlayHintLabelPartTooltip::String(s) => {
2568 InlayHintLabelPartTooltip::String(s)
2569 }
2570 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2571 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2572 kind: match markup_content.kind {
2573 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2574 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2575 },
2576 value: markup_content.value,
2577 })
2578 }
2579 }),
2580 location: Some(server_id).zip(lsp_part.location),
2581 });
2582 }
2583 InlayHintLabel::LabelParts(parts)
2584 }
2585 };
2586
2587 Ok(label)
2588 }
2589
2590 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2591 let (state, lsp_resolve_state) = match response_hint.resolve_state {
2592 ResolveState::Resolved => (0, None),
2593 ResolveState::CanResolve(server_id, resolve_data) => (
2594 1,
2595 Some(proto::resolve_state::LspResolveState {
2596 server_id: server_id.0 as u64,
2597 value: resolve_data.map(|json_data| {
2598 serde_json::to_string(&json_data)
2599 .expect("failed to serialize resolve json data")
2600 }),
2601 }),
2602 ),
2603 ResolveState::Resolving => (2, None),
2604 };
2605 let resolve_state = Some(proto::ResolveState {
2606 state,
2607 lsp_resolve_state,
2608 });
2609 proto::InlayHint {
2610 position: Some(language::proto::serialize_anchor(&response_hint.position)),
2611 padding_left: response_hint.padding_left,
2612 padding_right: response_hint.padding_right,
2613 label: Some(proto::InlayHintLabel {
2614 label: Some(match response_hint.label {
2615 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2616 InlayHintLabel::LabelParts(label_parts) => {
2617 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2618 parts: label_parts.into_iter().map(|label_part| {
2619 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2620 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 });
2621 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 });
2622 proto::InlayHintLabelPart {
2623 value: label_part.value,
2624 tooltip: label_part.tooltip.map(|tooltip| {
2625 let proto_tooltip = match tooltip {
2626 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2627 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2628 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2629 value: markup_content.value,
2630 }),
2631 };
2632 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2633 }),
2634 location_url,
2635 location_range_start,
2636 location_range_end,
2637 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2638 }}).collect()
2639 })
2640 }
2641 }),
2642 }),
2643 kind: response_hint.kind.map(|kind| kind.name().to_string()),
2644 tooltip: response_hint.tooltip.map(|response_tooltip| {
2645 let proto_tooltip = match response_tooltip {
2646 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2647 InlayHintTooltip::MarkupContent(markup_content) => {
2648 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2649 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2650 value: markup_content.value,
2651 })
2652 }
2653 };
2654 proto::InlayHintTooltip {
2655 content: Some(proto_tooltip),
2656 }
2657 }),
2658 resolve_state,
2659 }
2660 }
2661
2662 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2663 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2664 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2665 });
2666 let resolve_state_data = resolve_state
2667 .lsp_resolve_state.as_ref()
2668 .map(|lsp_resolve_state| {
2669 let value = lsp_resolve_state.value.as_deref().map(|value| {
2670 serde_json::from_str::<Option<lsp::LSPAny>>(value)
2671 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2672 }).transpose()?.flatten();
2673 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2674 })
2675 .transpose()?;
2676 let resolve_state = match resolve_state.state {
2677 0 => ResolveState::Resolved,
2678 1 => {
2679 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2680 format!(
2681 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2682 )
2683 })?;
2684 ResolveState::CanResolve(server_id, lsp_resolve_state)
2685 }
2686 2 => ResolveState::Resolving,
2687 invalid => {
2688 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2689 }
2690 };
2691 Ok(InlayHint {
2692 position: message_hint
2693 .position
2694 .and_then(language::proto::deserialize_anchor)
2695 .context("invalid position")?,
2696 label: match message_hint
2697 .label
2698 .and_then(|label| label.label)
2699 .context("missing label")?
2700 {
2701 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2702 proto::inlay_hint_label::Label::LabelParts(parts) => {
2703 let mut label_parts = Vec::new();
2704 for part in parts.parts {
2705 label_parts.push(InlayHintLabelPart {
2706 value: part.value,
2707 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2708 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2709 InlayHintLabelPartTooltip::String(s)
2710 }
2711 Some(
2712 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2713 markup_content,
2714 ),
2715 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2716 kind: if markup_content.is_markdown {
2717 HoverBlockKind::Markdown
2718 } else {
2719 HoverBlockKind::PlainText
2720 },
2721 value: markup_content.value,
2722 }),
2723 None => InlayHintLabelPartTooltip::String(String::new()),
2724 }),
2725 location: {
2726 match part
2727 .location_url
2728 .zip(
2729 part.location_range_start.and_then(|start| {
2730 Some(start..part.location_range_end?)
2731 }),
2732 )
2733 .zip(part.language_server_id)
2734 {
2735 Some(((uri, range), server_id)) => Some((
2736 LanguageServerId(server_id as usize),
2737 lsp::Location {
2738 uri: lsp::Url::parse(&uri)
2739 .context("invalid uri in hint part {part:?}")?,
2740 range: lsp::Range::new(
2741 point_to_lsp(PointUtf16::new(
2742 range.start.row,
2743 range.start.column,
2744 )),
2745 point_to_lsp(PointUtf16::new(
2746 range.end.row,
2747 range.end.column,
2748 )),
2749 ),
2750 },
2751 )),
2752 None => None,
2753 }
2754 },
2755 });
2756 }
2757
2758 InlayHintLabel::LabelParts(label_parts)
2759 }
2760 },
2761 padding_left: message_hint.padding_left,
2762 padding_right: message_hint.padding_right,
2763 kind: message_hint
2764 .kind
2765 .as_deref()
2766 .and_then(InlayHintKind::from_name),
2767 tooltip: message_hint.tooltip.and_then(|tooltip| {
2768 Some(match tooltip.content? {
2769 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2770 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2771 InlayHintTooltip::MarkupContent(MarkupContent {
2772 kind: if markup_content.is_markdown {
2773 HoverBlockKind::Markdown
2774 } else {
2775 HoverBlockKind::PlainText
2776 },
2777 value: markup_content.value,
2778 })
2779 }
2780 })
2781 }),
2782 resolve_state,
2783 })
2784 }
2785
2786 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
2787 lsp::InlayHint {
2788 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
2789 kind: hint.kind.map(|kind| match kind {
2790 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
2791 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
2792 }),
2793 text_edits: None,
2794 tooltip: hint.tooltip.and_then(|tooltip| {
2795 Some(match tooltip {
2796 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
2797 InlayHintTooltip::MarkupContent(markup_content) => {
2798 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
2799 kind: match markup_content.kind {
2800 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
2801 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
2802 HoverBlockKind::Code { .. } => return None,
2803 },
2804 value: markup_content.value,
2805 })
2806 }
2807 })
2808 }),
2809 label: match hint.label {
2810 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
2811 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
2812 label_parts
2813 .into_iter()
2814 .map(|part| lsp::InlayHintLabelPart {
2815 value: part.value,
2816 tooltip: part.tooltip.and_then(|tooltip| {
2817 Some(match tooltip {
2818 InlayHintLabelPartTooltip::String(s) => {
2819 lsp::InlayHintLabelPartTooltip::String(s)
2820 }
2821 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2822 lsp::InlayHintLabelPartTooltip::MarkupContent(
2823 lsp::MarkupContent {
2824 kind: match markup_content.kind {
2825 HoverBlockKind::PlainText => {
2826 lsp::MarkupKind::PlainText
2827 }
2828 HoverBlockKind::Markdown => {
2829 lsp::MarkupKind::Markdown
2830 }
2831 HoverBlockKind::Code { .. } => return None,
2832 },
2833 value: markup_content.value,
2834 },
2835 )
2836 }
2837 })
2838 }),
2839 location: part.location.map(|(_, location)| location),
2840 command: None,
2841 })
2842 .collect(),
2843 ),
2844 },
2845 padding_left: Some(hint.padding_left),
2846 padding_right: Some(hint.padding_right),
2847 data: match hint.resolve_state {
2848 ResolveState::CanResolve(_, data) => data,
2849 ResolveState::Resolving | ResolveState::Resolved => None,
2850 },
2851 }
2852 }
2853
2854 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
2855 capabilities
2856 .inlay_hint_provider
2857 .as_ref()
2858 .and_then(|options| match options {
2859 OneOf::Left(_is_supported) => None,
2860 OneOf::Right(capabilities) => match capabilities {
2861 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
2862 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
2863 o.inlay_hint_options.resolve_provider
2864 }
2865 },
2866 })
2867 .unwrap_or(false)
2868 }
2869}
2870
2871#[async_trait(?Send)]
2872impl LspCommand for InlayHints {
2873 type Response = Vec<InlayHint>;
2874 type LspRequest = lsp::InlayHintRequest;
2875 type ProtoRequest = proto::InlayHints;
2876
2877 fn display_name(&self) -> &str {
2878 "Inlay hints"
2879 }
2880
2881 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2882 let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
2883 else {
2884 return false;
2885 };
2886 match inlay_hint_provider {
2887 lsp::OneOf::Left(enabled) => *enabled,
2888 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
2889 lsp::InlayHintServerCapabilities::Options(_) => true,
2890 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
2891 },
2892 }
2893 }
2894
2895 fn to_lsp(
2896 &self,
2897 path: &Path,
2898 buffer: &Buffer,
2899 _: &Arc<LanguageServer>,
2900 _: &App,
2901 ) -> Result<lsp::InlayHintParams> {
2902 Ok(lsp::InlayHintParams {
2903 text_document: lsp::TextDocumentIdentifier {
2904 uri: file_path_to_lsp_url(path)?,
2905 },
2906 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2907 work_done_progress_params: Default::default(),
2908 })
2909 }
2910
2911 async fn response_from_lsp(
2912 self,
2913 message: Option<Vec<lsp::InlayHint>>,
2914 lsp_store: Entity<LspStore>,
2915 buffer: Entity<Buffer>,
2916 server_id: LanguageServerId,
2917 mut cx: AsyncApp,
2918 ) -> anyhow::Result<Vec<InlayHint>> {
2919 let (lsp_adapter, lsp_server) =
2920 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2921 // `typescript-language-server` adds padding to the left for type hints, turning
2922 // `const foo: boolean` into `const foo : boolean` which looks odd.
2923 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
2924 //
2925 // We could trim the whole string, but being pessimistic on par with the situation above,
2926 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
2927 // Hence let's use a heuristic first to handle the most awkward case and look for more.
2928 let force_no_type_left_padding =
2929 lsp_adapter.name.0.as_ref() == "typescript-language-server";
2930
2931 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
2932 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
2933 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
2934 } else {
2935 ResolveState::Resolved
2936 };
2937
2938 let buffer = buffer.clone();
2939 cx.spawn(move |mut cx| async move {
2940 InlayHints::lsp_to_project_hint(
2941 lsp_hint,
2942 &buffer,
2943 server_id,
2944 resolve_state,
2945 force_no_type_left_padding,
2946 &mut cx,
2947 )
2948 .await
2949 })
2950 });
2951 future::join_all(hints)
2952 .await
2953 .into_iter()
2954 .collect::<anyhow::Result<_>>()
2955 .context("lsp to project inlay hints conversion")
2956 }
2957
2958 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
2959 proto::InlayHints {
2960 project_id,
2961 buffer_id: buffer.remote_id().into(),
2962 start: Some(language::proto::serialize_anchor(&self.range.start)),
2963 end: Some(language::proto::serialize_anchor(&self.range.end)),
2964 version: serialize_version(&buffer.version()),
2965 }
2966 }
2967
2968 async fn from_proto(
2969 message: proto::InlayHints,
2970 _: Entity<LspStore>,
2971 buffer: Entity<Buffer>,
2972 mut cx: AsyncApp,
2973 ) -> Result<Self> {
2974 let start = message
2975 .start
2976 .and_then(language::proto::deserialize_anchor)
2977 .context("invalid start")?;
2978 let end = message
2979 .end
2980 .and_then(language::proto::deserialize_anchor)
2981 .context("invalid end")?;
2982 buffer
2983 .update(&mut cx, |buffer, _| {
2984 buffer.wait_for_version(deserialize_version(&message.version))
2985 })?
2986 .await?;
2987
2988 Ok(Self { range: start..end })
2989 }
2990
2991 fn response_to_proto(
2992 response: Vec<InlayHint>,
2993 _: &mut LspStore,
2994 _: PeerId,
2995 buffer_version: &clock::Global,
2996 _: &mut App,
2997 ) -> proto::InlayHintsResponse {
2998 proto::InlayHintsResponse {
2999 hints: response
3000 .into_iter()
3001 .map(InlayHints::project_to_proto_hint)
3002 .collect(),
3003 version: serialize_version(buffer_version),
3004 }
3005 }
3006
3007 async fn response_from_proto(
3008 self,
3009 message: proto::InlayHintsResponse,
3010 _: Entity<LspStore>,
3011 buffer: Entity<Buffer>,
3012 mut cx: AsyncApp,
3013 ) -> anyhow::Result<Vec<InlayHint>> {
3014 buffer
3015 .update(&mut cx, |buffer, _| {
3016 buffer.wait_for_version(deserialize_version(&message.version))
3017 })?
3018 .await?;
3019
3020 let mut hints = Vec::new();
3021 for message_hint in message.hints {
3022 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3023 }
3024
3025 Ok(hints)
3026 }
3027
3028 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3029 BufferId::new(message.buffer_id)
3030 }
3031}
3032
3033#[async_trait(?Send)]
3034impl LspCommand for LinkedEditingRange {
3035 type Response = Vec<Range<Anchor>>;
3036 type LspRequest = lsp::request::LinkedEditingRange;
3037 type ProtoRequest = proto::LinkedEditingRange;
3038
3039 fn display_name(&self) -> &str {
3040 "Linked editing range"
3041 }
3042
3043 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3044 let Some(linked_editing_options) = &capabilities
3045 .server_capabilities
3046 .linked_editing_range_provider
3047 else {
3048 return false;
3049 };
3050 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3051 return false;
3052 }
3053 true
3054 }
3055
3056 fn to_lsp(
3057 &self,
3058 path: &Path,
3059 buffer: &Buffer,
3060 _server: &Arc<LanguageServer>,
3061 _: &App,
3062 ) -> Result<lsp::LinkedEditingRangeParams> {
3063 let position = self.position.to_point_utf16(&buffer.snapshot());
3064 Ok(lsp::LinkedEditingRangeParams {
3065 text_document_position_params: make_lsp_text_document_position(path, position)?,
3066 work_done_progress_params: Default::default(),
3067 })
3068 }
3069
3070 async fn response_from_lsp(
3071 self,
3072 message: Option<lsp::LinkedEditingRanges>,
3073 _: Entity<LspStore>,
3074 buffer: Entity<Buffer>,
3075 _server_id: LanguageServerId,
3076 cx: AsyncApp,
3077 ) -> Result<Vec<Range<Anchor>>> {
3078 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3079 ranges.sort_by_key(|range| range.start);
3080
3081 buffer.read_with(&cx, |buffer, _| {
3082 ranges
3083 .into_iter()
3084 .map(|range| {
3085 let start =
3086 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3087 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3088 buffer.anchor_before(start)..buffer.anchor_after(end)
3089 })
3090 .collect()
3091 })
3092 } else {
3093 Ok(vec![])
3094 }
3095 }
3096
3097 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3098 proto::LinkedEditingRange {
3099 project_id,
3100 buffer_id: buffer.remote_id().to_proto(),
3101 position: Some(serialize_anchor(&self.position)),
3102 version: serialize_version(&buffer.version()),
3103 }
3104 }
3105
3106 async fn from_proto(
3107 message: proto::LinkedEditingRange,
3108 _: Entity<LspStore>,
3109 buffer: Entity<Buffer>,
3110 mut cx: AsyncApp,
3111 ) -> Result<Self> {
3112 let position = message
3113 .position
3114 .ok_or_else(|| anyhow!("invalid position"))?;
3115 buffer
3116 .update(&mut cx, |buffer, _| {
3117 buffer.wait_for_version(deserialize_version(&message.version))
3118 })?
3119 .await?;
3120 let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3121 buffer
3122 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3123 .await?;
3124 Ok(Self { position })
3125 }
3126
3127 fn response_to_proto(
3128 response: Vec<Range<Anchor>>,
3129 _: &mut LspStore,
3130 _: PeerId,
3131 buffer_version: &clock::Global,
3132 _: &mut App,
3133 ) -> proto::LinkedEditingRangeResponse {
3134 proto::LinkedEditingRangeResponse {
3135 items: response
3136 .into_iter()
3137 .map(|range| proto::AnchorRange {
3138 start: Some(serialize_anchor(&range.start)),
3139 end: Some(serialize_anchor(&range.end)),
3140 })
3141 .collect(),
3142 version: serialize_version(buffer_version),
3143 }
3144 }
3145
3146 async fn response_from_proto(
3147 self,
3148 message: proto::LinkedEditingRangeResponse,
3149 _: Entity<LspStore>,
3150 buffer: Entity<Buffer>,
3151 mut cx: AsyncApp,
3152 ) -> Result<Vec<Range<Anchor>>> {
3153 buffer
3154 .update(&mut cx, |buffer, _| {
3155 buffer.wait_for_version(deserialize_version(&message.version))
3156 })?
3157 .await?;
3158 let items: Vec<Range<Anchor>> = message
3159 .items
3160 .into_iter()
3161 .filter_map(|range| {
3162 let start = deserialize_anchor(range.start?)?;
3163 let end = deserialize_anchor(range.end?)?;
3164 Some(start..end)
3165 })
3166 .collect();
3167 for range in &items {
3168 buffer
3169 .update(&mut cx, |buffer, _| {
3170 buffer.wait_for_anchors([range.start, range.end])
3171 })?
3172 .await?;
3173 }
3174 Ok(items)
3175 }
3176
3177 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3178 BufferId::new(message.buffer_id)
3179 }
3180}