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