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