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