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