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