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