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