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