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