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