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