1use crate::{
2 DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint, InlayHintKind, InlayHintLabel,
3 InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location, LocationLink,
4 MarkupContent, Project, ProjectTransaction,
5};
6use anyhow::{anyhow, Context, Result};
7use async_trait::async_trait;
8use client::proto::{self, PeerId};
9use fs::LineEnding;
10use gpui::{AppContext, AsyncAppContext, ModelHandle};
11use language::{
12 language_settings::language_settings,
13 point_from_lsp, point_to_lsp,
14 proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
15 range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction,
16 Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
17};
18use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities};
19use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
20
21pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions {
22 lsp::FormattingOptions {
23 tab_size,
24 insert_spaces: true,
25 insert_final_newline: Some(true),
26 ..lsp::FormattingOptions::default()
27 }
28}
29
30#[async_trait(?Send)]
31pub(crate) trait LspCommand: 'static + Sized {
32 type Response: 'static + Default + Send;
33 type LspRequest: 'static + Send + lsp::request::Request;
34 type ProtoRequest: 'static + Send + proto::RequestMessage;
35
36 fn check_capabilities(&self, _: &lsp::ServerCapabilities) -> bool {
37 true
38 }
39
40 fn to_lsp(
41 &self,
42 path: &Path,
43 buffer: &Buffer,
44 language_server: &Arc<LanguageServer>,
45 cx: &AppContext,
46 ) -> <Self::LspRequest as lsp::request::Request>::Params;
47
48 async fn response_from_lsp(
49 self,
50 message: <Self::LspRequest as lsp::request::Request>::Result,
51 project: ModelHandle<Project>,
52 buffer: ModelHandle<Buffer>,
53 server_id: LanguageServerId,
54 cx: AsyncAppContext,
55 ) -> Result<Self::Response>;
56
57 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest;
58
59 async fn from_proto(
60 message: Self::ProtoRequest,
61 project: ModelHandle<Project>,
62 buffer: ModelHandle<Buffer>,
63 cx: AsyncAppContext,
64 ) -> Result<Self>;
65
66 fn response_to_proto(
67 response: Self::Response,
68 project: &mut Project,
69 peer_id: PeerId,
70 buffer_version: &clock::Global,
71 cx: &mut AppContext,
72 ) -> <Self::ProtoRequest as proto::RequestMessage>::Response;
73
74 async fn response_from_proto(
75 self,
76 message: <Self::ProtoRequest as proto::RequestMessage>::Response,
77 project: ModelHandle<Project>,
78 buffer: ModelHandle<Buffer>,
79 cx: AsyncAppContext,
80 ) -> Result<Self::Response>;
81
82 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64;
83}
84
85pub(crate) struct PrepareRename {
86 pub position: PointUtf16,
87}
88
89pub(crate) struct PerformRename {
90 pub position: PointUtf16,
91 pub new_name: String,
92 pub push_to_history: bool,
93}
94
95pub(crate) struct GetDefinition {
96 pub position: PointUtf16,
97}
98
99pub(crate) struct GetTypeDefinition {
100 pub position: PointUtf16,
101}
102
103pub(crate) struct GetReferences {
104 pub position: PointUtf16,
105}
106
107pub(crate) struct GetDocumentHighlights {
108 pub position: PointUtf16,
109}
110
111pub(crate) struct GetHover {
112 pub position: PointUtf16,
113}
114
115pub(crate) struct GetCompletions {
116 pub position: PointUtf16,
117}
118
119pub(crate) struct GetCodeActions {
120 pub range: Range<Anchor>,
121}
122
123pub(crate) struct OnTypeFormatting {
124 pub position: PointUtf16,
125 pub trigger: String,
126 pub options: FormattingOptions,
127 pub push_to_history: bool,
128}
129
130pub(crate) struct InlayHints {
131 pub range: Range<Anchor>,
132}
133
134pub(crate) struct FormattingOptions {
135 tab_size: u32,
136}
137
138impl From<lsp::FormattingOptions> for FormattingOptions {
139 fn from(value: lsp::FormattingOptions) -> Self {
140 Self {
141 tab_size: value.tab_size,
142 }
143 }
144}
145
146#[async_trait(?Send)]
147impl LspCommand for PrepareRename {
148 type Response = Option<Range<Anchor>>;
149 type LspRequest = lsp::request::PrepareRenameRequest;
150 type ProtoRequest = proto::PrepareRename;
151
152 fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
153 if let Some(lsp::OneOf::Right(rename)) = &capabilities.rename_provider {
154 rename.prepare_provider == Some(true)
155 } else {
156 false
157 }
158 }
159
160 fn to_lsp(
161 &self,
162 path: &Path,
163 _: &Buffer,
164 _: &Arc<LanguageServer>,
165 _: &AppContext,
166 ) -> lsp::TextDocumentPositionParams {
167 lsp::TextDocumentPositionParams {
168 text_document: lsp::TextDocumentIdentifier {
169 uri: lsp::Url::from_file_path(path).unwrap(),
170 },
171 position: point_to_lsp(self.position),
172 }
173 }
174
175 async fn response_from_lsp(
176 self,
177 message: Option<lsp::PrepareRenameResponse>,
178 _: ModelHandle<Project>,
179 buffer: ModelHandle<Buffer>,
180 _: LanguageServerId,
181 cx: AsyncAppContext,
182 ) -> Result<Option<Range<Anchor>>> {
183 buffer.read_with(&cx, |buffer, _| {
184 if let Some(
185 lsp::PrepareRenameResponse::Range(range)
186 | lsp::PrepareRenameResponse::RangeWithPlaceholder { range, .. },
187 ) = message
188 {
189 let Range { start, end } = range_from_lsp(range);
190 if buffer.clip_point_utf16(start, Bias::Left) == start.0
191 && buffer.clip_point_utf16(end, Bias::Left) == end.0
192 {
193 return Ok(Some(buffer.anchor_after(start)..buffer.anchor_before(end)));
194 }
195 }
196 Ok(None)
197 })
198 }
199
200 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PrepareRename {
201 proto::PrepareRename {
202 project_id,
203 buffer_id: buffer.remote_id(),
204 position: Some(language::proto::serialize_anchor(
205 &buffer.anchor_before(self.position),
206 )),
207 version: serialize_version(&buffer.version()),
208 }
209 }
210
211 async fn from_proto(
212 message: proto::PrepareRename,
213 _: ModelHandle<Project>,
214 buffer: ModelHandle<Buffer>,
215 mut cx: AsyncAppContext,
216 ) -> Result<Self> {
217 let position = message
218 .position
219 .and_then(deserialize_anchor)
220 .ok_or_else(|| anyhow!("invalid position"))?;
221 buffer
222 .update(&mut cx, |buffer, _| {
223 buffer.wait_for_version(deserialize_version(&message.version))
224 })
225 .await?;
226
227 Ok(Self {
228 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
229 })
230 }
231
232 fn response_to_proto(
233 range: Option<Range<Anchor>>,
234 _: &mut Project,
235 _: PeerId,
236 buffer_version: &clock::Global,
237 _: &mut AppContext,
238 ) -> proto::PrepareRenameResponse {
239 proto::PrepareRenameResponse {
240 can_rename: range.is_some(),
241 start: range
242 .as_ref()
243 .map(|range| language::proto::serialize_anchor(&range.start)),
244 end: range
245 .as_ref()
246 .map(|range| language::proto::serialize_anchor(&range.end)),
247 version: serialize_version(buffer_version),
248 }
249 }
250
251 async fn response_from_proto(
252 self,
253 message: proto::PrepareRenameResponse,
254 _: ModelHandle<Project>,
255 buffer: ModelHandle<Buffer>,
256 mut cx: AsyncAppContext,
257 ) -> Result<Option<Range<Anchor>>> {
258 if message.can_rename {
259 buffer
260 .update(&mut cx, |buffer, _| {
261 buffer.wait_for_version(deserialize_version(&message.version))
262 })
263 .await?;
264 let start = message.start.and_then(deserialize_anchor);
265 let end = message.end.and_then(deserialize_anchor);
266 Ok(start.zip(end).map(|(start, end)| start..end))
267 } else {
268 Ok(None)
269 }
270 }
271
272 fn buffer_id_from_proto(message: &proto::PrepareRename) -> u64 {
273 message.buffer_id
274 }
275}
276
277#[async_trait(?Send)]
278impl LspCommand for PerformRename {
279 type Response = ProjectTransaction;
280 type LspRequest = lsp::request::Rename;
281 type ProtoRequest = proto::PerformRename;
282
283 fn to_lsp(
284 &self,
285 path: &Path,
286 _: &Buffer,
287 _: &Arc<LanguageServer>,
288 _: &AppContext,
289 ) -> lsp::RenameParams {
290 lsp::RenameParams {
291 text_document_position: lsp::TextDocumentPositionParams {
292 text_document: lsp::TextDocumentIdentifier {
293 uri: lsp::Url::from_file_path(path).unwrap(),
294 },
295 position: point_to_lsp(self.position),
296 },
297 new_name: self.new_name.clone(),
298 work_done_progress_params: Default::default(),
299 }
300 }
301
302 async fn response_from_lsp(
303 self,
304 message: Option<lsp::WorkspaceEdit>,
305 project: ModelHandle<Project>,
306 buffer: ModelHandle<Buffer>,
307 server_id: LanguageServerId,
308 mut cx: AsyncAppContext,
309 ) -> Result<ProjectTransaction> {
310 if let Some(edit) = message {
311 let (lsp_adapter, lsp_server) =
312 language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
313 Project::deserialize_workspace_edit(
314 project,
315 edit,
316 self.push_to_history,
317 lsp_adapter,
318 lsp_server,
319 &mut cx,
320 )
321 .await
322 } else {
323 Ok(ProjectTransaction::default())
324 }
325 }
326
327 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::PerformRename {
328 proto::PerformRename {
329 project_id,
330 buffer_id: buffer.remote_id(),
331 position: Some(language::proto::serialize_anchor(
332 &buffer.anchor_before(self.position),
333 )),
334 new_name: self.new_name.clone(),
335 version: serialize_version(&buffer.version()),
336 }
337 }
338
339 async fn from_proto(
340 message: proto::PerformRename,
341 _: ModelHandle<Project>,
342 buffer: ModelHandle<Buffer>,
343 mut cx: AsyncAppContext,
344 ) -> Result<Self> {
345 let position = message
346 .position
347 .and_then(deserialize_anchor)
348 .ok_or_else(|| anyhow!("invalid position"))?;
349 buffer
350 .update(&mut cx, |buffer, _| {
351 buffer.wait_for_version(deserialize_version(&message.version))
352 })
353 .await?;
354 Ok(Self {
355 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
356 new_name: message.new_name,
357 push_to_history: false,
358 })
359 }
360
361 fn response_to_proto(
362 response: ProjectTransaction,
363 project: &mut Project,
364 peer_id: PeerId,
365 _: &clock::Global,
366 cx: &mut AppContext,
367 ) -> proto::PerformRenameResponse {
368 let transaction = project.serialize_project_transaction_for_peer(response, peer_id, cx);
369 proto::PerformRenameResponse {
370 transaction: Some(transaction),
371 }
372 }
373
374 async fn response_from_proto(
375 self,
376 message: proto::PerformRenameResponse,
377 project: ModelHandle<Project>,
378 _: ModelHandle<Buffer>,
379 mut cx: AsyncAppContext,
380 ) -> Result<ProjectTransaction> {
381 let message = message
382 .transaction
383 .ok_or_else(|| anyhow!("missing transaction"))?;
384 project
385 .update(&mut cx, |project, cx| {
386 project.deserialize_project_transaction(message, self.push_to_history, cx)
387 })
388 .await
389 }
390
391 fn buffer_id_from_proto(message: &proto::PerformRename) -> u64 {
392 message.buffer_id
393 }
394}
395
396#[async_trait(?Send)]
397impl LspCommand for GetDefinition {
398 type Response = Vec<LocationLink>;
399 type LspRequest = lsp::request::GotoDefinition;
400 type ProtoRequest = proto::GetDefinition;
401
402 fn to_lsp(
403 &self,
404 path: &Path,
405 _: &Buffer,
406 _: &Arc<LanguageServer>,
407 _: &AppContext,
408 ) -> lsp::GotoDefinitionParams {
409 lsp::GotoDefinitionParams {
410 text_document_position_params: lsp::TextDocumentPositionParams {
411 text_document: lsp::TextDocumentIdentifier {
412 uri: lsp::Url::from_file_path(path).unwrap(),
413 },
414 position: point_to_lsp(self.position),
415 },
416 work_done_progress_params: Default::default(),
417 partial_result_params: Default::default(),
418 }
419 }
420
421 async fn response_from_lsp(
422 self,
423 message: Option<lsp::GotoDefinitionResponse>,
424 project: ModelHandle<Project>,
425 buffer: ModelHandle<Buffer>,
426 server_id: LanguageServerId,
427 cx: AsyncAppContext,
428 ) -> Result<Vec<LocationLink>> {
429 location_links_from_lsp(message, project, buffer, server_id, cx).await
430 }
431
432 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDefinition {
433 proto::GetDefinition {
434 project_id,
435 buffer_id: buffer.remote_id(),
436 position: Some(language::proto::serialize_anchor(
437 &buffer.anchor_before(self.position),
438 )),
439 version: serialize_version(&buffer.version()),
440 }
441 }
442
443 async fn from_proto(
444 message: proto::GetDefinition,
445 _: ModelHandle<Project>,
446 buffer: ModelHandle<Buffer>,
447 mut cx: AsyncAppContext,
448 ) -> Result<Self> {
449 let position = message
450 .position
451 .and_then(deserialize_anchor)
452 .ok_or_else(|| anyhow!("invalid position"))?;
453 buffer
454 .update(&mut cx, |buffer, _| {
455 buffer.wait_for_version(deserialize_version(&message.version))
456 })
457 .await?;
458 Ok(Self {
459 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
460 })
461 }
462
463 fn response_to_proto(
464 response: Vec<LocationLink>,
465 project: &mut Project,
466 peer_id: PeerId,
467 _: &clock::Global,
468 cx: &mut AppContext,
469 ) -> proto::GetDefinitionResponse {
470 let links = location_links_to_proto(response, project, peer_id, cx);
471 proto::GetDefinitionResponse { links }
472 }
473
474 async fn response_from_proto(
475 self,
476 message: proto::GetDefinitionResponse,
477 project: ModelHandle<Project>,
478 _: ModelHandle<Buffer>,
479 cx: AsyncAppContext,
480 ) -> Result<Vec<LocationLink>> {
481 location_links_from_proto(message.links, project, cx).await
482 }
483
484 fn buffer_id_from_proto(message: &proto::GetDefinition) -> u64 {
485 message.buffer_id
486 }
487}
488
489#[async_trait(?Send)]
490impl LspCommand for GetTypeDefinition {
491 type Response = Vec<LocationLink>;
492 type LspRequest = lsp::request::GotoTypeDefinition;
493 type ProtoRequest = proto::GetTypeDefinition;
494
495 fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
496 match &capabilities.type_definition_provider {
497 None => false,
498 Some(lsp::TypeDefinitionProviderCapability::Simple(false)) => false,
499 _ => true,
500 }
501 }
502
503 fn to_lsp(
504 &self,
505 path: &Path,
506 _: &Buffer,
507 _: &Arc<LanguageServer>,
508 _: &AppContext,
509 ) -> lsp::GotoTypeDefinitionParams {
510 lsp::GotoTypeDefinitionParams {
511 text_document_position_params: lsp::TextDocumentPositionParams {
512 text_document: lsp::TextDocumentIdentifier {
513 uri: lsp::Url::from_file_path(path).unwrap(),
514 },
515 position: point_to_lsp(self.position),
516 },
517 work_done_progress_params: Default::default(),
518 partial_result_params: Default::default(),
519 }
520 }
521
522 async fn response_from_lsp(
523 self,
524 message: Option<lsp::GotoTypeDefinitionResponse>,
525 project: ModelHandle<Project>,
526 buffer: ModelHandle<Buffer>,
527 server_id: LanguageServerId,
528 cx: AsyncAppContext,
529 ) -> Result<Vec<LocationLink>> {
530 location_links_from_lsp(message, project, buffer, server_id, cx).await
531 }
532
533 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetTypeDefinition {
534 proto::GetTypeDefinition {
535 project_id,
536 buffer_id: buffer.remote_id(),
537 position: Some(language::proto::serialize_anchor(
538 &buffer.anchor_before(self.position),
539 )),
540 version: serialize_version(&buffer.version()),
541 }
542 }
543
544 async fn from_proto(
545 message: proto::GetTypeDefinition,
546 _: ModelHandle<Project>,
547 buffer: ModelHandle<Buffer>,
548 mut cx: AsyncAppContext,
549 ) -> Result<Self> {
550 let position = message
551 .position
552 .and_then(deserialize_anchor)
553 .ok_or_else(|| anyhow!("invalid position"))?;
554 buffer
555 .update(&mut cx, |buffer, _| {
556 buffer.wait_for_version(deserialize_version(&message.version))
557 })
558 .await?;
559 Ok(Self {
560 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
561 })
562 }
563
564 fn response_to_proto(
565 response: Vec<LocationLink>,
566 project: &mut Project,
567 peer_id: PeerId,
568 _: &clock::Global,
569 cx: &mut AppContext,
570 ) -> proto::GetTypeDefinitionResponse {
571 let links = location_links_to_proto(response, project, peer_id, cx);
572 proto::GetTypeDefinitionResponse { links }
573 }
574
575 async fn response_from_proto(
576 self,
577 message: proto::GetTypeDefinitionResponse,
578 project: ModelHandle<Project>,
579 _: ModelHandle<Buffer>,
580 cx: AsyncAppContext,
581 ) -> Result<Vec<LocationLink>> {
582 location_links_from_proto(message.links, project, cx).await
583 }
584
585 fn buffer_id_from_proto(message: &proto::GetTypeDefinition) -> u64 {
586 message.buffer_id
587 }
588}
589
590fn language_server_for_buffer(
591 project: &ModelHandle<Project>,
592 buffer: &ModelHandle<Buffer>,
593 server_id: LanguageServerId,
594 cx: &mut AsyncAppContext,
595) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
596 project
597 .read_with(cx, |project, cx| {
598 project
599 .language_server_for_buffer(buffer.read(cx), server_id, cx)
600 .map(|(adapter, server)| (adapter.clone(), server.clone()))
601 })
602 .ok_or_else(|| anyhow!("no language server found for buffer"))
603}
604
605async fn location_links_from_proto(
606 proto_links: Vec<proto::LocationLink>,
607 project: ModelHandle<Project>,
608 mut cx: AsyncAppContext,
609) -> Result<Vec<LocationLink>> {
610 let mut links = Vec::new();
611
612 for link in proto_links {
613 let origin = match link.origin {
614 Some(origin) => {
615 let buffer = project
616 .update(&mut cx, |this, cx| {
617 this.wait_for_remote_buffer(origin.buffer_id, cx)
618 })
619 .await?;
620 let start = origin
621 .start
622 .and_then(deserialize_anchor)
623 .ok_or_else(|| anyhow!("missing origin start"))?;
624 let end = origin
625 .end
626 .and_then(deserialize_anchor)
627 .ok_or_else(|| anyhow!("missing origin end"))?;
628 buffer
629 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
630 .await?;
631 Some(Location {
632 buffer,
633 range: start..end,
634 })
635 }
636 None => None,
637 };
638
639 let target = link.target.ok_or_else(|| anyhow!("missing target"))?;
640 let buffer = project
641 .update(&mut cx, |this, cx| {
642 this.wait_for_remote_buffer(target.buffer_id, cx)
643 })
644 .await?;
645 let start = target
646 .start
647 .and_then(deserialize_anchor)
648 .ok_or_else(|| anyhow!("missing target start"))?;
649 let end = target
650 .end
651 .and_then(deserialize_anchor)
652 .ok_or_else(|| anyhow!("missing target end"))?;
653 buffer
654 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
655 .await?;
656 let target = Location {
657 buffer,
658 range: start..end,
659 };
660
661 links.push(LocationLink { origin, target })
662 }
663
664 Ok(links)
665}
666
667async fn location_links_from_lsp(
668 message: Option<lsp::GotoDefinitionResponse>,
669 project: ModelHandle<Project>,
670 buffer: ModelHandle<Buffer>,
671 server_id: LanguageServerId,
672 mut cx: AsyncAppContext,
673) -> Result<Vec<LocationLink>> {
674 let message = match message {
675 Some(message) => message,
676 None => return Ok(Vec::new()),
677 };
678
679 let mut unresolved_links = Vec::new();
680 match message {
681 lsp::GotoDefinitionResponse::Scalar(loc) => {
682 unresolved_links.push((None, loc.uri, loc.range));
683 }
684
685 lsp::GotoDefinitionResponse::Array(locs) => {
686 unresolved_links.extend(locs.into_iter().map(|l| (None, l.uri, l.range)));
687 }
688
689 lsp::GotoDefinitionResponse::Link(links) => {
690 unresolved_links.extend(links.into_iter().map(|l| {
691 (
692 l.origin_selection_range,
693 l.target_uri,
694 l.target_selection_range,
695 )
696 }));
697 }
698 }
699
700 let (lsp_adapter, language_server) =
701 language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
702 let mut definitions = Vec::new();
703 for (origin_range, target_uri, target_range) in unresolved_links {
704 let target_buffer_handle = project
705 .update(&mut cx, |this, cx| {
706 this.open_local_buffer_via_lsp(
707 target_uri,
708 language_server.server_id(),
709 lsp_adapter.name.clone(),
710 cx,
711 )
712 })
713 .await?;
714
715 cx.read(|cx| {
716 let origin_location = origin_range.map(|origin_range| {
717 let origin_buffer = buffer.read(cx);
718 let origin_start =
719 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.start), Bias::Left);
720 let origin_end =
721 origin_buffer.clip_point_utf16(point_from_lsp(origin_range.end), Bias::Left);
722 Location {
723 buffer: buffer.clone(),
724 range: origin_buffer.anchor_after(origin_start)
725 ..origin_buffer.anchor_before(origin_end),
726 }
727 });
728
729 let target_buffer = target_buffer_handle.read(cx);
730 let target_start =
731 target_buffer.clip_point_utf16(point_from_lsp(target_range.start), Bias::Left);
732 let target_end =
733 target_buffer.clip_point_utf16(point_from_lsp(target_range.end), Bias::Left);
734 let target_location = Location {
735 buffer: target_buffer_handle,
736 range: target_buffer.anchor_after(target_start)
737 ..target_buffer.anchor_before(target_end),
738 };
739
740 definitions.push(LocationLink {
741 origin: origin_location,
742 target: target_location,
743 })
744 });
745 }
746 Ok(definitions)
747}
748
749fn location_links_to_proto(
750 links: Vec<LocationLink>,
751 project: &mut Project,
752 peer_id: PeerId,
753 cx: &mut AppContext,
754) -> Vec<proto::LocationLink> {
755 links
756 .into_iter()
757 .map(|definition| {
758 let origin = definition.origin.map(|origin| {
759 let buffer_id = project.create_buffer_for_peer(&origin.buffer, peer_id, cx);
760 proto::Location {
761 start: Some(serialize_anchor(&origin.range.start)),
762 end: Some(serialize_anchor(&origin.range.end)),
763 buffer_id,
764 }
765 });
766
767 let buffer_id = project.create_buffer_for_peer(&definition.target.buffer, peer_id, cx);
768 let target = proto::Location {
769 start: Some(serialize_anchor(&definition.target.range.start)),
770 end: Some(serialize_anchor(&definition.target.range.end)),
771 buffer_id,
772 };
773
774 proto::LocationLink {
775 origin,
776 target: Some(target),
777 }
778 })
779 .collect()
780}
781
782#[async_trait(?Send)]
783impl LspCommand for GetReferences {
784 type Response = Vec<Location>;
785 type LspRequest = lsp::request::References;
786 type ProtoRequest = proto::GetReferences;
787
788 fn to_lsp(
789 &self,
790 path: &Path,
791 _: &Buffer,
792 _: &Arc<LanguageServer>,
793 _: &AppContext,
794 ) -> lsp::ReferenceParams {
795 lsp::ReferenceParams {
796 text_document_position: lsp::TextDocumentPositionParams {
797 text_document: lsp::TextDocumentIdentifier {
798 uri: lsp::Url::from_file_path(path).unwrap(),
799 },
800 position: point_to_lsp(self.position),
801 },
802 work_done_progress_params: Default::default(),
803 partial_result_params: Default::default(),
804 context: lsp::ReferenceContext {
805 include_declaration: true,
806 },
807 }
808 }
809
810 async fn response_from_lsp(
811 self,
812 locations: Option<Vec<lsp::Location>>,
813 project: ModelHandle<Project>,
814 buffer: ModelHandle<Buffer>,
815 server_id: LanguageServerId,
816 mut cx: AsyncAppContext,
817 ) -> Result<Vec<Location>> {
818 let mut references = Vec::new();
819 let (lsp_adapter, language_server) =
820 language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
821
822 if let Some(locations) = locations {
823 for lsp_location in locations {
824 let target_buffer_handle = project
825 .update(&mut cx, |this, cx| {
826 this.open_local_buffer_via_lsp(
827 lsp_location.uri,
828 language_server.server_id(),
829 lsp_adapter.name.clone(),
830 cx,
831 )
832 })
833 .await?;
834
835 cx.read(|cx| {
836 let target_buffer = target_buffer_handle.read(cx);
837 let target_start = target_buffer
838 .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
839 let target_end = target_buffer
840 .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
841 references.push(Location {
842 buffer: target_buffer_handle,
843 range: target_buffer.anchor_after(target_start)
844 ..target_buffer.anchor_before(target_end),
845 });
846 });
847 }
848 }
849
850 Ok(references)
851 }
852
853 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetReferences {
854 proto::GetReferences {
855 project_id,
856 buffer_id: buffer.remote_id(),
857 position: Some(language::proto::serialize_anchor(
858 &buffer.anchor_before(self.position),
859 )),
860 version: serialize_version(&buffer.version()),
861 }
862 }
863
864 async fn from_proto(
865 message: proto::GetReferences,
866 _: ModelHandle<Project>,
867 buffer: ModelHandle<Buffer>,
868 mut cx: AsyncAppContext,
869 ) -> Result<Self> {
870 let position = message
871 .position
872 .and_then(deserialize_anchor)
873 .ok_or_else(|| anyhow!("invalid position"))?;
874 buffer
875 .update(&mut cx, |buffer, _| {
876 buffer.wait_for_version(deserialize_version(&message.version))
877 })
878 .await?;
879 Ok(Self {
880 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
881 })
882 }
883
884 fn response_to_proto(
885 response: Vec<Location>,
886 project: &mut Project,
887 peer_id: PeerId,
888 _: &clock::Global,
889 cx: &mut AppContext,
890 ) -> proto::GetReferencesResponse {
891 let locations = response
892 .into_iter()
893 .map(|definition| {
894 let buffer_id = project.create_buffer_for_peer(&definition.buffer, peer_id, cx);
895 proto::Location {
896 start: Some(serialize_anchor(&definition.range.start)),
897 end: Some(serialize_anchor(&definition.range.end)),
898 buffer_id,
899 }
900 })
901 .collect();
902 proto::GetReferencesResponse { locations }
903 }
904
905 async fn response_from_proto(
906 self,
907 message: proto::GetReferencesResponse,
908 project: ModelHandle<Project>,
909 _: ModelHandle<Buffer>,
910 mut cx: AsyncAppContext,
911 ) -> Result<Vec<Location>> {
912 let mut locations = Vec::new();
913 for location in message.locations {
914 let target_buffer = project
915 .update(&mut cx, |this, cx| {
916 this.wait_for_remote_buffer(location.buffer_id, cx)
917 })
918 .await?;
919 let start = location
920 .start
921 .and_then(deserialize_anchor)
922 .ok_or_else(|| anyhow!("missing target start"))?;
923 let end = location
924 .end
925 .and_then(deserialize_anchor)
926 .ok_or_else(|| anyhow!("missing target end"))?;
927 target_buffer
928 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
929 .await?;
930 locations.push(Location {
931 buffer: target_buffer,
932 range: start..end,
933 })
934 }
935 Ok(locations)
936 }
937
938 fn buffer_id_from_proto(message: &proto::GetReferences) -> u64 {
939 message.buffer_id
940 }
941}
942
943#[async_trait(?Send)]
944impl LspCommand for GetDocumentHighlights {
945 type Response = Vec<DocumentHighlight>;
946 type LspRequest = lsp::request::DocumentHighlightRequest;
947 type ProtoRequest = proto::GetDocumentHighlights;
948
949 fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
950 capabilities.document_highlight_provider.is_some()
951 }
952
953 fn to_lsp(
954 &self,
955 path: &Path,
956 _: &Buffer,
957 _: &Arc<LanguageServer>,
958 _: &AppContext,
959 ) -> lsp::DocumentHighlightParams {
960 lsp::DocumentHighlightParams {
961 text_document_position_params: lsp::TextDocumentPositionParams {
962 text_document: lsp::TextDocumentIdentifier {
963 uri: lsp::Url::from_file_path(path).unwrap(),
964 },
965 position: point_to_lsp(self.position),
966 },
967 work_done_progress_params: Default::default(),
968 partial_result_params: Default::default(),
969 }
970 }
971
972 async fn response_from_lsp(
973 self,
974 lsp_highlights: Option<Vec<lsp::DocumentHighlight>>,
975 _: ModelHandle<Project>,
976 buffer: ModelHandle<Buffer>,
977 _: LanguageServerId,
978 cx: AsyncAppContext,
979 ) -> Result<Vec<DocumentHighlight>> {
980 buffer.read_with(&cx, |buffer, _| {
981 let mut lsp_highlights = lsp_highlights.unwrap_or_default();
982 lsp_highlights.sort_unstable_by_key(|h| (h.range.start, Reverse(h.range.end)));
983 Ok(lsp_highlights
984 .into_iter()
985 .map(|lsp_highlight| {
986 let start = buffer
987 .clip_point_utf16(point_from_lsp(lsp_highlight.range.start), Bias::Left);
988 let end = buffer
989 .clip_point_utf16(point_from_lsp(lsp_highlight.range.end), Bias::Left);
990 DocumentHighlight {
991 range: buffer.anchor_after(start)..buffer.anchor_before(end),
992 kind: lsp_highlight
993 .kind
994 .unwrap_or(lsp::DocumentHighlightKind::READ),
995 }
996 })
997 .collect())
998 })
999 }
1000
1001 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetDocumentHighlights {
1002 proto::GetDocumentHighlights {
1003 project_id,
1004 buffer_id: buffer.remote_id(),
1005 position: Some(language::proto::serialize_anchor(
1006 &buffer.anchor_before(self.position),
1007 )),
1008 version: serialize_version(&buffer.version()),
1009 }
1010 }
1011
1012 async fn from_proto(
1013 message: proto::GetDocumentHighlights,
1014 _: ModelHandle<Project>,
1015 buffer: ModelHandle<Buffer>,
1016 mut cx: AsyncAppContext,
1017 ) -> Result<Self> {
1018 let position = message
1019 .position
1020 .and_then(deserialize_anchor)
1021 .ok_or_else(|| anyhow!("invalid position"))?;
1022 buffer
1023 .update(&mut cx, |buffer, _| {
1024 buffer.wait_for_version(deserialize_version(&message.version))
1025 })
1026 .await?;
1027 Ok(Self {
1028 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1029 })
1030 }
1031
1032 fn response_to_proto(
1033 response: Vec<DocumentHighlight>,
1034 _: &mut Project,
1035 _: PeerId,
1036 _: &clock::Global,
1037 _: &mut AppContext,
1038 ) -> proto::GetDocumentHighlightsResponse {
1039 let highlights = response
1040 .into_iter()
1041 .map(|highlight| proto::DocumentHighlight {
1042 start: Some(serialize_anchor(&highlight.range.start)),
1043 end: Some(serialize_anchor(&highlight.range.end)),
1044 kind: match highlight.kind {
1045 DocumentHighlightKind::TEXT => proto::document_highlight::Kind::Text.into(),
1046 DocumentHighlightKind::WRITE => proto::document_highlight::Kind::Write.into(),
1047 DocumentHighlightKind::READ => proto::document_highlight::Kind::Read.into(),
1048 _ => proto::document_highlight::Kind::Text.into(),
1049 },
1050 })
1051 .collect();
1052 proto::GetDocumentHighlightsResponse { highlights }
1053 }
1054
1055 async fn response_from_proto(
1056 self,
1057 message: proto::GetDocumentHighlightsResponse,
1058 _: ModelHandle<Project>,
1059 buffer: ModelHandle<Buffer>,
1060 mut cx: AsyncAppContext,
1061 ) -> Result<Vec<DocumentHighlight>> {
1062 let mut highlights = Vec::new();
1063 for highlight in message.highlights {
1064 let start = highlight
1065 .start
1066 .and_then(deserialize_anchor)
1067 .ok_or_else(|| anyhow!("missing target start"))?;
1068 let end = highlight
1069 .end
1070 .and_then(deserialize_anchor)
1071 .ok_or_else(|| anyhow!("missing target end"))?;
1072 buffer
1073 .update(&mut cx, |buffer, _| buffer.wait_for_anchors([start, end]))
1074 .await?;
1075 let kind = match proto::document_highlight::Kind::from_i32(highlight.kind) {
1076 Some(proto::document_highlight::Kind::Text) => DocumentHighlightKind::TEXT,
1077 Some(proto::document_highlight::Kind::Read) => DocumentHighlightKind::READ,
1078 Some(proto::document_highlight::Kind::Write) => DocumentHighlightKind::WRITE,
1079 None => DocumentHighlightKind::TEXT,
1080 };
1081 highlights.push(DocumentHighlight {
1082 range: start..end,
1083 kind,
1084 });
1085 }
1086 Ok(highlights)
1087 }
1088
1089 fn buffer_id_from_proto(message: &proto::GetDocumentHighlights) -> u64 {
1090 message.buffer_id
1091 }
1092}
1093
1094#[async_trait(?Send)]
1095impl LspCommand for GetHover {
1096 type Response = Option<Hover>;
1097 type LspRequest = lsp::request::HoverRequest;
1098 type ProtoRequest = proto::GetHover;
1099
1100 fn to_lsp(
1101 &self,
1102 path: &Path,
1103 _: &Buffer,
1104 _: &Arc<LanguageServer>,
1105 _: &AppContext,
1106 ) -> lsp::HoverParams {
1107 lsp::HoverParams {
1108 text_document_position_params: lsp::TextDocumentPositionParams {
1109 text_document: lsp::TextDocumentIdentifier {
1110 uri: lsp::Url::from_file_path(path).unwrap(),
1111 },
1112 position: point_to_lsp(self.position),
1113 },
1114 work_done_progress_params: Default::default(),
1115 }
1116 }
1117
1118 async fn response_from_lsp(
1119 self,
1120 message: Option<lsp::Hover>,
1121 _: ModelHandle<Project>,
1122 buffer: ModelHandle<Buffer>,
1123 _: LanguageServerId,
1124 cx: AsyncAppContext,
1125 ) -> Result<Self::Response> {
1126 Ok(message.and_then(|hover| {
1127 let (language, range) = cx.read(|cx| {
1128 let buffer = buffer.read(cx);
1129 (
1130 buffer.language().cloned(),
1131 hover.range.map(|range| {
1132 let token_start =
1133 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1134 let token_end =
1135 buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1136 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1137 }),
1138 )
1139 });
1140
1141 fn hover_blocks_from_marked_string(
1142 marked_string: lsp::MarkedString,
1143 ) -> Option<HoverBlock> {
1144 let block = match marked_string {
1145 lsp::MarkedString::String(content) => HoverBlock {
1146 text: content,
1147 kind: HoverBlockKind::Markdown,
1148 },
1149 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1150 HoverBlock {
1151 text: value,
1152 kind: HoverBlockKind::Code { language },
1153 }
1154 }
1155 };
1156 if block.text.is_empty() {
1157 None
1158 } else {
1159 Some(block)
1160 }
1161 }
1162
1163 let contents = cx.read(|_| match hover.contents {
1164 lsp::HoverContents::Scalar(marked_string) => {
1165 hover_blocks_from_marked_string(marked_string)
1166 .into_iter()
1167 .collect()
1168 }
1169 lsp::HoverContents::Array(marked_strings) => marked_strings
1170 .into_iter()
1171 .filter_map(hover_blocks_from_marked_string)
1172 .collect(),
1173 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1174 text: markup_content.value,
1175 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1176 HoverBlockKind::Markdown
1177 } else {
1178 HoverBlockKind::PlainText
1179 },
1180 }],
1181 });
1182
1183 Some(Hover {
1184 contents,
1185 range,
1186 language,
1187 })
1188 }))
1189 }
1190
1191 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1192 proto::GetHover {
1193 project_id,
1194 buffer_id: buffer.remote_id(),
1195 position: Some(language::proto::serialize_anchor(
1196 &buffer.anchor_before(self.position),
1197 )),
1198 version: serialize_version(&buffer.version),
1199 }
1200 }
1201
1202 async fn from_proto(
1203 message: Self::ProtoRequest,
1204 _: ModelHandle<Project>,
1205 buffer: ModelHandle<Buffer>,
1206 mut cx: AsyncAppContext,
1207 ) -> Result<Self> {
1208 let position = message
1209 .position
1210 .and_then(deserialize_anchor)
1211 .ok_or_else(|| anyhow!("invalid position"))?;
1212 buffer
1213 .update(&mut cx, |buffer, _| {
1214 buffer.wait_for_version(deserialize_version(&message.version))
1215 })
1216 .await?;
1217 Ok(Self {
1218 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1219 })
1220 }
1221
1222 fn response_to_proto(
1223 response: Self::Response,
1224 _: &mut Project,
1225 _: PeerId,
1226 _: &clock::Global,
1227 _: &mut AppContext,
1228 ) -> proto::GetHoverResponse {
1229 if let Some(response) = response {
1230 let (start, end) = if let Some(range) = response.range {
1231 (
1232 Some(language::proto::serialize_anchor(&range.start)),
1233 Some(language::proto::serialize_anchor(&range.end)),
1234 )
1235 } else {
1236 (None, None)
1237 };
1238
1239 let contents = response
1240 .contents
1241 .into_iter()
1242 .map(|block| proto::HoverBlock {
1243 text: block.text,
1244 is_markdown: block.kind == HoverBlockKind::Markdown,
1245 language: if let HoverBlockKind::Code { language } = block.kind {
1246 Some(language)
1247 } else {
1248 None
1249 },
1250 })
1251 .collect();
1252
1253 proto::GetHoverResponse {
1254 start,
1255 end,
1256 contents,
1257 }
1258 } else {
1259 proto::GetHoverResponse {
1260 start: None,
1261 end: None,
1262 contents: Vec::new(),
1263 }
1264 }
1265 }
1266
1267 async fn response_from_proto(
1268 self,
1269 message: proto::GetHoverResponse,
1270 _: ModelHandle<Project>,
1271 buffer: ModelHandle<Buffer>,
1272 cx: AsyncAppContext,
1273 ) -> Result<Self::Response> {
1274 let contents: Vec<_> = message
1275 .contents
1276 .into_iter()
1277 .map(|block| HoverBlock {
1278 text: block.text,
1279 kind: if let Some(language) = block.language {
1280 HoverBlockKind::Code { language }
1281 } else if block.is_markdown {
1282 HoverBlockKind::Markdown
1283 } else {
1284 HoverBlockKind::PlainText
1285 },
1286 })
1287 .collect();
1288 if contents.is_empty() {
1289 return Ok(None);
1290 }
1291
1292 let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1293 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1294 language::proto::deserialize_anchor(start)
1295 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1296 } else {
1297 None
1298 };
1299
1300 Ok(Some(Hover {
1301 contents,
1302 range,
1303 language,
1304 }))
1305 }
1306
1307 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1308 message.buffer_id
1309 }
1310}
1311
1312#[async_trait(?Send)]
1313impl LspCommand for GetCompletions {
1314 type Response = Vec<Completion>;
1315 type LspRequest = lsp::request::Completion;
1316 type ProtoRequest = proto::GetCompletions;
1317
1318 fn to_lsp(
1319 &self,
1320 path: &Path,
1321 _: &Buffer,
1322 _: &Arc<LanguageServer>,
1323 _: &AppContext,
1324 ) -> lsp::CompletionParams {
1325 lsp::CompletionParams {
1326 text_document_position: lsp::TextDocumentPositionParams::new(
1327 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1328 point_to_lsp(self.position),
1329 ),
1330 context: Default::default(),
1331 work_done_progress_params: Default::default(),
1332 partial_result_params: Default::default(),
1333 }
1334 }
1335
1336 async fn response_from_lsp(
1337 self,
1338 completions: Option<lsp::CompletionResponse>,
1339 _: ModelHandle<Project>,
1340 buffer: ModelHandle<Buffer>,
1341 _: LanguageServerId,
1342 cx: AsyncAppContext,
1343 ) -> Result<Vec<Completion>> {
1344 let completions = if let Some(completions) = completions {
1345 match completions {
1346 lsp::CompletionResponse::Array(completions) => completions,
1347 lsp::CompletionResponse::List(list) => list.items,
1348 }
1349 } else {
1350 Default::default()
1351 };
1352
1353 let completions = buffer.read_with(&cx, |buffer, _| {
1354 let language = buffer.language().cloned();
1355 let snapshot = buffer.snapshot();
1356 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1357 let mut range_for_token = None;
1358 completions
1359 .into_iter()
1360 .filter_map(move |mut lsp_completion| {
1361 // For now, we can only handle additional edits if they are returned
1362 // when resolving the completion, not if they are present initially.
1363 if lsp_completion
1364 .additional_text_edits
1365 .as_ref()
1366 .map_or(false, |edits| !edits.is_empty())
1367 {
1368 return None;
1369 }
1370
1371 let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
1372 // If the language server provides a range to overwrite, then
1373 // check that the range is valid.
1374 Some(lsp::CompletionTextEdit::Edit(edit)) => {
1375 let range = range_from_lsp(edit.range);
1376 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1377 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1378 if start != range.start.0 || end != range.end.0 {
1379 log::info!("completion out of expected range");
1380 return None;
1381 }
1382 (
1383 snapshot.anchor_before(start)..snapshot.anchor_after(end),
1384 edit.new_text.clone(),
1385 )
1386 }
1387 // If the language server does not provide a range, then infer
1388 // the range based on the syntax tree.
1389 None => {
1390 if self.position != clipped_position {
1391 log::info!("completion out of expected range");
1392 return None;
1393 }
1394 let Range { start, end } = range_for_token
1395 .get_or_insert_with(|| {
1396 let offset = self.position.to_offset(&snapshot);
1397 let (range, kind) = snapshot.surrounding_word(offset);
1398 if kind == Some(CharKind::Word) {
1399 range
1400 } else {
1401 offset..offset
1402 }
1403 })
1404 .clone();
1405 let text = lsp_completion
1406 .insert_text
1407 .as_ref()
1408 .unwrap_or(&lsp_completion.label)
1409 .clone();
1410 (
1411 snapshot.anchor_before(start)..snapshot.anchor_after(end),
1412 text,
1413 )
1414 }
1415 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
1416 log::info!("unsupported insert/replace completion");
1417 return None;
1418 }
1419 };
1420
1421 let language = language.clone();
1422 LineEnding::normalize(&mut new_text);
1423 Some(async move {
1424 let mut label = None;
1425 if let Some(language) = language {
1426 language.process_completion(&mut lsp_completion).await;
1427 label = language.label_for_completion(&lsp_completion).await;
1428 }
1429 Completion {
1430 old_range,
1431 new_text,
1432 label: label.unwrap_or_else(|| {
1433 language::CodeLabel::plain(
1434 lsp_completion.label.clone(),
1435 lsp_completion.filter_text.as_deref(),
1436 )
1437 }),
1438 lsp_completion,
1439 }
1440 })
1441 })
1442 });
1443
1444 Ok(futures::future::join_all(completions).await)
1445 }
1446
1447 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1448 let anchor = buffer.anchor_after(self.position);
1449 proto::GetCompletions {
1450 project_id,
1451 buffer_id: buffer.remote_id(),
1452 position: Some(language::proto::serialize_anchor(&anchor)),
1453 version: serialize_version(&buffer.version()),
1454 }
1455 }
1456
1457 async fn from_proto(
1458 message: proto::GetCompletions,
1459 _: ModelHandle<Project>,
1460 buffer: ModelHandle<Buffer>,
1461 mut cx: AsyncAppContext,
1462 ) -> Result<Self> {
1463 let version = deserialize_version(&message.version);
1464 buffer
1465 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1466 .await?;
1467 let position = message
1468 .position
1469 .and_then(language::proto::deserialize_anchor)
1470 .map(|p| {
1471 buffer.read_with(&cx, |buffer, _| {
1472 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1473 })
1474 })
1475 .ok_or_else(|| anyhow!("invalid position"))?;
1476 Ok(Self { position })
1477 }
1478
1479 fn response_to_proto(
1480 completions: Vec<Completion>,
1481 _: &mut Project,
1482 _: PeerId,
1483 buffer_version: &clock::Global,
1484 _: &mut AppContext,
1485 ) -> proto::GetCompletionsResponse {
1486 proto::GetCompletionsResponse {
1487 completions: completions
1488 .iter()
1489 .map(language::proto::serialize_completion)
1490 .collect(),
1491 version: serialize_version(&buffer_version),
1492 }
1493 }
1494
1495 async fn response_from_proto(
1496 self,
1497 message: proto::GetCompletionsResponse,
1498 _: ModelHandle<Project>,
1499 buffer: ModelHandle<Buffer>,
1500 mut cx: AsyncAppContext,
1501 ) -> Result<Vec<Completion>> {
1502 buffer
1503 .update(&mut cx, |buffer, _| {
1504 buffer.wait_for_version(deserialize_version(&message.version))
1505 })
1506 .await?;
1507
1508 let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1509 let completions = message.completions.into_iter().map(|completion| {
1510 language::proto::deserialize_completion(completion, language.clone())
1511 });
1512 futures::future::try_join_all(completions).await
1513 }
1514
1515 fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1516 message.buffer_id
1517 }
1518}
1519
1520#[async_trait(?Send)]
1521impl LspCommand for GetCodeActions {
1522 type Response = Vec<CodeAction>;
1523 type LspRequest = lsp::request::CodeActionRequest;
1524 type ProtoRequest = proto::GetCodeActions;
1525
1526 fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1527 match &capabilities.code_action_provider {
1528 None => false,
1529 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
1530 _ => true,
1531 }
1532 }
1533
1534 fn to_lsp(
1535 &self,
1536 path: &Path,
1537 buffer: &Buffer,
1538 language_server: &Arc<LanguageServer>,
1539 _: &AppContext,
1540 ) -> lsp::CodeActionParams {
1541 let relevant_diagnostics = buffer
1542 .snapshot()
1543 .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1544 .map(|entry| entry.to_lsp_diagnostic_stub())
1545 .collect();
1546 lsp::CodeActionParams {
1547 text_document: lsp::TextDocumentIdentifier::new(
1548 lsp::Url::from_file_path(path).unwrap(),
1549 ),
1550 range: range_to_lsp(self.range.to_point_utf16(buffer)),
1551 work_done_progress_params: Default::default(),
1552 partial_result_params: Default::default(),
1553 context: lsp::CodeActionContext {
1554 diagnostics: relevant_diagnostics,
1555 only: language_server.code_action_kinds(),
1556 ..lsp::CodeActionContext::default()
1557 },
1558 }
1559 }
1560
1561 async fn response_from_lsp(
1562 self,
1563 actions: Option<lsp::CodeActionResponse>,
1564 _: ModelHandle<Project>,
1565 _: ModelHandle<Buffer>,
1566 server_id: LanguageServerId,
1567 _: AsyncAppContext,
1568 ) -> Result<Vec<CodeAction>> {
1569 Ok(actions
1570 .unwrap_or_default()
1571 .into_iter()
1572 .filter_map(|entry| {
1573 if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1574 Some(CodeAction {
1575 server_id,
1576 range: self.range.clone(),
1577 lsp_action,
1578 })
1579 } else {
1580 None
1581 }
1582 })
1583 .collect())
1584 }
1585
1586 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1587 proto::GetCodeActions {
1588 project_id,
1589 buffer_id: buffer.remote_id(),
1590 start: Some(language::proto::serialize_anchor(&self.range.start)),
1591 end: Some(language::proto::serialize_anchor(&self.range.end)),
1592 version: serialize_version(&buffer.version()),
1593 }
1594 }
1595
1596 async fn from_proto(
1597 message: proto::GetCodeActions,
1598 _: ModelHandle<Project>,
1599 buffer: ModelHandle<Buffer>,
1600 mut cx: AsyncAppContext,
1601 ) -> Result<Self> {
1602 let start = message
1603 .start
1604 .and_then(language::proto::deserialize_anchor)
1605 .ok_or_else(|| anyhow!("invalid start"))?;
1606 let end = message
1607 .end
1608 .and_then(language::proto::deserialize_anchor)
1609 .ok_or_else(|| anyhow!("invalid end"))?;
1610 buffer
1611 .update(&mut cx, |buffer, _| {
1612 buffer.wait_for_version(deserialize_version(&message.version))
1613 })
1614 .await?;
1615
1616 Ok(Self { range: start..end })
1617 }
1618
1619 fn response_to_proto(
1620 code_actions: Vec<CodeAction>,
1621 _: &mut Project,
1622 _: PeerId,
1623 buffer_version: &clock::Global,
1624 _: &mut AppContext,
1625 ) -> proto::GetCodeActionsResponse {
1626 proto::GetCodeActionsResponse {
1627 actions: code_actions
1628 .iter()
1629 .map(language::proto::serialize_code_action)
1630 .collect(),
1631 version: serialize_version(&buffer_version),
1632 }
1633 }
1634
1635 async fn response_from_proto(
1636 self,
1637 message: proto::GetCodeActionsResponse,
1638 _: ModelHandle<Project>,
1639 buffer: ModelHandle<Buffer>,
1640 mut cx: AsyncAppContext,
1641 ) -> Result<Vec<CodeAction>> {
1642 buffer
1643 .update(&mut cx, |buffer, _| {
1644 buffer.wait_for_version(deserialize_version(&message.version))
1645 })
1646 .await?;
1647 message
1648 .actions
1649 .into_iter()
1650 .map(language::proto::deserialize_code_action)
1651 .collect()
1652 }
1653
1654 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1655 message.buffer_id
1656 }
1657}
1658
1659#[async_trait(?Send)]
1660impl LspCommand for OnTypeFormatting {
1661 type Response = Option<Transaction>;
1662 type LspRequest = lsp::request::OnTypeFormatting;
1663 type ProtoRequest = proto::OnTypeFormatting;
1664
1665 fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1666 let Some(on_type_formatting_options) = &server_capabilities.document_on_type_formatting_provider else { return false };
1667 on_type_formatting_options
1668 .first_trigger_character
1669 .contains(&self.trigger)
1670 || on_type_formatting_options
1671 .more_trigger_character
1672 .iter()
1673 .flatten()
1674 .any(|chars| chars.contains(&self.trigger))
1675 }
1676
1677 fn to_lsp(
1678 &self,
1679 path: &Path,
1680 _: &Buffer,
1681 _: &Arc<LanguageServer>,
1682 _: &AppContext,
1683 ) -> lsp::DocumentOnTypeFormattingParams {
1684 lsp::DocumentOnTypeFormattingParams {
1685 text_document_position: lsp::TextDocumentPositionParams::new(
1686 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1687 point_to_lsp(self.position),
1688 ),
1689 ch: self.trigger.clone(),
1690 options: lsp_formatting_options(self.options.tab_size),
1691 }
1692 }
1693
1694 async fn response_from_lsp(
1695 self,
1696 message: Option<Vec<lsp::TextEdit>>,
1697 project: ModelHandle<Project>,
1698 buffer: ModelHandle<Buffer>,
1699 server_id: LanguageServerId,
1700 mut cx: AsyncAppContext,
1701 ) -> Result<Option<Transaction>> {
1702 if let Some(edits) = message {
1703 let (lsp_adapter, lsp_server) =
1704 language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1705 Project::deserialize_edits(
1706 project,
1707 buffer,
1708 edits,
1709 self.push_to_history,
1710 lsp_adapter,
1711 lsp_server,
1712 &mut cx,
1713 )
1714 .await
1715 } else {
1716 Ok(None)
1717 }
1718 }
1719
1720 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
1721 proto::OnTypeFormatting {
1722 project_id,
1723 buffer_id: buffer.remote_id(),
1724 position: Some(language::proto::serialize_anchor(
1725 &buffer.anchor_before(self.position),
1726 )),
1727 trigger: self.trigger.clone(),
1728 version: serialize_version(&buffer.version()),
1729 }
1730 }
1731
1732 async fn from_proto(
1733 message: proto::OnTypeFormatting,
1734 _: ModelHandle<Project>,
1735 buffer: ModelHandle<Buffer>,
1736 mut cx: AsyncAppContext,
1737 ) -> Result<Self> {
1738 let position = message
1739 .position
1740 .and_then(deserialize_anchor)
1741 .ok_or_else(|| anyhow!("invalid position"))?;
1742 buffer
1743 .update(&mut cx, |buffer, _| {
1744 buffer.wait_for_version(deserialize_version(&message.version))
1745 })
1746 .await?;
1747
1748 let tab_size = buffer.read_with(&cx, |buffer, cx| {
1749 language_settings(buffer.language(), buffer.file(), cx).tab_size
1750 });
1751
1752 Ok(Self {
1753 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1754 trigger: message.trigger.clone(),
1755 options: lsp_formatting_options(tab_size.get()).into(),
1756 push_to_history: false,
1757 })
1758 }
1759
1760 fn response_to_proto(
1761 response: Option<Transaction>,
1762 _: &mut Project,
1763 _: PeerId,
1764 _: &clock::Global,
1765 _: &mut AppContext,
1766 ) -> proto::OnTypeFormattingResponse {
1767 proto::OnTypeFormattingResponse {
1768 transaction: response
1769 .map(|transaction| language::proto::serialize_transaction(&transaction)),
1770 }
1771 }
1772
1773 async fn response_from_proto(
1774 self,
1775 message: proto::OnTypeFormattingResponse,
1776 _: ModelHandle<Project>,
1777 _: ModelHandle<Buffer>,
1778 _: AsyncAppContext,
1779 ) -> Result<Option<Transaction>> {
1780 let Some(transaction) = message.transaction else { return Ok(None) };
1781 Ok(Some(language::proto::deserialize_transaction(transaction)?))
1782 }
1783
1784 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
1785 message.buffer_id
1786 }
1787}
1788
1789#[async_trait(?Send)]
1790impl LspCommand for InlayHints {
1791 type Response = Vec<InlayHint>;
1792 type LspRequest = lsp::InlayHintRequest;
1793 type ProtoRequest = proto::InlayHints;
1794
1795 fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1796 let Some(inlay_hint_provider) = &server_capabilities.inlay_hint_provider else { return false };
1797 match inlay_hint_provider {
1798 lsp::OneOf::Left(enabled) => *enabled,
1799 lsp::OneOf::Right(inlay_hint_capabilities) => match inlay_hint_capabilities {
1800 lsp::InlayHintServerCapabilities::Options(_) => true,
1801 lsp::InlayHintServerCapabilities::RegistrationOptions(_) => false,
1802 },
1803 }
1804 }
1805
1806 fn to_lsp(
1807 &self,
1808 path: &Path,
1809 buffer: &Buffer,
1810 _: &Arc<LanguageServer>,
1811 _: &AppContext,
1812 ) -> lsp::InlayHintParams {
1813 lsp::InlayHintParams {
1814 text_document: lsp::TextDocumentIdentifier {
1815 uri: lsp::Url::from_file_path(path).unwrap(),
1816 },
1817 range: range_to_lsp(self.range.to_point_utf16(buffer)),
1818 work_done_progress_params: Default::default(),
1819 }
1820 }
1821
1822 async fn response_from_lsp(
1823 self,
1824 message: Option<Vec<lsp::InlayHint>>,
1825 _: ModelHandle<Project>,
1826 buffer: ModelHandle<Buffer>,
1827 _: LanguageServerId,
1828 cx: AsyncAppContext,
1829 ) -> Result<Vec<InlayHint>> {
1830 cx.read(|cx| {
1831 let origin_buffer = buffer.read(cx);
1832 Ok(message
1833 .unwrap_or_default()
1834 .into_iter()
1835 .map(|lsp_hint| {
1836 let kind = lsp_hint.kind.and_then(|kind| match kind {
1837 lsp::InlayHintKind::TYPE => Some(InlayHintKind::Type),
1838 lsp::InlayHintKind::PARAMETER => Some(InlayHintKind::Parameter),
1839 _ => None,
1840 });
1841 let position = origin_buffer
1842 .clip_point_utf16(point_from_lsp(lsp_hint.position), Bias::Left);
1843 InlayHint {
1844 buffer_id: origin_buffer.remote_id(),
1845 position: if kind == Some(InlayHintKind::Parameter) {
1846 origin_buffer.anchor_before(position)
1847 } else {
1848 origin_buffer.anchor_after(position)
1849 },
1850 padding_left: lsp_hint.padding_left.unwrap_or(false),
1851 padding_right: lsp_hint.padding_right.unwrap_or(false),
1852 label: match lsp_hint.label {
1853 lsp::InlayHintLabel::String(s) => InlayHintLabel::String(s),
1854 lsp::InlayHintLabel::LabelParts(lsp_parts) => {
1855 InlayHintLabel::LabelParts(
1856 lsp_parts
1857 .into_iter()
1858 .map(|label_part| InlayHintLabelPart {
1859 value: label_part.value,
1860 tooltip: label_part.tooltip.map(
1861 |tooltip| {
1862 match tooltip {
1863 lsp::InlayHintLabelPartTooltip::String(s) => {
1864 InlayHintLabelPartTooltip::String(s)
1865 }
1866 lsp::InlayHintLabelPartTooltip::MarkupContent(
1867 markup_content,
1868 ) => InlayHintLabelPartTooltip::MarkupContent(
1869 MarkupContent {
1870 kind: format!("{:?}", markup_content.kind),
1871 value: markup_content.value,
1872 },
1873 ),
1874 }
1875 },
1876 ),
1877 location: label_part.location.map(|lsp_location| {
1878 let target_start = origin_buffer.clip_point_utf16(
1879 point_from_lsp(lsp_location.range.start),
1880 Bias::Left,
1881 );
1882 let target_end = origin_buffer.clip_point_utf16(
1883 point_from_lsp(lsp_location.range.end),
1884 Bias::Left,
1885 );
1886 Location {
1887 buffer: buffer.clone(),
1888 range: origin_buffer.anchor_after(target_start)
1889 ..origin_buffer.anchor_before(target_end),
1890 }
1891 }),
1892 })
1893 .collect(),
1894 )
1895 }
1896 },
1897 kind,
1898 tooltip: lsp_hint.tooltip.map(|tooltip| match tooltip {
1899 lsp::InlayHintTooltip::String(s) => InlayHintTooltip::String(s),
1900 lsp::InlayHintTooltip::MarkupContent(markup_content) => {
1901 InlayHintTooltip::MarkupContent(MarkupContent {
1902 kind: format!("{:?}", markup_content.kind),
1903 value: markup_content.value,
1904 })
1905 }
1906 }),
1907 }
1908 })
1909 .collect())
1910 })
1911 }
1912
1913 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::InlayHints {
1914 proto::InlayHints {
1915 project_id,
1916 buffer_id: buffer.remote_id(),
1917 start: Some(language::proto::serialize_anchor(&self.range.start)),
1918 end: Some(language::proto::serialize_anchor(&self.range.end)),
1919 version: serialize_version(&buffer.version()),
1920 }
1921 }
1922
1923 async fn from_proto(
1924 message: proto::InlayHints,
1925 _: ModelHandle<Project>,
1926 buffer: ModelHandle<Buffer>,
1927 mut cx: AsyncAppContext,
1928 ) -> Result<Self> {
1929 let start = message
1930 .start
1931 .and_then(language::proto::deserialize_anchor)
1932 .context("invalid start")?;
1933 let end = message
1934 .end
1935 .and_then(language::proto::deserialize_anchor)
1936 .context("invalid end")?;
1937 buffer
1938 .update(&mut cx, |buffer, _| {
1939 buffer.wait_for_version(deserialize_version(&message.version))
1940 })
1941 .await?;
1942
1943 Ok(Self { range: start..end })
1944 }
1945
1946 fn response_to_proto(
1947 response: Vec<InlayHint>,
1948 _: &mut Project,
1949 _: PeerId,
1950 buffer_version: &clock::Global,
1951 cx: &mut AppContext,
1952 ) -> proto::InlayHintsResponse {
1953 proto::InlayHintsResponse {
1954 hints: response
1955 .into_iter()
1956 .map(|response_hint| proto::InlayHint {
1957 position: Some(language::proto::serialize_anchor(&response_hint.position)),
1958 padding_left: response_hint.padding_left,
1959 padding_right: response_hint.padding_right,
1960 label: Some(proto::InlayHintLabel {
1961 label: Some(match response_hint.label {
1962 InlayHintLabel::String(s) => proto::inlay_hint_label::Label::Value(s),
1963 InlayHintLabel::LabelParts(label_parts) => {
1964 proto::inlay_hint_label::Label::LabelParts(proto::InlayHintLabelParts {
1965 parts: label_parts.into_iter().map(|label_part| proto::InlayHintLabelPart {
1966 value: label_part.value,
1967 tooltip: label_part.tooltip.map(|tooltip| {
1968 let proto_tooltip = match tooltip {
1969 InlayHintLabelPartTooltip::String(s) => proto::inlay_hint_label_part_tooltip::Content::Value(s),
1970 InlayHintLabelPartTooltip::MarkupContent(markup_content) => proto::inlay_hint_label_part_tooltip::Content::MarkupContent(proto::MarkupContent {
1971 kind: markup_content.kind,
1972 value: markup_content.value,
1973 }),
1974 };
1975 proto::InlayHintLabelPartTooltip {content: Some(proto_tooltip)}
1976 }),
1977 location: label_part.location.map(|location| proto::Location {
1978 start: Some(serialize_anchor(&location.range.start)),
1979 end: Some(serialize_anchor(&location.range.end)),
1980 buffer_id: location.buffer.read(cx).remote_id(),
1981 }),
1982 }).collect()
1983 })
1984 }
1985 }),
1986 }),
1987 kind: response_hint.kind.map(|kind| kind.name().to_string()),
1988 tooltip: response_hint.tooltip.map(|response_tooltip| {
1989 let proto_tooltip = match response_tooltip {
1990 InlayHintTooltip::String(s) => {
1991 proto::inlay_hint_tooltip::Content::Value(s)
1992 }
1993 InlayHintTooltip::MarkupContent(markup_content) => {
1994 proto::inlay_hint_tooltip::Content::MarkupContent(
1995 proto::MarkupContent {
1996 kind: markup_content.kind,
1997 value: markup_content.value,
1998 },
1999 )
2000 }
2001 };
2002 proto::InlayHintTooltip {
2003 content: Some(proto_tooltip),
2004 }
2005 }),
2006 })
2007 .collect(),
2008 version: serialize_version(buffer_version),
2009 }
2010 }
2011
2012 async fn response_from_proto(
2013 self,
2014 message: proto::InlayHintsResponse,
2015 project: ModelHandle<Project>,
2016 buffer: ModelHandle<Buffer>,
2017 mut cx: AsyncAppContext,
2018 ) -> Result<Vec<InlayHint>> {
2019 buffer
2020 .update(&mut cx, |buffer, _| {
2021 buffer.wait_for_version(deserialize_version(&message.version))
2022 })
2023 .await?;
2024
2025 let mut hints = Vec::new();
2026 for message_hint in message.hints {
2027 let buffer_id = message_hint
2028 .position
2029 .as_ref()
2030 .and_then(|location| location.buffer_id)
2031 .context("missing buffer id")?;
2032 let hint = InlayHint {
2033 buffer_id,
2034 position: message_hint
2035 .position
2036 .and_then(language::proto::deserialize_anchor)
2037 .context("invalid position")?,
2038 label: match message_hint
2039 .label
2040 .and_then(|label| label.label)
2041 .context("missing label")?
2042 {
2043 proto::inlay_hint_label::Label::Value(s) => InlayHintLabel::String(s),
2044 proto::inlay_hint_label::Label::LabelParts(parts) => {
2045 let mut label_parts = Vec::new();
2046 for part in parts.parts {
2047 label_parts.push(InlayHintLabelPart {
2048 value: part.value,
2049 tooltip: part.tooltip.map(|tooltip| match tooltip.content {
2050 Some(proto::inlay_hint_label_part_tooltip::Content::Value(s)) => InlayHintLabelPartTooltip::String(s),
2051 Some(proto::inlay_hint_label_part_tooltip::Content::MarkupContent(markup_content)) => InlayHintLabelPartTooltip::MarkupContent(MarkupContent {
2052 kind: markup_content.kind,
2053 value: markup_content.value,
2054 }),
2055 None => InlayHintLabelPartTooltip::String(String::new()),
2056 }),
2057 location: match part.location {
2058 Some(location) => {
2059 let target_buffer = project
2060 .update(&mut cx, |this, cx| {
2061 this.wait_for_remote_buffer(location.buffer_id, cx)
2062 })
2063 .await?;
2064 Some(Location {
2065 range: location
2066 .start
2067 .and_then(language::proto::deserialize_anchor)
2068 .context("invalid start")?
2069 ..location
2070 .end
2071 .and_then(language::proto::deserialize_anchor)
2072 .context("invalid end")?,
2073 buffer: target_buffer,
2074 })},
2075 None => None,
2076 },
2077 });
2078 }
2079
2080 InlayHintLabel::LabelParts(label_parts)
2081 }
2082 },
2083 padding_left: message_hint.padding_left,
2084 padding_right: message_hint.padding_right,
2085 kind: message_hint
2086 .kind
2087 .as_deref()
2088 .and_then(InlayHintKind::from_name),
2089 tooltip: message_hint.tooltip.and_then(|tooltip| {
2090 Some(match tooltip.content? {
2091 proto::inlay_hint_tooltip::Content::Value(s) => InlayHintTooltip::String(s),
2092 proto::inlay_hint_tooltip::Content::MarkupContent(markup_content) => {
2093 InlayHintTooltip::MarkupContent(MarkupContent {
2094 kind: markup_content.kind,
2095 value: markup_content.value,
2096 })
2097 }
2098 })
2099 }),
2100 };
2101
2102 hints.push(hint);
2103 }
2104
2105 Ok(hints)
2106 }
2107
2108 fn buffer_id_from_proto(message: &proto::InlayHints) -> u64 {
2109 message.buffer_id
2110 }
2111}