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