1pub mod signature_help;
2
3use crate::{
4 CodeAction, CompletionSource, CoreCompletion, CoreCompletionResponse, DocumentColor,
5 DocumentHighlight, DocumentSymbol, Hover, HoverBlock, HoverBlockKind, InlayHint,
6 InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
7 LocationLink, LspAction, LspPullDiagnostics, MarkupContent, PrepareRenameResponse,
8 ProjectTransaction, PulledDiagnostics, ResolveState,
9 lsp_store::{LocalLspStore, LspFoldingRange, LspStore},
10};
11use anyhow::{Context as _, Result};
12use async_trait::async_trait;
13use client::proto::{self, PeerId};
14use clock::Global;
15use collections::HashMap;
16use futures::future;
17use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::FluentBuilder};
18use language::{
19 Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, CharScopeContext,
20 OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
21 language_settings::{InlayHintKind, LanguageSettings},
22 point_from_lsp, point_to_lsp,
23 proto::{
24 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
25 serialize_anchor_range, serialize_version,
26 },
27 range_from_lsp, range_to_lsp,
28};
29use lsp::{
30 AdapterServerCapabilities, CodeActionKind, CodeActionOptions, CodeDescription,
31 CompletionContext, CompletionListItemDefaultsEditRange, CompletionTriggerKind,
32 DocumentHighlightKind, LanguageServer, LanguageServerId, LinkedEditingRangeServerCapabilities,
33 OneOf, RenameOptions, ServerCapabilities,
34};
35use serde_json::Value;
36
37use signature_help::{lsp_to_proto_signature, proto_to_lsp_signature};
38use std::{
39 cmp::Reverse, collections::hash_map, mem, ops::Range, path::Path, str::FromStr, sync::Arc,
40};
41use text::{BufferId, LineEnding};
42use util::{ResultExt as _, debug_panic};
43
44pub use signature_help::SignatureHelp;
45
46fn code_action_kind_matches(requested: &lsp::CodeActionKind, actual: &lsp::CodeActionKind) -> bool {
47 let requested_str = requested.as_str();
48 let actual_str = actual.as_str();
49
50 // Exact match or hierarchical match
51 actual_str == requested_str
52 || actual_str
53 .strip_prefix(requested_str)
54 .is_some_and(|suffix| suffix.starts_with('.'))
55}
56
57pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOptions {
58 lsp::FormattingOptions {
59 tab_size: settings.tab_size.into(),
60 insert_spaces: !settings.hard_tabs,
61 trim_trailing_whitespace: Some(settings.remove_trailing_whitespace_on_save),
62 trim_final_newlines: Some(settings.ensure_final_newline_on_save),
63 insert_final_newline: Some(settings.ensure_final_newline_on_save),
64 ..lsp::FormattingOptions::default()
65 }
66}
67
68pub fn file_path_to_lsp_url(path: &Path) -> Result<lsp::Uri> {
69 match lsp::Uri::from_file_path(path) {
70 Ok(url) => Ok(url),
71 Err(()) => anyhow::bail!("Invalid file path provided to LSP request: {path:?}"),
72 }
73}
74
75pub(crate) fn make_text_document_identifier(path: &Path) -> Result<lsp::TextDocumentIdentifier> {
76 Ok(lsp::TextDocumentIdentifier {
77 uri: file_path_to_lsp_url(path)?,
78 })
79}
80
81pub(crate) fn make_lsp_text_document_position(
82 path: &Path,
83 position: PointUtf16,
84) -> Result<lsp::TextDocumentPositionParams> {
85 Ok(lsp::TextDocumentPositionParams {
86 text_document: make_text_document_identifier(path)?,
87 position: point_to_lsp(position),
88 })
89}
90
91#[async_trait(?Send)]
92pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {
93 type Response: 'static + Default + Send + std::fmt::Debug;
94 type LspRequest: 'static + Send + lsp::request::Request;
95 type ProtoRequest: 'static + Send + proto::RequestMessage;
96
97 fn display_name(&self) -> &str;
98
99 fn status(&self) -> Option<String> {
100 None
101 }
102
103 fn to_lsp_params_or_response(
104 &self,
105 path: &Path,
106 buffer: &Buffer,
107 language_server: &Arc<LanguageServer>,
108 cx: &App,
109 ) -> Result<
110 LspParamsOrResponse<<Self::LspRequest as lsp::request::Request>::Params, Self::Response>,
111 > {
112 if self.check_capabilities(language_server.adapter_server_capabilities()) {
113 Ok(LspParamsOrResponse::Params(self.to_lsp(
114 path,
115 buffer,
116 language_server,
117 cx,
118 )?))
119 } else {
120 Ok(LspParamsOrResponse::Response(Default::default()))
121 }
122 }
123
124 /// When false, `to_lsp_params_or_response` default implementation will return the default response.
125 fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool;
126
127 fn to_lsp(
128 &self,
129 path: &Path,
130 buffer: &Buffer,
131 language_server: &Arc<LanguageServer>,
132 cx: &App,
133 ) -> Result<<Self::LspRequest as lsp::request::Request>::Params>;
134
135 async fn response_from_lsp(
136 self,
137 message: <Self::LspRequest as lsp::request::Request>::Result,
138 lsp_store: Entity<LspStore>,
139 buffer: Entity<Buffer>,
140 server_id: LanguageServerId,
141 cx: AsyncApp,
142 ) -> Result<Self::Response>;
143
144 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
145
146 async fn from_proto(
147 message: Self::ProtoRequest,
148 lsp_store: Entity<LspStore>,
149 buffer: Entity<Buffer>,
150 cx: AsyncApp,
151 ) -> Result<Self>;
152
153 fn response_to_proto(
154 response: Self::Response,
155 lsp_store: &mut LspStore,
156 peer_id: PeerId,
157 buffer_version: &clock::Global,
158 cx: &mut App,
159 ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
160
161 async fn response_from_proto(
162 self,
163 message: <Self::ProtoRequest as proto::RequestMessage>::Response,
164 lsp_store: Entity<LspStore>,
165 buffer: Entity<Buffer>,
166 cx: AsyncApp,
167 ) -> Result<Self::Response>;
168
169 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
170}
171
172pub enum LspParamsOrResponse<P, R> {
173 Params(P),
174 Response(R),
175}
176
177#[derive(Debug)]
178pub(crate) struct PrepareRename {
179 pub position: PointUtf16,
180}
181
182#[derive(Debug)]
183pub(crate) struct PerformRename {
184 pub position: PointUtf16,
185 pub new_name: String,
186 pub push_to_history: bool,
187}
188
189#[derive(Debug, Clone, Copy)]
190pub struct GetDefinitions {
191 pub position: PointUtf16,
192}
193
194#[derive(Debug, Clone, Copy)]
195pub(crate) struct GetDeclarations {
196 pub position: PointUtf16,
197}
198
199#[derive(Debug, Clone, Copy)]
200pub(crate) struct GetTypeDefinitions {
201 pub position: PointUtf16,
202}
203
204#[derive(Debug, Clone, Copy)]
205pub(crate) struct GetImplementations {
206 pub position: PointUtf16,
207}
208
209#[derive(Debug, Clone, Copy)]
210pub(crate) struct GetReferences {
211 pub position: PointUtf16,
212}
213
214#[derive(Debug)]
215pub(crate) struct GetDocumentHighlights {
216 pub position: PointUtf16,
217}
218
219#[derive(Debug, Copy, Clone)]
220pub(crate) struct GetDocumentSymbols;
221
222#[derive(Clone, Debug)]
223pub(crate) struct GetSignatureHelp {
224 pub position: PointUtf16,
225}
226
227#[derive(Clone, Debug)]
228pub(crate) struct GetHover {
229 pub position: PointUtf16,
230}
231
232#[derive(Debug)]
233pub(crate) struct GetCompletions {
234 pub position: PointUtf16,
235 pub context: CompletionContext,
236 pub server_id: Option<lsp::LanguageServerId>,
237}
238
239#[derive(Clone, Debug)]
240pub(crate) struct GetCodeActions {
241 pub range: Range<Anchor>,
242 pub kinds: Option<Vec<lsp::CodeActionKind>>,
243}
244
245#[derive(Debug)]
246pub(crate) struct OnTypeFormatting {
247 pub position: PointUtf16,
248 pub trigger: String,
249 pub options: lsp::FormattingOptions,
250 pub push_to_history: bool,
251}
252
253#[derive(Clone, Debug)]
254pub(crate) struct InlayHints {
255 pub range: Range<Anchor>,
256}
257
258#[derive(Debug, Clone, Copy)]
259pub(crate) struct SemanticTokensFull {
260 pub for_server: Option<LanguageServerId>,
261}
262
263#[derive(Debug, Clone)]
264pub(crate) struct SemanticTokensDelta {
265 pub previous_result_id: SharedString,
266}
267
268#[derive(Debug)]
269pub(crate) enum SemanticTokensResponse {
270 Full {
271 data: Vec<u32>,
272 result_id: Option<SharedString>,
273 },
274 Delta {
275 edits: Vec<SemanticTokensEdit>,
276 result_id: Option<SharedString>,
277 },
278}
279
280impl Default for SemanticTokensResponse {
281 fn default() -> Self {
282 Self::Delta {
283 edits: Vec::new(),
284 result_id: None,
285 }
286 }
287}
288
289#[derive(Debug)]
290pub(crate) struct SemanticTokensEdit {
291 pub start: u32,
292 pub delete_count: u32,
293 pub data: Vec<u32>,
294}
295
296#[derive(Debug, Copy, Clone)]
297pub(crate) struct GetCodeLens;
298
299#[derive(Debug, Copy, Clone)]
300pub(crate) struct GetDocumentColor;
301
302#[derive(Debug, Copy, Clone)]
303pub(crate) struct GetFoldingRanges;
304
305impl GetCodeLens {
306 pub(crate) fn can_resolve_lens(capabilities: &ServerCapabilities) -> bool {
307 capabilities
308 .code_lens_provider
309 .as_ref()
310 .and_then(|code_lens_options| code_lens_options.resolve_provider)
311 .unwrap_or(false)
312 }
313}
314
315#[derive(Debug)]
316pub(crate) struct LinkedEditingRange {
317 pub position: Anchor,
318}
319
320#[derive(Clone, Debug)]
321pub struct GetDocumentDiagnostics {
322 /// We cannot blindly rely on server's capabilities.diagnostic_provider, as they're a singular field, whereas
323 /// a server can register multiple diagnostic providers post-mortem.
324 pub registration_id: Option<SharedString>,
325 pub identifier: Option<SharedString>,
326 pub previous_result_id: Option<SharedString>,
327}
328
329#[async_trait(?Send)]
330impl LspCommand for PrepareRename {
331 type Response = PrepareRenameResponse;
332 type LspRequest = lsp::request::PrepareRenameRequest;
333 type ProtoRequest = proto::PrepareRename;
334
335 fn display_name(&self) -> &str {
336 "Prepare rename"
337 }
338
339 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
340 capabilities
341 .server_capabilities
342 .rename_provider
343 .is_some_and(|capability| match capability {
344 OneOf::Left(enabled) => enabled,
345 OneOf::Right(options) => options.prepare_provider.unwrap_or(false),
346 })
347 }
348
349 fn to_lsp_params_or_response(
350 &self,
351 path: &Path,
352 buffer: &Buffer,
353 language_server: &Arc<LanguageServer>,
354 cx: &App,
355 ) -> Result<LspParamsOrResponse<lsp::TextDocumentPositionParams, PrepareRenameResponse>> {
356 let rename_provider = language_server
357 .adapter_server_capabilities()
358 .server_capabilities
359 .rename_provider;
360 match rename_provider {
361 Some(lsp::OneOf::Right(RenameOptions {
362 prepare_provider: Some(true),
363 ..
364 })) => Ok(LspParamsOrResponse::Params(self.to_lsp(
365 path,
366 buffer,
367 language_server,
368 cx,
369 )?)),
370 Some(lsp::OneOf::Right(_)) => Ok(LspParamsOrResponse::Response(
371 PrepareRenameResponse::OnlyUnpreparedRenameSupported,
372 )),
373 Some(lsp::OneOf::Left(true)) => Ok(LspParamsOrResponse::Response(
374 PrepareRenameResponse::OnlyUnpreparedRenameSupported,
375 )),
376 _ => anyhow::bail!("Rename not supported"),
377 }
378 }
379
380 fn to_lsp(
381 &self,
382 path: &Path,
383 _: &Buffer,
384 _: &Arc<LanguageServer>,
385 _: &App,
386 ) -> Result<lsp::TextDocumentPositionParams> {
387 make_lsp_text_document_position(path, self.position)
388 }
389
390 async fn response_from_lsp(
391 self,
392 message: Option<lsp::PrepareRenameResponse>,
393 _: Entity<LspStore>,
394 buffer: Entity<Buffer>,
395 _: LanguageServerId,
396 cx: AsyncApp,
397 ) -> Result<PrepareRenameResponse> {
398 buffer.read_with(&cx, |buffer, _| match message {
399 Some(lsp::PrepareRenameResponse::Range(range))
400 | Some(lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. }) => {
401 let Range { start, end } = range_from_lsp(range);
402 if buffer.clip_point_utf16(start, Bias::Left) == start.0
403 && buffer.clip_point_utf16(end, Bias::Left) == end.0
404 {
405 Ok(PrepareRenameResponse::Success(
406 buffer.anchor_after(start)..buffer.anchor_before(end),
407 ))
408 } else {
409 Ok(PrepareRenameResponse::InvalidPosition)
410 }
411 }
412 Some(lsp::PrepareRenameResponse::DefaultBehavior { .. }) => {
413 let snapshot = buffer.snapshot();
414 let (range, _) = snapshot.surrounding_word(self.position, None);
415 let range = snapshot.anchor_after(range.start)..snapshot.anchor_before(range.end);
416 Ok(PrepareRenameResponse::Success(range))
417 }
418 None => Ok(PrepareRenameResponse::InvalidPosition),
419 })
420 }
421
422 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
423 proto::PrepareRename {
424 project_id,
425 buffer_id: buffer.remote_id().into(),
426 position: Some(language::proto::serialize_anchor(
427 &buffer.anchor_before(self.position),
428 )),
429 version: serialize_version(&buffer.version()),
430 }
431 }
432
433 async fn from_proto(
434 message: proto::PrepareRename,
435 _: Entity<LspStore>,
436 buffer: Entity<Buffer>,
437 mut cx: AsyncApp,
438 ) -> Result<Self> {
439 let position = message
440 .position
441 .and_then(deserialize_anchor)
442 .context("invalid position")?;
443 buffer
444 .update(&mut cx, |buffer, _| {
445 buffer.wait_for_version(deserialize_version(&message.version))
446 })
447 .await?;
448
449 Ok(Self {
450 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
451 })
452 }
453
454 fn response_to_proto(
455 response: PrepareRenameResponse,
456 _: &mut LspStore,
457 _: PeerId,
458 buffer_version: &clock::Global,
459 _: &mut App,
460 ) -> proto::PrepareRenameResponse {
461 match response {
462 PrepareRenameResponse::Success(range) => proto::PrepareRenameResponse {
463 can_rename: true,
464 only_unprepared_rename_supported: false,
465 start: Some(language::proto::serialize_anchor(&range.start)),
466 end: Some(language::proto::serialize_anchor(&range.end)),
467 version: serialize_version(buffer_version),
468 },
469 PrepareRenameResponse::OnlyUnpreparedRenameSupported => proto::PrepareRenameResponse {
470 can_rename: false,
471 only_unprepared_rename_supported: true,
472 start: None,
473 end: None,
474 version: vec![],
475 },
476 PrepareRenameResponse::InvalidPosition => proto::PrepareRenameResponse {
477 can_rename: false,
478 only_unprepared_rename_supported: false,
479 start: None,
480 end: None,
481 version: vec![],
482 },
483 }
484 }
485
486 async fn response_from_proto(
487 self,
488 message: proto::PrepareRenameResponse,
489 _: Entity<LspStore>,
490 buffer: Entity<Buffer>,
491 mut cx: AsyncApp,
492 ) -> Result<PrepareRenameResponse> {
493 if message.can_rename {
494 buffer
495 .update(&mut cx, |buffer, _| {
496 buffer.wait_for_version(deserialize_version(&message.version))
497 })
498 .await?;
499 if let (Some(start), Some(end)) = (
500 message.start.and_then(deserialize_anchor),
501 message.end.and_then(deserialize_anchor),
502 ) {
503 Ok(PrepareRenameResponse::Success(start..end))
504 } else {
505 anyhow::bail!(
506 "Missing start or end position in remote project PrepareRenameResponse"
507 );
508 }
509 } else if message.only_unprepared_rename_supported {
510 Ok(PrepareRenameResponse::OnlyUnpreparedRenameSupported)
511 } else {
512 Ok(PrepareRenameResponse::InvalidPosition)
513 }
514 }
515
516 fn buffer_id_from_proto(message: &proto::PrepareRename) -> Result<BufferId> {
517 BufferId::new(message.buffer_id)
518 }
519}
520
521#[async_trait(?Send)]
522impl LspCommand for PerformRename {
523 type Response = ProjectTransaction;
524 type LspRequest = lsp::request::Rename;
525 type ProtoRequest = proto::PerformRename;
526
527 fn display_name(&self) -> &str {
528 "Rename"
529 }
530
531 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
532 capabilities
533 .server_capabilities
534 .rename_provider
535 .is_some_and(|capability| match capability {
536 OneOf::Left(enabled) => enabled,
537 OneOf::Right(_) => true,
538 })
539 }
540
541 fn to_lsp(
542 &self,
543 path: &Path,
544 _: &Buffer,
545 _: &Arc<LanguageServer>,
546 _: &App,
547 ) -> Result<lsp::RenameParams> {
548 Ok(lsp::RenameParams {
549 text_document_position: make_lsp_text_document_position(path, self.position)?,
550 new_name: self.new_name.clone(),
551 work_done_progress_params: Default::default(),
552 })
553 }
554
555 async fn response_from_lsp(
556 self,
557 message: Option<lsp::WorkspaceEdit>,
558 lsp_store: Entity<LspStore>,
559 buffer: Entity<Buffer>,
560 server_id: LanguageServerId,
561 mut cx: AsyncApp,
562 ) -> Result<ProjectTransaction> {
563 if let Some(edit) = message {
564 let (_, lsp_server) =
565 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
566 LocalLspStore::deserialize_workspace_edit(
567 lsp_store,
568 edit,
569 self.push_to_history,
570 lsp_server,
571 &mut cx,
572 )
573 .await
574 } else {
575 Ok(ProjectTransaction::default())
576 }
577 }
578
579 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
580 proto::PerformRename {
581 project_id,
582 buffer_id: buffer.remote_id().into(),
583 position: Some(language::proto::serialize_anchor(
584 &buffer.anchor_before(self.position),
585 )),
586 new_name: self.new_name.clone(),
587 version: serialize_version(&buffer.version()),
588 }
589 }
590
591 async fn from_proto(
592 message: proto::PerformRename,
593 _: Entity<LspStore>,
594 buffer: Entity<Buffer>,
595 mut cx: AsyncApp,
596 ) -> Result<Self> {
597 let position = message
598 .position
599 .and_then(deserialize_anchor)
600 .context("invalid position")?;
601 buffer
602 .update(&mut cx, |buffer, _| {
603 buffer.wait_for_version(deserialize_version(&message.version))
604 })
605 .await?;
606 Ok(Self {
607 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
608 new_name: message.new_name,
609 push_to_history: false,
610 })
611 }
612
613 fn response_to_proto(
614 response: ProjectTransaction,
615 lsp_store: &mut LspStore,
616 peer_id: PeerId,
617 _: &clock::Global,
618 cx: &mut App,
619 ) -> proto::PerformRenameResponse {
620 let transaction = lsp_store.buffer_store().update(cx, |buffer_store, cx| {
621 buffer_store.serialize_project_transaction_for_peer(response, peer_id, cx)
622 });
623 proto::PerformRenameResponse {
624 transaction: Some(transaction),
625 }
626 }
627
628 async fn response_from_proto(
629 self,
630 message: proto::PerformRenameResponse,
631 lsp_store: Entity<LspStore>,
632 _: Entity<Buffer>,
633 mut cx: AsyncApp,
634 ) -> Result<ProjectTransaction> {
635 let message = message.transaction.context("missing transaction")?;
636 lsp_store
637 .update(&mut cx, |lsp_store, cx| {
638 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
639 buffer_store.deserialize_project_transaction(message, self.push_to_history, cx)
640 })
641 })
642 .await
643 }
644
645 fn buffer_id_from_proto(message: &proto::PerformRename) -> Result<BufferId> {
646 BufferId::new(message.buffer_id)
647 }
648}
649
650#[async_trait(?Send)]
651impl LspCommand for GetDefinitions {
652 type Response = Vec<LocationLink>;
653 type LspRequest = lsp::request::GotoDefinition;
654 type ProtoRequest = proto::GetDefinition;
655
656 fn display_name(&self) -> &str {
657 "Get definition"
658 }
659
660 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
661 capabilities
662 .server_capabilities
663 .definition_provider
664 .is_some_and(|capability| match capability {
665 OneOf::Left(supported) => supported,
666 OneOf::Right(_options) => true,
667 })
668 }
669
670 fn to_lsp(
671 &self,
672 path: &Path,
673 _: &Buffer,
674 _: &Arc<LanguageServer>,
675 _: &App,
676 ) -> Result<lsp::GotoDefinitionParams> {
677 Ok(lsp::GotoDefinitionParams {
678 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
679 work_done_progress_params: Default::default(),
680 partial_result_params: Default::default(),
681 })
682 }
683
684 async fn response_from_lsp(
685 self,
686 message: Option<lsp::GotoDefinitionResponse>,
687 lsp_store: Entity<LspStore>,
688 buffer: Entity<Buffer>,
689 server_id: LanguageServerId,
690 cx: AsyncApp,
691 ) -> Result<Vec<LocationLink>> {
692 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
693 }
694
695 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
696 proto::GetDefinition {
697 project_id,
698 buffer_id: buffer.remote_id().into(),
699 position: Some(language::proto::serialize_anchor(
700 &buffer.anchor_before(self.position),
701 )),
702 version: serialize_version(&buffer.version()),
703 }
704 }
705
706 async fn from_proto(
707 message: proto::GetDefinition,
708 _: Entity<LspStore>,
709 buffer: Entity<Buffer>,
710 mut cx: AsyncApp,
711 ) -> Result<Self> {
712 let position = message
713 .position
714 .and_then(deserialize_anchor)
715 .context("invalid position")?;
716 buffer
717 .update(&mut cx, |buffer, _| {
718 buffer.wait_for_version(deserialize_version(&message.version))
719 })
720 .await?;
721 Ok(Self {
722 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
723 })
724 }
725
726 fn response_to_proto(
727 response: Vec<LocationLink>,
728 lsp_store: &mut LspStore,
729 peer_id: PeerId,
730 _: &clock::Global,
731 cx: &mut App,
732 ) -> proto::GetDefinitionResponse {
733 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
734 proto::GetDefinitionResponse { links }
735 }
736
737 async fn response_from_proto(
738 self,
739 message: proto::GetDefinitionResponse,
740 lsp_store: Entity<LspStore>,
741 _: Entity<Buffer>,
742 cx: AsyncApp,
743 ) -> Result<Vec<LocationLink>> {
744 location_links_from_proto(message.links, lsp_store, cx).await
745 }
746
747 fn buffer_id_from_proto(message: &proto::GetDefinition) -> Result<BufferId> {
748 BufferId::new(message.buffer_id)
749 }
750}
751
752#[async_trait(?Send)]
753impl LspCommand for GetDeclarations {
754 type Response = Vec<LocationLink>;
755 type LspRequest = lsp::request::GotoDeclaration;
756 type ProtoRequest = proto::GetDeclaration;
757
758 fn display_name(&self) -> &str {
759 "Get declaration"
760 }
761
762 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
763 capabilities
764 .server_capabilities
765 .declaration_provider
766 .is_some_and(|capability| match capability {
767 lsp::DeclarationCapability::Simple(supported) => supported,
768 lsp::DeclarationCapability::RegistrationOptions(..) => true,
769 lsp::DeclarationCapability::Options(..) => true,
770 })
771 }
772
773 fn to_lsp(
774 &self,
775 path: &Path,
776 _: &Buffer,
777 _: &Arc<LanguageServer>,
778 _: &App,
779 ) -> Result<lsp::GotoDeclarationParams> {
780 Ok(lsp::GotoDeclarationParams {
781 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
782 work_done_progress_params: Default::default(),
783 partial_result_params: Default::default(),
784 })
785 }
786
787 async fn response_from_lsp(
788 self,
789 message: Option<lsp::GotoDeclarationResponse>,
790 lsp_store: Entity<LspStore>,
791 buffer: Entity<Buffer>,
792 server_id: LanguageServerId,
793 cx: AsyncApp,
794 ) -> Result<Vec<LocationLink>> {
795 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
796 }
797
798 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDeclaration {
799 proto::GetDeclaration {
800 project_id,
801 buffer_id: buffer.remote_id().into(),
802 position: Some(language::proto::serialize_anchor(
803 &buffer.anchor_before(self.position),
804 )),
805 version: serialize_version(&buffer.version()),
806 }
807 }
808
809 async fn from_proto(
810 message: proto::GetDeclaration,
811 _: Entity<LspStore>,
812 buffer: Entity<Buffer>,
813 mut cx: AsyncApp,
814 ) -> Result<Self> {
815 let position = message
816 .position
817 .and_then(deserialize_anchor)
818 .context("invalid position")?;
819 buffer
820 .update(&mut cx, |buffer, _| {
821 buffer.wait_for_version(deserialize_version(&message.version))
822 })
823 .await?;
824 Ok(Self {
825 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
826 })
827 }
828
829 fn response_to_proto(
830 response: Vec<LocationLink>,
831 lsp_store: &mut LspStore,
832 peer_id: PeerId,
833 _: &clock::Global,
834 cx: &mut App,
835 ) -> proto::GetDeclarationResponse {
836 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
837 proto::GetDeclarationResponse { links }
838 }
839
840 async fn response_from_proto(
841 self,
842 message: proto::GetDeclarationResponse,
843 lsp_store: Entity<LspStore>,
844 _: Entity<Buffer>,
845 cx: AsyncApp,
846 ) -> Result<Vec<LocationLink>> {
847 location_links_from_proto(message.links, lsp_store, cx).await
848 }
849
850 fn buffer_id_from_proto(message: &proto::GetDeclaration) -> Result<BufferId> {
851 BufferId::new(message.buffer_id)
852 }
853}
854
855#[async_trait(?Send)]
856impl LspCommand for GetImplementations {
857 type Response = Vec<LocationLink>;
858 type LspRequest = lsp::request::GotoImplementation;
859 type ProtoRequest = proto::GetImplementation;
860
861 fn display_name(&self) -> &str {
862 "Get implementation"
863 }
864
865 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
866 capabilities
867 .server_capabilities
868 .implementation_provider
869 .is_some_and(|capability| match capability {
870 lsp::ImplementationProviderCapability::Simple(enabled) => enabled,
871 lsp::ImplementationProviderCapability::Options(_options) => true,
872 })
873 }
874
875 fn to_lsp(
876 &self,
877 path: &Path,
878 _: &Buffer,
879 _: &Arc<LanguageServer>,
880 _: &App,
881 ) -> Result<lsp::GotoImplementationParams> {
882 Ok(lsp::GotoImplementationParams {
883 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
884 work_done_progress_params: Default::default(),
885 partial_result_params: Default::default(),
886 })
887 }
888
889 async fn response_from_lsp(
890 self,
891 message: Option<lsp::GotoImplementationResponse>,
892 lsp_store: Entity<LspStore>,
893 buffer: Entity<Buffer>,
894 server_id: LanguageServerId,
895 cx: AsyncApp,
896 ) -> Result<Vec<LocationLink>> {
897 location_links_from_lsp(message, lsp_store, buffer, server_id, cx).await
898 }
899
900 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetImplementation {
901 proto::GetImplementation {
902 project_id,
903 buffer_id: buffer.remote_id().into(),
904 position: Some(language::proto::serialize_anchor(
905 &buffer.anchor_before(self.position),
906 )),
907 version: serialize_version(&buffer.version()),
908 }
909 }
910
911 async fn from_proto(
912 message: proto::GetImplementation,
913 _: Entity<LspStore>,
914 buffer: Entity<Buffer>,
915 mut cx: AsyncApp,
916 ) -> Result<Self> {
917 let position = message
918 .position
919 .and_then(deserialize_anchor)
920 .context("invalid position")?;
921 buffer
922 .update(&mut cx, |buffer, _| {
923 buffer.wait_for_version(deserialize_version(&message.version))
924 })
925 .await?;
926 Ok(Self {
927 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
928 })
929 }
930
931 fn response_to_proto(
932 response: Vec<LocationLink>,
933 lsp_store: &mut LspStore,
934 peer_id: PeerId,
935 _: &clock::Global,
936 cx: &mut App,
937 ) -> proto::GetImplementationResponse {
938 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
939 proto::GetImplementationResponse { links }
940 }
941
942 async fn response_from_proto(
943 self,
944 message: proto::GetImplementationResponse,
945 project: Entity<LspStore>,
946 _: Entity<Buffer>,
947 cx: AsyncApp,
948 ) -> Result<Vec<LocationLink>> {
949 location_links_from_proto(message.links, project, cx).await
950 }
951
952 fn buffer_id_from_proto(message: &proto::GetImplementation) -> Result<BufferId> {
953 BufferId::new(message.buffer_id)
954 }
955}
956
957#[async_trait(?Send)]
958impl LspCommand for GetTypeDefinitions {
959 type Response = Vec<LocationLink>;
960 type LspRequest = lsp::request::GotoTypeDefinition;
961 type ProtoRequest = proto::GetTypeDefinition;
962
963 fn display_name(&self) -> &str {
964 "Get type definition"
965 }
966
967 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
968 !matches!(
969 &capabilities.server_capabilities.type_definition_provider,
970 None | Some(lsp::TypeDefinitionProviderCapability::Simple(false))
971 )
972 }
973
974 fn to_lsp(
975 &self,
976 path: &Path,
977 _: &Buffer,
978 _: &Arc<LanguageServer>,
979 _: &App,
980 ) -> Result<lsp::GotoTypeDefinitionParams> {
981 Ok(lsp::GotoTypeDefinitionParams {
982 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
983 work_done_progress_params: Default::default(),
984 partial_result_params: Default::default(),
985 })
986 }
987
988 async fn response_from_lsp(
989 self,
990 message: Option<lsp::GotoTypeDefinitionResponse>,
991 project: Entity<LspStore>,
992 buffer: Entity<Buffer>,
993 server_id: LanguageServerId,
994 cx: AsyncApp,
995 ) -> Result<Vec<LocationLink>> {
996 location_links_from_lsp(message, project, buffer, server_id, cx).await
997 }
998
999 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
1000 proto::GetTypeDefinition {
1001 project_id,
1002 buffer_id: buffer.remote_id().into(),
1003 position: Some(language::proto::serialize_anchor(
1004 &buffer.anchor_before(self.position),
1005 )),
1006 version: serialize_version(&buffer.version()),
1007 }
1008 }
1009
1010 async fn from_proto(
1011 message: proto::GetTypeDefinition,
1012 _: Entity<LspStore>,
1013 buffer: Entity<Buffer>,
1014 mut cx: AsyncApp,
1015 ) -> Result<Self> {
1016 let position = message
1017 .position
1018 .and_then(deserialize_anchor)
1019 .context("invalid position")?;
1020 buffer
1021 .update(&mut cx, |buffer, _| {
1022 buffer.wait_for_version(deserialize_version(&message.version))
1023 })
1024 .await?;
1025 Ok(Self {
1026 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1027 })
1028 }
1029
1030 fn response_to_proto(
1031 response: Vec<LocationLink>,
1032 lsp_store: &mut LspStore,
1033 peer_id: PeerId,
1034 _: &clock::Global,
1035 cx: &mut App,
1036 ) -> proto::GetTypeDefinitionResponse {
1037 let links = location_links_to_proto(response, lsp_store, peer_id, cx);
1038 proto::GetTypeDefinitionResponse { links }
1039 }
1040
1041 async fn response_from_proto(
1042 self,
1043 message: proto::GetTypeDefinitionResponse,
1044 project: Entity<LspStore>,
1045 _: Entity<Buffer>,
1046 cx: AsyncApp,
1047 ) -> Result<Vec<LocationLink>> {
1048 location_links_from_proto(message.links, project, cx).await
1049 }
1050
1051 fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> Result<BufferId> {
1052 BufferId::new(message.buffer_id)
1053 }
1054}
1055
1056fn language_server_for_buffer(
1057 lsp_store: &Entity<LspStore>,
1058 buffer: &Entity<Buffer>,
1059 server_id: LanguageServerId,
1060 cx: &mut AsyncApp,
1061) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
1062 lsp_store
1063 .update(cx, |lsp_store, cx| {
1064 buffer.update(cx, |buffer, cx| {
1065 lsp_store
1066 .language_server_for_local_buffer(buffer, server_id, cx)
1067 .map(|(adapter, server)| (adapter.clone(), server.clone()))
1068 })
1069 })
1070 .context("no language server found for buffer")
1071}
1072
1073pub async fn location_links_from_proto(
1074 proto_links: Vec<proto::LocationLink>,
1075 lsp_store: Entity<LspStore>,
1076 mut cx: AsyncApp,
1077) -> Result<Vec<LocationLink>> {
1078 let mut links = Vec::new();
1079
1080 for link in proto_links {
1081 links.push(location_link_from_proto(link, lsp_store.clone(), &mut cx).await?)
1082 }
1083
1084 Ok(links)
1085}
1086
1087pub fn location_link_from_proto(
1088 link: proto::LocationLink,
1089 lsp_store: Entity<LspStore>,
1090 cx: &mut AsyncApp,
1091) -> Task<Result<LocationLink>> {
1092 cx.spawn(async move |cx| {
1093 let origin = match link.origin {
1094 Some(origin) => {
1095 let buffer_id = BufferId::new(origin.buffer_id)?;
1096 let buffer = lsp_store
1097 .update(cx, |lsp_store, cx| {
1098 lsp_store.wait_for_remote_buffer(buffer_id, cx)
1099 })
1100 .await?;
1101 let start = origin
1102 .start
1103 .and_then(deserialize_anchor)
1104 .context("missing origin start")?;
1105 let end = origin
1106 .end
1107 .and_then(deserialize_anchor)
1108 .context("missing origin end")?;
1109 buffer
1110 .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1111 .await?;
1112 Some(Location {
1113 buffer,
1114 range: start..end,
1115 })
1116 }
1117 None => None,
1118 };
1119
1120 let target = link.target.context("missing target")?;
1121 let buffer_id = BufferId::new(target.buffer_id)?;
1122 let buffer = lsp_store
1123 .update(cx, |lsp_store, cx| {
1124 lsp_store.wait_for_remote_buffer(buffer_id, cx)
1125 })
1126 .await?;
1127 let start = target
1128 .start
1129 .and_then(deserialize_anchor)
1130 .context("missing target start")?;
1131 let end = target
1132 .end
1133 .and_then(deserialize_anchor)
1134 .context("missing target end")?;
1135 buffer
1136 .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1137 .await?;
1138 let target = Location {
1139 buffer,
1140 range: start..end,
1141 };
1142 Ok(LocationLink { origin, target })
1143 })
1144}
1145
1146pub async fn location_links_from_lsp(
1147 message: Option<lsp::GotoDefinitionResponse>,
1148 lsp_store: Entity<LspStore>,
1149 buffer: Entity<Buffer>,
1150 server_id: LanguageServerId,
1151 mut cx: AsyncApp,
1152) -> Result<Vec<LocationLink>> {
1153 let message = match message {
1154 Some(message) => message,
1155 None => return Ok(Vec::new()),
1156 };
1157
1158 let mut unresolved_links = Vec::new();
1159 match message {
1160 lsp::GotoDefinitionResponse::Scalar(loc) => {
1161 unresolved_links.push((None, loc.uri, loc.range));
1162 }
1163
1164 lsp::GotoDefinitionResponse::Array(locs) => {
1165 unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
1166 }
1167
1168 lsp::GotoDefinitionResponse::Link(links) => {
1169 unresolved_links.extend(links.into_iter().map(|l| {
1170 (
1171 l.origin_selection_range,
1172 l.target_uri,
1173 l.target_selection_range,
1174 )
1175 }));
1176 }
1177 }
1178
1179 let (_, language_server) = language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1180 let mut definitions = Vec::new();
1181 for (origin_range, target_uri, target_range) in unresolved_links {
1182 let target_buffer_handle = lsp_store
1183 .update(&mut cx, |this, cx| {
1184 this.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
1185 })
1186 .await?;
1187
1188 cx.update(|cx| {
1189 let origin_location = origin_range.map(|origin_range| {
1190 let origin_buffer = buffer.read(cx);
1191 let origin_start =
1192 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1193 let origin_end =
1194 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1195 Location {
1196 buffer: buffer.clone(),
1197 range: origin_buffer.anchor_after(origin_start)
1198 ..origin_buffer.anchor_before(origin_end),
1199 }
1200 });
1201
1202 let target_buffer = target_buffer_handle.read(cx);
1203 let target_start =
1204 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1205 let target_end =
1206 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1207 let target_location = Location {
1208 buffer: target_buffer_handle,
1209 range: target_buffer.anchor_after(target_start)
1210 ..target_buffer.anchor_before(target_end),
1211 };
1212
1213 definitions.push(LocationLink {
1214 origin: origin_location,
1215 target: target_location,
1216 })
1217 });
1218 }
1219 Ok(definitions)
1220}
1221
1222pub async fn location_link_from_lsp(
1223 link: lsp::LocationLink,
1224 lsp_store: &Entity<LspStore>,
1225 buffer: &Entity<Buffer>,
1226 server_id: LanguageServerId,
1227 cx: &mut AsyncApp,
1228) -> Result<LocationLink> {
1229 let (_, language_server) = language_server_for_buffer(lsp_store, buffer, server_id, cx)?;
1230
1231 let (origin_range, target_uri, target_range) = (
1232 link.origin_selection_range,
1233 link.target_uri,
1234 link.target_selection_range,
1235 );
1236
1237 let target_buffer_handle = lsp_store
1238 .update(cx, |lsp_store, cx| {
1239 lsp_store.open_local_buffer_via_lsp(target_uri, language_server.server_id(), cx)
1240 })
1241 .await?;
1242
1243 Ok(cx.update(|cx| {
1244 let origin_location = origin_range.map(|origin_range| {
1245 let origin_buffer = buffer.read(cx);
1246 let origin_start =
1247 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1248 let origin_end =
1249 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1250 Location {
1251 buffer: buffer.clone(),
1252 range: origin_buffer.anchor_after(origin_start)
1253 ..origin_buffer.anchor_before(origin_end),
1254 }
1255 });
1256
1257 let target_buffer = target_buffer_handle.read(cx);
1258 let target_start =
1259 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1260 let target_end =
1261 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1262 let target_location = Location {
1263 buffer: target_buffer_handle,
1264 range: target_buffer.anchor_after(target_start)
1265 ..target_buffer.anchor_before(target_end),
1266 };
1267
1268 LocationLink {
1269 origin: origin_location,
1270 target: target_location,
1271 }
1272 }))
1273}
1274
1275pub fn location_links_to_proto(
1276 links: Vec<LocationLink>,
1277 lsp_store: &mut LspStore,
1278 peer_id: PeerId,
1279 cx: &mut App,
1280) -> Vec<proto::LocationLink> {
1281 links
1282 .into_iter()
1283 .map(|definition| location_link_to_proto(definition, lsp_store, peer_id, cx))
1284 .collect()
1285}
1286
1287pub fn location_link_to_proto(
1288 location: LocationLink,
1289 lsp_store: &mut LspStore,
1290 peer_id: PeerId,
1291 cx: &mut App,
1292) -> proto::LocationLink {
1293 let origin = location.origin.map(|origin| {
1294 lsp_store
1295 .buffer_store()
1296 .update(cx, |buffer_store, cx| {
1297 buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1298 })
1299 .detach_and_log_err(cx);
1300
1301 let buffer_id = origin.buffer.read(cx).remote_id().into();
1302 proto::Location {
1303 start: Some(serialize_anchor(&origin.range.start)),
1304 end: Some(serialize_anchor(&origin.range.end)),
1305 buffer_id,
1306 }
1307 });
1308
1309 lsp_store
1310 .buffer_store()
1311 .update(cx, |buffer_store, cx| {
1312 buffer_store.create_buffer_for_peer(&location.target.buffer, peer_id, cx)
1313 })
1314 .detach_and_log_err(cx);
1315
1316 let buffer_id = location.target.buffer.read(cx).remote_id().into();
1317 let target = proto::Location {
1318 start: Some(serialize_anchor(&location.target.range.start)),
1319 end: Some(serialize_anchor(&location.target.range.end)),
1320 buffer_id,
1321 };
1322
1323 proto::LocationLink {
1324 origin,
1325 target: Some(target),
1326 }
1327}
1328
1329#[async_trait(?Send)]
1330impl LspCommand for GetReferences {
1331 type Response = Vec<Location>;
1332 type LspRequest = lsp::request::References;
1333 type ProtoRequest = proto::GetReferences;
1334
1335 fn display_name(&self) -> &str {
1336 "Find all references"
1337 }
1338
1339 fn status(&self) -> Option<String> {
1340 Some("Finding references...".to_owned())
1341 }
1342
1343 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1344 match &capabilities.server_capabilities.references_provider {
1345 Some(OneOf::Left(has_support)) => *has_support,
1346 Some(OneOf::Right(_)) => true,
1347 None => false,
1348 }
1349 }
1350
1351 fn to_lsp(
1352 &self,
1353 path: &Path,
1354 _: &Buffer,
1355 _: &Arc<LanguageServer>,
1356 _: &App,
1357 ) -> Result<lsp::ReferenceParams> {
1358 Ok(lsp::ReferenceParams {
1359 text_document_position: make_lsp_text_document_position(path, self.position)?,
1360 work_done_progress_params: Default::default(),
1361 partial_result_params: Default::default(),
1362 context: lsp::ReferenceContext {
1363 include_declaration: true,
1364 },
1365 })
1366 }
1367
1368 async fn response_from_lsp(
1369 self,
1370 locations: Option<Vec<lsp::Location>>,
1371 lsp_store: Entity<LspStore>,
1372 buffer: Entity<Buffer>,
1373 server_id: LanguageServerId,
1374 mut cx: AsyncApp,
1375 ) -> Result<Vec<Location>> {
1376 let mut references = Vec::new();
1377 let (_, language_server) =
1378 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1379
1380 if let Some(locations) = locations {
1381 for lsp_location in locations {
1382 let target_buffer_handle = lsp_store
1383 .update(&mut cx, |lsp_store, cx| {
1384 lsp_store.open_local_buffer_via_lsp(
1385 lsp_location.uri,
1386 language_server.server_id(),
1387 cx,
1388 )
1389 })
1390 .await?;
1391
1392 target_buffer_handle
1393 .clone()
1394 .read_with(&cx, |target_buffer, _| {
1395 let target_start = target_buffer
1396 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1397 let target_end = target_buffer
1398 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1399 references.push(Location {
1400 buffer: target_buffer_handle,
1401 range: target_buffer.anchor_after(target_start)
1402 ..target_buffer.anchor_before(target_end),
1403 });
1404 });
1405 }
1406 }
1407
1408 Ok(references)
1409 }
1410
1411 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1412 proto::GetReferences {
1413 project_id,
1414 buffer_id: buffer.remote_id().into(),
1415 position: Some(language::proto::serialize_anchor(
1416 &buffer.anchor_before(self.position),
1417 )),
1418 version: serialize_version(&buffer.version()),
1419 }
1420 }
1421
1422 async fn from_proto(
1423 message: proto::GetReferences,
1424 _: Entity<LspStore>,
1425 buffer: Entity<Buffer>,
1426 mut cx: AsyncApp,
1427 ) -> Result<Self> {
1428 let position = message
1429 .position
1430 .and_then(deserialize_anchor)
1431 .context("invalid position")?;
1432 buffer
1433 .update(&mut cx, |buffer, _| {
1434 buffer.wait_for_version(deserialize_version(&message.version))
1435 })
1436 .await?;
1437 Ok(Self {
1438 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1439 })
1440 }
1441
1442 fn response_to_proto(
1443 response: Vec<Location>,
1444 lsp_store: &mut LspStore,
1445 peer_id: PeerId,
1446 _: &clock::Global,
1447 cx: &mut App,
1448 ) -> proto::GetReferencesResponse {
1449 let locations = response
1450 .into_iter()
1451 .map(|definition| {
1452 lsp_store
1453 .buffer_store()
1454 .update(cx, |buffer_store, cx| {
1455 buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1456 })
1457 .detach_and_log_err(cx);
1458 let buffer_id = definition.buffer.read(cx).remote_id();
1459 proto::Location {
1460 start: Some(serialize_anchor(&definition.range.start)),
1461 end: Some(serialize_anchor(&definition.range.end)),
1462 buffer_id: buffer_id.into(),
1463 }
1464 })
1465 .collect();
1466 proto::GetReferencesResponse { locations }
1467 }
1468
1469 async fn response_from_proto(
1470 self,
1471 message: proto::GetReferencesResponse,
1472 project: Entity<LspStore>,
1473 _: Entity<Buffer>,
1474 mut cx: AsyncApp,
1475 ) -> Result<Vec<Location>> {
1476 let mut locations = Vec::new();
1477 for location in message.locations {
1478 let buffer_id = BufferId::new(location.buffer_id)?;
1479 let target_buffer = project
1480 .update(&mut cx, |this, cx| {
1481 this.wait_for_remote_buffer(buffer_id, cx)
1482 })
1483 .await?;
1484 let start = location
1485 .start
1486 .and_then(deserialize_anchor)
1487 .context("missing target start")?;
1488 let end = location
1489 .end
1490 .and_then(deserialize_anchor)
1491 .context("missing target end")?;
1492 target_buffer
1493 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1494 .await?;
1495 locations.push(Location {
1496 buffer: target_buffer,
1497 range: start..end,
1498 })
1499 }
1500 Ok(locations)
1501 }
1502
1503 fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1504 BufferId::new(message.buffer_id)
1505 }
1506}
1507
1508#[async_trait(?Send)]
1509impl LspCommand for GetDocumentHighlights {
1510 type Response = Vec<DocumentHighlight>;
1511 type LspRequest = lsp::request::DocumentHighlightRequest;
1512 type ProtoRequest = proto::GetDocumentHighlights;
1513
1514 fn display_name(&self) -> &str {
1515 "Get document highlights"
1516 }
1517
1518 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1519 capabilities
1520 .server_capabilities
1521 .document_highlight_provider
1522 .is_some_and(|capability| match capability {
1523 OneOf::Left(supported) => supported,
1524 OneOf::Right(_options) => true,
1525 })
1526 }
1527
1528 fn to_lsp(
1529 &self,
1530 path: &Path,
1531 _: &Buffer,
1532 _: &Arc<LanguageServer>,
1533 _: &App,
1534 ) -> Result<lsp::DocumentHighlightParams> {
1535 Ok(lsp::DocumentHighlightParams {
1536 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1537 work_done_progress_params: Default::default(),
1538 partial_result_params: Default::default(),
1539 })
1540 }
1541
1542 async fn response_from_lsp(
1543 self,
1544 lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1545 _: Entity<LspStore>,
1546 buffer: Entity<Buffer>,
1547 _: LanguageServerId,
1548 cx: AsyncApp,
1549 ) -> Result<Vec<DocumentHighlight>> {
1550 Ok(buffer.read_with(&cx, |buffer, _| {
1551 let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1552 lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1553 lsp_highlights
1554 .into_iter()
1555 .map(|lsp_highlight| {
1556 let start = buffer
1557 .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1558 let end = buffer
1559 .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1560 DocumentHighlight {
1561 range: buffer.anchor_after(start)..buffer.anchor_before(end),
1562 kind: lsp_highlight
1563 .kind
1564 .unwrap_or(lsp::DocumentHighlightKind::READ),
1565 }
1566 })
1567 .collect()
1568 }))
1569 }
1570
1571 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1572 proto::GetDocumentHighlights {
1573 project_id,
1574 buffer_id: buffer.remote_id().into(),
1575 position: Some(language::proto::serialize_anchor(
1576 &buffer.anchor_before(self.position),
1577 )),
1578 version: serialize_version(&buffer.version()),
1579 }
1580 }
1581
1582 async fn from_proto(
1583 message: proto::GetDocumentHighlights,
1584 _: Entity<LspStore>,
1585 buffer: Entity<Buffer>,
1586 mut cx: AsyncApp,
1587 ) -> Result<Self> {
1588 let position = message
1589 .position
1590 .and_then(deserialize_anchor)
1591 .context("invalid position")?;
1592 buffer
1593 .update(&mut cx, |buffer, _| {
1594 buffer.wait_for_version(deserialize_version(&message.version))
1595 })
1596 .await?;
1597 Ok(Self {
1598 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1599 })
1600 }
1601
1602 fn response_to_proto(
1603 response: Vec<DocumentHighlight>,
1604 _: &mut LspStore,
1605 _: PeerId,
1606 _: &clock::Global,
1607 _: &mut App,
1608 ) -> proto::GetDocumentHighlightsResponse {
1609 let highlights = response
1610 .into_iter()
1611 .map(|highlight| proto::DocumentHighlight {
1612 start: Some(serialize_anchor(&highlight.range.start)),
1613 end: Some(serialize_anchor(&highlight.range.end)),
1614 kind: match highlight.kind {
1615 DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1616 DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1617 DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1618 _ => proto::document_highlight::Kind::Text.into(),
1619 },
1620 })
1621 .collect();
1622 proto::GetDocumentHighlightsResponse { highlights }
1623 }
1624
1625 async fn response_from_proto(
1626 self,
1627 message: proto::GetDocumentHighlightsResponse,
1628 _: Entity<LspStore>,
1629 buffer: Entity<Buffer>,
1630 mut cx: AsyncApp,
1631 ) -> Result<Vec<DocumentHighlight>> {
1632 let mut highlights = Vec::new();
1633 for highlight in message.highlights {
1634 let start = highlight
1635 .start
1636 .and_then(deserialize_anchor)
1637 .context("missing target start")?;
1638 let end = highlight
1639 .end
1640 .and_then(deserialize_anchor)
1641 .context("missing target end")?;
1642 buffer
1643 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1644 .await?;
1645 let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1646 Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1647 Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1648 Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1649 None => DocumentHighlightKind::TEXT,
1650 };
1651 highlights.push(DocumentHighlight {
1652 range: start..end,
1653 kind,
1654 });
1655 }
1656 Ok(highlights)
1657 }
1658
1659 fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1660 BufferId::new(message.buffer_id)
1661 }
1662}
1663
1664#[async_trait(?Send)]
1665impl LspCommand for GetDocumentSymbols {
1666 type Response = Vec<DocumentSymbol>;
1667 type LspRequest = lsp::request::DocumentSymbolRequest;
1668 type ProtoRequest = proto::GetDocumentSymbols;
1669
1670 fn display_name(&self) -> &str {
1671 "Get document symbols"
1672 }
1673
1674 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1675 capabilities
1676 .server_capabilities
1677 .document_symbol_provider
1678 .is_some_and(|capability| match capability {
1679 OneOf::Left(supported) => supported,
1680 OneOf::Right(_options) => true,
1681 })
1682 }
1683
1684 fn to_lsp(
1685 &self,
1686 path: &Path,
1687 _: &Buffer,
1688 _: &Arc<LanguageServer>,
1689 _: &App,
1690 ) -> Result<lsp::DocumentSymbolParams> {
1691 Ok(lsp::DocumentSymbolParams {
1692 text_document: make_text_document_identifier(path)?,
1693 work_done_progress_params: Default::default(),
1694 partial_result_params: Default::default(),
1695 })
1696 }
1697
1698 async fn response_from_lsp(
1699 self,
1700 lsp_symbols: Option<lsp::DocumentSymbolResponse>,
1701 _: Entity<LspStore>,
1702 _: Entity<Buffer>,
1703 _: LanguageServerId,
1704 _: AsyncApp,
1705 ) -> Result<Vec<DocumentSymbol>> {
1706 let Some(lsp_symbols) = lsp_symbols else {
1707 return Ok(Vec::new());
1708 };
1709
1710 let symbols = match lsp_symbols {
1711 lsp::DocumentSymbolResponse::Flat(symbol_information) => symbol_information
1712 .into_iter()
1713 .map(|lsp_symbol| DocumentSymbol {
1714 name: lsp_symbol.name,
1715 kind: lsp_symbol.kind,
1716 range: range_from_lsp(lsp_symbol.location.range),
1717 selection_range: range_from_lsp(lsp_symbol.location.range),
1718 children: Vec::new(),
1719 })
1720 .collect(),
1721 lsp::DocumentSymbolResponse::Nested(nested_responses) => {
1722 fn convert_symbol(lsp_symbol: lsp::DocumentSymbol) -> DocumentSymbol {
1723 DocumentSymbol {
1724 name: lsp_symbol.name,
1725 kind: lsp_symbol.kind,
1726 range: range_from_lsp(lsp_symbol.range),
1727 selection_range: range_from_lsp(lsp_symbol.selection_range),
1728 children: lsp_symbol
1729 .children
1730 .map(|children| {
1731 children.into_iter().map(convert_symbol).collect::<Vec<_>>()
1732 })
1733 .unwrap_or_default(),
1734 }
1735 }
1736 nested_responses.into_iter().map(convert_symbol).collect()
1737 }
1738 };
1739 Ok(symbols)
1740 }
1741
1742 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentSymbols {
1743 proto::GetDocumentSymbols {
1744 project_id,
1745 buffer_id: buffer.remote_id().into(),
1746 version: serialize_version(&buffer.version()),
1747 }
1748 }
1749
1750 async fn from_proto(
1751 message: proto::GetDocumentSymbols,
1752 _: Entity<LspStore>,
1753 buffer: Entity<Buffer>,
1754 mut cx: AsyncApp,
1755 ) -> Result<Self> {
1756 buffer
1757 .update(&mut cx, |buffer, _| {
1758 buffer.wait_for_version(deserialize_version(&message.version))
1759 })
1760 .await?;
1761 Ok(Self)
1762 }
1763
1764 fn response_to_proto(
1765 response: Vec<DocumentSymbol>,
1766 _: &mut LspStore,
1767 _: PeerId,
1768 _: &clock::Global,
1769 _: &mut App,
1770 ) -> proto::GetDocumentSymbolsResponse {
1771 let symbols = response
1772 .into_iter()
1773 .map(|symbol| {
1774 fn convert_symbol_to_proto(symbol: DocumentSymbol) -> proto::DocumentSymbol {
1775 proto::DocumentSymbol {
1776 name: symbol.name.clone(),
1777 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
1778 start: Some(proto::PointUtf16 {
1779 row: symbol.range.start.0.row,
1780 column: symbol.range.start.0.column,
1781 }),
1782 end: Some(proto::PointUtf16 {
1783 row: symbol.range.end.0.row,
1784 column: symbol.range.end.0.column,
1785 }),
1786 selection_start: Some(proto::PointUtf16 {
1787 row: symbol.selection_range.start.0.row,
1788 column: symbol.selection_range.start.0.column,
1789 }),
1790 selection_end: Some(proto::PointUtf16 {
1791 row: symbol.selection_range.end.0.row,
1792 column: symbol.selection_range.end.0.column,
1793 }),
1794 children: symbol
1795 .children
1796 .into_iter()
1797 .map(convert_symbol_to_proto)
1798 .collect(),
1799 }
1800 }
1801 convert_symbol_to_proto(symbol)
1802 })
1803 .collect::<Vec<_>>();
1804
1805 proto::GetDocumentSymbolsResponse { symbols }
1806 }
1807
1808 async fn response_from_proto(
1809 self,
1810 message: proto::GetDocumentSymbolsResponse,
1811 _: Entity<LspStore>,
1812 _: Entity<Buffer>,
1813 _: AsyncApp,
1814 ) -> Result<Vec<DocumentSymbol>> {
1815 let mut symbols = Vec::with_capacity(message.symbols.len());
1816 for serialized_symbol in message.symbols {
1817 fn deserialize_symbol_with_children(
1818 serialized_symbol: proto::DocumentSymbol,
1819 ) -> Result<DocumentSymbol> {
1820 let kind =
1821 unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
1822
1823 let start = serialized_symbol.start.context("invalid start")?;
1824 let end = serialized_symbol.end.context("invalid end")?;
1825
1826 let selection_start = serialized_symbol
1827 .selection_start
1828 .context("invalid selection start")?;
1829 let selection_end = serialized_symbol
1830 .selection_end
1831 .context("invalid selection end")?;
1832
1833 Ok(DocumentSymbol {
1834 name: serialized_symbol.name,
1835 kind,
1836 range: Unclipped(PointUtf16::new(start.row, start.column))
1837 ..Unclipped(PointUtf16::new(end.row, end.column)),
1838 selection_range: Unclipped(PointUtf16::new(
1839 selection_start.row,
1840 selection_start.column,
1841 ))
1842 ..Unclipped(PointUtf16::new(selection_end.row, selection_end.column)),
1843 children: serialized_symbol
1844 .children
1845 .into_iter()
1846 .filter_map(|symbol| deserialize_symbol_with_children(symbol).ok())
1847 .collect::<Vec<_>>(),
1848 })
1849 }
1850
1851 symbols.push(deserialize_symbol_with_children(serialized_symbol)?);
1852 }
1853
1854 Ok(symbols)
1855 }
1856
1857 fn buffer_id_from_proto(message: &proto::GetDocumentSymbols) -> Result<BufferId> {
1858 BufferId::new(message.buffer_id)
1859 }
1860}
1861
1862#[async_trait(?Send)]
1863impl LspCommand for GetSignatureHelp {
1864 type Response = Option<SignatureHelp>;
1865 type LspRequest = lsp::SignatureHelpRequest;
1866 type ProtoRequest = proto::GetSignatureHelp;
1867
1868 fn display_name(&self) -> &str {
1869 "Get signature help"
1870 }
1871
1872 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1873 capabilities
1874 .server_capabilities
1875 .signature_help_provider
1876 .is_some()
1877 }
1878
1879 fn to_lsp(
1880 &self,
1881 path: &Path,
1882 _: &Buffer,
1883 _: &Arc<LanguageServer>,
1884 _cx: &App,
1885 ) -> Result<lsp::SignatureHelpParams> {
1886 Ok(lsp::SignatureHelpParams {
1887 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1888 context: None,
1889 work_done_progress_params: Default::default(),
1890 })
1891 }
1892
1893 async fn response_from_lsp(
1894 self,
1895 message: Option<lsp::SignatureHelp>,
1896 lsp_store: Entity<LspStore>,
1897 _: Entity<Buffer>,
1898 id: LanguageServerId,
1899 cx: AsyncApp,
1900 ) -> Result<Self::Response> {
1901 let Some(message) = message else {
1902 return Ok(None);
1903 };
1904 Ok(cx.update(|cx| {
1905 SignatureHelp::new(
1906 message,
1907 Some(lsp_store.read(cx).languages.clone()),
1908 Some(id),
1909 cx,
1910 )
1911 }))
1912 }
1913
1914 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1915 let offset = buffer.point_utf16_to_offset(self.position);
1916 proto::GetSignatureHelp {
1917 project_id,
1918 buffer_id: buffer.remote_id().to_proto(),
1919 position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1920 version: serialize_version(&buffer.version()),
1921 }
1922 }
1923
1924 async fn from_proto(
1925 payload: Self::ProtoRequest,
1926 _: Entity<LspStore>,
1927 buffer: Entity<Buffer>,
1928 mut cx: AsyncApp,
1929 ) -> Result<Self> {
1930 buffer
1931 .update(&mut cx, |buffer, _| {
1932 buffer.wait_for_version(deserialize_version(&payload.version))
1933 })
1934 .await
1935 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1936 let buffer_snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
1937 Ok(Self {
1938 position: payload
1939 .position
1940 .and_then(deserialize_anchor)
1941 .context("invalid position")?
1942 .to_point_utf16(&buffer_snapshot),
1943 })
1944 }
1945
1946 fn response_to_proto(
1947 response: Self::Response,
1948 _: &mut LspStore,
1949 _: PeerId,
1950 _: &Global,
1951 _: &mut App,
1952 ) -> proto::GetSignatureHelpResponse {
1953 proto::GetSignatureHelpResponse {
1954 signature_help: response
1955 .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1956 }
1957 }
1958
1959 async fn response_from_proto(
1960 self,
1961 response: proto::GetSignatureHelpResponse,
1962 lsp_store: Entity<LspStore>,
1963 _: Entity<Buffer>,
1964 cx: AsyncApp,
1965 ) -> Result<Self::Response> {
1966 Ok(cx.update(|cx| {
1967 response
1968 .signature_help
1969 .map(proto_to_lsp_signature)
1970 .and_then(|signature| {
1971 SignatureHelp::new(
1972 signature,
1973 Some(lsp_store.read(cx).languages.clone()),
1974 None,
1975 cx,
1976 )
1977 })
1978 }))
1979 }
1980
1981 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1982 BufferId::new(message.buffer_id)
1983 }
1984}
1985
1986#[async_trait(?Send)]
1987impl LspCommand for GetHover {
1988 type Response = Option<Hover>;
1989 type LspRequest = lsp::request::HoverRequest;
1990 type ProtoRequest = proto::GetHover;
1991
1992 fn display_name(&self) -> &str {
1993 "Get hover"
1994 }
1995
1996 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1997 match capabilities.server_capabilities.hover_provider {
1998 Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1999 Some(lsp::HoverProviderCapability::Options(_)) => true,
2000 None => false,
2001 }
2002 }
2003
2004 fn to_lsp(
2005 &self,
2006 path: &Path,
2007 _: &Buffer,
2008 _: &Arc<LanguageServer>,
2009 _: &App,
2010 ) -> Result<lsp::HoverParams> {
2011 Ok(lsp::HoverParams {
2012 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
2013 work_done_progress_params: Default::default(),
2014 })
2015 }
2016
2017 async fn response_from_lsp(
2018 self,
2019 message: Option<lsp::Hover>,
2020 _: Entity<LspStore>,
2021 buffer: Entity<Buffer>,
2022 _: LanguageServerId,
2023 cx: AsyncApp,
2024 ) -> Result<Self::Response> {
2025 let Some(hover) = message else {
2026 return Ok(None);
2027 };
2028
2029 let (language, range) = buffer.read_with(&cx, |buffer, _| {
2030 (
2031 buffer.language().cloned(),
2032 hover.range.map(|range| {
2033 let token_start =
2034 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
2035 let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
2036 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
2037 }),
2038 )
2039 });
2040
2041 fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
2042 let block = match marked_string {
2043 lsp::MarkedString::String(content) => HoverBlock {
2044 text: content,
2045 kind: HoverBlockKind::Markdown,
2046 },
2047 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
2048 HoverBlock {
2049 text: value,
2050 kind: HoverBlockKind::Code { language },
2051 }
2052 }
2053 };
2054 if block.text.is_empty() {
2055 None
2056 } else {
2057 Some(block)
2058 }
2059 }
2060
2061 let contents = match hover.contents {
2062 lsp::HoverContents::Scalar(marked_string) => {
2063 hover_blocks_from_marked_string(marked_string)
2064 .into_iter()
2065 .collect()
2066 }
2067 lsp::HoverContents::Array(marked_strings) => marked_strings
2068 .into_iter()
2069 .filter_map(hover_blocks_from_marked_string)
2070 .collect(),
2071 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
2072 text: markup_content.value,
2073 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
2074 HoverBlockKind::Markdown
2075 } else {
2076 HoverBlockKind::PlainText
2077 },
2078 }],
2079 };
2080
2081 Ok(Some(Hover {
2082 contents,
2083 range,
2084 language,
2085 }))
2086 }
2087
2088 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
2089 proto::GetHover {
2090 project_id,
2091 buffer_id: buffer.remote_id().into(),
2092 position: Some(language::proto::serialize_anchor(
2093 &buffer.anchor_before(self.position),
2094 )),
2095 version: serialize_version(&buffer.version),
2096 }
2097 }
2098
2099 async fn from_proto(
2100 message: Self::ProtoRequest,
2101 _: Entity<LspStore>,
2102 buffer: Entity<Buffer>,
2103 mut cx: AsyncApp,
2104 ) -> Result<Self> {
2105 let position = message
2106 .position
2107 .and_then(deserialize_anchor)
2108 .context("invalid position")?;
2109 buffer
2110 .update(&mut cx, |buffer, _| {
2111 buffer.wait_for_version(deserialize_version(&message.version))
2112 })
2113 .await?;
2114 Ok(Self {
2115 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
2116 })
2117 }
2118
2119 fn response_to_proto(
2120 response: Self::Response,
2121 _: &mut LspStore,
2122 _: PeerId,
2123 _: &clock::Global,
2124 _: &mut App,
2125 ) -> proto::GetHoverResponse {
2126 if let Some(response) = response {
2127 let (start, end) = if let Some(range) = response.range {
2128 (
2129 Some(language::proto::serialize_anchor(&range.start)),
2130 Some(language::proto::serialize_anchor(&range.end)),
2131 )
2132 } else {
2133 (None, None)
2134 };
2135
2136 let contents = response
2137 .contents
2138 .into_iter()
2139 .map(|block| proto::HoverBlock {
2140 text: block.text,
2141 is_markdown: block.kind == HoverBlockKind::Markdown,
2142 language: if let HoverBlockKind::Code { language } = block.kind {
2143 Some(language)
2144 } else {
2145 None
2146 },
2147 })
2148 .collect();
2149
2150 proto::GetHoverResponse {
2151 start,
2152 end,
2153 contents,
2154 }
2155 } else {
2156 proto::GetHoverResponse {
2157 start: None,
2158 end: None,
2159 contents: Vec::new(),
2160 }
2161 }
2162 }
2163
2164 async fn response_from_proto(
2165 self,
2166 message: proto::GetHoverResponse,
2167 _: Entity<LspStore>,
2168 buffer: Entity<Buffer>,
2169 mut cx: AsyncApp,
2170 ) -> Result<Self::Response> {
2171 let contents: Vec<_> = message
2172 .contents
2173 .into_iter()
2174 .map(|block| HoverBlock {
2175 text: block.text,
2176 kind: if let Some(language) = block.language {
2177 HoverBlockKind::Code { language }
2178 } else if block.is_markdown {
2179 HoverBlockKind::Markdown
2180 } else {
2181 HoverBlockKind::PlainText
2182 },
2183 })
2184 .collect();
2185 if contents.is_empty() {
2186 return Ok(None);
2187 }
2188
2189 let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
2190 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
2191 language::proto::deserialize_anchor(start)
2192 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
2193 } else {
2194 None
2195 };
2196 if let Some(range) = range.as_ref() {
2197 buffer
2198 .update(&mut cx, |buffer, _| {
2199 buffer.wait_for_anchors([range.start, range.end])
2200 })
2201 .await?;
2202 }
2203
2204 Ok(Some(Hover {
2205 contents,
2206 range,
2207 language,
2208 }))
2209 }
2210
2211 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
2212 BufferId::new(message.buffer_id)
2213 }
2214}
2215
2216impl GetCompletions {
2217 pub fn can_resolve_completions(capabilities: &lsp::ServerCapabilities) -> bool {
2218 capabilities
2219 .completion_provider
2220 .as_ref()
2221 .and_then(|options| options.resolve_provider)
2222 .unwrap_or(false)
2223 }
2224}
2225
2226#[async_trait(?Send)]
2227impl LspCommand for GetCompletions {
2228 type Response = CoreCompletionResponse;
2229 type LspRequest = lsp::request::Completion;
2230 type ProtoRequest = proto::GetCompletions;
2231
2232 fn display_name(&self) -> &str {
2233 "Get completion"
2234 }
2235
2236 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2237 capabilities
2238 .server_capabilities
2239 .completion_provider
2240 .is_some()
2241 }
2242
2243 fn to_lsp(
2244 &self,
2245 path: &Path,
2246 _: &Buffer,
2247 _: &Arc<LanguageServer>,
2248 _: &App,
2249 ) -> Result<lsp::CompletionParams> {
2250 Ok(lsp::CompletionParams {
2251 text_document_position: make_lsp_text_document_position(path, self.position)?,
2252 context: Some(self.context.clone()),
2253 work_done_progress_params: Default::default(),
2254 partial_result_params: Default::default(),
2255 })
2256 }
2257
2258 async fn response_from_lsp(
2259 self,
2260 completions: Option<lsp::CompletionResponse>,
2261 lsp_store: Entity<LspStore>,
2262 buffer: Entity<Buffer>,
2263 server_id: LanguageServerId,
2264 mut cx: AsyncApp,
2265 ) -> Result<Self::Response> {
2266 let mut response_list = None;
2267 let (mut completions, mut is_incomplete) = if let Some(completions) = completions {
2268 match completions {
2269 lsp::CompletionResponse::Array(completions) => (completions, false),
2270 lsp::CompletionResponse::List(mut list) => {
2271 let is_incomplete = list.is_incomplete;
2272 let items = std::mem::take(&mut list.items);
2273 response_list = Some(list);
2274 (items, is_incomplete)
2275 }
2276 }
2277 } else {
2278 (Vec::new(), false)
2279 };
2280
2281 let unfiltered_completions_count = completions.len();
2282
2283 let language_server_adapter = lsp_store
2284 .read_with(&cx, |lsp_store, _| {
2285 lsp_store.language_server_adapter_for_id(server_id)
2286 })
2287 .with_context(|| format!("no language server with id {server_id}"))?;
2288
2289 let lsp_defaults = response_list
2290 .as_ref()
2291 .and_then(|list| list.item_defaults.clone())
2292 .map(Arc::new);
2293
2294 let mut completion_edits = Vec::new();
2295 buffer.update(&mut cx, |buffer, _cx| {
2296 let snapshot = buffer.snapshot();
2297 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
2298
2299 let mut range_for_token = None;
2300 completions.retain(|lsp_completion| {
2301 let lsp_edit = lsp_completion.text_edit.clone().or_else(|| {
2302 let default_text_edit = lsp_defaults.as_deref()?.edit_range.as_ref()?;
2303 let new_text = lsp_completion
2304 .text_edit_text
2305 .as_ref()
2306 .unwrap_or(&lsp_completion.label)
2307 .clone();
2308 match default_text_edit {
2309 CompletionListItemDefaultsEditRange::Range(range) => {
2310 Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
2311 range: *range,
2312 new_text,
2313 }))
2314 }
2315 CompletionListItemDefaultsEditRange::InsertAndReplace {
2316 insert,
2317 replace,
2318 } => Some(lsp::CompletionTextEdit::InsertAndReplace(
2319 lsp::InsertReplaceEdit {
2320 new_text,
2321 insert: *insert,
2322 replace: *replace,
2323 },
2324 )),
2325 }
2326 });
2327
2328 let edit = match lsp_edit {
2329 // If the language server provides a range to overwrite, then
2330 // check that the range is valid.
2331 Some(completion_text_edit) => {
2332 match parse_completion_text_edit(&completion_text_edit, &snapshot) {
2333 Some(edit) => edit,
2334 None => return false,
2335 }
2336 }
2337 // If the language server does not provide a range, then infer
2338 // the range based on the syntax tree.
2339 None => {
2340 if self.position != clipped_position {
2341 log::info!("completion out of expected range ");
2342 return false;
2343 }
2344
2345 let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
2346 lsp_defaults
2347 .edit_range
2348 .as_ref()
2349 .and_then(|range| match range {
2350 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
2351 _ => None,
2352 })
2353 });
2354
2355 let range = if let Some(range) = default_edit_range {
2356 let range = range_from_lsp(*range);
2357 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2358 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2359 if start != range.start.0 || end != range.end.0 {
2360 log::info!("completion out of expected range");
2361 return false;
2362 }
2363
2364 snapshot.anchor_before(start)..snapshot.anchor_after(end)
2365 } else {
2366 range_for_token
2367 .get_or_insert_with(|| {
2368 let offset = self.position.to_offset(&snapshot);
2369 let (range, kind) = snapshot.surrounding_word(
2370 offset,
2371 Some(CharScopeContext::Completion),
2372 );
2373 let range = if kind == Some(CharKind::Word) {
2374 range
2375 } else {
2376 offset..offset
2377 };
2378
2379 snapshot.anchor_before(range.start)
2380 ..snapshot.anchor_after(range.end)
2381 })
2382 .clone()
2383 };
2384
2385 // We already know text_edit is None here
2386 let text = lsp_completion
2387 .insert_text
2388 .as_ref()
2389 .unwrap_or(&lsp_completion.label)
2390 .clone();
2391
2392 ParsedCompletionEdit {
2393 replace_range: range,
2394 insert_range: None,
2395 new_text: text,
2396 }
2397 }
2398 };
2399
2400 completion_edits.push(edit);
2401 true
2402 });
2403 });
2404
2405 // If completions were filtered out due to errors that may be transient, mark the result
2406 // incomplete so that it is re-queried.
2407 if unfiltered_completions_count != completions.len() {
2408 is_incomplete = true;
2409 }
2410
2411 language_server_adapter
2412 .process_completions(&mut completions)
2413 .await;
2414
2415 let completions = completions
2416 .into_iter()
2417 .zip(completion_edits)
2418 .map(|(mut lsp_completion, mut edit)| {
2419 LineEnding::normalize(&mut edit.new_text);
2420 if lsp_completion.data.is_none()
2421 && let Some(default_data) = lsp_defaults
2422 .as_ref()
2423 .and_then(|item_defaults| item_defaults.data.clone())
2424 {
2425 // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
2426 // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
2427 lsp_completion.data = Some(default_data);
2428 }
2429 CoreCompletion {
2430 replace_range: edit.replace_range,
2431 new_text: edit.new_text,
2432 source: CompletionSource::Lsp {
2433 insert_range: edit.insert_range,
2434 server_id,
2435 lsp_completion: Box::new(lsp_completion),
2436 lsp_defaults: lsp_defaults.clone(),
2437 resolved: false,
2438 },
2439 }
2440 })
2441 .collect();
2442
2443 Ok(CoreCompletionResponse {
2444 completions,
2445 is_incomplete,
2446 })
2447 }
2448
2449 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2450 let anchor = buffer.anchor_after(self.position);
2451 proto::GetCompletions {
2452 project_id,
2453 buffer_id: buffer.remote_id().into(),
2454 position: Some(language::proto::serialize_anchor(&anchor)),
2455 version: serialize_version(&buffer.version()),
2456 server_id: self.server_id.map(|id| id.to_proto()),
2457 }
2458 }
2459
2460 async fn from_proto(
2461 message: proto::GetCompletions,
2462 _: Entity<LspStore>,
2463 buffer: Entity<Buffer>,
2464 mut cx: AsyncApp,
2465 ) -> Result<Self> {
2466 let version = deserialize_version(&message.version);
2467 buffer
2468 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
2469 .await?;
2470 let position = message
2471 .position
2472 .and_then(language::proto::deserialize_anchor)
2473 .map(|p| {
2474 buffer.read_with(&cx, |buffer, _| {
2475 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2476 })
2477 })
2478 .context("invalid position")?;
2479 Ok(Self {
2480 position,
2481 context: CompletionContext {
2482 trigger_kind: CompletionTriggerKind::INVOKED,
2483 trigger_character: None,
2484 },
2485 server_id: message
2486 .server_id
2487 .map(|id| lsp::LanguageServerId::from_proto(id)),
2488 })
2489 }
2490
2491 fn response_to_proto(
2492 response: CoreCompletionResponse,
2493 _: &mut LspStore,
2494 _: PeerId,
2495 buffer_version: &clock::Global,
2496 _: &mut App,
2497 ) -> proto::GetCompletionsResponse {
2498 proto::GetCompletionsResponse {
2499 completions: response
2500 .completions
2501 .iter()
2502 .map(LspStore::serialize_completion)
2503 .collect(),
2504 version: serialize_version(buffer_version),
2505 can_reuse: !response.is_incomplete,
2506 }
2507 }
2508
2509 async fn response_from_proto(
2510 self,
2511 message: proto::GetCompletionsResponse,
2512 _project: Entity<LspStore>,
2513 buffer: Entity<Buffer>,
2514 mut cx: AsyncApp,
2515 ) -> Result<Self::Response> {
2516 buffer
2517 .update(&mut cx, |buffer, _| {
2518 buffer.wait_for_version(deserialize_version(&message.version))
2519 })
2520 .await?;
2521
2522 let completions = message
2523 .completions
2524 .into_iter()
2525 .map(LspStore::deserialize_completion)
2526 .collect::<Result<Vec<_>>>()?;
2527
2528 Ok(CoreCompletionResponse {
2529 completions,
2530 is_incomplete: !message.can_reuse,
2531 })
2532 }
2533
2534 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2535 BufferId::new(message.buffer_id)
2536 }
2537}
2538
2539pub struct ParsedCompletionEdit {
2540 pub replace_range: Range<Anchor>,
2541 pub insert_range: Option<Range<Anchor>>,
2542 pub new_text: String,
2543}
2544
2545pub(crate) fn parse_completion_text_edit(
2546 edit: &lsp::CompletionTextEdit,
2547 snapshot: &BufferSnapshot,
2548) -> Option<ParsedCompletionEdit> {
2549 let (replace_range, insert_range, new_text) = match edit {
2550 lsp::CompletionTextEdit::Edit(edit) => (edit.range, None, &edit.new_text),
2551 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2552 (edit.replace, Some(edit.insert), &edit.new_text)
2553 }
2554 };
2555
2556 let replace_range = {
2557 let range = range_from_lsp(replace_range);
2558 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2559 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2560 if start != range.start.0 || end != range.end.0 {
2561 log::info!(
2562 "completion out of expected range, start: {start:?}, end: {end:?}, range: {range:?}"
2563 );
2564 return None;
2565 }
2566 snapshot.anchor_before(start)..snapshot.anchor_after(end)
2567 };
2568
2569 let insert_range = match insert_range {
2570 None => None,
2571 Some(insert_range) => {
2572 let range = range_from_lsp(insert_range);
2573 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2574 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2575 if start != range.start.0 || end != range.end.0 {
2576 log::info!("completion (insert) out of expected range");
2577 return None;
2578 }
2579 Some(snapshot.anchor_before(start)..snapshot.anchor_after(end))
2580 }
2581 };
2582
2583 Some(ParsedCompletionEdit {
2584 insert_range,
2585 replace_range,
2586 new_text: new_text.clone(),
2587 })
2588}
2589
2590#[async_trait(?Send)]
2591impl LspCommand for GetCodeActions {
2592 type Response = Vec<CodeAction>;
2593 type LspRequest = lsp::request::CodeActionRequest;
2594 type ProtoRequest = proto::GetCodeActions;
2595
2596 fn display_name(&self) -> &str {
2597 "Get code actions"
2598 }
2599
2600 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2601 match &capabilities.server_capabilities.code_action_provider {
2602 None => false,
2603 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2604 _ => {
2605 // If we do know that we want specific code actions AND we know that
2606 // the server only supports specific code actions, then we want to filter
2607 // down to the ones that are supported.
2608 if let Some((requested, supported)) = self
2609 .kinds
2610 .as_ref()
2611 .zip(Self::supported_code_action_kinds(capabilities))
2612 {
2613 requested.iter().any(|requested_kind| {
2614 supported.iter().any(|supported_kind| {
2615 code_action_kind_matches(requested_kind, supported_kind)
2616 })
2617 })
2618 } else {
2619 true
2620 }
2621 }
2622 }
2623 }
2624
2625 fn to_lsp(
2626 &self,
2627 path: &Path,
2628 buffer: &Buffer,
2629 language_server: &Arc<LanguageServer>,
2630 _: &App,
2631 ) -> Result<lsp::CodeActionParams> {
2632 let mut relevant_diagnostics = Vec::new();
2633 for entry in buffer
2634 .snapshot()
2635 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2636 {
2637 relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2638 }
2639
2640 let only = if let Some(requested) = &self.kinds {
2641 if let Some(supported_kinds) =
2642 Self::supported_code_action_kinds(language_server.adapter_server_capabilities())
2643 {
2644 let filtered = requested
2645 .iter()
2646 .filter(|requested_kind| {
2647 supported_kinds.iter().any(|supported_kind| {
2648 code_action_kind_matches(requested_kind, supported_kind)
2649 })
2650 })
2651 .cloned()
2652 .collect();
2653 Some(filtered)
2654 } else {
2655 Some(requested.clone())
2656 }
2657 } else {
2658 None
2659 };
2660
2661 Ok(lsp::CodeActionParams {
2662 text_document: make_text_document_identifier(path)?,
2663 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2664 work_done_progress_params: Default::default(),
2665 partial_result_params: Default::default(),
2666 context: lsp::CodeActionContext {
2667 diagnostics: relevant_diagnostics,
2668 only,
2669 ..lsp::CodeActionContext::default()
2670 },
2671 })
2672 }
2673
2674 async fn response_from_lsp(
2675 self,
2676 actions: Option<lsp::CodeActionResponse>,
2677 lsp_store: Entity<LspStore>,
2678 _: Entity<Buffer>,
2679 server_id: LanguageServerId,
2680 cx: AsyncApp,
2681 ) -> Result<Vec<CodeAction>> {
2682 let requested_kinds = self.kinds.as_ref();
2683
2684 let language_server = cx.update(|cx| {
2685 lsp_store
2686 .read(cx)
2687 .language_server_for_id(server_id)
2688 .with_context(|| {
2689 format!("Missing the language server that just returned a response {server_id}")
2690 })
2691 })?;
2692
2693 let server_capabilities = language_server.capabilities();
2694 let available_commands = server_capabilities
2695 .execute_command_provider
2696 .as_ref()
2697 .map(|options| options.commands.as_slice())
2698 .unwrap_or_default();
2699 Ok(actions
2700 .unwrap_or_default()
2701 .into_iter()
2702 .filter_map(|entry| {
2703 let (lsp_action, resolved) = match entry {
2704 lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2705 if let Some(command) = lsp_action.command.as_ref()
2706 && !available_commands.contains(&command.command)
2707 {
2708 return None;
2709 }
2710 (LspAction::Action(Box::new(lsp_action)), false)
2711 }
2712 lsp::CodeActionOrCommand::Command(command) => {
2713 if available_commands.contains(&command.command) {
2714 (LspAction::Command(command), true)
2715 } else {
2716 return None;
2717 }
2718 }
2719 };
2720
2721 if let Some((kinds, kind)) = requested_kinds.zip(lsp_action.action_kind())
2722 && !kinds
2723 .iter()
2724 .any(|requested_kind| code_action_kind_matches(requested_kind, &kind))
2725 {
2726 return None;
2727 }
2728
2729 Some(CodeAction {
2730 server_id,
2731 range: self.range.clone(),
2732 lsp_action,
2733 resolved,
2734 })
2735 })
2736 .collect())
2737 }
2738
2739 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2740 proto::GetCodeActions {
2741 project_id,
2742 buffer_id: buffer.remote_id().into(),
2743 start: Some(language::proto::serialize_anchor(&self.range.start)),
2744 end: Some(language::proto::serialize_anchor(&self.range.end)),
2745 version: serialize_version(&buffer.version()),
2746 }
2747 }
2748
2749 async fn from_proto(
2750 message: proto::GetCodeActions,
2751 _: Entity<LspStore>,
2752 buffer: Entity<Buffer>,
2753 mut cx: AsyncApp,
2754 ) -> Result<Self> {
2755 let start = message
2756 .start
2757 .and_then(language::proto::deserialize_anchor)
2758 .context("invalid start")?;
2759 let end = message
2760 .end
2761 .and_then(language::proto::deserialize_anchor)
2762 .context("invalid end")?;
2763 buffer
2764 .update(&mut cx, |buffer, _| {
2765 buffer.wait_for_version(deserialize_version(&message.version))
2766 })
2767 .await?;
2768
2769 Ok(Self {
2770 range: start..end,
2771 kinds: None,
2772 })
2773 }
2774
2775 fn response_to_proto(
2776 code_actions: Vec<CodeAction>,
2777 _: &mut LspStore,
2778 _: PeerId,
2779 buffer_version: &clock::Global,
2780 _: &mut App,
2781 ) -> proto::GetCodeActionsResponse {
2782 proto::GetCodeActionsResponse {
2783 actions: code_actions
2784 .iter()
2785 .map(LspStore::serialize_code_action)
2786 .collect(),
2787 version: serialize_version(buffer_version),
2788 }
2789 }
2790
2791 async fn response_from_proto(
2792 self,
2793 message: proto::GetCodeActionsResponse,
2794 _: Entity<LspStore>,
2795 buffer: Entity<Buffer>,
2796 mut cx: AsyncApp,
2797 ) -> Result<Vec<CodeAction>> {
2798 buffer
2799 .update(&mut cx, |buffer, _| {
2800 buffer.wait_for_version(deserialize_version(&message.version))
2801 })
2802 .await?;
2803 message
2804 .actions
2805 .into_iter()
2806 .map(LspStore::deserialize_code_action)
2807 .collect()
2808 }
2809
2810 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2811 BufferId::new(message.buffer_id)
2812 }
2813}
2814
2815impl GetCodeActions {
2816 fn supported_code_action_kinds(
2817 capabilities: AdapterServerCapabilities,
2818 ) -> Option<Vec<CodeActionKind>> {
2819 match capabilities.server_capabilities.code_action_provider {
2820 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2821 code_action_kinds: Some(supported_action_kinds),
2822 ..
2823 })) => Some(supported_action_kinds),
2824 _ => capabilities.code_action_kinds,
2825 }
2826 }
2827
2828 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2829 capabilities
2830 .code_action_provider
2831 .as_ref()
2832 .and_then(|options| match options {
2833 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2834 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2835 })
2836 .unwrap_or(false)
2837 }
2838}
2839
2840impl OnTypeFormatting {
2841 pub fn supports_on_type_formatting(trigger: &str, capabilities: &ServerCapabilities) -> bool {
2842 let Some(on_type_formatting_options) = &capabilities.document_on_type_formatting_provider
2843 else {
2844 return false;
2845 };
2846 on_type_formatting_options
2847 .first_trigger_character
2848 .contains(trigger)
2849 || on_type_formatting_options
2850 .more_trigger_character
2851 .iter()
2852 .flatten()
2853 .any(|chars| chars.contains(trigger))
2854 }
2855}
2856
2857#[async_trait(?Send)]
2858impl LspCommand for OnTypeFormatting {
2859 type Response = Option<Transaction>;
2860 type LspRequest = lsp::request::OnTypeFormatting;
2861 type ProtoRequest = proto::OnTypeFormatting;
2862
2863 fn display_name(&self) -> &str {
2864 "Formatting on typing"
2865 }
2866
2867 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2868 Self::supports_on_type_formatting(&self.trigger, &capabilities.server_capabilities)
2869 }
2870
2871 fn to_lsp(
2872 &self,
2873 path: &Path,
2874 _: &Buffer,
2875 _: &Arc<LanguageServer>,
2876 _: &App,
2877 ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2878 Ok(lsp::DocumentOnTypeFormattingParams {
2879 text_document_position: make_lsp_text_document_position(path, self.position)?,
2880 ch: self.trigger.clone(),
2881 options: self.options.clone(),
2882 })
2883 }
2884
2885 async fn response_from_lsp(
2886 self,
2887 message: Option<Vec<lsp::TextEdit>>,
2888 lsp_store: Entity<LspStore>,
2889 buffer: Entity<Buffer>,
2890 server_id: LanguageServerId,
2891 mut cx: AsyncApp,
2892 ) -> Result<Option<Transaction>> {
2893 if let Some(edits) = message {
2894 let (lsp_adapter, lsp_server) =
2895 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2896 LocalLspStore::deserialize_text_edits(
2897 lsp_store,
2898 buffer,
2899 edits,
2900 self.push_to_history,
2901 lsp_adapter,
2902 lsp_server,
2903 &mut cx,
2904 )
2905 .await
2906 } else {
2907 Ok(None)
2908 }
2909 }
2910
2911 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2912 proto::OnTypeFormatting {
2913 project_id,
2914 buffer_id: buffer.remote_id().into(),
2915 position: Some(language::proto::serialize_anchor(
2916 &buffer.anchor_before(self.position),
2917 )),
2918 trigger: self.trigger.clone(),
2919 version: serialize_version(&buffer.version()),
2920 }
2921 }
2922
2923 async fn from_proto(
2924 message: proto::OnTypeFormatting,
2925 _: Entity<LspStore>,
2926 buffer: Entity<Buffer>,
2927 mut cx: AsyncApp,
2928 ) -> Result<Self> {
2929 let position = message
2930 .position
2931 .and_then(deserialize_anchor)
2932 .context("invalid position")?;
2933 buffer
2934 .update(&mut cx, |buffer, _| {
2935 buffer.wait_for_version(deserialize_version(&message.version))
2936 })
2937 .await?;
2938
2939 let options = buffer.update(&mut cx, |buffer, cx| {
2940 lsp_formatting_options(LanguageSettings::for_buffer(buffer, cx).as_ref())
2941 });
2942
2943 Ok(Self {
2944 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
2945 trigger: message.trigger.clone(),
2946 options,
2947 push_to_history: false,
2948 })
2949 }
2950
2951 fn response_to_proto(
2952 response: Option<Transaction>,
2953 _: &mut LspStore,
2954 _: PeerId,
2955 _: &clock::Global,
2956 _: &mut App,
2957 ) -> proto::OnTypeFormattingResponse {
2958 proto::OnTypeFormattingResponse {
2959 transaction: response
2960 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2961 }
2962 }
2963
2964 async fn response_from_proto(
2965 self,
2966 message: proto::OnTypeFormattingResponse,
2967 _: Entity<LspStore>,
2968 _: Entity<Buffer>,
2969 _: AsyncApp,
2970 ) -> Result<Option<Transaction>> {
2971 let Some(transaction) = message.transaction else {
2972 return Ok(None);
2973 };
2974 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2975 }
2976
2977 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2978 BufferId::new(message.buffer_id)
2979 }
2980}
2981
2982impl InlayHints {
2983 pub async fn lsp_to_project_hint(
2984 lsp_hint: lsp::InlayHint,
2985 buffer_handle: &Entity<Buffer>,
2986 server_id: LanguageServerId,
2987 resolve_state: ResolveState,
2988 force_no_type_left_padding: bool,
2989 cx: &mut AsyncApp,
2990 ) -> anyhow::Result<InlayHint> {
2991 let kind = lsp_hint.kind.and_then(|kind| match kind {
2992 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2993 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2994 _ => None,
2995 });
2996
2997 let position = buffer_handle.read_with(cx, |buffer, _| {
2998 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2999 if kind == Some(InlayHintKind::Parameter) {
3000 buffer.anchor_before(position)
3001 } else {
3002 buffer.anchor_after(position)
3003 }
3004 });
3005 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
3006 .await
3007 .context("lsp to project inlay hint conversion")?;
3008 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
3009 false
3010 } else {
3011 lsp_hint.padding_left.unwrap_or(false)
3012 };
3013
3014 Ok(InlayHint {
3015 position,
3016 padding_left,
3017 padding_right: lsp_hint.padding_right.unwrap_or(false),
3018 label,
3019 kind,
3020 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
3021 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
3022 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
3023 InlayHintTooltip::MarkupContent(MarkupContent {
3024 kind: match markup_content.kind {
3025 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
3026 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
3027 },
3028 value: markup_content.value,
3029 })
3030 }
3031 }),
3032 resolve_state,
3033 })
3034 }
3035
3036 async fn lsp_inlay_label_to_project(
3037 lsp_label: lsp::InlayHintLabel,
3038 server_id: LanguageServerId,
3039 ) -> anyhow::Result<InlayHintLabel> {
3040 let label = match lsp_label {
3041 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
3042 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
3043 let mut parts = Vec::with_capacity(lsp_parts.len());
3044 for lsp_part in lsp_parts {
3045 parts.push(InlayHintLabelPart {
3046 value: lsp_part.value,
3047 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
3048 lsp::InlayHintLabelPartTooltip::String(s) => {
3049 InlayHintLabelPartTooltip::String(s)
3050 }
3051 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3052 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3053 kind: match markup_content.kind {
3054 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
3055 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
3056 },
3057 value: markup_content.value,
3058 })
3059 }
3060 }),
3061 location: Some(server_id).zip(lsp_part.location),
3062 });
3063 }
3064 InlayHintLabel::LabelParts(parts)
3065 }
3066 };
3067
3068 Ok(label)
3069 }
3070
3071 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
3072 let (state, lsp_resolve_state) = match response_hint.resolve_state {
3073 ResolveState::Resolved => (0, None),
3074 ResolveState::CanResolve(server_id, resolve_data) => (
3075 1,
3076 Some(proto::resolve_state::LspResolveState {
3077 server_id: server_id.0 as u64,
3078 value: resolve_data.map(|json_data| {
3079 serde_json::to_string(&json_data)
3080 .expect("failed to serialize resolve json data")
3081 }),
3082 }),
3083 ),
3084 ResolveState::Resolving => (2, None),
3085 };
3086 let resolve_state = Some(proto::ResolveState {
3087 state,
3088 lsp_resolve_state,
3089 });
3090 proto::InlayHint {
3091 position: Some(language::proto::serialize_anchor(&response_hint.position)),
3092 padding_left: response_hint.padding_left,
3093 padding_right: response_hint.padding_right,
3094 label: Some(proto::InlayHintLabel {
3095 label: Some(match response_hint.label {
3096 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
3097 InlayHintLabel::LabelParts(label_parts) => {
3098 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
3099 parts: label_parts.into_iter().map(|label_part| {
3100 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
3101 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 });
3102 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 });
3103 proto::InlayHintLabelPart {
3104 value: label_part.value,
3105 tooltip: label_part.tooltip.map(|tooltip| {
3106 let proto_tooltip = match tooltip {
3107 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
3108 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
3109 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3110 value: markup_content.value,
3111 }),
3112 };
3113 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
3114 }),
3115 location_url,
3116 location_range_start,
3117 location_range_end,
3118 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
3119 }}).collect()
3120 })
3121 }
3122 }),
3123 }),
3124 kind: response_hint.kind.map(|kind| kind.name().to_string()),
3125 tooltip: response_hint.tooltip.map(|response_tooltip| {
3126 let proto_tooltip = match response_tooltip {
3127 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
3128 InlayHintTooltip::MarkupContent(markup_content) => {
3129 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
3130 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
3131 value: markup_content.value,
3132 })
3133 }
3134 };
3135 proto::InlayHintTooltip {
3136 content: Some(proto_tooltip),
3137 }
3138 }),
3139 resolve_state,
3140 }
3141 }
3142
3143 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
3144 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
3145 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
3146 });
3147 let resolve_state_data = resolve_state
3148 .lsp_resolve_state.as_ref()
3149 .map(|lsp_resolve_state| {
3150 let value = lsp_resolve_state.value.as_deref().map(|value| {
3151 serde_json::from_str::<Option<lsp::LSPAny>>(value)
3152 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
3153 }).transpose()?.flatten();
3154 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
3155 })
3156 .transpose()?;
3157 let resolve_state = match resolve_state.state {
3158 0 => ResolveState::Resolved,
3159 1 => {
3160 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
3161 format!(
3162 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
3163 )
3164 })?;
3165 ResolveState::CanResolve(server_id, lsp_resolve_state)
3166 }
3167 2 => ResolveState::Resolving,
3168 invalid => {
3169 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
3170 }
3171 };
3172 Ok(InlayHint {
3173 position: message_hint
3174 .position
3175 .and_then(language::proto::deserialize_anchor)
3176 .context("invalid position")?,
3177 label: match message_hint
3178 .label
3179 .and_then(|label| label.label)
3180 .context("missing label")?
3181 {
3182 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
3183 proto::inlay_hint_label::Label::LabelParts(parts) => {
3184 let mut label_parts = Vec::new();
3185 for part in parts.parts {
3186 label_parts.push(InlayHintLabelPart {
3187 value: part.value,
3188 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
3189 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
3190 InlayHintLabelPartTooltip::String(s)
3191 }
3192 Some(
3193 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
3194 markup_content,
3195 ),
3196 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3197 kind: if markup_content.is_markdown {
3198 HoverBlockKind::Markdown
3199 } else {
3200 HoverBlockKind::PlainText
3201 },
3202 value: markup_content.value,
3203 }),
3204 None => InlayHintLabelPartTooltip::String(String::new()),
3205 }),
3206 location: {
3207 match part
3208 .location_url
3209 .zip(
3210 part.location_range_start.and_then(|start| {
3211 Some(start..part.location_range_end?)
3212 }),
3213 )
3214 .zip(part.language_server_id)
3215 {
3216 Some(((uri, range), server_id)) => Some((
3217 LanguageServerId(server_id as usize),
3218 lsp::Location {
3219 uri: lsp::Uri::from_str(&uri).with_context(|| {
3220 format!("invalid uri in hint part {uri:?}")
3221 })?,
3222 range: lsp::Range::new(
3223 point_to_lsp(PointUtf16::new(
3224 range.start.row,
3225 range.start.column,
3226 )),
3227 point_to_lsp(PointUtf16::new(
3228 range.end.row,
3229 range.end.column,
3230 )),
3231 ),
3232 },
3233 )),
3234 None => None,
3235 }
3236 },
3237 });
3238 }
3239
3240 InlayHintLabel::LabelParts(label_parts)
3241 }
3242 },
3243 padding_left: message_hint.padding_left,
3244 padding_right: message_hint.padding_right,
3245 kind: message_hint
3246 .kind
3247 .as_deref()
3248 .and_then(InlayHintKind::from_name),
3249 tooltip: message_hint.tooltip.and_then(|tooltip| {
3250 Some(match tooltip.content? {
3251 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
3252 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3253 InlayHintTooltip::MarkupContent(MarkupContent {
3254 kind: if markup_content.is_markdown {
3255 HoverBlockKind::Markdown
3256 } else {
3257 HoverBlockKind::PlainText
3258 },
3259 value: markup_content.value,
3260 })
3261 }
3262 })
3263 }),
3264 resolve_state,
3265 })
3266 }
3267
3268 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3269 lsp::InlayHint {
3270 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3271 kind: hint.kind.map(|kind| match kind {
3272 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3273 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3274 }),
3275 text_edits: None,
3276 tooltip: hint.tooltip.and_then(|tooltip| {
3277 Some(match tooltip {
3278 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3279 InlayHintTooltip::MarkupContent(markup_content) => {
3280 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3281 kind: match markup_content.kind {
3282 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3283 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3284 HoverBlockKind::Code { .. } => return None,
3285 },
3286 value: markup_content.value,
3287 })
3288 }
3289 })
3290 }),
3291 label: match hint.label {
3292 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3293 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3294 label_parts
3295 .into_iter()
3296 .map(|part| lsp::InlayHintLabelPart {
3297 value: part.value,
3298 tooltip: part.tooltip.and_then(|tooltip| {
3299 Some(match tooltip {
3300 InlayHintLabelPartTooltip::String(s) => {
3301 lsp::InlayHintLabelPartTooltip::String(s)
3302 }
3303 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3304 lsp::InlayHintLabelPartTooltip::MarkupContent(
3305 lsp::MarkupContent {
3306 kind: match markup_content.kind {
3307 HoverBlockKind::PlainText => {
3308 lsp::MarkupKind::PlainText
3309 }
3310 HoverBlockKind::Markdown => {
3311 lsp::MarkupKind::Markdown
3312 }
3313 HoverBlockKind::Code { .. } => return None,
3314 },
3315 value: markup_content.value,
3316 },
3317 )
3318 }
3319 })
3320 }),
3321 location: part.location.map(|(_, location)| location),
3322 command: None,
3323 })
3324 .collect(),
3325 ),
3326 },
3327 padding_left: Some(hint.padding_left),
3328 padding_right: Some(hint.padding_right),
3329 data: match hint.resolve_state {
3330 ResolveState::CanResolve(_, data) => data,
3331 ResolveState::Resolving | ResolveState::Resolved => None,
3332 },
3333 }
3334 }
3335
3336 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3337 capabilities
3338 .inlay_hint_provider
3339 .as_ref()
3340 .and_then(|options| match options {
3341 OneOf::Left(_is_supported) => None,
3342 OneOf::Right(capabilities) => match capabilities {
3343 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3344 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3345 o.inlay_hint_options.resolve_provider
3346 }
3347 },
3348 })
3349 .unwrap_or(false)
3350 }
3351
3352 pub fn check_capabilities(capabilities: &ServerCapabilities) -> bool {
3353 capabilities
3354 .inlay_hint_provider
3355 .as_ref()
3356 .is_some_and(|inlay_hint_provider| match inlay_hint_provider {
3357 lsp::OneOf::Left(enabled) => *enabled,
3358 lsp::OneOf::Right(_) => true,
3359 })
3360 }
3361}
3362
3363#[async_trait(?Send)]
3364impl LspCommand for InlayHints {
3365 type Response = Vec<InlayHint>;
3366 type LspRequest = lsp::InlayHintRequest;
3367 type ProtoRequest = proto::InlayHints;
3368
3369 fn display_name(&self) -> &str {
3370 "Inlay hints"
3371 }
3372
3373 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3374 Self::check_capabilities(&capabilities.server_capabilities)
3375 }
3376
3377 fn to_lsp(
3378 &self,
3379 path: &Path,
3380 buffer: &Buffer,
3381 _: &Arc<LanguageServer>,
3382 _: &App,
3383 ) -> Result<lsp::InlayHintParams> {
3384 Ok(lsp::InlayHintParams {
3385 text_document: lsp::TextDocumentIdentifier {
3386 uri: file_path_to_lsp_url(path)?,
3387 },
3388 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3389 work_done_progress_params: Default::default(),
3390 })
3391 }
3392
3393 async fn response_from_lsp(
3394 self,
3395 message: Option<Vec<lsp::InlayHint>>,
3396 lsp_store: Entity<LspStore>,
3397 buffer: Entity<Buffer>,
3398 server_id: LanguageServerId,
3399 mut cx: AsyncApp,
3400 ) -> anyhow::Result<Vec<InlayHint>> {
3401 let (lsp_adapter, lsp_server) =
3402 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3403 // `typescript-language-server` adds padding to the left for type hints, turning
3404 // `const foo: boolean` into `const foo : boolean` which looks odd.
3405 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3406 //
3407 // We could trim the whole string, but being pessimistic on par with the situation above,
3408 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3409 // Hence let's use a heuristic first to handle the most awkward case and look for more.
3410 let force_no_type_left_padding =
3411 lsp_adapter.name.0.as_ref() == "typescript-language-server";
3412
3413 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3414 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3415 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3416 } else {
3417 ResolveState::Resolved
3418 };
3419
3420 let buffer = buffer.clone();
3421 cx.spawn(async move |cx| {
3422 InlayHints::lsp_to_project_hint(
3423 lsp_hint,
3424 &buffer,
3425 server_id,
3426 resolve_state,
3427 force_no_type_left_padding,
3428 cx,
3429 )
3430 .await
3431 })
3432 });
3433 future::join_all(hints)
3434 .await
3435 .into_iter()
3436 .collect::<anyhow::Result<_>>()
3437 .context("lsp to project inlay hints conversion")
3438 }
3439
3440 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3441 proto::InlayHints {
3442 project_id,
3443 buffer_id: buffer.remote_id().into(),
3444 start: Some(language::proto::serialize_anchor(&self.range.start)),
3445 end: Some(language::proto::serialize_anchor(&self.range.end)),
3446 version: serialize_version(&buffer.version()),
3447 }
3448 }
3449
3450 async fn from_proto(
3451 message: proto::InlayHints,
3452 _: Entity<LspStore>,
3453 buffer: Entity<Buffer>,
3454 mut cx: AsyncApp,
3455 ) -> Result<Self> {
3456 let start = message
3457 .start
3458 .and_then(language::proto::deserialize_anchor)
3459 .context("invalid start")?;
3460 let end = message
3461 .end
3462 .and_then(language::proto::deserialize_anchor)
3463 .context("invalid end")?;
3464 buffer
3465 .update(&mut cx, |buffer, _| {
3466 buffer.wait_for_version(deserialize_version(&message.version))
3467 })
3468 .await?;
3469
3470 Ok(Self { range: start..end })
3471 }
3472
3473 fn response_to_proto(
3474 response: Vec<InlayHint>,
3475 _: &mut LspStore,
3476 _: PeerId,
3477 buffer_version: &clock::Global,
3478 _: &mut App,
3479 ) -> proto::InlayHintsResponse {
3480 proto::InlayHintsResponse {
3481 hints: response
3482 .into_iter()
3483 .map(InlayHints::project_to_proto_hint)
3484 .collect(),
3485 version: serialize_version(buffer_version),
3486 }
3487 }
3488
3489 async fn response_from_proto(
3490 self,
3491 message: proto::InlayHintsResponse,
3492 _: Entity<LspStore>,
3493 buffer: Entity<Buffer>,
3494 mut cx: AsyncApp,
3495 ) -> anyhow::Result<Vec<InlayHint>> {
3496 buffer
3497 .update(&mut cx, |buffer, _| {
3498 buffer.wait_for_version(deserialize_version(&message.version))
3499 })
3500 .await?;
3501
3502 let mut hints = Vec::new();
3503 for message_hint in message.hints {
3504 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3505 }
3506
3507 Ok(hints)
3508 }
3509
3510 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3511 BufferId::new(message.buffer_id)
3512 }
3513}
3514
3515#[async_trait(?Send)]
3516impl LspCommand for SemanticTokensFull {
3517 type Response = SemanticTokensResponse;
3518 type LspRequest = lsp::SemanticTokensFullRequest;
3519 type ProtoRequest = proto::SemanticTokens;
3520
3521 fn display_name(&self) -> &str {
3522 "Semantic tokens full"
3523 }
3524
3525 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3526 capabilities
3527 .server_capabilities
3528 .semantic_tokens_provider
3529 .as_ref()
3530 .is_some_and(|semantic_tokens_provider| {
3531 let options = match semantic_tokens_provider {
3532 lsp::SemanticTokensServerCapabilities::SemanticTokensOptions(opts) => opts,
3533 lsp::SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
3534 opts,
3535 ) => &opts.semantic_tokens_options,
3536 };
3537
3538 match options.full {
3539 Some(lsp::SemanticTokensFullOptions::Bool(is_supported)) => is_supported,
3540 Some(lsp::SemanticTokensFullOptions::Delta { .. }) => true,
3541 None => false,
3542 }
3543 })
3544 }
3545
3546 fn to_lsp(
3547 &self,
3548 path: &Path,
3549 _: &Buffer,
3550 _: &Arc<LanguageServer>,
3551 _: &App,
3552 ) -> Result<lsp::SemanticTokensParams> {
3553 Ok(lsp::SemanticTokensParams {
3554 text_document: lsp::TextDocumentIdentifier {
3555 uri: file_path_to_lsp_url(path)?,
3556 },
3557 partial_result_params: Default::default(),
3558 work_done_progress_params: Default::default(),
3559 })
3560 }
3561
3562 async fn response_from_lsp(
3563 self,
3564 message: Option<lsp::SemanticTokensResult>,
3565 _: Entity<LspStore>,
3566 _: Entity<Buffer>,
3567 _: LanguageServerId,
3568 _: AsyncApp,
3569 ) -> anyhow::Result<SemanticTokensResponse> {
3570 match message {
3571 Some(lsp::SemanticTokensResult::Tokens(tokens)) => Ok(SemanticTokensResponse::Full {
3572 data: tokens.data,
3573 result_id: tokens.result_id.map(SharedString::new),
3574 }),
3575 Some(lsp::SemanticTokensResult::Partial(_)) => {
3576 anyhow::bail!(
3577 "Unexpected semantic tokens response with partial result for inlay hints"
3578 )
3579 }
3580 None => Ok(Default::default()),
3581 }
3582 }
3583
3584 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::SemanticTokens {
3585 proto::SemanticTokens {
3586 project_id,
3587 buffer_id: buffer.remote_id().into(),
3588 version: serialize_version(&buffer.version()),
3589 for_server: self.for_server.map(|id| id.to_proto()),
3590 }
3591 }
3592
3593 async fn from_proto(
3594 message: proto::SemanticTokens,
3595 _: Entity<LspStore>,
3596 buffer: Entity<Buffer>,
3597 mut cx: AsyncApp,
3598 ) -> Result<Self> {
3599 buffer
3600 .update(&mut cx, |buffer, _| {
3601 buffer.wait_for_version(deserialize_version(&message.version))
3602 })
3603 .await?;
3604
3605 Ok(Self {
3606 for_server: message
3607 .for_server
3608 .map(|id| LanguageServerId::from_proto(id)),
3609 })
3610 }
3611
3612 fn response_to_proto(
3613 response: SemanticTokensResponse,
3614 _: &mut LspStore,
3615 _: PeerId,
3616 buffer_version: &clock::Global,
3617 _: &mut App,
3618 ) -> proto::SemanticTokensResponse {
3619 match response {
3620 SemanticTokensResponse::Full { data, result_id } => proto::SemanticTokensResponse {
3621 data,
3622 edits: Vec::new(),
3623 result_id: result_id.map(|s| s.to_string()),
3624 version: serialize_version(buffer_version),
3625 },
3626 SemanticTokensResponse::Delta { edits, result_id } => proto::SemanticTokensResponse {
3627 data: Vec::new(),
3628 edits: edits
3629 .into_iter()
3630 .map(|edit| proto::SemanticTokensEdit {
3631 start: edit.start,
3632 delete_count: edit.delete_count,
3633 data: edit.data,
3634 })
3635 .collect(),
3636 result_id: result_id.map(|s| s.to_string()),
3637 version: serialize_version(buffer_version),
3638 },
3639 }
3640 }
3641
3642 async fn response_from_proto(
3643 self,
3644 message: proto::SemanticTokensResponse,
3645 _: Entity<LspStore>,
3646 buffer: Entity<Buffer>,
3647 mut cx: AsyncApp,
3648 ) -> anyhow::Result<SemanticTokensResponse> {
3649 buffer
3650 .update(&mut cx, |buffer, _| {
3651 buffer.wait_for_version(deserialize_version(&message.version))
3652 })
3653 .await?;
3654
3655 Ok(SemanticTokensResponse::Full {
3656 data: message.data,
3657 result_id: message.result_id.map(SharedString::new),
3658 })
3659 }
3660
3661 fn buffer_id_from_proto(message: &proto::SemanticTokens) -> Result<BufferId> {
3662 BufferId::new(message.buffer_id)
3663 }
3664}
3665
3666#[async_trait(?Send)]
3667impl LspCommand for SemanticTokensDelta {
3668 type Response = SemanticTokensResponse;
3669 type LspRequest = lsp::SemanticTokensFullDeltaRequest;
3670 type ProtoRequest = proto::SemanticTokens;
3671
3672 fn display_name(&self) -> &str {
3673 "Semantic tokens delta"
3674 }
3675
3676 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3677 capabilities
3678 .server_capabilities
3679 .semantic_tokens_provider
3680 .as_ref()
3681 .is_some_and(|semantic_tokens_provider| {
3682 let options = match semantic_tokens_provider {
3683 lsp::SemanticTokensServerCapabilities::SemanticTokensOptions(opts) => opts,
3684 lsp::SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
3685 opts,
3686 ) => &opts.semantic_tokens_options,
3687 };
3688
3689 match options.full {
3690 Some(lsp::SemanticTokensFullOptions::Delta { delta }) => delta.unwrap_or(false),
3691 // `full: true` (instead of `full: { delta: true }`) means no support for delta.
3692 _ => false,
3693 }
3694 })
3695 }
3696
3697 fn to_lsp(
3698 &self,
3699 path: &Path,
3700 _: &Buffer,
3701 _: &Arc<LanguageServer>,
3702 _: &App,
3703 ) -> Result<lsp::SemanticTokensDeltaParams> {
3704 Ok(lsp::SemanticTokensDeltaParams {
3705 text_document: lsp::TextDocumentIdentifier {
3706 uri: file_path_to_lsp_url(path)?,
3707 },
3708 previous_result_id: self.previous_result_id.clone().map(|s| s.to_string()),
3709 partial_result_params: Default::default(),
3710 work_done_progress_params: Default::default(),
3711 })
3712 }
3713
3714 async fn response_from_lsp(
3715 self,
3716 message: Option<lsp::SemanticTokensFullDeltaResult>,
3717 _: Entity<LspStore>,
3718 _: Entity<Buffer>,
3719 _: LanguageServerId,
3720 _: AsyncApp,
3721 ) -> anyhow::Result<SemanticTokensResponse> {
3722 match message {
3723 Some(lsp::SemanticTokensFullDeltaResult::Tokens(tokens)) => {
3724 Ok(SemanticTokensResponse::Full {
3725 data: tokens.data,
3726 result_id: tokens.result_id.map(SharedString::new),
3727 })
3728 }
3729 Some(lsp::SemanticTokensFullDeltaResult::TokensDelta(delta)) => {
3730 Ok(SemanticTokensResponse::Delta {
3731 edits: delta
3732 .edits
3733 .into_iter()
3734 .map(|e| SemanticTokensEdit {
3735 start: e.start,
3736 delete_count: e.delete_count,
3737 data: e.data.unwrap_or_default(),
3738 })
3739 .collect(),
3740 result_id: delta.result_id.map(SharedString::new),
3741 })
3742 }
3743 Some(lsp::SemanticTokensFullDeltaResult::PartialTokensDelta { .. }) => {
3744 anyhow::bail!(
3745 "Unexpected semantic tokens response with partial result for inlay hints"
3746 )
3747 }
3748 None => Ok(Default::default()),
3749 }
3750 }
3751
3752 fn to_proto(&self, _: u64, _: &Buffer) -> proto::SemanticTokens {
3753 unimplemented!("Delta requests are never initialted on the remote client side")
3754 }
3755
3756 async fn from_proto(
3757 _: proto::SemanticTokens,
3758 _: Entity<LspStore>,
3759 _: Entity<Buffer>,
3760 _: AsyncApp,
3761 ) -> Result<Self> {
3762 unimplemented!("Delta requests are never initialted on the remote client side")
3763 }
3764
3765 fn response_to_proto(
3766 response: SemanticTokensResponse,
3767 _: &mut LspStore,
3768 _: PeerId,
3769 buffer_version: &clock::Global,
3770 _: &mut App,
3771 ) -> proto::SemanticTokensResponse {
3772 match response {
3773 SemanticTokensResponse::Full { data, result_id } => proto::SemanticTokensResponse {
3774 data,
3775 edits: Vec::new(),
3776 result_id: result_id.map(|s| s.to_string()),
3777 version: serialize_version(buffer_version),
3778 },
3779 SemanticTokensResponse::Delta { edits, result_id } => proto::SemanticTokensResponse {
3780 data: Vec::new(),
3781 edits: edits
3782 .into_iter()
3783 .map(|edit| proto::SemanticTokensEdit {
3784 start: edit.start,
3785 delete_count: edit.delete_count,
3786 data: edit.data,
3787 })
3788 .collect(),
3789 result_id: result_id.map(|s| s.to_string()),
3790 version: serialize_version(buffer_version),
3791 },
3792 }
3793 }
3794
3795 async fn response_from_proto(
3796 self,
3797 message: proto::SemanticTokensResponse,
3798 _: Entity<LspStore>,
3799 buffer: Entity<Buffer>,
3800 mut cx: AsyncApp,
3801 ) -> anyhow::Result<SemanticTokensResponse> {
3802 buffer
3803 .update(&mut cx, |buffer, _| {
3804 buffer.wait_for_version(deserialize_version(&message.version))
3805 })
3806 .await?;
3807
3808 Ok(SemanticTokensResponse::Full {
3809 data: message.data,
3810 result_id: message.result_id.map(SharedString::new),
3811 })
3812 }
3813
3814 fn buffer_id_from_proto(message: &proto::SemanticTokens) -> Result<BufferId> {
3815 BufferId::new(message.buffer_id)
3816 }
3817}
3818
3819#[async_trait(?Send)]
3820impl LspCommand for GetCodeLens {
3821 type Response = Vec<CodeAction>;
3822 type LspRequest = lsp::CodeLensRequest;
3823 type ProtoRequest = proto::GetCodeLens;
3824
3825 fn display_name(&self) -> &str {
3826 "Code Lens"
3827 }
3828
3829 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3830 capabilities
3831 .server_capabilities
3832 .code_lens_provider
3833 .is_some()
3834 }
3835
3836 fn to_lsp(
3837 &self,
3838 path: &Path,
3839 _: &Buffer,
3840 _: &Arc<LanguageServer>,
3841 _: &App,
3842 ) -> Result<lsp::CodeLensParams> {
3843 Ok(lsp::CodeLensParams {
3844 text_document: lsp::TextDocumentIdentifier {
3845 uri: file_path_to_lsp_url(path)?,
3846 },
3847 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3848 partial_result_params: lsp::PartialResultParams::default(),
3849 })
3850 }
3851
3852 async fn response_from_lsp(
3853 self,
3854 message: Option<Vec<lsp::CodeLens>>,
3855 _lsp_store: Entity<LspStore>,
3856 buffer: Entity<Buffer>,
3857 server_id: LanguageServerId,
3858 cx: AsyncApp,
3859 ) -> anyhow::Result<Vec<CodeAction>> {
3860 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
3861 let code_lenses = message.unwrap_or_default();
3862
3863 Ok(code_lenses
3864 .into_iter()
3865 .map(|code_lens| {
3866 let code_lens_range = range_from_lsp(code_lens.range);
3867 let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3868 let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3869 let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3870 let resolved = code_lens.command.is_some();
3871 CodeAction {
3872 server_id,
3873 range,
3874 lsp_action: LspAction::CodeLens(code_lens),
3875 resolved,
3876 }
3877 })
3878 .collect())
3879 }
3880
3881 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3882 proto::GetCodeLens {
3883 project_id,
3884 buffer_id: buffer.remote_id().into(),
3885 version: serialize_version(&buffer.version()),
3886 }
3887 }
3888
3889 async fn from_proto(
3890 message: proto::GetCodeLens,
3891 _: Entity<LspStore>,
3892 buffer: Entity<Buffer>,
3893 mut cx: AsyncApp,
3894 ) -> Result<Self> {
3895 buffer
3896 .update(&mut cx, |buffer, _| {
3897 buffer.wait_for_version(deserialize_version(&message.version))
3898 })
3899 .await?;
3900 Ok(Self)
3901 }
3902
3903 fn response_to_proto(
3904 response: Vec<CodeAction>,
3905 _: &mut LspStore,
3906 _: PeerId,
3907 buffer_version: &clock::Global,
3908 _: &mut App,
3909 ) -> proto::GetCodeLensResponse {
3910 proto::GetCodeLensResponse {
3911 lens_actions: response
3912 .iter()
3913 .map(LspStore::serialize_code_action)
3914 .collect(),
3915 version: serialize_version(buffer_version),
3916 }
3917 }
3918
3919 async fn response_from_proto(
3920 self,
3921 message: proto::GetCodeLensResponse,
3922 _: Entity<LspStore>,
3923 buffer: Entity<Buffer>,
3924 mut cx: AsyncApp,
3925 ) -> anyhow::Result<Vec<CodeAction>> {
3926 buffer
3927 .update(&mut cx, |buffer, _| {
3928 buffer.wait_for_version(deserialize_version(&message.version))
3929 })
3930 .await?;
3931 message
3932 .lens_actions
3933 .into_iter()
3934 .map(LspStore::deserialize_code_action)
3935 .collect::<Result<Vec<_>>>()
3936 .context("deserializing proto code lens response")
3937 }
3938
3939 fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3940 BufferId::new(message.buffer_id)
3941 }
3942}
3943
3944impl LinkedEditingRange {
3945 pub fn check_server_capabilities(capabilities: ServerCapabilities) -> bool {
3946 let Some(linked_editing_options) = capabilities.linked_editing_range_provider else {
3947 return false;
3948 };
3949 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3950 return false;
3951 }
3952 true
3953 }
3954}
3955
3956#[async_trait(?Send)]
3957impl LspCommand for LinkedEditingRange {
3958 type Response = Vec<Range<Anchor>>;
3959 type LspRequest = lsp::request::LinkedEditingRange;
3960 type ProtoRequest = proto::LinkedEditingRange;
3961
3962 fn display_name(&self) -> &str {
3963 "Linked editing range"
3964 }
3965
3966 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3967 Self::check_server_capabilities(capabilities.server_capabilities)
3968 }
3969
3970 fn to_lsp(
3971 &self,
3972 path: &Path,
3973 buffer: &Buffer,
3974 _server: &Arc<LanguageServer>,
3975 _: &App,
3976 ) -> Result<lsp::LinkedEditingRangeParams> {
3977 let position = self.position.to_point_utf16(&buffer.snapshot());
3978 Ok(lsp::LinkedEditingRangeParams {
3979 text_document_position_params: make_lsp_text_document_position(path, position)?,
3980 work_done_progress_params: Default::default(),
3981 })
3982 }
3983
3984 async fn response_from_lsp(
3985 self,
3986 message: Option<lsp::LinkedEditingRanges>,
3987 _: Entity<LspStore>,
3988 buffer: Entity<Buffer>,
3989 _server_id: LanguageServerId,
3990 cx: AsyncApp,
3991 ) -> Result<Vec<Range<Anchor>>> {
3992 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3993 ranges.sort_by_key(|range| range.start);
3994
3995 Ok(buffer.read_with(&cx, |buffer, _| {
3996 ranges
3997 .into_iter()
3998 .map(|range| {
3999 let start =
4000 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
4001 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
4002 buffer.anchor_before(start)..buffer.anchor_after(end)
4003 })
4004 .collect()
4005 }))
4006 } else {
4007 Ok(vec![])
4008 }
4009 }
4010
4011 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
4012 proto::LinkedEditingRange {
4013 project_id,
4014 buffer_id: buffer.remote_id().to_proto(),
4015 position: Some(serialize_anchor(&self.position)),
4016 version: serialize_version(&buffer.version()),
4017 }
4018 }
4019
4020 async fn from_proto(
4021 message: proto::LinkedEditingRange,
4022 _: Entity<LspStore>,
4023 buffer: Entity<Buffer>,
4024 mut cx: AsyncApp,
4025 ) -> Result<Self> {
4026 let position = message.position.context("invalid position")?;
4027 buffer
4028 .update(&mut cx, |buffer, _| {
4029 buffer.wait_for_version(deserialize_version(&message.version))
4030 })
4031 .await?;
4032 let position = deserialize_anchor(position).context("invalid position")?;
4033 buffer
4034 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))
4035 .await?;
4036 Ok(Self { position })
4037 }
4038
4039 fn response_to_proto(
4040 response: Vec<Range<Anchor>>,
4041 _: &mut LspStore,
4042 _: PeerId,
4043 buffer_version: &clock::Global,
4044 _: &mut App,
4045 ) -> proto::LinkedEditingRangeResponse {
4046 proto::LinkedEditingRangeResponse {
4047 items: response
4048 .into_iter()
4049 .map(|range| proto::AnchorRange {
4050 start: Some(serialize_anchor(&range.start)),
4051 end: Some(serialize_anchor(&range.end)),
4052 })
4053 .collect(),
4054 version: serialize_version(buffer_version),
4055 }
4056 }
4057
4058 async fn response_from_proto(
4059 self,
4060 message: proto::LinkedEditingRangeResponse,
4061 _: Entity<LspStore>,
4062 buffer: Entity<Buffer>,
4063 mut cx: AsyncApp,
4064 ) -> Result<Vec<Range<Anchor>>> {
4065 buffer
4066 .update(&mut cx, |buffer, _| {
4067 buffer.wait_for_version(deserialize_version(&message.version))
4068 })
4069 .await?;
4070 let items: Vec<Range<Anchor>> = message
4071 .items
4072 .into_iter()
4073 .filter_map(|range| {
4074 let start = deserialize_anchor(range.start?)?;
4075 let end = deserialize_anchor(range.end?)?;
4076 Some(start..end)
4077 })
4078 .collect();
4079 for range in &items {
4080 buffer
4081 .update(&mut cx, |buffer, _| {
4082 buffer.wait_for_anchors([range.start, range.end])
4083 })
4084 .await?;
4085 }
4086 Ok(items)
4087 }
4088
4089 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
4090 BufferId::new(message.buffer_id)
4091 }
4092}
4093
4094impl GetDocumentDiagnostics {
4095 pub fn diagnostics_from_proto(
4096 response: proto::GetDocumentDiagnosticsResponse,
4097 ) -> Vec<LspPullDiagnostics> {
4098 response
4099 .pulled_diagnostics
4100 .into_iter()
4101 .filter_map(|diagnostics| {
4102 Some(LspPullDiagnostics::Response {
4103 registration_id: diagnostics.registration_id.map(SharedString::from),
4104 server_id: LanguageServerId::from_proto(diagnostics.server_id),
4105 uri: lsp::Uri::from_str(diagnostics.uri.as_str()).log_err()?,
4106 diagnostics: if diagnostics.changed {
4107 PulledDiagnostics::Unchanged {
4108 result_id: SharedString::new(diagnostics.result_id?),
4109 }
4110 } else {
4111 PulledDiagnostics::Changed {
4112 result_id: diagnostics.result_id.map(SharedString::new),
4113 diagnostics: diagnostics
4114 .diagnostics
4115 .into_iter()
4116 .filter_map(|diagnostic| {
4117 GetDocumentDiagnostics::deserialize_lsp_diagnostic(diagnostic)
4118 .context("deserializing diagnostics")
4119 .log_err()
4120 })
4121 .collect(),
4122 }
4123 },
4124 })
4125 })
4126 .collect()
4127 }
4128
4129 pub fn deserialize_lsp_diagnostic(diagnostic: proto::LspDiagnostic) -> Result<lsp::Diagnostic> {
4130 let start = diagnostic.start.context("invalid start range")?;
4131 let end = diagnostic.end.context("invalid end range")?;
4132
4133 let range = Range::<PointUtf16> {
4134 start: PointUtf16 {
4135 row: start.row,
4136 column: start.column,
4137 },
4138 end: PointUtf16 {
4139 row: end.row,
4140 column: end.column,
4141 },
4142 };
4143
4144 let data = diagnostic.data.and_then(|data| Value::from_str(&data).ok());
4145 let code = diagnostic.code.map(lsp::NumberOrString::String);
4146
4147 let related_information = diagnostic
4148 .related_information
4149 .into_iter()
4150 .map(|info| {
4151 let start = info.location_range_start.unwrap();
4152 let end = info.location_range_end.unwrap();
4153
4154 lsp::DiagnosticRelatedInformation {
4155 location: lsp::Location {
4156 range: lsp::Range {
4157 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
4158 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
4159 },
4160 uri: lsp::Uri::from_str(&info.location_url.unwrap()).unwrap(),
4161 },
4162 message: info.message,
4163 }
4164 })
4165 .collect::<Vec<_>>();
4166
4167 let tags = diagnostic
4168 .tags
4169 .into_iter()
4170 .filter_map(|tag| match proto::LspDiagnosticTag::from_i32(tag) {
4171 Some(proto::LspDiagnosticTag::Unnecessary) => Some(lsp::DiagnosticTag::UNNECESSARY),
4172 Some(proto::LspDiagnosticTag::Deprecated) => Some(lsp::DiagnosticTag::DEPRECATED),
4173 _ => None,
4174 })
4175 .collect::<Vec<_>>();
4176
4177 Ok(lsp::Diagnostic {
4178 range: language::range_to_lsp(range)?,
4179 severity: match proto::lsp_diagnostic::Severity::from_i32(diagnostic.severity).unwrap()
4180 {
4181 proto::lsp_diagnostic::Severity::Error => Some(lsp::DiagnosticSeverity::ERROR),
4182 proto::lsp_diagnostic::Severity::Warning => Some(lsp::DiagnosticSeverity::WARNING),
4183 proto::lsp_diagnostic::Severity::Information => {
4184 Some(lsp::DiagnosticSeverity::INFORMATION)
4185 }
4186 proto::lsp_diagnostic::Severity::Hint => Some(lsp::DiagnosticSeverity::HINT),
4187 _ => None,
4188 },
4189 code,
4190 code_description: diagnostic
4191 .code_description
4192 .map(|code_description| CodeDescription {
4193 href: Some(lsp::Uri::from_str(&code_description).unwrap()),
4194 }),
4195 related_information: Some(related_information),
4196 tags: Some(tags),
4197 source: diagnostic.source.clone(),
4198 message: diagnostic.message,
4199 data,
4200 })
4201 }
4202
4203 pub fn serialize_lsp_diagnostic(diagnostic: lsp::Diagnostic) -> Result<proto::LspDiagnostic> {
4204 let range = language::range_from_lsp(diagnostic.range);
4205 let related_information = diagnostic
4206 .related_information
4207 .unwrap_or_default()
4208 .into_iter()
4209 .map(|related_information| {
4210 let location_range_start =
4211 point_from_lsp(related_information.location.range.start).0;
4212 let location_range_end = point_from_lsp(related_information.location.range.end).0;
4213
4214 Ok(proto::LspDiagnosticRelatedInformation {
4215 location_url: Some(related_information.location.uri.to_string()),
4216 location_range_start: Some(proto::PointUtf16 {
4217 row: location_range_start.row,
4218 column: location_range_start.column,
4219 }),
4220 location_range_end: Some(proto::PointUtf16 {
4221 row: location_range_end.row,
4222 column: location_range_end.column,
4223 }),
4224 message: related_information.message,
4225 })
4226 })
4227 .collect::<Result<Vec<_>>>()?;
4228
4229 let tags = diagnostic
4230 .tags
4231 .unwrap_or_default()
4232 .into_iter()
4233 .map(|tag| match tag {
4234 lsp::DiagnosticTag::UNNECESSARY => proto::LspDiagnosticTag::Unnecessary,
4235 lsp::DiagnosticTag::DEPRECATED => proto::LspDiagnosticTag::Deprecated,
4236 _ => proto::LspDiagnosticTag::None,
4237 } as i32)
4238 .collect();
4239
4240 Ok(proto::LspDiagnostic {
4241 start: Some(proto::PointUtf16 {
4242 row: range.start.0.row,
4243 column: range.start.0.column,
4244 }),
4245 end: Some(proto::PointUtf16 {
4246 row: range.end.0.row,
4247 column: range.end.0.column,
4248 }),
4249 severity: match diagnostic.severity {
4250 Some(lsp::DiagnosticSeverity::ERROR) => proto::lsp_diagnostic::Severity::Error,
4251 Some(lsp::DiagnosticSeverity::WARNING) => proto::lsp_diagnostic::Severity::Warning,
4252 Some(lsp::DiagnosticSeverity::INFORMATION) => {
4253 proto::lsp_diagnostic::Severity::Information
4254 }
4255 Some(lsp::DiagnosticSeverity::HINT) => proto::lsp_diagnostic::Severity::Hint,
4256 _ => proto::lsp_diagnostic::Severity::None,
4257 } as i32,
4258 code: diagnostic.code.as_ref().map(|code| match code {
4259 lsp::NumberOrString::Number(code) => code.to_string(),
4260 lsp::NumberOrString::String(code) => code.clone(),
4261 }),
4262 source: diagnostic.source.clone(),
4263 related_information,
4264 tags,
4265 code_description: diagnostic
4266 .code_description
4267 .and_then(|desc| desc.href.map(|url| url.to_string())),
4268 message: diagnostic.message,
4269 data: diagnostic.data.as_ref().map(|data| data.to_string()),
4270 })
4271 }
4272
4273 pub fn deserialize_workspace_diagnostics_report(
4274 report: lsp::WorkspaceDiagnosticReportResult,
4275 server_id: LanguageServerId,
4276 registration_id: Option<SharedString>,
4277 ) -> Vec<WorkspaceLspPullDiagnostics> {
4278 let mut pulled_diagnostics = HashMap::default();
4279 match report {
4280 lsp::WorkspaceDiagnosticReportResult::Report(workspace_diagnostic_report) => {
4281 for report in workspace_diagnostic_report.items {
4282 match report {
4283 lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
4284 process_full_workspace_diagnostics_report(
4285 &mut pulled_diagnostics,
4286 server_id,
4287 report,
4288 registration_id.clone(),
4289 )
4290 }
4291 lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
4292 process_unchanged_workspace_diagnostics_report(
4293 &mut pulled_diagnostics,
4294 server_id,
4295 report,
4296 registration_id.clone(),
4297 )
4298 }
4299 }
4300 }
4301 }
4302 lsp::WorkspaceDiagnosticReportResult::Partial(
4303 workspace_diagnostic_report_partial_result,
4304 ) => {
4305 for report in workspace_diagnostic_report_partial_result.items {
4306 match report {
4307 lsp::WorkspaceDocumentDiagnosticReport::Full(report) => {
4308 process_full_workspace_diagnostics_report(
4309 &mut pulled_diagnostics,
4310 server_id,
4311 report,
4312 registration_id.clone(),
4313 )
4314 }
4315 lsp::WorkspaceDocumentDiagnosticReport::Unchanged(report) => {
4316 process_unchanged_workspace_diagnostics_report(
4317 &mut pulled_diagnostics,
4318 server_id,
4319 report,
4320 registration_id.clone(),
4321 )
4322 }
4323 }
4324 }
4325 }
4326 }
4327 pulled_diagnostics.into_values().collect()
4328 }
4329}
4330
4331#[derive(Debug)]
4332pub struct WorkspaceLspPullDiagnostics {
4333 pub version: Option<i32>,
4334 pub diagnostics: LspPullDiagnostics,
4335}
4336
4337fn process_full_workspace_diagnostics_report(
4338 diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4339 server_id: LanguageServerId,
4340 report: lsp::WorkspaceFullDocumentDiagnosticReport,
4341 registration_id: Option<SharedString>,
4342) {
4343 let mut new_diagnostics = HashMap::default();
4344 process_full_diagnostics_report(
4345 &mut new_diagnostics,
4346 server_id,
4347 report.uri,
4348 report.full_document_diagnostic_report,
4349 registration_id,
4350 );
4351 diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4352 (
4353 uri,
4354 WorkspaceLspPullDiagnostics {
4355 version: report.version.map(|v| v as i32),
4356 diagnostics,
4357 },
4358 )
4359 }));
4360}
4361
4362fn process_unchanged_workspace_diagnostics_report(
4363 diagnostics: &mut HashMap<lsp::Uri, WorkspaceLspPullDiagnostics>,
4364 server_id: LanguageServerId,
4365 report: lsp::WorkspaceUnchangedDocumentDiagnosticReport,
4366 registration_id: Option<SharedString>,
4367) {
4368 let mut new_diagnostics = HashMap::default();
4369 process_unchanged_diagnostics_report(
4370 &mut new_diagnostics,
4371 server_id,
4372 report.uri,
4373 report.unchanged_document_diagnostic_report,
4374 registration_id,
4375 );
4376 diagnostics.extend(new_diagnostics.into_iter().map(|(uri, diagnostics)| {
4377 (
4378 uri,
4379 WorkspaceLspPullDiagnostics {
4380 version: report.version.map(|v| v as i32),
4381 diagnostics,
4382 },
4383 )
4384 }));
4385}
4386
4387#[async_trait(?Send)]
4388impl LspCommand for GetDocumentDiagnostics {
4389 type Response = Vec<LspPullDiagnostics>;
4390 type LspRequest = lsp::request::DocumentDiagnosticRequest;
4391 type ProtoRequest = proto::GetDocumentDiagnostics;
4392
4393 fn display_name(&self) -> &str {
4394 "Get diagnostics"
4395 }
4396
4397 fn check_capabilities(&self, _: AdapterServerCapabilities) -> bool {
4398 true
4399 }
4400
4401 fn to_lsp(
4402 &self,
4403 path: &Path,
4404 _: &Buffer,
4405 _: &Arc<LanguageServer>,
4406 _: &App,
4407 ) -> Result<lsp::DocumentDiagnosticParams> {
4408 Ok(lsp::DocumentDiagnosticParams {
4409 text_document: lsp::TextDocumentIdentifier {
4410 uri: file_path_to_lsp_url(path)?,
4411 },
4412 identifier: self.identifier.as_ref().map(ToString::to_string),
4413 previous_result_id: self.previous_result_id.as_ref().map(ToString::to_string),
4414 partial_result_params: Default::default(),
4415 work_done_progress_params: Default::default(),
4416 })
4417 }
4418
4419 async fn response_from_lsp(
4420 self,
4421 message: lsp::DocumentDiagnosticReportResult,
4422 _: Entity<LspStore>,
4423 buffer: Entity<Buffer>,
4424 server_id: LanguageServerId,
4425 cx: AsyncApp,
4426 ) -> Result<Self::Response> {
4427 let url = buffer.read_with(&cx, |buffer, cx| {
4428 buffer
4429 .file()
4430 .and_then(|file| file.as_local())
4431 .map(|file| {
4432 let abs_path = file.abs_path(cx);
4433 file_path_to_lsp_url(&abs_path)
4434 })
4435 .transpose()?
4436 .with_context(|| format!("missing url on buffer {}", buffer.remote_id()))
4437 })?;
4438
4439 let mut pulled_diagnostics = HashMap::default();
4440 match message {
4441 lsp::DocumentDiagnosticReportResult::Report(report) => match report {
4442 lsp::DocumentDiagnosticReport::Full(report) => {
4443 if let Some(related_documents) = report.related_documents {
4444 process_related_documents(
4445 &mut pulled_diagnostics,
4446 server_id,
4447 related_documents,
4448 self.registration_id.clone(),
4449 );
4450 }
4451 process_full_diagnostics_report(
4452 &mut pulled_diagnostics,
4453 server_id,
4454 url,
4455 report.full_document_diagnostic_report,
4456 self.registration_id,
4457 );
4458 }
4459 lsp::DocumentDiagnosticReport::Unchanged(report) => {
4460 if let Some(related_documents) = report.related_documents {
4461 process_related_documents(
4462 &mut pulled_diagnostics,
4463 server_id,
4464 related_documents,
4465 self.registration_id.clone(),
4466 );
4467 }
4468 process_unchanged_diagnostics_report(
4469 &mut pulled_diagnostics,
4470 server_id,
4471 url,
4472 report.unchanged_document_diagnostic_report,
4473 self.registration_id,
4474 );
4475 }
4476 },
4477 lsp::DocumentDiagnosticReportResult::Partial(report) => {
4478 if let Some(related_documents) = report.related_documents {
4479 process_related_documents(
4480 &mut pulled_diagnostics,
4481 server_id,
4482 related_documents,
4483 self.registration_id,
4484 );
4485 }
4486 }
4487 }
4488
4489 Ok(pulled_diagnostics.into_values().collect())
4490 }
4491
4492 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentDiagnostics {
4493 proto::GetDocumentDiagnostics {
4494 project_id,
4495 buffer_id: buffer.remote_id().into(),
4496 version: serialize_version(&buffer.version()),
4497 }
4498 }
4499
4500 async fn from_proto(
4501 _: proto::GetDocumentDiagnostics,
4502 _: Entity<LspStore>,
4503 _: Entity<Buffer>,
4504 _: AsyncApp,
4505 ) -> Result<Self> {
4506 anyhow::bail!(
4507 "proto::GetDocumentDiagnostics is not expected to be converted from proto directly, as it needs `previous_result_id` fetched first"
4508 )
4509 }
4510
4511 fn response_to_proto(
4512 response: Self::Response,
4513 _: &mut LspStore,
4514 _: PeerId,
4515 _: &clock::Global,
4516 _: &mut App,
4517 ) -> proto::GetDocumentDiagnosticsResponse {
4518 let pulled_diagnostics = response
4519 .into_iter()
4520 .filter_map(|diagnostics| match diagnostics {
4521 LspPullDiagnostics::Default => None,
4522 LspPullDiagnostics::Response {
4523 server_id,
4524 uri,
4525 diagnostics,
4526 registration_id,
4527 } => {
4528 let mut changed = false;
4529 let (diagnostics, result_id) = match diagnostics {
4530 PulledDiagnostics::Unchanged { result_id } => (Vec::new(), Some(result_id)),
4531 PulledDiagnostics::Changed {
4532 result_id,
4533 diagnostics,
4534 } => {
4535 changed = true;
4536 (diagnostics, result_id)
4537 }
4538 };
4539 Some(proto::PulledDiagnostics {
4540 changed,
4541 result_id: result_id.map(|id| id.to_string()),
4542 uri: uri.to_string(),
4543 server_id: server_id.to_proto(),
4544 diagnostics: diagnostics
4545 .into_iter()
4546 .filter_map(|diagnostic| {
4547 GetDocumentDiagnostics::serialize_lsp_diagnostic(diagnostic)
4548 .context("serializing diagnostics")
4549 .log_err()
4550 })
4551 .collect(),
4552 registration_id: registration_id.as_ref().map(ToString::to_string),
4553 })
4554 }
4555 })
4556 .collect();
4557
4558 proto::GetDocumentDiagnosticsResponse { pulled_diagnostics }
4559 }
4560
4561 async fn response_from_proto(
4562 self,
4563 response: proto::GetDocumentDiagnosticsResponse,
4564 _: Entity<LspStore>,
4565 _: Entity<Buffer>,
4566 _: AsyncApp,
4567 ) -> Result<Self::Response> {
4568 Ok(Self::diagnostics_from_proto(response))
4569 }
4570
4571 fn buffer_id_from_proto(message: &proto::GetDocumentDiagnostics) -> Result<BufferId> {
4572 BufferId::new(message.buffer_id)
4573 }
4574}
4575
4576#[async_trait(?Send)]
4577impl LspCommand for GetDocumentColor {
4578 type Response = Vec<DocumentColor>;
4579 type LspRequest = lsp::request::DocumentColor;
4580 type ProtoRequest = proto::GetDocumentColor;
4581
4582 fn display_name(&self) -> &str {
4583 "Document color"
4584 }
4585
4586 fn check_capabilities(&self, server_capabilities: AdapterServerCapabilities) -> bool {
4587 server_capabilities
4588 .server_capabilities
4589 .color_provider
4590 .as_ref()
4591 .is_some_and(|capability| match capability {
4592 lsp::ColorProviderCapability::Simple(supported) => *supported,
4593 lsp::ColorProviderCapability::ColorProvider(..) => true,
4594 lsp::ColorProviderCapability::Options(..) => true,
4595 })
4596 }
4597
4598 fn to_lsp(
4599 &self,
4600 path: &Path,
4601 _: &Buffer,
4602 _: &Arc<LanguageServer>,
4603 _: &App,
4604 ) -> Result<lsp::DocumentColorParams> {
4605 Ok(lsp::DocumentColorParams {
4606 text_document: make_text_document_identifier(path)?,
4607 work_done_progress_params: Default::default(),
4608 partial_result_params: Default::default(),
4609 })
4610 }
4611
4612 async fn response_from_lsp(
4613 self,
4614 message: Vec<lsp::ColorInformation>,
4615 _: Entity<LspStore>,
4616 _: Entity<Buffer>,
4617 _: LanguageServerId,
4618 _: AsyncApp,
4619 ) -> Result<Self::Response> {
4620 Ok(message
4621 .into_iter()
4622 .map(|color| DocumentColor {
4623 lsp_range: color.range,
4624 color: color.color,
4625 resolved: false,
4626 color_presentations: Vec::new(),
4627 })
4628 .collect())
4629 }
4630
4631 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
4632 proto::GetDocumentColor {
4633 project_id,
4634 buffer_id: buffer.remote_id().to_proto(),
4635 version: serialize_version(&buffer.version()),
4636 }
4637 }
4638
4639 async fn from_proto(
4640 _: Self::ProtoRequest,
4641 _: Entity<LspStore>,
4642 _: Entity<Buffer>,
4643 _: AsyncApp,
4644 ) -> Result<Self> {
4645 Ok(Self {})
4646 }
4647
4648 fn response_to_proto(
4649 response: Self::Response,
4650 _: &mut LspStore,
4651 _: PeerId,
4652 buffer_version: &clock::Global,
4653 _: &mut App,
4654 ) -> proto::GetDocumentColorResponse {
4655 proto::GetDocumentColorResponse {
4656 colors: response
4657 .into_iter()
4658 .map(|color| {
4659 let start = point_from_lsp(color.lsp_range.start).0;
4660 let end = point_from_lsp(color.lsp_range.end).0;
4661 proto::ColorInformation {
4662 red: color.color.red,
4663 green: color.color.green,
4664 blue: color.color.blue,
4665 alpha: color.color.alpha,
4666 lsp_range_start: Some(proto::PointUtf16 {
4667 row: start.row,
4668 column: start.column,
4669 }),
4670 lsp_range_end: Some(proto::PointUtf16 {
4671 row: end.row,
4672 column: end.column,
4673 }),
4674 }
4675 })
4676 .collect(),
4677 version: serialize_version(buffer_version),
4678 }
4679 }
4680
4681 async fn response_from_proto(
4682 self,
4683 message: proto::GetDocumentColorResponse,
4684 _: Entity<LspStore>,
4685 _: Entity<Buffer>,
4686 _: AsyncApp,
4687 ) -> Result<Self::Response> {
4688 Ok(message
4689 .colors
4690 .into_iter()
4691 .filter_map(|color| {
4692 let start = color.lsp_range_start?;
4693 let start = PointUtf16::new(start.row, start.column);
4694 let end = color.lsp_range_end?;
4695 let end = PointUtf16::new(end.row, end.column);
4696 Some(DocumentColor {
4697 resolved: false,
4698 color_presentations: Vec::new(),
4699 lsp_range: lsp::Range {
4700 start: point_to_lsp(start),
4701 end: point_to_lsp(end),
4702 },
4703 color: lsp::Color {
4704 red: color.red,
4705 green: color.green,
4706 blue: color.blue,
4707 alpha: color.alpha,
4708 },
4709 })
4710 })
4711 .collect())
4712 }
4713
4714 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
4715 BufferId::new(message.buffer_id)
4716 }
4717}
4718
4719#[async_trait(?Send)]
4720impl LspCommand for GetFoldingRanges {
4721 type Response = Vec<LspFoldingRange>;
4722 type LspRequest = lsp::request::FoldingRangeRequest;
4723 type ProtoRequest = proto::GetFoldingRanges;
4724
4725 fn display_name(&self) -> &str {
4726 "Folding ranges"
4727 }
4728
4729 fn check_capabilities(&self, server_capabilities: AdapterServerCapabilities) -> bool {
4730 server_capabilities
4731 .server_capabilities
4732 .folding_range_provider
4733 .as_ref()
4734 .is_some_and(|capability| match capability {
4735 lsp::FoldingRangeProviderCapability::Simple(supported) => *supported,
4736 lsp::FoldingRangeProviderCapability::FoldingProvider(..)
4737 | lsp::FoldingRangeProviderCapability::Options(..) => true,
4738 })
4739 }
4740
4741 fn to_lsp(
4742 &self,
4743 path: &Path,
4744 _: &Buffer,
4745 _: &Arc<LanguageServer>,
4746 _: &App,
4747 ) -> Result<lsp::FoldingRangeParams> {
4748 Ok(lsp::FoldingRangeParams {
4749 text_document: make_text_document_identifier(path)?,
4750 work_done_progress_params: Default::default(),
4751 partial_result_params: Default::default(),
4752 })
4753 }
4754
4755 async fn response_from_lsp(
4756 self,
4757 message: Option<Vec<lsp::FoldingRange>>,
4758 _: Entity<LspStore>,
4759 buffer: Entity<Buffer>,
4760 _: LanguageServerId,
4761 cx: AsyncApp,
4762 ) -> Result<Self::Response> {
4763 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4764 let max_point = snapshot.max_point_utf16();
4765 Ok(message
4766 .unwrap_or_default()
4767 .into_iter()
4768 .filter(|range| range.start_line < range.end_line)
4769 .filter(|range| range.start_line <= max_point.row && range.end_line <= max_point.row)
4770 .map(|folding_range| {
4771 let start_col = folding_range.start_character.unwrap_or(u32::MAX);
4772 let end_col = folding_range.end_character.unwrap_or(u32::MAX);
4773 let start = snapshot.clip_point_utf16(
4774 Unclipped(PointUtf16::new(folding_range.start_line, start_col)),
4775 Bias::Right,
4776 );
4777 let end = snapshot.clip_point_utf16(
4778 Unclipped(PointUtf16::new(folding_range.end_line, end_col)),
4779 Bias::Left,
4780 );
4781 let start = snapshot.anchor_after(start);
4782 let end = snapshot.anchor_before(end);
4783 let collapsed_text = folding_range
4784 .collapsed_text
4785 .filter(|t| !t.is_empty())
4786 .map(|t| SharedString::from(crate::lsp_store::collapse_newlines(&t, " ")));
4787 LspFoldingRange {
4788 range: start..end,
4789 collapsed_text,
4790 }
4791 })
4792 .collect())
4793 }
4794
4795 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
4796 proto::GetFoldingRanges {
4797 project_id,
4798 buffer_id: buffer.remote_id().to_proto(),
4799 version: serialize_version(&buffer.version()),
4800 }
4801 }
4802
4803 async fn from_proto(
4804 _: Self::ProtoRequest,
4805 _: Entity<LspStore>,
4806 _: Entity<Buffer>,
4807 _: AsyncApp,
4808 ) -> Result<Self> {
4809 Ok(Self)
4810 }
4811
4812 fn response_to_proto(
4813 response: Self::Response,
4814 _: &mut LspStore,
4815 _: PeerId,
4816 buffer_version: &clock::Global,
4817 _: &mut App,
4818 ) -> proto::GetFoldingRangesResponse {
4819 let mut ranges = Vec::with_capacity(response.len());
4820 let mut collapsed_texts = Vec::with_capacity(response.len());
4821 for folding_range in response {
4822 ranges.push(serialize_anchor_range(folding_range.range));
4823 collapsed_texts.push(
4824 folding_range
4825 .collapsed_text
4826 .map(|t| t.to_string())
4827 .unwrap_or_default(),
4828 );
4829 }
4830 proto::GetFoldingRangesResponse {
4831 ranges,
4832 collapsed_texts,
4833 version: serialize_version(buffer_version),
4834 }
4835 }
4836
4837 async fn response_from_proto(
4838 self,
4839 message: proto::GetFoldingRangesResponse,
4840 _: Entity<LspStore>,
4841 buffer: Entity<Buffer>,
4842 mut cx: AsyncApp,
4843 ) -> Result<Self::Response> {
4844 buffer
4845 .update(&mut cx, |buffer, _| {
4846 buffer.wait_for_version(deserialize_version(&message.version))
4847 })
4848 .await?;
4849 message
4850 .ranges
4851 .into_iter()
4852 .zip(
4853 message
4854 .collapsed_texts
4855 .into_iter()
4856 .map(Some)
4857 .chain(std::iter::repeat(None)),
4858 )
4859 .map(|(range, collapsed_text)| {
4860 Ok(LspFoldingRange {
4861 range: deserialize_anchor_range(range)?,
4862 collapsed_text: collapsed_text
4863 .filter(|t| !t.is_empty())
4864 .map(SharedString::from),
4865 })
4866 })
4867 .collect()
4868 }
4869
4870 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
4871 BufferId::new(message.buffer_id)
4872 }
4873}
4874
4875fn process_related_documents(
4876 diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4877 server_id: LanguageServerId,
4878 documents: impl IntoIterator<Item = (lsp::Uri, lsp::DocumentDiagnosticReportKind)>,
4879 registration_id: Option<SharedString>,
4880) {
4881 for (url, report_kind) in documents {
4882 match report_kind {
4883 lsp::DocumentDiagnosticReportKind::Full(report) => process_full_diagnostics_report(
4884 diagnostics,
4885 server_id,
4886 url,
4887 report,
4888 registration_id.clone(),
4889 ),
4890 lsp::DocumentDiagnosticReportKind::Unchanged(report) => {
4891 process_unchanged_diagnostics_report(
4892 diagnostics,
4893 server_id,
4894 url,
4895 report,
4896 registration_id.clone(),
4897 )
4898 }
4899 }
4900 }
4901}
4902
4903fn process_unchanged_diagnostics_report(
4904 diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4905 server_id: LanguageServerId,
4906 uri: lsp::Uri,
4907 report: lsp::UnchangedDocumentDiagnosticReport,
4908 registration_id: Option<SharedString>,
4909) {
4910 let result_id = SharedString::new(report.result_id);
4911 match diagnostics.entry(uri.clone()) {
4912 hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4913 LspPullDiagnostics::Default => {
4914 o.insert(LspPullDiagnostics::Response {
4915 server_id,
4916 uri,
4917 diagnostics: PulledDiagnostics::Unchanged { result_id },
4918 registration_id,
4919 });
4920 }
4921 LspPullDiagnostics::Response {
4922 server_id: existing_server_id,
4923 uri: existing_uri,
4924 diagnostics: existing_diagnostics,
4925 ..
4926 } => {
4927 if server_id != *existing_server_id || &uri != existing_uri {
4928 debug_panic!(
4929 "Unexpected state: file {uri} has two different sets of diagnostics reported"
4930 );
4931 }
4932 match existing_diagnostics {
4933 PulledDiagnostics::Unchanged { .. } => {
4934 *existing_diagnostics = PulledDiagnostics::Unchanged { result_id };
4935 }
4936 PulledDiagnostics::Changed { .. } => {}
4937 }
4938 }
4939 },
4940 hash_map::Entry::Vacant(v) => {
4941 v.insert(LspPullDiagnostics::Response {
4942 server_id,
4943 uri,
4944 diagnostics: PulledDiagnostics::Unchanged { result_id },
4945 registration_id,
4946 });
4947 }
4948 }
4949}
4950
4951fn process_full_diagnostics_report(
4952 diagnostics: &mut HashMap<lsp::Uri, LspPullDiagnostics>,
4953 server_id: LanguageServerId,
4954 uri: lsp::Uri,
4955 report: lsp::FullDocumentDiagnosticReport,
4956 registration_id: Option<SharedString>,
4957) {
4958 let result_id = report.result_id.map(SharedString::new);
4959 match diagnostics.entry(uri.clone()) {
4960 hash_map::Entry::Occupied(mut o) => match o.get_mut() {
4961 LspPullDiagnostics::Default => {
4962 o.insert(LspPullDiagnostics::Response {
4963 server_id,
4964 uri,
4965 diagnostics: PulledDiagnostics::Changed {
4966 result_id,
4967 diagnostics: report.items,
4968 },
4969 registration_id,
4970 });
4971 }
4972 LspPullDiagnostics::Response {
4973 server_id: existing_server_id,
4974 uri: existing_uri,
4975 diagnostics: existing_diagnostics,
4976 ..
4977 } => {
4978 if server_id != *existing_server_id || &uri != existing_uri {
4979 debug_panic!(
4980 "Unexpected state: file {uri} has two different sets of diagnostics reported"
4981 );
4982 }
4983 match existing_diagnostics {
4984 PulledDiagnostics::Unchanged { .. } => {
4985 *existing_diagnostics = PulledDiagnostics::Changed {
4986 result_id,
4987 diagnostics: report.items,
4988 };
4989 }
4990 PulledDiagnostics::Changed {
4991 result_id: existing_result_id,
4992 diagnostics: existing_diagnostics,
4993 } => {
4994 if result_id.is_some() {
4995 *existing_result_id = result_id;
4996 }
4997 existing_diagnostics.extend(report.items);
4998 }
4999 }
5000 }
5001 },
5002 hash_map::Entry::Vacant(v) => {
5003 v.insert(LspPullDiagnostics::Response {
5004 server_id,
5005 uri,
5006 diagnostics: PulledDiagnostics::Changed {
5007 result_id,
5008 diagnostics: report.items,
5009 },
5010 registration_id,
5011 });
5012 }
5013 }
5014}