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