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