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