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