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