1mod signature_help;
2
3use crate::{
4 CodeAction, CompletionSource, CoreCompletion, DocumentHighlight, DocumentSymbol, Hover,
5 HoverBlock, HoverBlockKind, InlayHint, InlayHintLabel, InlayHintLabelPart,
6 InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink, LspAction, MarkupContent,
7 PrepareRenameResponse, ProjectTransaction, ResolveState,
8 lsp_store::{LocalLspStore, LspStore},
9};
10use anyhow::{Context as _, Result, anyhow};
11use async_trait::async_trait;
12use client::proto::{self, PeerId};
13use clock::Global;
14use collections::HashSet;
15use futures::future;
16use gpui::{App, AsyncApp, Entity};
17use language::{
18 Anchor, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CharKind, OffsetRangeExt, PointUtf16,
19 ToOffset, ToPointUtf16, Transaction, Unclipped,
20 language_settings::{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
969async 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, &mut cx).await?)
978 }
979
980 Ok(links)
981}
982
983pub async fn location_link_from_proto(
984 link: proto::LocationLink,
985 lsp_store: &Entity<LspStore>,
986 cx: &mut AsyncApp,
987) -> Result<LocationLink> {
988 let origin = match link.origin {
989 Some(origin) => {
990 let buffer_id = BufferId::new(origin.buffer_id)?;
991 let buffer = lsp_store
992 .update(cx, |lsp_store, cx| {
993 lsp_store.wait_for_remote_buffer(buffer_id, cx)
994 })?
995 .await?;
996 let start = origin
997 .start
998 .and_then(deserialize_anchor)
999 .ok_or_else(|| anyhow!("missing origin start"))?;
1000 let end = origin
1001 .end
1002 .and_then(deserialize_anchor)
1003 .ok_or_else(|| anyhow!("missing origin end"))?;
1004 buffer
1005 .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1006 .await?;
1007 Some(Location {
1008 buffer,
1009 range: start..end,
1010 })
1011 }
1012 None => None,
1013 };
1014
1015 let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
1016 let buffer_id = BufferId::new(target.buffer_id)?;
1017 let buffer = lsp_store
1018 .update(cx, |lsp_store, cx| {
1019 lsp_store.wait_for_remote_buffer(buffer_id, cx)
1020 })?
1021 .await?;
1022 let start = target
1023 .start
1024 .and_then(deserialize_anchor)
1025 .ok_or_else(|| anyhow!("missing target start"))?;
1026 let end = target
1027 .end
1028 .and_then(deserialize_anchor)
1029 .ok_or_else(|| anyhow!("missing target end"))?;
1030 buffer
1031 .update(cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1032 .await?;
1033 let target = Location {
1034 buffer,
1035 range: start..end,
1036 };
1037 Ok(LocationLink { origin, target })
1038}
1039
1040async fn location_links_from_lsp(
1041 message: Option<lsp::GotoDefinitionResponse>,
1042 lsp_store: Entity<LspStore>,
1043 buffer: Entity<Buffer>,
1044 server_id: LanguageServerId,
1045 mut cx: AsyncApp,
1046) -> Result<Vec<LocationLink>> {
1047 let message = match message {
1048 Some(message) => message,
1049 None => return Ok(Vec::new()),
1050 };
1051
1052 let mut unresolved_links = Vec::new();
1053 match message {
1054 lsp::GotoDefinitionResponse::Scalar(loc) => {
1055 unresolved_links.push((None, loc.uri, loc.range));
1056 }
1057
1058 lsp::GotoDefinitionResponse::Array(locs) => {
1059 unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
1060 }
1061
1062 lsp::GotoDefinitionResponse::Link(links) => {
1063 unresolved_links.extend(links.into_iter().map(|l| {
1064 (
1065 l.origin_selection_range,
1066 l.target_uri,
1067 l.target_selection_range,
1068 )
1069 }));
1070 }
1071 }
1072
1073 let (lsp_adapter, language_server) =
1074 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1075 let mut definitions = Vec::new();
1076 for (origin_range, target_uri, target_range) in unresolved_links {
1077 let target_buffer_handle = lsp_store
1078 .update(&mut cx, |this, cx| {
1079 this.open_local_buffer_via_lsp(
1080 target_uri,
1081 language_server.server_id(),
1082 lsp_adapter.name.clone(),
1083 cx,
1084 )
1085 })?
1086 .await?;
1087
1088 cx.update(|cx| {
1089 let origin_location = origin_range.map(|origin_range| {
1090 let origin_buffer = buffer.read(cx);
1091 let origin_start =
1092 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1093 let origin_end =
1094 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1095 Location {
1096 buffer: buffer.clone(),
1097 range: origin_buffer.anchor_after(origin_start)
1098 ..origin_buffer.anchor_before(origin_end),
1099 }
1100 });
1101
1102 let target_buffer = target_buffer_handle.read(cx);
1103 let target_start =
1104 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1105 let target_end =
1106 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1107 let target_location = Location {
1108 buffer: target_buffer_handle,
1109 range: target_buffer.anchor_after(target_start)
1110 ..target_buffer.anchor_before(target_end),
1111 };
1112
1113 definitions.push(LocationLink {
1114 origin: origin_location,
1115 target: target_location,
1116 })
1117 })?;
1118 }
1119 Ok(definitions)
1120}
1121
1122pub async fn location_link_from_lsp(
1123 link: lsp::LocationLink,
1124 lsp_store: &Entity<LspStore>,
1125 buffer: &Entity<Buffer>,
1126 server_id: LanguageServerId,
1127 cx: &mut AsyncApp,
1128) -> Result<LocationLink> {
1129 let (lsp_adapter, language_server) =
1130 language_server_for_buffer(&lsp_store, &buffer, server_id, cx)?;
1131
1132 let (origin_range, target_uri, target_range) = (
1133 link.origin_selection_range,
1134 link.target_uri,
1135 link.target_selection_range,
1136 );
1137
1138 let target_buffer_handle = lsp_store
1139 .update(cx, |lsp_store, cx| {
1140 lsp_store.open_local_buffer_via_lsp(
1141 target_uri,
1142 language_server.server_id(),
1143 lsp_adapter.name.clone(),
1144 cx,
1145 )
1146 })?
1147 .await?;
1148
1149 cx.update(|cx| {
1150 let origin_location = origin_range.map(|origin_range| {
1151 let origin_buffer = buffer.read(cx);
1152 let origin_start =
1153 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
1154 let origin_end =
1155 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
1156 Location {
1157 buffer: buffer.clone(),
1158 range: origin_buffer.anchor_after(origin_start)
1159 ..origin_buffer.anchor_before(origin_end),
1160 }
1161 });
1162
1163 let target_buffer = target_buffer_handle.read(cx);
1164 let target_start =
1165 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
1166 let target_end =
1167 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
1168 let target_location = Location {
1169 buffer: target_buffer_handle,
1170 range: target_buffer.anchor_after(target_start)
1171 ..target_buffer.anchor_before(target_end),
1172 };
1173
1174 LocationLink {
1175 origin: origin_location,
1176 target: target_location,
1177 }
1178 })
1179}
1180
1181fn location_links_to_proto(
1182 links: Vec<LocationLink>,
1183 lsp_store: &mut LspStore,
1184 peer_id: PeerId,
1185 cx: &mut App,
1186) -> Vec<proto::LocationLink> {
1187 links
1188 .into_iter()
1189 .map(|definition| location_link_to_proto(definition, lsp_store, peer_id, cx))
1190 .collect()
1191}
1192
1193pub fn location_link_to_proto(
1194 location: LocationLink,
1195 lsp_store: &mut LspStore,
1196 peer_id: PeerId,
1197 cx: &mut App,
1198) -> proto::LocationLink {
1199 let origin = location.origin.map(|origin| {
1200 lsp_store
1201 .buffer_store()
1202 .update(cx, |buffer_store, cx| {
1203 buffer_store.create_buffer_for_peer(&origin.buffer, peer_id, cx)
1204 })
1205 .detach_and_log_err(cx);
1206
1207 let buffer_id = origin.buffer.read(cx).remote_id().into();
1208 proto::Location {
1209 start: Some(serialize_anchor(&origin.range.start)),
1210 end: Some(serialize_anchor(&origin.range.end)),
1211 buffer_id,
1212 }
1213 });
1214
1215 lsp_store
1216 .buffer_store()
1217 .update(cx, |buffer_store, cx| {
1218 buffer_store.create_buffer_for_peer(&location.target.buffer, peer_id, cx)
1219 })
1220 .detach_and_log_err(cx);
1221
1222 let buffer_id = location.target.buffer.read(cx).remote_id().into();
1223 let target = proto::Location {
1224 start: Some(serialize_anchor(&location.target.range.start)),
1225 end: Some(serialize_anchor(&location.target.range.end)),
1226 buffer_id,
1227 };
1228
1229 proto::LocationLink {
1230 origin,
1231 target: Some(target),
1232 }
1233}
1234
1235#[async_trait(?Send)]
1236impl LspCommand for GetReferences {
1237 type Response = Vec<Location>;
1238 type LspRequest = lsp::request::References;
1239 type ProtoRequest = proto::GetReferences;
1240
1241 fn display_name(&self) -> &str {
1242 "Find all references"
1243 }
1244
1245 fn status(&self) -> Option<String> {
1246 Some("Finding references...".to_owned())
1247 }
1248
1249 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1250 match &capabilities.server_capabilities.references_provider {
1251 Some(OneOf::Left(has_support)) => *has_support,
1252 Some(OneOf::Right(_)) => true,
1253 None => false,
1254 }
1255 }
1256
1257 fn to_lsp(
1258 &self,
1259 path: &Path,
1260 _: &Buffer,
1261 _: &Arc<LanguageServer>,
1262 _: &App,
1263 ) -> Result<lsp::ReferenceParams> {
1264 Ok(lsp::ReferenceParams {
1265 text_document_position: make_lsp_text_document_position(path, self.position)?,
1266 work_done_progress_params: Default::default(),
1267 partial_result_params: Default::default(),
1268 context: lsp::ReferenceContext {
1269 include_declaration: true,
1270 },
1271 })
1272 }
1273
1274 async fn response_from_lsp(
1275 self,
1276 locations: Option<Vec<lsp::Location>>,
1277 lsp_store: Entity<LspStore>,
1278 buffer: Entity<Buffer>,
1279 server_id: LanguageServerId,
1280 mut cx: AsyncApp,
1281 ) -> Result<Vec<Location>> {
1282 let mut references = Vec::new();
1283 let (lsp_adapter, language_server) =
1284 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
1285
1286 if let Some(locations) = locations {
1287 for lsp_location in locations {
1288 let target_buffer_handle = lsp_store
1289 .update(&mut cx, |lsp_store, cx| {
1290 lsp_store.open_local_buffer_via_lsp(
1291 lsp_location.uri,
1292 language_server.server_id(),
1293 lsp_adapter.name.clone(),
1294 cx,
1295 )
1296 })?
1297 .await?;
1298
1299 target_buffer_handle
1300 .clone()
1301 .update(&mut cx, |target_buffer, _| {
1302 let target_start = target_buffer
1303 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
1304 let target_end = target_buffer
1305 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
1306 references.push(Location {
1307 buffer: target_buffer_handle,
1308 range: target_buffer.anchor_after(target_start)
1309 ..target_buffer.anchor_before(target_end),
1310 });
1311 })?;
1312 }
1313 }
1314
1315 Ok(references)
1316 }
1317
1318 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
1319 proto::GetReferences {
1320 project_id,
1321 buffer_id: buffer.remote_id().into(),
1322 position: Some(language::proto::serialize_anchor(
1323 &buffer.anchor_before(self.position),
1324 )),
1325 version: serialize_version(&buffer.version()),
1326 }
1327 }
1328
1329 async fn from_proto(
1330 message: proto::GetReferences,
1331 _: Entity<LspStore>,
1332 buffer: Entity<Buffer>,
1333 mut cx: AsyncApp,
1334 ) -> Result<Self> {
1335 let position = message
1336 .position
1337 .and_then(deserialize_anchor)
1338 .ok_or_else(|| anyhow!("invalid position"))?;
1339 buffer
1340 .update(&mut cx, |buffer, _| {
1341 buffer.wait_for_version(deserialize_version(&message.version))
1342 })?
1343 .await?;
1344 Ok(Self {
1345 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1346 })
1347 }
1348
1349 fn response_to_proto(
1350 response: Vec<Location>,
1351 lsp_store: &mut LspStore,
1352 peer_id: PeerId,
1353 _: &clock::Global,
1354 cx: &mut App,
1355 ) -> proto::GetReferencesResponse {
1356 let locations = response
1357 .into_iter()
1358 .map(|definition| {
1359 lsp_store
1360 .buffer_store()
1361 .update(cx, |buffer_store, cx| {
1362 buffer_store.create_buffer_for_peer(&definition.buffer, peer_id, cx)
1363 })
1364 .detach_and_log_err(cx);
1365 let buffer_id = definition.buffer.read(cx).remote_id();
1366 proto::Location {
1367 start: Some(serialize_anchor(&definition.range.start)),
1368 end: Some(serialize_anchor(&definition.range.end)),
1369 buffer_id: buffer_id.into(),
1370 }
1371 })
1372 .collect();
1373 proto::GetReferencesResponse { locations }
1374 }
1375
1376 async fn response_from_proto(
1377 self,
1378 message: proto::GetReferencesResponse,
1379 project: Entity<LspStore>,
1380 _: Entity<Buffer>,
1381 mut cx: AsyncApp,
1382 ) -> Result<Vec<Location>> {
1383 let mut locations = Vec::new();
1384 for location in message.locations {
1385 let buffer_id = BufferId::new(location.buffer_id)?;
1386 let target_buffer = project
1387 .update(&mut cx, |this, cx| {
1388 this.wait_for_remote_buffer(buffer_id, cx)
1389 })?
1390 .await?;
1391 let start = location
1392 .start
1393 .and_then(deserialize_anchor)
1394 .ok_or_else(|| anyhow!("missing target start"))?;
1395 let end = location
1396 .end
1397 .and_then(deserialize_anchor)
1398 .ok_or_else(|| anyhow!("missing target end"))?;
1399 target_buffer
1400 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1401 .await?;
1402 locations.push(Location {
1403 buffer: target_buffer,
1404 range: start..end,
1405 })
1406 }
1407 Ok(locations)
1408 }
1409
1410 fn buffer_id_from_proto(message: &proto::GetReferences) -> Result<BufferId> {
1411 BufferId::new(message.buffer_id)
1412 }
1413}
1414
1415#[async_trait(?Send)]
1416impl LspCommand for GetDocumentHighlights {
1417 type Response = Vec<DocumentHighlight>;
1418 type LspRequest = lsp::request::DocumentHighlightRequest;
1419 type ProtoRequest = proto::GetDocumentHighlights;
1420
1421 fn display_name(&self) -> &str {
1422 "Get document highlights"
1423 }
1424
1425 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1426 capabilities
1427 .server_capabilities
1428 .document_highlight_provider
1429 .is_some()
1430 }
1431
1432 fn to_lsp(
1433 &self,
1434 path: &Path,
1435 _: &Buffer,
1436 _: &Arc<LanguageServer>,
1437 _: &App,
1438 ) -> Result<lsp::DocumentHighlightParams> {
1439 Ok(lsp::DocumentHighlightParams {
1440 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1441 work_done_progress_params: Default::default(),
1442 partial_result_params: Default::default(),
1443 })
1444 }
1445
1446 async fn response_from_lsp(
1447 self,
1448 lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
1449 _: Entity<LspStore>,
1450 buffer: Entity<Buffer>,
1451 _: LanguageServerId,
1452 mut cx: AsyncApp,
1453 ) -> Result<Vec<DocumentHighlight>> {
1454 buffer.update(&mut cx, |buffer, _| {
1455 let mut lsp_highlights = lsp_highlights.unwrap_or_default();
1456 lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
1457 lsp_highlights
1458 .into_iter()
1459 .map(|lsp_highlight| {
1460 let start = buffer
1461 .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
1462 let end = buffer
1463 .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
1464 DocumentHighlight {
1465 range: buffer.anchor_after(start)..buffer.anchor_before(end),
1466 kind: lsp_highlight
1467 .kind
1468 .unwrap_or(lsp::DocumentHighlightKind::READ),
1469 }
1470 })
1471 .collect()
1472 })
1473 }
1474
1475 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1476 proto::GetDocumentHighlights {
1477 project_id,
1478 buffer_id: buffer.remote_id().into(),
1479 position: Some(language::proto::serialize_anchor(
1480 &buffer.anchor_before(self.position),
1481 )),
1482 version: serialize_version(&buffer.version()),
1483 }
1484 }
1485
1486 async fn from_proto(
1487 message: proto::GetDocumentHighlights,
1488 _: Entity<LspStore>,
1489 buffer: Entity<Buffer>,
1490 mut cx: AsyncApp,
1491 ) -> Result<Self> {
1492 let position = message
1493 .position
1494 .and_then(deserialize_anchor)
1495 .ok_or_else(|| anyhow!("invalid position"))?;
1496 buffer
1497 .update(&mut cx, |buffer, _| {
1498 buffer.wait_for_version(deserialize_version(&message.version))
1499 })?
1500 .await?;
1501 Ok(Self {
1502 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
1503 })
1504 }
1505
1506 fn response_to_proto(
1507 response: Vec<DocumentHighlight>,
1508 _: &mut LspStore,
1509 _: PeerId,
1510 _: &clock::Global,
1511 _: &mut App,
1512 ) -> proto::GetDocumentHighlightsResponse {
1513 let highlights = response
1514 .into_iter()
1515 .map(|highlight| proto::DocumentHighlight {
1516 start: Some(serialize_anchor(&highlight.range.start)),
1517 end: Some(serialize_anchor(&highlight.range.end)),
1518 kind: match highlight.kind {
1519 DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1520 DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1521 DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1522 _ => proto::document_highlight::Kind::Text.into(),
1523 },
1524 })
1525 .collect();
1526 proto::GetDocumentHighlightsResponse { highlights }
1527 }
1528
1529 async fn response_from_proto(
1530 self,
1531 message: proto::GetDocumentHighlightsResponse,
1532 _: Entity<LspStore>,
1533 buffer: Entity<Buffer>,
1534 mut cx: AsyncApp,
1535 ) -> Result<Vec<DocumentHighlight>> {
1536 let mut highlights = Vec::new();
1537 for highlight in message.highlights {
1538 let start = highlight
1539 .start
1540 .and_then(deserialize_anchor)
1541 .ok_or_else(|| anyhow!("missing target start"))?;
1542 let end = highlight
1543 .end
1544 .and_then(deserialize_anchor)
1545 .ok_or_else(|| anyhow!("missing target end"))?;
1546 buffer
1547 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))?
1548 .await?;
1549 let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1550 Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1551 Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1552 Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1553 None => DocumentHighlightKind::TEXT,
1554 };
1555 highlights.push(DocumentHighlight {
1556 range: start..end,
1557 kind,
1558 });
1559 }
1560 Ok(highlights)
1561 }
1562
1563 fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> Result<BufferId> {
1564 BufferId::new(message.buffer_id)
1565 }
1566}
1567
1568#[async_trait(?Send)]
1569impl LspCommand for GetDocumentSymbols {
1570 type Response = Vec<DocumentSymbol>;
1571 type LspRequest = lsp::request::DocumentSymbolRequest;
1572 type ProtoRequest = proto::GetDocumentSymbols;
1573
1574 fn display_name(&self) -> &str {
1575 "Get document symbols"
1576 }
1577
1578 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1579 capabilities
1580 .server_capabilities
1581 .document_symbol_provider
1582 .is_some()
1583 }
1584
1585 fn to_lsp(
1586 &self,
1587 path: &Path,
1588 _: &Buffer,
1589 _: &Arc<LanguageServer>,
1590 _: &App,
1591 ) -> Result<lsp::DocumentSymbolParams> {
1592 Ok(lsp::DocumentSymbolParams {
1593 text_document: make_text_document_identifier(path)?,
1594 work_done_progress_params: Default::default(),
1595 partial_result_params: Default::default(),
1596 })
1597 }
1598
1599 async fn response_from_lsp(
1600 self,
1601 lsp_symbols: Option<lsp::DocumentSymbolResponse>,
1602 _: Entity<LspStore>,
1603 _: Entity<Buffer>,
1604 _: LanguageServerId,
1605 _: AsyncApp,
1606 ) -> Result<Vec<DocumentSymbol>> {
1607 let Some(lsp_symbols) = lsp_symbols else {
1608 return Ok(Vec::new());
1609 };
1610
1611 let symbols: Vec<_> = match lsp_symbols {
1612 lsp::DocumentSymbolResponse::Flat(symbol_information) => symbol_information
1613 .into_iter()
1614 .map(|lsp_symbol| DocumentSymbol {
1615 name: lsp_symbol.name,
1616 kind: lsp_symbol.kind,
1617 range: range_from_lsp(lsp_symbol.location.range),
1618 selection_range: range_from_lsp(lsp_symbol.location.range),
1619 children: Vec::new(),
1620 })
1621 .collect(),
1622 lsp::DocumentSymbolResponse::Nested(nested_responses) => {
1623 fn convert_symbol(lsp_symbol: lsp::DocumentSymbol) -> DocumentSymbol {
1624 DocumentSymbol {
1625 name: lsp_symbol.name,
1626 kind: lsp_symbol.kind,
1627 range: range_from_lsp(lsp_symbol.range),
1628 selection_range: range_from_lsp(lsp_symbol.selection_range),
1629 children: lsp_symbol
1630 .children
1631 .map(|children| {
1632 children.into_iter().map(convert_symbol).collect::<Vec<_>>()
1633 })
1634 .unwrap_or_default(),
1635 }
1636 }
1637 nested_responses.into_iter().map(convert_symbol).collect()
1638 }
1639 };
1640 Ok(symbols)
1641 }
1642
1643 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentSymbols {
1644 proto::GetDocumentSymbols {
1645 project_id,
1646 buffer_id: buffer.remote_id().into(),
1647 version: serialize_version(&buffer.version()),
1648 }
1649 }
1650
1651 async fn from_proto(
1652 message: proto::GetDocumentSymbols,
1653 _: Entity<LspStore>,
1654 buffer: Entity<Buffer>,
1655 mut cx: AsyncApp,
1656 ) -> Result<Self> {
1657 buffer
1658 .update(&mut cx, |buffer, _| {
1659 buffer.wait_for_version(deserialize_version(&message.version))
1660 })?
1661 .await?;
1662 Ok(Self)
1663 }
1664
1665 fn response_to_proto(
1666 response: Vec<DocumentSymbol>,
1667 _: &mut LspStore,
1668 _: PeerId,
1669 _: &clock::Global,
1670 _: &mut App,
1671 ) -> proto::GetDocumentSymbolsResponse {
1672 let symbols = response
1673 .into_iter()
1674 .map(|symbol| {
1675 fn convert_symbol_to_proto(symbol: DocumentSymbol) -> proto::DocumentSymbol {
1676 proto::DocumentSymbol {
1677 name: symbol.name.clone(),
1678 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
1679 start: Some(proto::PointUtf16 {
1680 row: symbol.range.start.0.row,
1681 column: symbol.range.start.0.column,
1682 }),
1683 end: Some(proto::PointUtf16 {
1684 row: symbol.range.end.0.row,
1685 column: symbol.range.end.0.column,
1686 }),
1687 selection_start: Some(proto::PointUtf16 {
1688 row: symbol.selection_range.start.0.row,
1689 column: symbol.selection_range.start.0.column,
1690 }),
1691 selection_end: Some(proto::PointUtf16 {
1692 row: symbol.selection_range.end.0.row,
1693 column: symbol.selection_range.end.0.column,
1694 }),
1695 children: symbol
1696 .children
1697 .into_iter()
1698 .map(convert_symbol_to_proto)
1699 .collect(),
1700 }
1701 }
1702 convert_symbol_to_proto(symbol)
1703 })
1704 .collect::<Vec<_>>();
1705
1706 proto::GetDocumentSymbolsResponse { symbols }
1707 }
1708
1709 async fn response_from_proto(
1710 self,
1711 message: proto::GetDocumentSymbolsResponse,
1712 _: Entity<LspStore>,
1713 _: Entity<Buffer>,
1714 _: AsyncApp,
1715 ) -> Result<Vec<DocumentSymbol>> {
1716 let mut symbols = Vec::with_capacity(message.symbols.len());
1717 for serialized_symbol in message.symbols {
1718 fn deserialize_symbol_with_children(
1719 serialized_symbol: proto::DocumentSymbol,
1720 ) -> Result<DocumentSymbol> {
1721 let kind =
1722 unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
1723
1724 let start = serialized_symbol
1725 .start
1726 .ok_or_else(|| anyhow!("invalid start"))?;
1727 let end = serialized_symbol
1728 .end
1729 .ok_or_else(|| anyhow!("invalid end"))?;
1730
1731 let selection_start = serialized_symbol
1732 .selection_start
1733 .ok_or_else(|| anyhow!("invalid selection start"))?;
1734 let selection_end = serialized_symbol
1735 .selection_end
1736 .ok_or_else(|| anyhow!("invalid selection end"))?;
1737
1738 Ok(DocumentSymbol {
1739 name: serialized_symbol.name,
1740 kind,
1741 range: Unclipped(PointUtf16::new(start.row, start.column))
1742 ..Unclipped(PointUtf16::new(end.row, end.column)),
1743 selection_range: Unclipped(PointUtf16::new(
1744 selection_start.row,
1745 selection_start.column,
1746 ))
1747 ..Unclipped(PointUtf16::new(selection_end.row, selection_end.column)),
1748 children: serialized_symbol
1749 .children
1750 .into_iter()
1751 .filter_map(|symbol| deserialize_symbol_with_children(symbol).ok())
1752 .collect::<Vec<_>>(),
1753 })
1754 }
1755
1756 symbols.push(deserialize_symbol_with_children(serialized_symbol)?);
1757 }
1758
1759 Ok(symbols)
1760 }
1761
1762 fn buffer_id_from_proto(message: &proto::GetDocumentSymbols) -> Result<BufferId> {
1763 BufferId::new(message.buffer_id)
1764 }
1765}
1766
1767#[async_trait(?Send)]
1768impl LspCommand for GetSignatureHelp {
1769 type Response = Option<SignatureHelp>;
1770 type LspRequest = lsp::SignatureHelpRequest;
1771 type ProtoRequest = proto::GetSignatureHelp;
1772
1773 fn display_name(&self) -> &str {
1774 "Get signature help"
1775 }
1776
1777 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1778 capabilities
1779 .server_capabilities
1780 .signature_help_provider
1781 .is_some()
1782 }
1783
1784 fn to_lsp(
1785 &self,
1786 path: &Path,
1787 _: &Buffer,
1788 _: &Arc<LanguageServer>,
1789 _cx: &App,
1790 ) -> Result<lsp::SignatureHelpParams> {
1791 Ok(lsp::SignatureHelpParams {
1792 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1793 context: None,
1794 work_done_progress_params: Default::default(),
1795 })
1796 }
1797
1798 async fn response_from_lsp(
1799 self,
1800 message: Option<lsp::SignatureHelp>,
1801 _: Entity<LspStore>,
1802 _: Entity<Buffer>,
1803 _: LanguageServerId,
1804 _: AsyncApp,
1805 ) -> Result<Self::Response> {
1806 Ok(message.and_then(SignatureHelp::new))
1807 }
1808
1809 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1810 let offset = buffer.point_utf16_to_offset(self.position);
1811 proto::GetSignatureHelp {
1812 project_id,
1813 buffer_id: buffer.remote_id().to_proto(),
1814 position: Some(serialize_anchor(&buffer.anchor_after(offset))),
1815 version: serialize_version(&buffer.version()),
1816 }
1817 }
1818
1819 async fn from_proto(
1820 payload: Self::ProtoRequest,
1821 _: Entity<LspStore>,
1822 buffer: Entity<Buffer>,
1823 mut cx: AsyncApp,
1824 ) -> Result<Self> {
1825 buffer
1826 .update(&mut cx, |buffer, _| {
1827 buffer.wait_for_version(deserialize_version(&payload.version))
1828 })?
1829 .await
1830 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
1831 let buffer_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
1832 Ok(Self {
1833 position: payload
1834 .position
1835 .and_then(deserialize_anchor)
1836 .context("invalid position")?
1837 .to_point_utf16(&buffer_snapshot),
1838 })
1839 }
1840
1841 fn response_to_proto(
1842 response: Self::Response,
1843 _: &mut LspStore,
1844 _: PeerId,
1845 _: &Global,
1846 _: &mut App,
1847 ) -> proto::GetSignatureHelpResponse {
1848 proto::GetSignatureHelpResponse {
1849 signature_help: response
1850 .map(|signature_help| lsp_to_proto_signature(signature_help.original_data)),
1851 }
1852 }
1853
1854 async fn response_from_proto(
1855 self,
1856 response: proto::GetSignatureHelpResponse,
1857 _: Entity<LspStore>,
1858 _: Entity<Buffer>,
1859 _: AsyncApp,
1860 ) -> Result<Self::Response> {
1861 Ok(response
1862 .signature_help
1863 .map(proto_to_lsp_signature)
1864 .and_then(SignatureHelp::new))
1865 }
1866
1867 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
1868 BufferId::new(message.buffer_id)
1869 }
1870}
1871
1872#[async_trait(?Send)]
1873impl LspCommand for GetHover {
1874 type Response = Option<Hover>;
1875 type LspRequest = lsp::request::HoverRequest;
1876 type ProtoRequest = proto::GetHover;
1877
1878 fn display_name(&self) -> &str {
1879 "Get hover"
1880 }
1881
1882 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
1883 match capabilities.server_capabilities.hover_provider {
1884 Some(lsp::HoverProviderCapability::Simple(enabled)) => enabled,
1885 Some(lsp::HoverProviderCapability::Options(_)) => true,
1886 None => false,
1887 }
1888 }
1889
1890 fn to_lsp(
1891 &self,
1892 path: &Path,
1893 _: &Buffer,
1894 _: &Arc<LanguageServer>,
1895 _: &App,
1896 ) -> Result<lsp::HoverParams> {
1897 Ok(lsp::HoverParams {
1898 text_document_position_params: make_lsp_text_document_position(path, self.position)?,
1899 work_done_progress_params: Default::default(),
1900 })
1901 }
1902
1903 async fn response_from_lsp(
1904 self,
1905 message: Option<lsp::Hover>,
1906 _: Entity<LspStore>,
1907 buffer: Entity<Buffer>,
1908 _: LanguageServerId,
1909 mut cx: AsyncApp,
1910 ) -> Result<Self::Response> {
1911 let Some(hover) = message else {
1912 return Ok(None);
1913 };
1914
1915 let (language, range) = buffer.update(&mut cx, |buffer, _| {
1916 (
1917 buffer.language().cloned(),
1918 hover.range.map(|range| {
1919 let token_start =
1920 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1921 let token_end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1922 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1923 }),
1924 )
1925 })?;
1926
1927 fn hover_blocks_from_marked_string(marked_string: lsp::MarkedString) -> Option<HoverBlock> {
1928 let block = match marked_string {
1929 lsp::MarkedString::String(content) => HoverBlock {
1930 text: content,
1931 kind: HoverBlockKind::Markdown,
1932 },
1933 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1934 HoverBlock {
1935 text: value,
1936 kind: HoverBlockKind::Code { language },
1937 }
1938 }
1939 };
1940 if block.text.is_empty() {
1941 None
1942 } else {
1943 Some(block)
1944 }
1945 }
1946
1947 let contents = match hover.contents {
1948 lsp::HoverContents::Scalar(marked_string) => {
1949 hover_blocks_from_marked_string(marked_string)
1950 .into_iter()
1951 .collect()
1952 }
1953 lsp::HoverContents::Array(marked_strings) => marked_strings
1954 .into_iter()
1955 .filter_map(hover_blocks_from_marked_string)
1956 .collect(),
1957 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1958 text: markup_content.value,
1959 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1960 HoverBlockKind::Markdown
1961 } else {
1962 HoverBlockKind::PlainText
1963 },
1964 }],
1965 };
1966
1967 Ok(Some(Hover {
1968 contents,
1969 range,
1970 language,
1971 }))
1972 }
1973
1974 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1975 proto::GetHover {
1976 project_id,
1977 buffer_id: buffer.remote_id().into(),
1978 position: Some(language::proto::serialize_anchor(
1979 &buffer.anchor_before(self.position),
1980 )),
1981 version: serialize_version(&buffer.version),
1982 }
1983 }
1984
1985 async fn from_proto(
1986 message: Self::ProtoRequest,
1987 _: Entity<LspStore>,
1988 buffer: Entity<Buffer>,
1989 mut cx: AsyncApp,
1990 ) -> Result<Self> {
1991 let position = message
1992 .position
1993 .and_then(deserialize_anchor)
1994 .ok_or_else(|| anyhow!("invalid position"))?;
1995 buffer
1996 .update(&mut cx, |buffer, _| {
1997 buffer.wait_for_version(deserialize_version(&message.version))
1998 })?
1999 .await?;
2000 Ok(Self {
2001 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2002 })
2003 }
2004
2005 fn response_to_proto(
2006 response: Self::Response,
2007 _: &mut LspStore,
2008 _: PeerId,
2009 _: &clock::Global,
2010 _: &mut App,
2011 ) -> proto::GetHoverResponse {
2012 if let Some(response) = response {
2013 let (start, end) = if let Some(range) = response.range {
2014 (
2015 Some(language::proto::serialize_anchor(&range.start)),
2016 Some(language::proto::serialize_anchor(&range.end)),
2017 )
2018 } else {
2019 (None, None)
2020 };
2021
2022 let contents = response
2023 .contents
2024 .into_iter()
2025 .map(|block| proto::HoverBlock {
2026 text: block.text,
2027 is_markdown: block.kind == HoverBlockKind::Markdown,
2028 language: if let HoverBlockKind::Code { language } = block.kind {
2029 Some(language)
2030 } else {
2031 None
2032 },
2033 })
2034 .collect();
2035
2036 proto::GetHoverResponse {
2037 start,
2038 end,
2039 contents,
2040 }
2041 } else {
2042 proto::GetHoverResponse {
2043 start: None,
2044 end: None,
2045 contents: Vec::new(),
2046 }
2047 }
2048 }
2049
2050 async fn response_from_proto(
2051 self,
2052 message: proto::GetHoverResponse,
2053 _: Entity<LspStore>,
2054 buffer: Entity<Buffer>,
2055 mut cx: AsyncApp,
2056 ) -> Result<Self::Response> {
2057 let contents: Vec<_> = message
2058 .contents
2059 .into_iter()
2060 .map(|block| HoverBlock {
2061 text: block.text,
2062 kind: if let Some(language) = block.language {
2063 HoverBlockKind::Code { language }
2064 } else if block.is_markdown {
2065 HoverBlockKind::Markdown
2066 } else {
2067 HoverBlockKind::PlainText
2068 },
2069 })
2070 .collect();
2071 if contents.is_empty() {
2072 return Ok(None);
2073 }
2074
2075 let language = buffer.update(&mut cx, |buffer, _| buffer.language().cloned())?;
2076 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
2077 language::proto::deserialize_anchor(start)
2078 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
2079 } else {
2080 None
2081 };
2082 if let Some(range) = range.as_ref() {
2083 buffer
2084 .update(&mut cx, |buffer, _| {
2085 buffer.wait_for_anchors([range.start, range.end])
2086 })?
2087 .await?;
2088 }
2089
2090 Ok(Some(Hover {
2091 contents,
2092 range,
2093 language,
2094 }))
2095 }
2096
2097 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId> {
2098 BufferId::new(message.buffer_id)
2099 }
2100}
2101
2102#[async_trait(?Send)]
2103impl LspCommand for GetCompletions {
2104 type Response = Vec<CoreCompletion>;
2105 type LspRequest = lsp::request::Completion;
2106 type ProtoRequest = proto::GetCompletions;
2107
2108 fn display_name(&self) -> &str {
2109 "Get completion"
2110 }
2111
2112 fn to_lsp(
2113 &self,
2114 path: &Path,
2115 _: &Buffer,
2116 _: &Arc<LanguageServer>,
2117 _: &App,
2118 ) -> Result<lsp::CompletionParams> {
2119 Ok(lsp::CompletionParams {
2120 text_document_position: make_lsp_text_document_position(path, self.position)?,
2121 context: Some(self.context.clone()),
2122 work_done_progress_params: Default::default(),
2123 partial_result_params: Default::default(),
2124 })
2125 }
2126
2127 async fn response_from_lsp(
2128 self,
2129 completions: Option<lsp::CompletionResponse>,
2130 lsp_store: Entity<LspStore>,
2131 buffer: Entity<Buffer>,
2132 server_id: LanguageServerId,
2133 mut cx: AsyncApp,
2134 ) -> Result<Self::Response> {
2135 let mut response_list = None;
2136 let mut completions = if let Some(completions) = completions {
2137 match completions {
2138 lsp::CompletionResponse::Array(completions) => completions,
2139 lsp::CompletionResponse::List(mut list) => {
2140 let items = std::mem::take(&mut list.items);
2141 response_list = Some(list);
2142 items
2143 }
2144 }
2145 } else {
2146 Vec::new()
2147 };
2148
2149 let language_server_adapter = lsp_store
2150 .update(&mut cx, |lsp_store, _| {
2151 lsp_store.language_server_adapter_for_id(server_id)
2152 })?
2153 .with_context(|| format!("no language server with id {server_id}"))?;
2154
2155 let lsp_defaults = response_list
2156 .as_ref()
2157 .and_then(|list| list.item_defaults.clone())
2158 .map(Arc::new);
2159
2160 let mut completion_edits = Vec::new();
2161 buffer.update(&mut cx, |buffer, _cx| {
2162 let snapshot = buffer.snapshot();
2163 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
2164
2165 let mut range_for_token = None;
2166 completions.retain(|lsp_completion| {
2167 let lsp_edit = lsp_completion.text_edit.clone().or_else(|| {
2168 let default_text_edit = lsp_defaults.as_deref()?.edit_range.as_ref()?;
2169 let new_text = lsp_completion
2170 .insert_text
2171 .as_ref()
2172 .unwrap_or(&lsp_completion.label)
2173 .clone();
2174 match default_text_edit {
2175 CompletionListItemDefaultsEditRange::Range(range) => {
2176 Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
2177 range: *range,
2178 new_text,
2179 }))
2180 }
2181 CompletionListItemDefaultsEditRange::InsertAndReplace {
2182 insert,
2183 replace,
2184 } => Some(lsp::CompletionTextEdit::InsertAndReplace(
2185 lsp::InsertReplaceEdit {
2186 new_text,
2187 insert: *insert,
2188 replace: *replace,
2189 },
2190 )),
2191 }
2192 });
2193
2194 let edit = match lsp_edit {
2195 // If the language server provides a range to overwrite, then
2196 // check that the range is valid.
2197 Some(completion_text_edit) => {
2198 match parse_completion_text_edit(&completion_text_edit, &snapshot) {
2199 Some(edit) => edit,
2200 None => return false,
2201 }
2202 }
2203 // If the language server does not provide a range, then infer
2204 // the range based on the syntax tree.
2205 None => {
2206 if self.position != clipped_position {
2207 log::info!("completion out of expected range");
2208 return false;
2209 }
2210
2211 let default_edit_range = lsp_defaults.as_ref().and_then(|lsp_defaults| {
2212 lsp_defaults
2213 .edit_range
2214 .as_ref()
2215 .and_then(|range| match range {
2216 CompletionListItemDefaultsEditRange::Range(r) => Some(r),
2217 _ => None,
2218 })
2219 });
2220
2221 let range = if let Some(range) = default_edit_range {
2222 let range = range_from_lsp(*range);
2223 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2224 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2225 if start != range.start.0 || end != range.end.0 {
2226 log::info!("completion out of expected range");
2227 return false;
2228 }
2229
2230 snapshot.anchor_before(start)..snapshot.anchor_after(end)
2231 } else {
2232 range_for_token
2233 .get_or_insert_with(|| {
2234 let offset = self.position.to_offset(&snapshot);
2235 let (range, kind) = snapshot.surrounding_word(offset);
2236 let range = if kind == Some(CharKind::Word) {
2237 range
2238 } else {
2239 offset..offset
2240 };
2241
2242 snapshot.anchor_before(range.start)
2243 ..snapshot.anchor_after(range.end)
2244 })
2245 .clone()
2246 };
2247
2248 // We already know text_edit is None here
2249 let text = lsp_completion
2250 .insert_text
2251 .as_ref()
2252 .unwrap_or(&lsp_completion.label)
2253 .clone();
2254
2255 ParsedCompletionEdit {
2256 replace_range: range,
2257 insert_range: None,
2258 new_text: text,
2259 }
2260 }
2261 };
2262
2263 completion_edits.push(edit);
2264 true
2265 });
2266 })?;
2267
2268 language_server_adapter
2269 .process_completions(&mut completions)
2270 .await;
2271
2272 Ok(completions
2273 .into_iter()
2274 .zip(completion_edits)
2275 .map(|(mut lsp_completion, mut edit)| {
2276 LineEnding::normalize(&mut edit.new_text);
2277 if lsp_completion.data.is_none() {
2278 if let Some(default_data) = lsp_defaults
2279 .as_ref()
2280 .and_then(|item_defaults| item_defaults.data.clone())
2281 {
2282 // Servers (e.g. JDTLS) prefer unchanged completions, when resolving the items later,
2283 // so we do not insert the defaults here, but `data` is needed for resolving, so this is an exception.
2284 lsp_completion.data = Some(default_data);
2285 }
2286 }
2287 CoreCompletion {
2288 replace_range: edit.replace_range,
2289 new_text: edit.new_text,
2290 source: CompletionSource::Lsp {
2291 insert_range: edit.insert_range,
2292 server_id,
2293 lsp_completion: Box::new(lsp_completion),
2294 lsp_defaults: lsp_defaults.clone(),
2295 resolved: false,
2296 },
2297 }
2298 })
2299 .collect())
2300 }
2301
2302 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
2303 let anchor = buffer.anchor_after(self.position);
2304 proto::GetCompletions {
2305 project_id,
2306 buffer_id: buffer.remote_id().into(),
2307 position: Some(language::proto::serialize_anchor(&anchor)),
2308 version: serialize_version(&buffer.version()),
2309 }
2310 }
2311
2312 async fn from_proto(
2313 message: proto::GetCompletions,
2314 _: Entity<LspStore>,
2315 buffer: Entity<Buffer>,
2316 mut cx: AsyncApp,
2317 ) -> Result<Self> {
2318 let version = deserialize_version(&message.version);
2319 buffer
2320 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))?
2321 .await?;
2322 let position = message
2323 .position
2324 .and_then(language::proto::deserialize_anchor)
2325 .map(|p| {
2326 buffer.update(&mut cx, |buffer, _| {
2327 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
2328 })
2329 })
2330 .ok_or_else(|| anyhow!("invalid position"))??;
2331 Ok(Self {
2332 position,
2333 context: CompletionContext {
2334 trigger_kind: CompletionTriggerKind::INVOKED,
2335 trigger_character: None,
2336 },
2337 })
2338 }
2339
2340 fn response_to_proto(
2341 completions: Vec<CoreCompletion>,
2342 _: &mut LspStore,
2343 _: PeerId,
2344 buffer_version: &clock::Global,
2345 _: &mut App,
2346 ) -> proto::GetCompletionsResponse {
2347 proto::GetCompletionsResponse {
2348 completions: completions
2349 .iter()
2350 .map(LspStore::serialize_completion)
2351 .collect(),
2352 version: serialize_version(buffer_version),
2353 }
2354 }
2355
2356 async fn response_from_proto(
2357 self,
2358 message: proto::GetCompletionsResponse,
2359 _project: Entity<LspStore>,
2360 buffer: Entity<Buffer>,
2361 mut cx: AsyncApp,
2362 ) -> Result<Self::Response> {
2363 buffer
2364 .update(&mut cx, |buffer, _| {
2365 buffer.wait_for_version(deserialize_version(&message.version))
2366 })?
2367 .await?;
2368
2369 message
2370 .completions
2371 .into_iter()
2372 .map(LspStore::deserialize_completion)
2373 .collect()
2374 }
2375
2376 fn buffer_id_from_proto(message: &proto::GetCompletions) -> Result<BufferId> {
2377 BufferId::new(message.buffer_id)
2378 }
2379}
2380
2381pub struct ParsedCompletionEdit {
2382 pub replace_range: Range<Anchor>,
2383 pub insert_range: Option<Range<Anchor>>,
2384 pub new_text: String,
2385}
2386
2387pub(crate) fn parse_completion_text_edit(
2388 edit: &lsp::CompletionTextEdit,
2389 snapshot: &BufferSnapshot,
2390) -> Option<ParsedCompletionEdit> {
2391 let (replace_range, insert_range, new_text) = match edit {
2392 lsp::CompletionTextEdit::Edit(edit) => (edit.range, None, &edit.new_text),
2393 lsp::CompletionTextEdit::InsertAndReplace(edit) => {
2394 (edit.replace, Some(edit.insert), &edit.new_text)
2395 }
2396 };
2397
2398 let replace_range = {
2399 let range = range_from_lsp(replace_range);
2400 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2401 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2402 if start != range.start.0 || end != range.end.0 {
2403 log::info!("completion out of expected range");
2404 return None;
2405 }
2406 snapshot.anchor_before(start)..snapshot.anchor_after(end)
2407 };
2408
2409 let insert_range = match insert_range {
2410 None => None,
2411 Some(insert_range) => {
2412 let range = range_from_lsp(insert_range);
2413 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
2414 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
2415 if start != range.start.0 || end != range.end.0 {
2416 log::info!("completion (insert) out of expected range");
2417 return None;
2418 }
2419 Some(snapshot.anchor_before(start)..snapshot.anchor_after(end))
2420 }
2421 };
2422
2423 Some(ParsedCompletionEdit {
2424 insert_range: insert_range,
2425 replace_range: replace_range,
2426 new_text: new_text.clone(),
2427 })
2428}
2429
2430#[async_trait(?Send)]
2431impl LspCommand for GetCodeActions {
2432 type Response = Vec<CodeAction>;
2433 type LspRequest = lsp::request::CodeActionRequest;
2434 type ProtoRequest = proto::GetCodeActions;
2435
2436 fn display_name(&self) -> &str {
2437 "Get code actions"
2438 }
2439
2440 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2441 match &capabilities.server_capabilities.code_action_provider {
2442 None => false,
2443 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
2444 _ => {
2445 // If we do know that we want specific code actions AND we know that
2446 // the server only supports specific code actions, then we want to filter
2447 // down to the ones that are supported.
2448 if let Some((requested, supported)) = self
2449 .kinds
2450 .as_ref()
2451 .zip(Self::supported_code_action_kinds(capabilities))
2452 {
2453 let server_supported = supported.into_iter().collect::<HashSet<_>>();
2454 requested.iter().any(|kind| server_supported.contains(kind))
2455 } else {
2456 true
2457 }
2458 }
2459 }
2460 }
2461
2462 fn to_lsp(
2463 &self,
2464 path: &Path,
2465 buffer: &Buffer,
2466 language_server: &Arc<LanguageServer>,
2467 _: &App,
2468 ) -> Result<lsp::CodeActionParams> {
2469 let mut relevant_diagnostics = Vec::new();
2470 for entry in buffer
2471 .snapshot()
2472 .diagnostics_in_range::<_, language::PointUtf16>(self.range.clone(), false)
2473 {
2474 relevant_diagnostics.push(entry.to_lsp_diagnostic_stub()?);
2475 }
2476
2477 let supported =
2478 Self::supported_code_action_kinds(language_server.adapter_server_capabilities());
2479
2480 let only = if let Some(requested) = &self.kinds {
2481 if let Some(supported_kinds) = supported {
2482 let server_supported = supported_kinds.into_iter().collect::<HashSet<_>>();
2483
2484 let filtered = requested
2485 .iter()
2486 .filter(|kind| server_supported.contains(kind))
2487 .cloned()
2488 .collect();
2489 Some(filtered)
2490 } else {
2491 Some(requested.clone())
2492 }
2493 } else {
2494 supported
2495 };
2496
2497 Ok(lsp::CodeActionParams {
2498 text_document: make_text_document_identifier(path)?,
2499 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
2500 work_done_progress_params: Default::default(),
2501 partial_result_params: Default::default(),
2502 context: lsp::CodeActionContext {
2503 diagnostics: relevant_diagnostics,
2504 only,
2505 ..lsp::CodeActionContext::default()
2506 },
2507 })
2508 }
2509
2510 async fn response_from_lsp(
2511 self,
2512 actions: Option<lsp::CodeActionResponse>,
2513 lsp_store: Entity<LspStore>,
2514 _: Entity<Buffer>,
2515 server_id: LanguageServerId,
2516 cx: AsyncApp,
2517 ) -> Result<Vec<CodeAction>> {
2518 let requested_kinds_set = if let Some(kinds) = self.kinds {
2519 Some(kinds.into_iter().collect::<HashSet<_>>())
2520 } else {
2521 None
2522 };
2523
2524 let language_server = cx.update(|cx| {
2525 lsp_store
2526 .read(cx)
2527 .language_server_for_id(server_id)
2528 .with_context(|| {
2529 format!("Missing the language server that just returned a response {server_id}")
2530 })
2531 })??;
2532
2533 let server_capabilities = language_server.capabilities();
2534 let available_commands = server_capabilities
2535 .execute_command_provider
2536 .as_ref()
2537 .map(|options| options.commands.as_slice())
2538 .unwrap_or_default();
2539 Ok(actions
2540 .unwrap_or_default()
2541 .into_iter()
2542 .filter_map(|entry| {
2543 let (lsp_action, resolved) = match entry {
2544 lsp::CodeActionOrCommand::CodeAction(lsp_action) => {
2545 if let Some(command) = lsp_action.command.as_ref() {
2546 if !available_commands.contains(&command.command) {
2547 return None;
2548 }
2549 }
2550 (LspAction::Action(Box::new(lsp_action)), false)
2551 }
2552 lsp::CodeActionOrCommand::Command(command) => {
2553 if available_commands.contains(&command.command) {
2554 (LspAction::Command(command), true)
2555 } else {
2556 return None;
2557 }
2558 }
2559 };
2560
2561 if let Some((requested_kinds, kind)) =
2562 requested_kinds_set.as_ref().zip(lsp_action.action_kind())
2563 {
2564 if !requested_kinds.contains(&kind) {
2565 return None;
2566 }
2567 }
2568
2569 Some(CodeAction {
2570 server_id,
2571 range: self.range.clone(),
2572 lsp_action,
2573 resolved,
2574 })
2575 })
2576 .collect())
2577 }
2578
2579 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
2580 proto::GetCodeActions {
2581 project_id,
2582 buffer_id: buffer.remote_id().into(),
2583 start: Some(language::proto::serialize_anchor(&self.range.start)),
2584 end: Some(language::proto::serialize_anchor(&self.range.end)),
2585 version: serialize_version(&buffer.version()),
2586 }
2587 }
2588
2589 async fn from_proto(
2590 message: proto::GetCodeActions,
2591 _: Entity<LspStore>,
2592 buffer: Entity<Buffer>,
2593 mut cx: AsyncApp,
2594 ) -> Result<Self> {
2595 let start = message
2596 .start
2597 .and_then(language::proto::deserialize_anchor)
2598 .ok_or_else(|| anyhow!("invalid start"))?;
2599 let end = message
2600 .end
2601 .and_then(language::proto::deserialize_anchor)
2602 .ok_or_else(|| anyhow!("invalid end"))?;
2603 buffer
2604 .update(&mut cx, |buffer, _| {
2605 buffer.wait_for_version(deserialize_version(&message.version))
2606 })?
2607 .await?;
2608
2609 Ok(Self {
2610 range: start..end,
2611 kinds: None,
2612 })
2613 }
2614
2615 fn response_to_proto(
2616 code_actions: Vec<CodeAction>,
2617 _: &mut LspStore,
2618 _: PeerId,
2619 buffer_version: &clock::Global,
2620 _: &mut App,
2621 ) -> proto::GetCodeActionsResponse {
2622 proto::GetCodeActionsResponse {
2623 actions: code_actions
2624 .iter()
2625 .map(LspStore::serialize_code_action)
2626 .collect(),
2627 version: serialize_version(buffer_version),
2628 }
2629 }
2630
2631 async fn response_from_proto(
2632 self,
2633 message: proto::GetCodeActionsResponse,
2634 _: Entity<LspStore>,
2635 buffer: Entity<Buffer>,
2636 mut cx: AsyncApp,
2637 ) -> Result<Vec<CodeAction>> {
2638 buffer
2639 .update(&mut cx, |buffer, _| {
2640 buffer.wait_for_version(deserialize_version(&message.version))
2641 })?
2642 .await?;
2643 message
2644 .actions
2645 .into_iter()
2646 .map(LspStore::deserialize_code_action)
2647 .collect()
2648 }
2649
2650 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> Result<BufferId> {
2651 BufferId::new(message.buffer_id)
2652 }
2653}
2654
2655impl GetCodeActions {
2656 fn supported_code_action_kinds(
2657 capabilities: AdapterServerCapabilities,
2658 ) -> Option<Vec<CodeActionKind>> {
2659 match capabilities.server_capabilities.code_action_provider {
2660 Some(lsp::CodeActionProviderCapability::Options(CodeActionOptions {
2661 code_action_kinds: Some(supported_action_kinds),
2662 ..
2663 })) => Some(supported_action_kinds.clone()),
2664 _ => capabilities.code_action_kinds,
2665 }
2666 }
2667
2668 pub fn can_resolve_actions(capabilities: &ServerCapabilities) -> bool {
2669 capabilities
2670 .code_action_provider
2671 .as_ref()
2672 .and_then(|options| match options {
2673 lsp::CodeActionProviderCapability::Simple(_is_supported) => None,
2674 lsp::CodeActionProviderCapability::Options(options) => options.resolve_provider,
2675 })
2676 .unwrap_or(false)
2677 }
2678}
2679
2680#[async_trait(?Send)]
2681impl LspCommand for OnTypeFormatting {
2682 type Response = Option<Transaction>;
2683 type LspRequest = lsp::request::OnTypeFormatting;
2684 type ProtoRequest = proto::OnTypeFormatting;
2685
2686 fn display_name(&self) -> &str {
2687 "Formatting on typing"
2688 }
2689
2690 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
2691 let Some(on_type_formatting_options) = &capabilities
2692 .server_capabilities
2693 .document_on_type_formatting_provider
2694 else {
2695 return false;
2696 };
2697 on_type_formatting_options
2698 .first_trigger_character
2699 .contains(&self.trigger)
2700 || on_type_formatting_options
2701 .more_trigger_character
2702 .iter()
2703 .flatten()
2704 .any(|chars| chars.contains(&self.trigger))
2705 }
2706
2707 fn to_lsp(
2708 &self,
2709 path: &Path,
2710 _: &Buffer,
2711 _: &Arc<LanguageServer>,
2712 _: &App,
2713 ) -> Result<lsp::DocumentOnTypeFormattingParams> {
2714 Ok(lsp::DocumentOnTypeFormattingParams {
2715 text_document_position: make_lsp_text_document_position(path, self.position)?,
2716 ch: self.trigger.clone(),
2717 options: self.options.clone(),
2718 })
2719 }
2720
2721 async fn response_from_lsp(
2722 self,
2723 message: Option<Vec<lsp::TextEdit>>,
2724 lsp_store: Entity<LspStore>,
2725 buffer: Entity<Buffer>,
2726 server_id: LanguageServerId,
2727 mut cx: AsyncApp,
2728 ) -> Result<Option<Transaction>> {
2729 if let Some(edits) = message {
2730 let (lsp_adapter, lsp_server) =
2731 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
2732 LocalLspStore::deserialize_text_edits(
2733 lsp_store,
2734 buffer,
2735 edits,
2736 self.push_to_history,
2737 lsp_adapter,
2738 lsp_server,
2739 &mut cx,
2740 )
2741 .await
2742 } else {
2743 Ok(None)
2744 }
2745 }
2746
2747 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
2748 proto::OnTypeFormatting {
2749 project_id,
2750 buffer_id: buffer.remote_id().into(),
2751 position: Some(language::proto::serialize_anchor(
2752 &buffer.anchor_before(self.position),
2753 )),
2754 trigger: self.trigger.clone(),
2755 version: serialize_version(&buffer.version()),
2756 }
2757 }
2758
2759 async fn from_proto(
2760 message: proto::OnTypeFormatting,
2761 _: Entity<LspStore>,
2762 buffer: Entity<Buffer>,
2763 mut cx: AsyncApp,
2764 ) -> Result<Self> {
2765 let position = message
2766 .position
2767 .and_then(deserialize_anchor)
2768 .ok_or_else(|| anyhow!("invalid position"))?;
2769 buffer
2770 .update(&mut cx, |buffer, _| {
2771 buffer.wait_for_version(deserialize_version(&message.version))
2772 })?
2773 .await?;
2774
2775 let options = buffer.update(&mut cx, |buffer, cx| {
2776 lsp_formatting_options(
2777 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx).as_ref(),
2778 )
2779 })?;
2780
2781 Ok(Self {
2782 position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
2783 trigger: message.trigger.clone(),
2784 options,
2785 push_to_history: false,
2786 })
2787 }
2788
2789 fn response_to_proto(
2790 response: Option<Transaction>,
2791 _: &mut LspStore,
2792 _: PeerId,
2793 _: &clock::Global,
2794 _: &mut App,
2795 ) -> proto::OnTypeFormattingResponse {
2796 proto::OnTypeFormattingResponse {
2797 transaction: response
2798 .map(|transaction| language::proto::serialize_transaction(&transaction)),
2799 }
2800 }
2801
2802 async fn response_from_proto(
2803 self,
2804 message: proto::OnTypeFormattingResponse,
2805 _: Entity<LspStore>,
2806 _: Entity<Buffer>,
2807 _: AsyncApp,
2808 ) -> Result<Option<Transaction>> {
2809 let Some(transaction) = message.transaction else {
2810 return Ok(None);
2811 };
2812 Ok(Some(language::proto::deserialize_transaction(transaction)?))
2813 }
2814
2815 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> Result<BufferId> {
2816 BufferId::new(message.buffer_id)
2817 }
2818}
2819
2820impl InlayHints {
2821 pub async fn lsp_to_project_hint(
2822 lsp_hint: lsp::InlayHint,
2823 buffer_handle: &Entity<Buffer>,
2824 server_id: LanguageServerId,
2825 resolve_state: ResolveState,
2826 force_no_type_left_padding: bool,
2827 cx: &mut AsyncApp,
2828 ) -> anyhow::Result<InlayHint> {
2829 let kind = lsp_hint.kind.and_then(|kind| match kind {
2830 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
2831 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
2832 _ => None,
2833 });
2834
2835 let position = buffer_handle.update(cx, |buffer, _| {
2836 let position = buffer.clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
2837 if kind == Some(InlayHintKind::Parameter) {
2838 buffer.anchor_before(position)
2839 } else {
2840 buffer.anchor_after(position)
2841 }
2842 })?;
2843 let label = Self::lsp_inlay_label_to_project(lsp_hint.label, server_id)
2844 .await
2845 .context("lsp to project inlay hint conversion")?;
2846 let padding_left = if force_no_type_left_padding && kind == Some(InlayHintKind::Type) {
2847 false
2848 } else {
2849 lsp_hint.padding_left.unwrap_or(false)
2850 };
2851
2852 Ok(InlayHint {
2853 position,
2854 padding_left,
2855 padding_right: lsp_hint.padding_right.unwrap_or(false),
2856 label,
2857 kind,
2858 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
2859 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
2860 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
2861 InlayHintTooltip::MarkupContent(MarkupContent {
2862 kind: match markup_content.kind {
2863 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2864 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2865 },
2866 value: markup_content.value,
2867 })
2868 }
2869 }),
2870 resolve_state,
2871 })
2872 }
2873
2874 async fn lsp_inlay_label_to_project(
2875 lsp_label: lsp::InlayHintLabel,
2876 server_id: LanguageServerId,
2877 ) -> anyhow::Result<InlayHintLabel> {
2878 let label = match lsp_label {
2879 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
2880 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
2881 let mut parts = Vec::with_capacity(lsp_parts.len());
2882 for lsp_part in lsp_parts {
2883 parts.push(InlayHintLabelPart {
2884 value: lsp_part.value,
2885 tooltip: lsp_part.tooltip.map(|tooltip| match tooltip {
2886 lsp::InlayHintLabelPartTooltip::String(s) => {
2887 InlayHintLabelPartTooltip::String(s)
2888 }
2889 lsp::InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
2890 InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2891 kind: match markup_content.kind {
2892 lsp::MarkupKind::PlainText => HoverBlockKind::PlainText,
2893 lsp::MarkupKind::Markdown => HoverBlockKind::Markdown,
2894 },
2895 value: markup_content.value,
2896 })
2897 }
2898 }),
2899 location: Some(server_id).zip(lsp_part.location),
2900 });
2901 }
2902 InlayHintLabel::LabelParts(parts)
2903 }
2904 };
2905
2906 Ok(label)
2907 }
2908
2909 pub fn project_to_proto_hint(response_hint: InlayHint) -> proto::InlayHint {
2910 let (state, lsp_resolve_state) = match response_hint.resolve_state {
2911 ResolveState::Resolved => (0, None),
2912 ResolveState::CanResolve(server_id, resolve_data) => (
2913 1,
2914 Some(proto::resolve_state::LspResolveState {
2915 server_id: server_id.0 as u64,
2916 value: resolve_data.map(|json_data| {
2917 serde_json::to_string(&json_data)
2918 .expect("failed to serialize resolve json data")
2919 }),
2920 }),
2921 ),
2922 ResolveState::Resolving => (2, None),
2923 };
2924 let resolve_state = Some(proto::ResolveState {
2925 state,
2926 lsp_resolve_state,
2927 });
2928 proto::InlayHint {
2929 position: Some(language::proto::serialize_anchor(&response_hint.position)),
2930 padding_left: response_hint.padding_left,
2931 padding_right: response_hint.padding_right,
2932 label: Some(proto::InlayHintLabel {
2933 label: Some(match response_hint.label {
2934 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
2935 InlayHintLabel::LabelParts(label_parts) => {
2936 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
2937 parts: label_parts.into_iter().map(|label_part| {
2938 let location_url = label_part.location.as_ref().map(|(_, location)| location.uri.to_string());
2939 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 });
2940 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 });
2941 proto::InlayHintLabelPart {
2942 value: label_part.value,
2943 tooltip: label_part.tooltip.map(|tooltip| {
2944 let proto_tooltip = match tooltip {
2945 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
2946 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
2947 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2948 value: markup_content.value,
2949 }),
2950 };
2951 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
2952 }),
2953 location_url,
2954 location_range_start,
2955 location_range_end,
2956 language_server_id: label_part.location.as_ref().map(|(server_id, _)| server_id.0 as u64),
2957 }}).collect()
2958 })
2959 }
2960 }),
2961 }),
2962 kind: response_hint.kind.map(|kind| kind.name().to_string()),
2963 tooltip: response_hint.tooltip.map(|response_tooltip| {
2964 let proto_tooltip = match response_tooltip {
2965 InlayHintTooltip::String(s) => proto::inlay_hint_tooltip::Content::Value(s),
2966 InlayHintTooltip::MarkupContent(markup_content) => {
2967 proto::inlay_hint_tooltip::Content::MarkupContent(proto::MarkupContent {
2968 is_markdown: markup_content.kind == HoverBlockKind::Markdown,
2969 value: markup_content.value,
2970 })
2971 }
2972 };
2973 proto::InlayHintTooltip {
2974 content: Some(proto_tooltip),
2975 }
2976 }),
2977 resolve_state,
2978 }
2979 }
2980
2981 pub fn proto_to_project_hint(message_hint: proto::InlayHint) -> anyhow::Result<InlayHint> {
2982 let resolve_state = message_hint.resolve_state.as_ref().unwrap_or_else(|| {
2983 panic!("incorrect proto inlay hint message: no resolve state in hint {message_hint:?}",)
2984 });
2985 let resolve_state_data = resolve_state
2986 .lsp_resolve_state.as_ref()
2987 .map(|lsp_resolve_state| {
2988 let value = lsp_resolve_state.value.as_deref().map(|value| {
2989 serde_json::from_str::<Option<lsp::LSPAny>>(value)
2990 .with_context(|| format!("incorrect proto inlay hint message: non-json resolve state {lsp_resolve_state:?}"))
2991 }).transpose()?.flatten();
2992 anyhow::Ok((LanguageServerId(lsp_resolve_state.server_id as usize), value))
2993 })
2994 .transpose()?;
2995 let resolve_state = match resolve_state.state {
2996 0 => ResolveState::Resolved,
2997 1 => {
2998 let (server_id, lsp_resolve_state) = resolve_state_data.with_context(|| {
2999 format!(
3000 "No lsp resolve data for the hint that can be resolved: {message_hint:?}"
3001 )
3002 })?;
3003 ResolveState::CanResolve(server_id, lsp_resolve_state)
3004 }
3005 2 => ResolveState::Resolving,
3006 invalid => {
3007 anyhow::bail!("Unexpected resolve state {invalid} for hint {message_hint:?}")
3008 }
3009 };
3010 Ok(InlayHint {
3011 position: message_hint
3012 .position
3013 .and_then(language::proto::deserialize_anchor)
3014 .context("invalid position")?,
3015 label: match message_hint
3016 .label
3017 .and_then(|label| label.label)
3018 .context("missing label")?
3019 {
3020 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
3021 proto::inlay_hint_label::Label::LabelParts(parts) => {
3022 let mut label_parts = Vec::new();
3023 for part in parts.parts {
3024 label_parts.push(InlayHintLabelPart {
3025 value: part.value,
3026 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
3027 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => {
3028 InlayHintLabelPartTooltip::String(s)
3029 }
3030 Some(
3031 proto::inlay_hint_label_part_tooltip::Content::MarkupContent(
3032 markup_content,
3033 ),
3034 ) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
3035 kind: if markup_content.is_markdown {
3036 HoverBlockKind::Markdown
3037 } else {
3038 HoverBlockKind::PlainText
3039 },
3040 value: markup_content.value,
3041 }),
3042 None => InlayHintLabelPartTooltip::String(String::new()),
3043 }),
3044 location: {
3045 match part
3046 .location_url
3047 .zip(
3048 part.location_range_start.and_then(|start| {
3049 Some(start..part.location_range_end?)
3050 }),
3051 )
3052 .zip(part.language_server_id)
3053 {
3054 Some(((uri, range), server_id)) => Some((
3055 LanguageServerId(server_id as usize),
3056 lsp::Location {
3057 uri: lsp::Url::parse(&uri)
3058 .context("invalid uri in hint part {part:?}")?,
3059 range: lsp::Range::new(
3060 point_to_lsp(PointUtf16::new(
3061 range.start.row,
3062 range.start.column,
3063 )),
3064 point_to_lsp(PointUtf16::new(
3065 range.end.row,
3066 range.end.column,
3067 )),
3068 ),
3069 },
3070 )),
3071 None => None,
3072 }
3073 },
3074 });
3075 }
3076
3077 InlayHintLabel::LabelParts(label_parts)
3078 }
3079 },
3080 padding_left: message_hint.padding_left,
3081 padding_right: message_hint.padding_right,
3082 kind: message_hint
3083 .kind
3084 .as_deref()
3085 .and_then(InlayHintKind::from_name),
3086 tooltip: message_hint.tooltip.and_then(|tooltip| {
3087 Some(match tooltip.content? {
3088 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
3089 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
3090 InlayHintTooltip::MarkupContent(MarkupContent {
3091 kind: if markup_content.is_markdown {
3092 HoverBlockKind::Markdown
3093 } else {
3094 HoverBlockKind::PlainText
3095 },
3096 value: markup_content.value,
3097 })
3098 }
3099 })
3100 }),
3101 resolve_state,
3102 })
3103 }
3104
3105 pub fn project_to_lsp_hint(hint: InlayHint, snapshot: &BufferSnapshot) -> lsp::InlayHint {
3106 lsp::InlayHint {
3107 position: point_to_lsp(hint.position.to_point_utf16(snapshot)),
3108 kind: hint.kind.map(|kind| match kind {
3109 InlayHintKind::Type => lsp::InlayHintKind::TYPE,
3110 InlayHintKind::Parameter => lsp::InlayHintKind::PARAMETER,
3111 }),
3112 text_edits: None,
3113 tooltip: hint.tooltip.and_then(|tooltip| {
3114 Some(match tooltip {
3115 InlayHintTooltip::String(s) => lsp::InlayHintTooltip::String(s),
3116 InlayHintTooltip::MarkupContent(markup_content) => {
3117 lsp::InlayHintTooltip::MarkupContent(lsp::MarkupContent {
3118 kind: match markup_content.kind {
3119 HoverBlockKind::PlainText => lsp::MarkupKind::PlainText,
3120 HoverBlockKind::Markdown => lsp::MarkupKind::Markdown,
3121 HoverBlockKind::Code { .. } => return None,
3122 },
3123 value: markup_content.value,
3124 })
3125 }
3126 })
3127 }),
3128 label: match hint.label {
3129 InlayHintLabel::String(s) => lsp::InlayHintLabel::String(s),
3130 InlayHintLabel::LabelParts(label_parts) => lsp::InlayHintLabel::LabelParts(
3131 label_parts
3132 .into_iter()
3133 .map(|part| lsp::InlayHintLabelPart {
3134 value: part.value,
3135 tooltip: part.tooltip.and_then(|tooltip| {
3136 Some(match tooltip {
3137 InlayHintLabelPartTooltip::String(s) => {
3138 lsp::InlayHintLabelPartTooltip::String(s)
3139 }
3140 InlayHintLabelPartTooltip::MarkupContent(markup_content) => {
3141 lsp::InlayHintLabelPartTooltip::MarkupContent(
3142 lsp::MarkupContent {
3143 kind: match markup_content.kind {
3144 HoverBlockKind::PlainText => {
3145 lsp::MarkupKind::PlainText
3146 }
3147 HoverBlockKind::Markdown => {
3148 lsp::MarkupKind::Markdown
3149 }
3150 HoverBlockKind::Code { .. } => return None,
3151 },
3152 value: markup_content.value,
3153 },
3154 )
3155 }
3156 })
3157 }),
3158 location: part.location.map(|(_, location)| location),
3159 command: None,
3160 })
3161 .collect(),
3162 ),
3163 },
3164 padding_left: Some(hint.padding_left),
3165 padding_right: Some(hint.padding_right),
3166 data: match hint.resolve_state {
3167 ResolveState::CanResolve(_, data) => data,
3168 ResolveState::Resolving | ResolveState::Resolved => None,
3169 },
3170 }
3171 }
3172
3173 pub fn can_resolve_inlays(capabilities: &ServerCapabilities) -> bool {
3174 capabilities
3175 .inlay_hint_provider
3176 .as_ref()
3177 .and_then(|options| match options {
3178 OneOf::Left(_is_supported) => None,
3179 OneOf::Right(capabilities) => match capabilities {
3180 lsp::InlayHintServerCapabilities::Options(o) => o.resolve_provider,
3181 lsp::InlayHintServerCapabilities::RegistrationOptions(o) => {
3182 o.inlay_hint_options.resolve_provider
3183 }
3184 },
3185 })
3186 .unwrap_or(false)
3187 }
3188}
3189
3190#[async_trait(?Send)]
3191impl LspCommand for InlayHints {
3192 type Response = Vec<InlayHint>;
3193 type LspRequest = lsp::InlayHintRequest;
3194 type ProtoRequest = proto::InlayHints;
3195
3196 fn display_name(&self) -> &str {
3197 "Inlay hints"
3198 }
3199
3200 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3201 let Some(inlay_hint_provider) = &capabilities.server_capabilities.inlay_hint_provider
3202 else {
3203 return false;
3204 };
3205 match inlay_hint_provider {
3206 lsp::OneOf::Left(enabled) => *enabled,
3207 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
3208 lsp::InlayHintServerCapabilities::Options(_) => true,
3209 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
3210 },
3211 }
3212 }
3213
3214 fn to_lsp(
3215 &self,
3216 path: &Path,
3217 buffer: &Buffer,
3218 _: &Arc<LanguageServer>,
3219 _: &App,
3220 ) -> Result<lsp::InlayHintParams> {
3221 Ok(lsp::InlayHintParams {
3222 text_document: lsp::TextDocumentIdentifier {
3223 uri: file_path_to_lsp_url(path)?,
3224 },
3225 range: range_to_lsp(self.range.to_point_utf16(buffer))?,
3226 work_done_progress_params: Default::default(),
3227 })
3228 }
3229
3230 async fn response_from_lsp(
3231 self,
3232 message: Option<Vec<lsp::InlayHint>>,
3233 lsp_store: Entity<LspStore>,
3234 buffer: Entity<Buffer>,
3235 server_id: LanguageServerId,
3236 mut cx: AsyncApp,
3237 ) -> anyhow::Result<Vec<InlayHint>> {
3238 let (lsp_adapter, lsp_server) =
3239 language_server_for_buffer(&lsp_store, &buffer, server_id, &mut cx)?;
3240 // `typescript-language-server` adds padding to the left for type hints, turning
3241 // `const foo: boolean` into `const foo : boolean` which looks odd.
3242 // `rust-analyzer` does not have the padding for this case, and we have to accommodate both.
3243 //
3244 // We could trim the whole string, but being pessimistic on par with the situation above,
3245 // there might be a hint with multiple whitespaces at the end(s) which we need to display properly.
3246 // Hence let's use a heuristic first to handle the most awkward case and look for more.
3247 let force_no_type_left_padding =
3248 lsp_adapter.name.0.as_ref() == "typescript-language-server";
3249
3250 let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
3251 let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
3252 ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
3253 } else {
3254 ResolveState::Resolved
3255 };
3256
3257 let buffer = buffer.clone();
3258 cx.spawn(async move |cx| {
3259 InlayHints::lsp_to_project_hint(
3260 lsp_hint,
3261 &buffer,
3262 server_id,
3263 resolve_state,
3264 force_no_type_left_padding,
3265 cx,
3266 )
3267 .await
3268 })
3269 });
3270 future::join_all(hints)
3271 .await
3272 .into_iter()
3273 .collect::<anyhow::Result<_>>()
3274 .context("lsp to project inlay hints conversion")
3275 }
3276
3277 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
3278 proto::InlayHints {
3279 project_id,
3280 buffer_id: buffer.remote_id().into(),
3281 start: Some(language::proto::serialize_anchor(&self.range.start)),
3282 end: Some(language::proto::serialize_anchor(&self.range.end)),
3283 version: serialize_version(&buffer.version()),
3284 }
3285 }
3286
3287 async fn from_proto(
3288 message: proto::InlayHints,
3289 _: Entity<LspStore>,
3290 buffer: Entity<Buffer>,
3291 mut cx: AsyncApp,
3292 ) -> Result<Self> {
3293 let start = message
3294 .start
3295 .and_then(language::proto::deserialize_anchor)
3296 .context("invalid start")?;
3297 let end = message
3298 .end
3299 .and_then(language::proto::deserialize_anchor)
3300 .context("invalid end")?;
3301 buffer
3302 .update(&mut cx, |buffer, _| {
3303 buffer.wait_for_version(deserialize_version(&message.version))
3304 })?
3305 .await?;
3306
3307 Ok(Self { range: start..end })
3308 }
3309
3310 fn response_to_proto(
3311 response: Vec<InlayHint>,
3312 _: &mut LspStore,
3313 _: PeerId,
3314 buffer_version: &clock::Global,
3315 _: &mut App,
3316 ) -> proto::InlayHintsResponse {
3317 proto::InlayHintsResponse {
3318 hints: response
3319 .into_iter()
3320 .map(InlayHints::project_to_proto_hint)
3321 .collect(),
3322 version: serialize_version(buffer_version),
3323 }
3324 }
3325
3326 async fn response_from_proto(
3327 self,
3328 message: proto::InlayHintsResponse,
3329 _: Entity<LspStore>,
3330 buffer: Entity<Buffer>,
3331 mut cx: AsyncApp,
3332 ) -> anyhow::Result<Vec<InlayHint>> {
3333 buffer
3334 .update(&mut cx, |buffer, _| {
3335 buffer.wait_for_version(deserialize_version(&message.version))
3336 })?
3337 .await?;
3338
3339 let mut hints = Vec::new();
3340 for message_hint in message.hints {
3341 hints.push(InlayHints::proto_to_project_hint(message_hint)?);
3342 }
3343
3344 Ok(hints)
3345 }
3346
3347 fn buffer_id_from_proto(message: &proto::InlayHints) -> Result<BufferId> {
3348 BufferId::new(message.buffer_id)
3349 }
3350}
3351
3352#[async_trait(?Send)]
3353impl LspCommand for GetCodeLens {
3354 type Response = Vec<CodeAction>;
3355 type LspRequest = lsp::CodeLensRequest;
3356 type ProtoRequest = proto::GetCodeLens;
3357
3358 fn display_name(&self) -> &str {
3359 "Code Lens"
3360 }
3361
3362 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3363 capabilities
3364 .server_capabilities
3365 .code_lens_provider
3366 .as_ref()
3367 .map_or(false, |code_lens_options| {
3368 code_lens_options.resolve_provider.unwrap_or(false)
3369 })
3370 }
3371
3372 fn to_lsp(
3373 &self,
3374 path: &Path,
3375 _: &Buffer,
3376 _: &Arc<LanguageServer>,
3377 _: &App,
3378 ) -> Result<lsp::CodeLensParams> {
3379 Ok(lsp::CodeLensParams {
3380 text_document: lsp::TextDocumentIdentifier {
3381 uri: file_path_to_lsp_url(path)?,
3382 },
3383 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
3384 partial_result_params: lsp::PartialResultParams::default(),
3385 })
3386 }
3387
3388 async fn response_from_lsp(
3389 self,
3390 message: Option<Vec<lsp::CodeLens>>,
3391 lsp_store: Entity<LspStore>,
3392 buffer: Entity<Buffer>,
3393 server_id: LanguageServerId,
3394 mut cx: AsyncApp,
3395 ) -> anyhow::Result<Vec<CodeAction>> {
3396 let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
3397 let language_server = cx.update(|cx| {
3398 lsp_store
3399 .read(cx)
3400 .language_server_for_id(server_id)
3401 .with_context(|| {
3402 format!("Missing the language server that just returned a response {server_id}")
3403 })
3404 })??;
3405 let server_capabilities = language_server.capabilities();
3406 let available_commands = server_capabilities
3407 .execute_command_provider
3408 .as_ref()
3409 .map(|options| options.commands.as_slice())
3410 .unwrap_or_default();
3411 Ok(message
3412 .unwrap_or_default()
3413 .into_iter()
3414 .filter(|code_lens| {
3415 code_lens
3416 .command
3417 .as_ref()
3418 .is_none_or(|command| available_commands.contains(&command.command))
3419 })
3420 .map(|code_lens| {
3421 let code_lens_range = range_from_lsp(code_lens.range);
3422 let start = snapshot.clip_point_utf16(code_lens_range.start, Bias::Left);
3423 let end = snapshot.clip_point_utf16(code_lens_range.end, Bias::Right);
3424 let range = snapshot.anchor_before(start)..snapshot.anchor_after(end);
3425 CodeAction {
3426 server_id,
3427 range,
3428 lsp_action: LspAction::CodeLens(code_lens),
3429 resolved: false,
3430 }
3431 })
3432 .collect())
3433 }
3434
3435 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeLens {
3436 proto::GetCodeLens {
3437 project_id,
3438 buffer_id: buffer.remote_id().into(),
3439 version: serialize_version(&buffer.version()),
3440 }
3441 }
3442
3443 async fn from_proto(
3444 message: proto::GetCodeLens,
3445 _: Entity<LspStore>,
3446 buffer: Entity<Buffer>,
3447 mut cx: AsyncApp,
3448 ) -> Result<Self> {
3449 buffer
3450 .update(&mut cx, |buffer, _| {
3451 buffer.wait_for_version(deserialize_version(&message.version))
3452 })?
3453 .await?;
3454 Ok(Self)
3455 }
3456
3457 fn response_to_proto(
3458 response: Vec<CodeAction>,
3459 _: &mut LspStore,
3460 _: PeerId,
3461 buffer_version: &clock::Global,
3462 _: &mut App,
3463 ) -> proto::GetCodeLensResponse {
3464 proto::GetCodeLensResponse {
3465 lens_actions: response
3466 .iter()
3467 .map(LspStore::serialize_code_action)
3468 .collect(),
3469 version: serialize_version(buffer_version),
3470 }
3471 }
3472
3473 async fn response_from_proto(
3474 self,
3475 message: proto::GetCodeLensResponse,
3476 _: Entity<LspStore>,
3477 buffer: Entity<Buffer>,
3478 mut cx: AsyncApp,
3479 ) -> anyhow::Result<Vec<CodeAction>> {
3480 buffer
3481 .update(&mut cx, |buffer, _| {
3482 buffer.wait_for_version(deserialize_version(&message.version))
3483 })?
3484 .await?;
3485 message
3486 .lens_actions
3487 .into_iter()
3488 .map(LspStore::deserialize_code_action)
3489 .collect::<Result<Vec<_>>>()
3490 .context("deserializing proto code lens response")
3491 }
3492
3493 fn buffer_id_from_proto(message: &proto::GetCodeLens) -> Result<BufferId> {
3494 BufferId::new(message.buffer_id)
3495 }
3496}
3497
3498#[async_trait(?Send)]
3499impl LspCommand for LinkedEditingRange {
3500 type Response = Vec<Range<Anchor>>;
3501 type LspRequest = lsp::request::LinkedEditingRange;
3502 type ProtoRequest = proto::LinkedEditingRange;
3503
3504 fn display_name(&self) -> &str {
3505 "Linked editing range"
3506 }
3507
3508 fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
3509 let Some(linked_editing_options) = &capabilities
3510 .server_capabilities
3511 .linked_editing_range_provider
3512 else {
3513 return false;
3514 };
3515 if let LinkedEditingRangeServerCapabilities::Simple(false) = linked_editing_options {
3516 return false;
3517 }
3518 true
3519 }
3520
3521 fn to_lsp(
3522 &self,
3523 path: &Path,
3524 buffer: &Buffer,
3525 _server: &Arc<LanguageServer>,
3526 _: &App,
3527 ) -> Result<lsp::LinkedEditingRangeParams> {
3528 let position = self.position.to_point_utf16(&buffer.snapshot());
3529 Ok(lsp::LinkedEditingRangeParams {
3530 text_document_position_params: make_lsp_text_document_position(path, position)?,
3531 work_done_progress_params: Default::default(),
3532 })
3533 }
3534
3535 async fn response_from_lsp(
3536 self,
3537 message: Option<lsp::LinkedEditingRanges>,
3538 _: Entity<LspStore>,
3539 buffer: Entity<Buffer>,
3540 _server_id: LanguageServerId,
3541 cx: AsyncApp,
3542 ) -> Result<Vec<Range<Anchor>>> {
3543 if let Some(lsp::LinkedEditingRanges { mut ranges, .. }) = message {
3544 ranges.sort_by_key(|range| range.start);
3545
3546 buffer.read_with(&cx, |buffer, _| {
3547 ranges
3548 .into_iter()
3549 .map(|range| {
3550 let start =
3551 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
3552 let end = buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
3553 buffer.anchor_before(start)..buffer.anchor_after(end)
3554 })
3555 .collect()
3556 })
3557 } else {
3558 Ok(vec![])
3559 }
3560 }
3561
3562 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::LinkedEditingRange {
3563 proto::LinkedEditingRange {
3564 project_id,
3565 buffer_id: buffer.remote_id().to_proto(),
3566 position: Some(serialize_anchor(&self.position)),
3567 version: serialize_version(&buffer.version()),
3568 }
3569 }
3570
3571 async fn from_proto(
3572 message: proto::LinkedEditingRange,
3573 _: Entity<LspStore>,
3574 buffer: Entity<Buffer>,
3575 mut cx: AsyncApp,
3576 ) -> Result<Self> {
3577 let position = message
3578 .position
3579 .ok_or_else(|| anyhow!("invalid position"))?;
3580 buffer
3581 .update(&mut cx, |buffer, _| {
3582 buffer.wait_for_version(deserialize_version(&message.version))
3583 })?
3584 .await?;
3585 let position = deserialize_anchor(position).ok_or_else(|| anyhow!("invalid position"))?;
3586 buffer
3587 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([position]))?
3588 .await?;
3589 Ok(Self { position })
3590 }
3591
3592 fn response_to_proto(
3593 response: Vec<Range<Anchor>>,
3594 _: &mut LspStore,
3595 _: PeerId,
3596 buffer_version: &clock::Global,
3597 _: &mut App,
3598 ) -> proto::LinkedEditingRangeResponse {
3599 proto::LinkedEditingRangeResponse {
3600 items: response
3601 .into_iter()
3602 .map(|range| proto::AnchorRange {
3603 start: Some(serialize_anchor(&range.start)),
3604 end: Some(serialize_anchor(&range.end)),
3605 })
3606 .collect(),
3607 version: serialize_version(buffer_version),
3608 }
3609 }
3610
3611 async fn response_from_proto(
3612 self,
3613 message: proto::LinkedEditingRangeResponse,
3614 _: Entity<LspStore>,
3615 buffer: Entity<Buffer>,
3616 mut cx: AsyncApp,
3617 ) -> Result<Vec<Range<Anchor>>> {
3618 buffer
3619 .update(&mut cx, |buffer, _| {
3620 buffer.wait_for_version(deserialize_version(&message.version))
3621 })?
3622 .await?;
3623 let items: Vec<Range<Anchor>> = message
3624 .items
3625 .into_iter()
3626 .filter_map(|range| {
3627 let start = deserialize_anchor(range.start?)?;
3628 let end = deserialize_anchor(range.end?)?;
3629 Some(start..end)
3630 })
3631 .collect();
3632 for range in &items {
3633 buffer
3634 .update(&mut cx, |buffer, _| {
3635 buffer.wait_for_anchors([range.start, range.end])
3636 })?
3637 .await?;
3638 }
3639 Ok(items)
3640 }
3641
3642 fn buffer_id_from_proto(message: &proto::LinkedEditingRange) -> Result<BufferId> {
3643 BufferId::new(message.buffer_id)
3644 }
3645}