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