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 let new_text = lsp_completion
2096 .insert_text
2097 .as_ref()
2098 .unwrap_or(&lsp_completion.label)
2099 .clone();
2100 match default_text_edit {
2101 CompletionListItemDefaultsEditRange::Range(range) => {
2102 Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
2103 range: *range,
2104 new_text,
2105 }))
2106 }
2107 CompletionListItemDefaultsEditRange::InsertAndReplace {
2108 insert,
2109 replace,
2110 } => Some(lsp::CompletionTextEdit::InsertAndReplace(
2111 lsp::InsertReplaceEdit {
2112 new_text,
2113 insert: *insert,
2114 replace: *replace,
2115 },
2116 )),
2117 }
2118 });
2119
2120 let edit = match lsp_edit {
2121 // If the language server provides a range to overwrite, then
2122 // check that the range is valid.
2123 Some(completion_text_edit) => {
2124 match parse_completion_text_edit(&completion_text_edit, &snapshot) {
2125 Some(edit) => edit,
2126 None => return false,
2127 }
2128 }
2129
2130 // If the language server does not provide a range, then infer
2131 // the range based on the syntax tree.
2132 None => {
2133 if self.position != clipped_position {
2134 log::info!("completion out of expected range");
2135 return false;
2136 }
2137
2138 let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
2139 lsp_defaults
2140 .edit_range
2141 .as_ref()
2142 .and_then(|range| match range {
2143 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
2144 _ => None,
2145 })
2146 });
2147
2148 let range = if let Some(range) = default_edit_range {
2149 let range = range_from_lsp(*range);
2150 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2151 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2152 if start != range.start.0 || end != range.end.0 {
2153 log::info!("completion out of expected range");
2154 return false;
2155 }
2156
2157 snapshot.anchor_before(start)..snapshot.anchor_after(end)
2158 } else {
2159 range_for_token
2160 .get_or_insert_with(|| {
2161 let offset = self.position.to_offset(&snapshot);
2162 let (range, kind) = snapshot.surrounding_word(offset);
2163 let range = if kind == Some(CharKind::Word) {
2164 range
2165 } else {
2166 offset..offset
2167 };
2168
2169 snapshot.anchor_before(range.start)
2170 ..snapshot.anchor_after(range.end)
2171 })
2172 .clone()
2173 };
2174
2175 // We already know text_edit is None here
2176 let text = lsp_completion
2177 .insert_text
2178 .as_ref()
2179 .unwrap_or(&lsp_completion.label)
2180 .clone();
2181 (range, text)
2182 }
2183 };
2184
2185 completion_edits.push(edit);
2186 true
2187 });
2188 })?;
2189
2190 language_server_adapter
2191 .process_completions(&mut completions)
2192 .await;
2193
2194 Ok(completions
2195 .into_iter()
2196 .zip(completion_edits)
2197 .map(|(mut lsp_completion, (old_range, mut new_text))| {
2198 LineEnding::normalize(&mut new_text);
2199 if lsp_completion.data.is_none() {
2200 if let Some(default_data) = lsp_defaults
2201 .as_ref()
2202 .and_then(|item_defaults| item_defaults.data.clone())
2203 {
2204 // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
2205 // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
2206 lsp_completion.data = Some(default_data);
2207 }
2208 }
2209 CoreCompletion {
2210 old_range,
2211 new_text,
2212 source: CompletionSource::Lsp {
2213 server_id,
2214 lsp_completion: Box::new(lsp_completion),
2215 lsp_defaults: lsp_defaults.clone(),
2216 resolved: false,
2217 },
2218 }
2219 })
2220 .collect())
2221 }
2222
2223 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2224 let anchor = buffer.anchor_after(self.position);
2225 proto::GetCompletions {
2226 project_id,
2227 buffer_id: buffer.remote_id().into(),
2228 position: Some(language::proto::serialize_anchor(&anchor)),
2229 version: serialize_version(&buffer.version()),
2230 }
2231 }
2232
2233 async fn from_proto(
2234 message: proto::GetCompletions,
2235 _: Entity<LspStore>,
2236 buffer: Entity<Buffer>,
2237 mut cx: AsyncApp,
2238 ) -> Result<Self> {
2239 let version = deserialize_version(&message.version);
2240 buffer
2241 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2242 .await?;
2243 let position = message
2244 .position
2245 .and_then(language::proto::deserialize_anchor)
2246 .map(|p| {
2247 buffer.update(&mut cx, |buffer, _| {
2248 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2249 })
2250 })
2251 .ok_or_else(|| anyhow!("invalid position"))??;
2252 Ok(Self {
2253 position,
2254 context: CompletionContext {
2255 trigger_kind: CompletionTriggerKind::INVOKED,
2256 trigger_character: None,
2257 },
2258 })
2259 }
2260
2261 fn response_to_proto(
2262 completions: Vec<CoreCompletion>,
2263 _: &mut LspStore,
2264 _: PeerId,
2265 buffer_version: &clock::Global,
2266 _: &mut App,
2267 ) -> proto::GetCompletionsResponse {
2268 proto::GetCompletionsResponse {
2269 completions: completions
2270 .iter()
2271 .map(LspStore::serialize_completion)
2272 .collect(),
2273 version: serialize_version(buffer_version),
2274 }
2275 }
2276
2277 async fn response_from_proto(
2278 self,
2279 message: proto::GetCompletionsResponse,
2280 _project: Entity<LspStore>,
2281 buffer: Entity<Buffer>,
2282 mut cx: AsyncApp,
2283 ) -> Result<Self::Response> {
2284 buffer
2285 .update(&mut cx, |buffer, _| {
2286 buffer.wait_for_version(deserialize_version(&message.version))
2287 })?
2288 .await?;
2289
2290 message
2291 .completions
2292 .into_iter()
2293 .map(LspStore::deserialize_completion)
2294 .collect()
2295 }
2296
2297 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2298 BufferId::new(message.buffer_id)
2299 }
2300}
2301
2302pub(crate) fn parse_completion_text_edit(
2303 edit: &lsp::CompletionTextEdit,
2304 snapshot: &BufferSnapshot,
2305) -> Option<(Range<Anchor>, String)> {
2306 match edit {
2307 lsp::CompletionTextEdit::Edit(edit) => {
2308 let range = range_from_lsp(edit.range);
2309 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2310 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2311 if start != range.start.0 || end != range.end.0 {
2312 log::info!("completion out of expected range");
2313 None
2314 } else {
2315 Some((
2316 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2317 edit.new_text.clone(),
2318 ))
2319 }
2320 }
2321
2322 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2323 let range = range_from_lsp(edit.replace);
2324
2325 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2326 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2327 if start != range.start.0 || end != range.end.0 {
2328 log::info!("completion out of expected range");
2329 None
2330 } else {
2331 Some((
2332 snapshot.anchor_before(start)..snapshot.anchor_after(end),
2333 edit.new_text.clone(),
2334 ))
2335 }
2336 }
2337 }
2338}
2339
2340#[async_trait(?Send)]
2341impl LspCommand for GetCodeActions {
2342 type Response = Vec<CodeAction>;
2343 type LspRequest = lsp::request::CodeActionRequest;
2344 type ProtoRequest = proto::GetCodeActions;
2345
2346 fn display_name(&self) -> &str {
2347 "Get code actions"
2348 }
2349
2350 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2351 match &capabilities.server_capabilities.code_action_provider {
2352 None => false,
2353 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2354 _ => {
2355 // If we do know that we want specific code actions AND we know that
2356 // the server only supports specific code actions, then we want to filter
2357 // down to the ones that are supported.
2358 if let Some((requested, supported)) = self
2359 .kinds
2360 .as_ref()
2361 .zip(Self::supported_code_action_kinds(capabilities))
2362 {
2363 let server_supported = supported.into_iter().collect::<HashSet<_>>();
2364 requested.iter().any(|kind| server_supported.contains(kind))
2365 } else {
2366 true
2367 }
2368 }
2369 }
2370 }
2371
2372 fn to_lsp(
2373 &self,
2374 path: &Path,
2375 buffer: &Buffer,
2376 language_server: &Arc<LanguageServer>,
2377 _: &App,
2378 ) -> Result<lsp::CodeActionParams> {
2379 let mut relevant_diagnostics = Vec::new();
2380 for entry in buffer
2381 .snapshot()
2382 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2383 {
2384 relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2385 }
2386
2387 let supported =
2388 Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2389
2390 let only = if let Some(requested) = &self.kinds {
2391 if let Some(supported_kinds) = supported {
2392 let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2393
2394 let filtered = requested
2395 .iter()
2396 .filter(|kind| server_supported.contains(kind))
2397 .cloned()
2398 .collect();
2399 Some(filtered)
2400 } else {
2401 Some(requested.clone())
2402 }
2403 } else {
2404 supported
2405 };
2406
2407 Ok(lsp::CodeActionParams {
2408 text_document: make_text_document_identifier(path)?,
2409 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2410 work_done_progress_params: Default::default(),
2411 partial_result_params: Default::default(),
2412 context: lsp::CodeActionContext {
2413 diagnostics: relevant_diagnostics,
2414 only,
2415 ..lsp::CodeActionContext::default()
2416 },
2417 })
2418 }
2419
2420 async fn response_from_lsp(
2421 self,
2422 actions: Option<lsp::CodeActionResponse>,
2423 lsp_store: Entity<LspStore>,
2424 _: Entity<Buffer>,
2425 server_id: LanguageServerId,
2426 cx: AsyncApp,
2427 ) -> Result<Vec<CodeAction>> {
2428 let requested_kinds_set = if let Some(kinds) = self.kinds {
2429 Some(kinds.into_iter().collect::<HashSet<_>>())
2430 } else {
2431 None
2432 };
2433
2434 let language_server = cx.update(|cx| {
2435 lsp_store
2436 .read(cx)
2437 .language_server_for_id(server_id)
2438 .with_context(|| {
2439 format!("Missing the language server that just returned a response {server_id}")
2440 })
2441 })??;
2442
2443 let server_capabilities = language_server.capabilities();
2444 let available_commands = server_capabilities
2445 .execute_command_provider
2446 .as_ref()
2447 .map(|options| options.commands.as_slice())
2448 .unwrap_or_default();
2449 Ok(actions
2450 .unwrap_or_default()
2451 .into_iter()
2452 .filter_map(|entry| {
2453 let (lsp_action, resolved) = match entry {
2454 lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2455 if let Some(command) = lsp_action.command.as_ref() {
2456 if !available_commands.contains(&command.command) {
2457 return None;
2458 }
2459 }
2460 (LspAction::Action(Box::new(lsp_action)), false)
2461 }
2462 lsp::CodeActionOrCommand::Command(command) => {
2463 if available_commands.contains(&command.command) {
2464 (LspAction::Command(command), true)
2465 } else {
2466 return None;
2467 }
2468 }
2469 };
2470
2471 if let Some((requested_kinds, kind)) =
2472 requested_kinds_set.as_ref().zip(lsp_action.action_kind())
2473 {
2474 if !requested_kinds.contains(&kind) {
2475 return None;
2476 }
2477 }
2478
2479 Some(CodeAction {
2480 server_id,
2481 range: self.range.clone(),
2482 lsp_action,
2483 resolved,
2484 })
2485 })
2486 .collect())
2487 }
2488
2489 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2490 proto::GetCodeActions {
2491 project_id,
2492 buffer_id: buffer.remote_id().into(),
2493 start: Some(language::proto::serialize_anchor(&self.range.start)),
2494 end: Some(language::proto::serialize_anchor(&self.range.end)),
2495 version: serialize_version(&buffer.version()),
2496 }
2497 }
2498
2499 async fn from_proto(
2500 message: proto::GetCodeActions,
2501 _: Entity<LspStore>,
2502 buffer: Entity<Buffer>,
2503 mut cx: AsyncApp,
2504 ) -> Result<Self> {
2505 let start = message
2506 .start
2507 .and_then(language::proto::deserialize_anchor)
2508 .ok_or_else(|| anyhow!("invalid start"))?;
2509 let end = message
2510 .end
2511 .and_then(language::proto::deserialize_anchor)
2512 .ok_or_else(|| anyhow!("invalid end"))?;
2513 buffer
2514 .update(&mut cx, |buffer, _| {
2515 buffer.wait_for_version(deserialize_version(&message.version))
2516 })?
2517 .await?;
2518
2519 Ok(Self {
2520 range: start..end,
2521 kinds: None,
2522 })
2523 }
2524
2525 fn response_to_proto(
2526 code_actions: Vec<CodeAction>,
2527 _: &mut LspStore,
2528 _: PeerId,
2529 buffer_version: &clock::Global,
2530 _: &mut App,
2531 ) -> proto::GetCodeActionsResponse {
2532 proto::GetCodeActionsResponse {
2533 actions: code_actions
2534 .iter()
2535 .map(LspStore::serialize_code_action)
2536 .collect(),
2537 version: serialize_version(buffer_version),
2538 }
2539 }
2540
2541 async fn response_from_proto(
2542 self,
2543 message: proto::GetCodeActionsResponse,
2544 _: Entity<LspStore>,
2545 buffer: Entity<Buffer>,
2546 mut cx: AsyncApp,
2547 ) -> Result<Vec<CodeAction>> {
2548 buffer
2549 .update(&mut cx, |buffer, _| {
2550 buffer.wait_for_version(deserialize_version(&message.version))
2551 })?
2552 .await?;
2553 message
2554 .actions
2555 .into_iter()
2556 .map(LspStore::deserialize_code_action)
2557 .collect()
2558 }
2559
2560 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2561 BufferId::new(message.buffer_id)
2562 }
2563}
2564
2565impl GetCodeActions {
2566 fn supported_code_action_kinds(
2567 capabilities: AdapterServerCapabilities,
2568 ) -> Option<Vec<CodeActionKind>> {
2569 match capabilities.server_capabilities.code_action_provider {
2570 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2571 code_action_kinds: Some(supported_action_kinds),
2572 ..
2573 })) => Some(supported_action_kinds.clone()),
2574 _ => capabilities.code_action_kinds,
2575 }
2576 }
2577
2578 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2579 capabilities
2580 .code_action_provider
2581 .as_ref()
2582 .and_then(|options| match options {
2583 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2584 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2585 })
2586 .unwrap_or(false)
2587 }
2588}
2589
2590#[async_trait(?Send)]
2591impl LspCommand for OnTypeFormatting {
2592 type Response = Option<Transaction>;
2593 type LspRequest = lsp::request::OnTypeFormatting;
2594 type ProtoRequest = proto::OnTypeFormatting;
2595
2596 fn display_name(&self) -> &str {
2597 "Formatting on typing"
2598 }
2599
2600 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2601 let Some(on_type_formatting_options) = &capabilities
2602 .server_capabilities
2603 .document_on_type_formatting_provider
2604 else {
2605 return false;
2606 };
2607 on_type_formatting_options
2608 .first_trigger_character
2609 .contains(&self.trigger)
2610 || on_type_formatting_options
2611 .more_trigger_character
2612 .iter()
2613 .flatten()
2614 .any(|chars| chars.contains(&self.trigger))
2615 }
2616
2617 fn to_lsp(
2618 &self,
2619 path: &Path,
2620 _: &Buffer,
2621 _: &Arc<LanguageServer>,
2622 _: &App,
2623 ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2624 Ok(lsp::DocumentOnTypeFormattingParams {
2625 text_document_position: make_lsp_text_document_position(path, self.position)?,
2626 ch: self.trigger.clone(),
2627 options: self.options.clone(),
2628 })
2629 }
2630
2631 async fn response_from_lsp(
2632 self,
2633 message: Option<Vec<lsp::TextEdit>>,
2634 lsp_store: Entity<LspStore>,
2635 buffer: Entity<Buffer>,
2636 server_id: LanguageServerId,
2637 mut cx: AsyncApp,
2638 ) -> Result<Option<Transaction>> {
2639 if let Some(edits) = message {
2640 let (lsp_adapter, lsp_server) =
2641 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2642 LocalLspStore::deserialize_text_edits(
2643 lsp_store,
2644 buffer,
2645 edits,
2646 self.push_to_history,
2647 lsp_adapter,
2648 lsp_server,
2649 &mut cx,
2650 )
2651 .await
2652 } else {
2653 Ok(None)
2654 }
2655 }
2656
2657 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2658 proto::OnTypeFormatting {
2659 project_id,
2660 buffer_id: buffer.remote_id().into(),
2661 position: Some(language::proto::serialize_anchor(
2662 &buffer.anchor_before(self.position),
2663 )),
2664 trigger: self.trigger.clone(),
2665 version: serialize_version(&buffer.version()),
2666 }
2667 }
2668
2669 async fn from_proto(
2670 message: proto::OnTypeFormatting,
2671 _: Entity<LspStore>,
2672 buffer: Entity<Buffer>,
2673 mut cx: AsyncApp,
2674 ) -> Result<Self> {
2675 let position = message
2676 .position
2677 .and_then(deserialize_anchor)
2678 .ok_or_else(|| anyhow!("invalid position"))?;
2679 buffer
2680 .update(&mut cx, |buffer, _| {
2681 buffer.wait_for_version(deserialize_version(&message.version))
2682 })?
2683 .await?;
2684
2685 let options = buffer.update(&mut cx, |buffer, cx| {
2686 lsp_formatting_options(
2687 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2688 )
2689 })?;
2690
2691 Ok(Self {
2692 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2693 trigger: message.trigger.clone(),
2694 options,
2695 push_to_history: false,
2696 })
2697 }
2698
2699 fn response_to_proto(
2700 response: Option<Transaction>,
2701 _: &mut LspStore,
2702 _: PeerId,
2703 _: &clock::Global,
2704 _: &mut App,
2705 ) -> proto::OnTypeFormattingResponse {
2706 proto::OnTypeFormattingResponse {
2707 transaction: response
2708 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2709 }
2710 }
2711
2712 async fn response_from_proto(
2713 self,
2714 message: proto::OnTypeFormattingResponse,
2715 _: Entity<LspStore>,
2716 _: Entity<Buffer>,
2717 _: AsyncApp,
2718 ) -> Result<Option<Transaction>> {
2719 let Some(transaction) = message.transaction else {
2720 return Ok(None);
2721 };
2722 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2723 }
2724
2725 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2726 BufferId::new(message.buffer_id)
2727 }
2728}
2729
2730impl InlayHints {
2731 pub async fn lsp_to_project_hint(
2732 lsp_hint: lsp::InlayHint,
2733 buffer_handle: &Entity<Buffer>,
2734 server_id: LanguageServerId,
2735 resolve_state: ResolveState,
2736 force_no_type_left_padding: bool,
2737 cx: &mut AsyncApp,
2738 ) -> anyhow::Result<InlayHint> {
2739 let kind = lsp_hint.kind.and_then(|kind| match kind {
2740 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2741 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2742 _ => None,
2743 });
2744
2745 let position = buffer_handle.update(cx, |buffer, _| {
2746 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2747 if kind == Some(InlayHintKind::Parameter) {
2748 buffer.anchor_before(position)
2749 } else {
2750 buffer.anchor_after(position)
2751 }
2752 })?;
2753 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2754 .await
2755 .context("lsp to project inlay hint conversion")?;
2756 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2757 false
2758 } else {
2759 lsp_hint.padding_left.unwrap_or(false)
2760 };
2761
2762 Ok(InlayHint {
2763 position,
2764 padding_left,
2765 padding_right: lsp_hint.padding_right.unwrap_or(false),
2766 label,
2767 kind,
2768 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2769 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2770 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2771 InlayHintTooltip::MarkupContent(MarkupContent {
2772 kind: match markup_content.kind {
2773 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2774 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2775 },
2776 value: markup_content.value,
2777 })
2778 }
2779 }),
2780 resolve_state,
2781 })
2782 }
2783
2784 async fn lsp_inlay_label_to_project(
2785 lsp_label: lsp::InlayHintLabel,
2786 server_id: LanguageServerId,
2787 ) -> anyhow::Result<InlayHintLabel> {
2788 let label = match lsp_label {
2789 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2790 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2791 let mut parts = Vec::with_capacity(lsp_parts.len());
2792 for lsp_part in lsp_parts {
2793 parts.push(InlayHintLabelPart {
2794 value: lsp_part.value,
2795 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2796 lsp::InlayHintLabelPartTooltip::String(s) => {
2797 InlayHintLabelPartTooltip::String(s)
2798 }
2799 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2800 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2801 kind: match markup_content.kind {
2802 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2803 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2804 },
2805 value: markup_content.value,
2806 })
2807 }
2808 }),
2809 location: Some(server_id).zip(lsp_part.location),
2810 });
2811 }
2812 InlayHintLabel::LabelParts(parts)
2813 }
2814 };
2815
2816 Ok(label)
2817 }
2818
2819 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2820 let (state, lsp_resolve_state) = match response_hint.resolve_state {
2821 ResolveState::Resolved => (0, None),
2822 ResolveState::CanResolve(server_id, resolve_data) => (
2823 1,
2824 Some(proto::resolve_state::LspResolveState {
2825 server_id: server_id.0 as u64,
2826 value: resolve_data.map(|json_data| {
2827 serde_json::to_string(&json_data)
2828 .expect("failed to serialize resolve json data")
2829 }),
2830 }),
2831 ),
2832 ResolveState::Resolving => (2, None),
2833 };
2834 let resolve_state = Some(proto::ResolveState {
2835 state,
2836 lsp_resolve_state,
2837 });
2838 proto::InlayHint {
2839 position: Some(language::proto::serialize_anchor(&response_hint.position)),
2840 padding_left: response_hint.padding_left,
2841 padding_right: response_hint.padding_right,
2842 label: Some(proto::InlayHintLabel {
2843 label: Some(match response_hint.label {
2844 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2845 InlayHintLabel::LabelParts(label_parts) => {
2846 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2847 parts: label_parts.into_iter().map(|label_part| {
2848 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2849 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 });
2850 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 });
2851 proto::InlayHintLabelPart {
2852 value: label_part.value,
2853 tooltip: label_part.tooltip.map(|tooltip| {
2854 let proto_tooltip = match tooltip {
2855 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2856 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2857 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2858 value: markup_content.value,
2859 }),
2860 };
2861 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2862 }),
2863 location_url,
2864 location_range_start,
2865 location_range_end,
2866 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2867 }}).collect()
2868 })
2869 }
2870 }),
2871 }),
2872 kind: response_hint.kind.map(|kind| kind.name().to_string()),
2873 tooltip: response_hint.tooltip.map(|response_tooltip| {
2874 let proto_tooltip = match response_tooltip {
2875 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2876 InlayHintTooltip::MarkupContent(markup_content) => {
2877 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2878 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2879 value: markup_content.value,
2880 })
2881 }
2882 };
2883 proto::InlayHintTooltip {
2884 content: Some(proto_tooltip),
2885 }
2886 }),
2887 resolve_state,
2888 }
2889 }
2890
2891 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2892 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2893 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2894 });
2895 let resolve_state_data = resolve_state
2896 .lsp_resolve_state.as_ref()
2897 .map(|lsp_resolve_state| {
2898 let value = lsp_resolve_state.value.as_deref().map(|value| {
2899 serde_json::from_str::<Option<lsp::LSPAny>>(value)
2900 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2901 }).transpose()?.flatten();
2902 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2903 })
2904 .transpose()?;
2905 let resolve_state = match resolve_state.state {
2906 0 => ResolveState::Resolved,
2907 1 => {
2908 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2909 format!(
2910 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
2911 )
2912 })?;
2913 ResolveState::CanResolve(server_id, lsp_resolve_state)
2914 }
2915 2 => ResolveState::Resolving,
2916 invalid => {
2917 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
2918 }
2919 };
2920 Ok(InlayHint {
2921 position: message_hint
2922 .position
2923 .and_then(language::proto::deserialize_anchor)
2924 .context("invalid position")?,
2925 label: match message_hint
2926 .label
2927 .and_then(|label| label.label)
2928 .context("missing label")?
2929 {
2930 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2931 proto::inlay_hint_label::Label::LabelParts(parts) => {
2932 let mut label_parts = Vec::new();
2933 for part in parts.parts {
2934 label_parts.push(InlayHintLabelPart {
2935 value: part.value,
2936 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2937 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
2938 InlayHintLabelPartTooltip::String(s)
2939 }
2940 Some(
2941 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
2942 markup_content,
2943 ),
2944 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2945 kind: if markup_content.is_markdown {
2946 HoverBlockKind::Markdown
2947 } else {
2948 HoverBlockKind::PlainText
2949 },
2950 value: markup_content.value,
2951 }),
2952 None => InlayHintLabelPartTooltip::String(String::new()),
2953 }),
2954 location: {
2955 match part
2956 .location_url
2957 .zip(
2958 part.location_range_start.and_then(|start| {
2959 Some(start..part.location_range_end?)
2960 }),
2961 )
2962 .zip(part.language_server_id)
2963 {
2964 Some(((uri, range), server_id)) => Some((
2965 LanguageServerId(server_id as usize),
2966 lsp::Location {
2967 uri: lsp::Url::parse(&uri)
2968 .context("invalid uri in hint part {part:?}")?,
2969 range: lsp::Range::new(
2970 point_to_lsp(PointUtf16::new(
2971 range.start.row,
2972 range.start.column,
2973 )),
2974 point_to_lsp(PointUtf16::new(
2975 range.end.row,
2976 range.end.column,
2977 )),
2978 ),
2979 },
2980 )),
2981 None => None,
2982 }
2983 },
2984 });
2985 }
2986
2987 InlayHintLabel::LabelParts(label_parts)
2988 }
2989 },
2990 padding_left: message_hint.padding_left,
2991 padding_right: message_hint.padding_right,
2992 kind: message_hint
2993 .kind
2994 .as_deref()
2995 .and_then(InlayHintKind::from_name),
2996 tooltip: message_hint.tooltip.and_then(|tooltip| {
2997 Some(match tooltip.content? {
2998 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2999 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3000 InlayHintTooltip::MarkupContent(MarkupContent {
3001 kind: if markup_content.is_markdown {
3002 HoverBlockKind::Markdown
3003 } else {
3004 HoverBlockKind::PlainText
3005 },
3006 value: markup_content.value,
3007 })
3008 }
3009 })
3010 }),
3011 resolve_state,
3012 })
3013 }
3014
3015 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3016 lsp::InlayHint {
3017 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3018 kind: hint.kind.map(|kind| match kind {
3019 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3020 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3021 }),
3022 text_edits: None,
3023 tooltip: hint.tooltip.and_then(|tooltip| {
3024 Some(match tooltip {
3025 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3026 InlayHintTooltip::MarkupContent(markup_content) => {
3027 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3028 kind: match markup_content.kind {
3029 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3030 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3031 HoverBlockKind::Code { .. } => return None,
3032 },
3033 value: markup_content.value,
3034 })
3035 }
3036 })
3037 }),
3038 label: match hint.label {
3039 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3040 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3041 label_parts
3042 .into_iter()
3043 .map(|part| lsp::InlayHintLabelPart {
3044 value: part.value,
3045 tooltip: part.tooltip.and_then(|tooltip| {
3046 Some(match tooltip {
3047 InlayHintLabelPartTooltip::String(s) => {
3048 lsp::InlayHintLabelPartTooltip::String(s)
3049 }
3050 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3051 lsp::InlayHintLabelPartTooltip::MarkupContent(
3052 lsp::MarkupContent {
3053 kind: match markup_content.kind {
3054 HoverBlockKind::PlainText => {
3055 lsp::MarkupKind::PlainText
3056 }
3057 HoverBlockKind::Markdown => {
3058 lsp::MarkupKind::Markdown
3059 }
3060 HoverBlockKind::Code { .. } => return None,
3061 },
3062 value: markup_content.value,
3063 },
3064 )
3065 }
3066 })
3067 }),
3068 location: part.location.map(|(_, location)| location),
3069 command: None,
3070 })
3071 .collect(),
3072 ),
3073 },
3074 padding_left: Some(hint.padding_left),
3075 padding_right: Some(hint.padding_right),
3076 data: match hint.resolve_state {
3077 ResolveState::CanResolve(_, data) => data,
3078 ResolveState::Resolving | ResolveState::Resolved => None,
3079 },
3080 }
3081 }
3082
3083 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3084 capabilities
3085 .inlay_hint_provider
3086 .as_ref()
3087 .and_then(|options| match options {
3088 OneOf::Left(_is_supported) => None,
3089 OneOf::Right(capabilities) => match capabilities {
3090 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3091 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3092 o.inlay_hint_options.resolve_provider
3093 }
3094 },
3095 })
3096 .unwrap_or(false)
3097 }
3098}
3099
3100#[async_trait(?Send)]
3101impl LspCommand for InlayHints {
3102 type Response = Vec<InlayHint>;
3103 type LspRequest = lsp::InlayHintRequest;
3104 type ProtoRequest = proto::InlayHints;
3105
3106 fn display_name(&self) -> &str {
3107 "Inlay hints"
3108 }
3109
3110 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3111 let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
3112 else {
3113 return false;
3114 };
3115 match inlay_hint_provider {
3116 lsp::OneOf::Left(enabled) => *enabled,
3117 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
3118 lsp::InlayHintServerCapabilities::Options(_) => true,
3119 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
3120 },
3121 }
3122 }
3123
3124 fn to_lsp(
3125 &self,
3126 path: &Path,
3127 buffer: &Buffer,
3128 _: &Arc<LanguageServer>,
3129 _: &App,
3130 ) -> Result<lsp::InlayHintParams> {
3131 Ok(lsp::InlayHintParams {
3132 text_document: lsp::TextDocumentIdentifier {
3133 uri: file_path_to_lsp_url(path)?,
3134 },
3135 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3136 work_done_progress_params: Default::default(),
3137 })
3138 }
3139
3140 async fn response_from_lsp(
3141 self,
3142 message: Option<Vec<lsp::InlayHint>>,
3143 lsp_store: Entity<LspStore>,
3144 buffer: Entity<Buffer>,
3145 server_id: LanguageServerId,
3146 mut cx: AsyncApp,
3147 ) -> anyhow::Result<Vec<InlayHint>> {
3148 let (lsp_adapter, lsp_server) =
3149 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3150 // `typescript-language-server` adds padding to the left for type hints, turning
3151 // `const foo: boolean` into `const foo : boolean` which looks odd.
3152 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3153 //
3154 // We could trim the whole string, but being pessimistic on par with the situation above,
3155 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3156 // Hence let's use a heuristic first to handle the most awkward case and look for more.
3157 let force_no_type_left_padding =
3158 lsp_adapter.name.0.as_ref() == "typescript-language-server";
3159
3160 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3161 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3162 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3163 } else {
3164 ResolveState::Resolved
3165 };
3166
3167 let buffer = buffer.clone();
3168 cx.spawn(async move |cx| {
3169 InlayHints::lsp_to_project_hint(
3170 lsp_hint,
3171 &buffer,
3172 server_id,
3173 resolve_state,
3174 force_no_type_left_padding,
3175 cx,
3176 )
3177 .await
3178 })
3179 });
3180 future::join_all(hints)
3181 .await
3182 .into_iter()
3183 .collect::<anyhow::Result<_>>()
3184 .context("lsp to project inlay hints conversion")
3185 }
3186
3187 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3188 proto::InlayHints {
3189 project_id,
3190 buffer_id: buffer.remote_id().into(),
3191 start: Some(language::proto::serialize_anchor(&self.range.start)),
3192 end: Some(language::proto::serialize_anchor(&self.range.end)),
3193 version: serialize_version(&buffer.version()),
3194 }
3195 }
3196
3197 async fn from_proto(
3198 message: proto::InlayHints,
3199 _: Entity<LspStore>,
3200 buffer: Entity<Buffer>,
3201 mut cx: AsyncApp,
3202 ) -> Result<Self> {
3203 let start = message
3204 .start
3205 .and_then(language::proto::deserialize_anchor)
3206 .context("invalid start")?;
3207 let end = message
3208 .end
3209 .and_then(language::proto::deserialize_anchor)
3210 .context("invalid end")?;
3211 buffer
3212 .update(&mut cx, |buffer, _| {
3213 buffer.wait_for_version(deserialize_version(&message.version))
3214 })?
3215 .await?;
3216
3217 Ok(Self { range: start..end })
3218 }
3219
3220 fn response_to_proto(
3221 response: Vec<InlayHint>,
3222 _: &mut LspStore,
3223 _: PeerId,
3224 buffer_version: &clock::Global,
3225 _: &mut App,
3226 ) -> proto::InlayHintsResponse {
3227 proto::InlayHintsResponse {
3228 hints: response
3229 .into_iter()
3230 .map(InlayHints::project_to_proto_hint)
3231 .collect(),
3232 version: serialize_version(buffer_version),
3233 }
3234 }
3235
3236 async fn response_from_proto(
3237 self,
3238 message: proto::InlayHintsResponse,
3239 _: Entity<LspStore>,
3240 buffer: Entity<Buffer>,
3241 mut cx: AsyncApp,
3242 ) -> anyhow::Result<Vec<InlayHint>> {
3243 buffer
3244 .update(&mut cx, |buffer, _| {
3245 buffer.wait_for_version(deserialize_version(&message.version))
3246 })?
3247 .await?;
3248
3249 let mut hints = Vec::new();
3250 for message_hint in message.hints {
3251 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3252 }
3253
3254 Ok(hints)
3255 }
3256
3257 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3258 BufferId::new(message.buffer_id)
3259 }
3260}
3261
3262#[async_trait(?Send)]
3263impl LspCommand for GetCodeLens {
3264 type Response = Vec<CodeAction>;
3265 type LspRequest = lsp::CodeLensRequest;
3266 type ProtoRequest = proto::GetCodeLens;
3267
3268 fn display_name(&self) -> &str {
3269 "Code Lens"
3270 }
3271
3272 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3273 capabilities
3274 .server_capabilities
3275 .code_lens_provider
3276 .as_ref()
3277 .map_or(false, |code_lens_options| {
3278 code_lens_options.resolve_provider.unwrap_or(false)
3279 })
3280 }
3281
3282 fn to_lsp(
3283 &self,
3284 path: &Path,
3285 _: &Buffer,
3286 _: &Arc<LanguageServer>,
3287 _: &App,
3288 ) -> Result<lsp::CodeLensParams> {
3289 Ok(lsp::CodeLensParams {
3290 text_document: lsp::TextDocumentIdentifier {
3291 uri: file_path_to_lsp_url(path)?,
3292 },
3293 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3294 partial_result_params: lsp::PartialResultParams::default(),
3295 })
3296 }
3297
3298 async fn response_from_lsp(
3299 self,
3300 message: Option<Vec<lsp::CodeLens>>,
3301 lsp_store: Entity<LspStore>,
3302 buffer: Entity<Buffer>,
3303 server_id: LanguageServerId,
3304 mut cx: AsyncApp,
3305 ) -> anyhow::Result<Vec<CodeAction>> {
3306 let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
3307 let language_server = cx.update(|cx| {
3308 lsp_store
3309 .read(cx)
3310 .language_server_for_id(server_id)
3311 .with_context(|| {
3312 format!("Missing the language server that just returned a response {server_id}")
3313 })
3314 })??;
3315 let server_capabilities = language_server.capabilities();
3316 let available_commands = server_capabilities
3317 .execute_command_provider
3318 .as_ref()
3319 .map(|options| options.commands.as_slice())
3320 .unwrap_or_default();
3321 Ok(message
3322 .unwrap_or_default()
3323 .into_iter()
3324 .filter(|code_lens| {
3325 code_lens
3326 .command
3327 .as_ref()
3328 .is_none_or(|command| available_commands.contains(&command.command))
3329 })
3330 .map(|code_lens| {
3331 let code_lens_range = range_from_lsp(code_lens.range);
3332 let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3333 let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3334 let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3335 CodeAction {
3336 server_id,
3337 range,
3338 lsp_action: LspAction::CodeLens(code_lens),
3339 resolved: false,
3340 }
3341 })
3342 .collect())
3343 }
3344
3345 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3346 proto::GetCodeLens {
3347 project_id,
3348 buffer_id: buffer.remote_id().into(),
3349 version: serialize_version(&buffer.version()),
3350 }
3351 }
3352
3353 async fn from_proto(
3354 message: proto::GetCodeLens,
3355 _: Entity<LspStore>,
3356 buffer: Entity<Buffer>,
3357 mut cx: AsyncApp,
3358 ) -> Result<Self> {
3359 buffer
3360 .update(&mut cx, |buffer, _| {
3361 buffer.wait_for_version(deserialize_version(&message.version))
3362 })?
3363 .await?;
3364 Ok(Self)
3365 }
3366
3367 fn response_to_proto(
3368 response: Vec<CodeAction>,
3369 _: &mut LspStore,
3370 _: PeerId,
3371 buffer_version: &clock::Global,
3372 _: &mut App,
3373 ) -> proto::GetCodeLensResponse {
3374 proto::GetCodeLensResponse {
3375 lens_actions: response
3376 .iter()
3377 .map(LspStore::serialize_code_action)
3378 .collect(),
3379 version: serialize_version(buffer_version),
3380 }
3381 }
3382
3383 async fn response_from_proto(
3384 self,
3385 message: proto::GetCodeLensResponse,
3386 _: Entity<LspStore>,
3387 buffer: Entity<Buffer>,
3388 mut cx: AsyncApp,
3389 ) -> anyhow::Result<Vec<CodeAction>> {
3390 buffer
3391 .update(&mut cx, |buffer, _| {
3392 buffer.wait_for_version(deserialize_version(&message.version))
3393 })?
3394 .await?;
3395 message
3396 .lens_actions
3397 .into_iter()
3398 .map(LspStore::deserialize_code_action)
3399 .collect::<Result<Vec<_>>>()
3400 .context("deserializing proto code lens response")
3401 }
3402
3403 fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3404 BufferId::new(message.buffer_id)
3405 }
3406}
3407
3408#[async_trait(?Send)]
3409impl LspCommand for LinkedEditingRange {
3410 type Response = Vec<Range<Anchor>>;
3411 type LspRequest = lsp::request::LinkedEditingRange;
3412 type ProtoRequest = proto::LinkedEditingRange;
3413
3414 fn display_name(&self) -> &str {
3415 "Linked editing range"
3416 }
3417
3418 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3419 let Some(linked_editing_options) = &capabilities
3420 .server_capabilities
3421 .linked_editing_range_provider
3422 else {
3423 return false;
3424 };
3425 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3426 return false;
3427 }
3428 true
3429 }
3430
3431 fn to_lsp(
3432 &self,
3433 path: &Path,
3434 buffer: &Buffer,
3435 _server: &Arc<LanguageServer>,
3436 _: &App,
3437 ) -> Result<lsp::LinkedEditingRangeParams> {
3438 let position = self.position.to_point_utf16(&buffer.snapshot());
3439 Ok(lsp::LinkedEditingRangeParams {
3440 text_document_position_params: make_lsp_text_document_position(path, position)?,
3441 work_done_progress_params: Default::default(),
3442 })
3443 }
3444
3445 async fn response_from_lsp(
3446 self,
3447 message: Option<lsp::LinkedEditingRanges>,
3448 _: Entity<LspStore>,
3449 buffer: Entity<Buffer>,
3450 _server_id: LanguageServerId,
3451 cx: AsyncApp,
3452 ) -> Result<Vec<Range<Anchor>>> {
3453 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3454 ranges.sort_by_key(|range| range.start);
3455
3456 buffer.read_with(&cx, |buffer, _| {
3457 ranges
3458 .into_iter()
3459 .map(|range| {
3460 let start =
3461 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3462 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3463 buffer.anchor_before(start)..buffer.anchor_after(end)
3464 })
3465 .collect()
3466 })
3467 } else {
3468 Ok(vec![])
3469 }
3470 }
3471
3472 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3473 proto::LinkedEditingRange {
3474 project_id,
3475 buffer_id: buffer.remote_id().to_proto(),
3476 position: Some(serialize_anchor(&self.position)),
3477 version: serialize_version(&buffer.version()),
3478 }
3479 }
3480
3481 async fn from_proto(
3482 message: proto::LinkedEditingRange,
3483 _: Entity<LspStore>,
3484 buffer: Entity<Buffer>,
3485 mut cx: AsyncApp,
3486 ) -> Result<Self> {
3487 let position = message
3488 .position
3489 .ok_or_else(|| anyhow!("invalid position"))?;
3490 buffer
3491 .update(&mut cx, |buffer, _| {
3492 buffer.wait_for_version(deserialize_version(&message.version))
3493 })?
3494 .await?;
3495 let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3496 buffer
3497 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3498 .await?;
3499 Ok(Self { position })
3500 }
3501
3502 fn response_to_proto(
3503 response: Vec<Range<Anchor>>,
3504 _: &mut LspStore,
3505 _: PeerId,
3506 buffer_version: &clock::Global,
3507 _: &mut App,
3508 ) -> proto::LinkedEditingRangeResponse {
3509 proto::LinkedEditingRangeResponse {
3510 items: response
3511 .into_iter()
3512 .map(|range| proto::AnchorRange {
3513 start: Some(serialize_anchor(&range.start)),
3514 end: Some(serialize_anchor(&range.end)),
3515 })
3516 .collect(),
3517 version: serialize_version(buffer_version),
3518 }
3519 }
3520
3521 async fn response_from_proto(
3522 self,
3523 message: proto::LinkedEditingRangeResponse,
3524 _: Entity<LspStore>,
3525 buffer: Entity<Buffer>,
3526 mut cx: AsyncApp,
3527 ) -> Result<Vec<Range<Anchor>>> {
3528 buffer
3529 .update(&mut cx, |buffer, _| {
3530 buffer.wait_for_version(deserialize_version(&message.version))
3531 })?
3532 .await?;
3533 let items: Vec<Range<Anchor>> = message
3534 .items
3535 .into_iter()
3536 .filter_map(|range| {
3537 let start = deserialize_anchor(range.start?)?;
3538 let end = deserialize_anchor(range.end?)?;
3539 Some(start..end)
3540 })
3541 .collect();
3542 for range in &items {
3543 buffer
3544 .update(&mut cx, |buffer, _| {
3545 buffer.wait_for_anchors([range.start, range.end])
3546 })?
3547 .await?;
3548 }
3549 Ok(items)
3550 }
3551
3552 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3553 BufferId::new(message.buffer_id)
3554 }
3555}