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