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 (language, range) = cx.read(|cx| {
1115 let buffer = buffer.read(cx);
1116 (
1117 buffer.language().cloned(),
1118 hover.range.map(|range| {
1119 let token_start =
1120 buffer.clip_point_utf16(point_from_lsp(range.start), Bias::Left);
1121 let token_end =
1122 buffer.clip_point_utf16(point_from_lsp(range.end), Bias::Left);
1123 buffer.anchor_after(token_start)..buffer.anchor_before(token_end)
1124 }),
1125 )
1126 });
1127
1128 fn hover_blocks_from_marked_string(
1129 marked_string: lsp::MarkedString,
1130 ) -> Option<HoverBlock> {
1131 let block = match marked_string {
1132 lsp::MarkedString::String(content) => HoverBlock {
1133 text: content,
1134 kind: HoverBlockKind::Markdown,
1135 },
1136 lsp::MarkedString::LanguageString(lsp::LanguageString { language, value }) => {
1137 HoverBlock {
1138 text: value,
1139 kind: HoverBlockKind::Code { language },
1140 }
1141 }
1142 };
1143 if block.text.is_empty() {
1144 None
1145 } else {
1146 Some(block)
1147 }
1148 }
1149
1150 let contents = cx.read(|_| match hover.contents {
1151 lsp::HoverContents::Scalar(marked_string) => {
1152 hover_blocks_from_marked_string(marked_string)
1153 .into_iter()
1154 .collect()
1155 }
1156 lsp::HoverContents::Array(marked_strings) => marked_strings
1157 .into_iter()
1158 .filter_map(hover_blocks_from_marked_string)
1159 .collect(),
1160 lsp::HoverContents::Markup(markup_content) => vec![HoverBlock {
1161 text: markup_content.value,
1162 kind: if markup_content.kind == lsp::MarkupKind::Markdown {
1163 HoverBlockKind::Markdown
1164 } else {
1165 HoverBlockKind::PlainText
1166 },
1167 }],
1168 });
1169
1170 Some(Hover {
1171 contents,
1172 range,
1173 language,
1174 })
1175 }))
1176 }
1177
1178 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
1179 proto::GetHover {
1180 project_id,
1181 buffer_id: buffer.remote_id(),
1182 position: Some(language::proto::serialize_anchor(
1183 &buffer.anchor_before(self.position),
1184 )),
1185 version: serialize_version(&buffer.version),
1186 }
1187 }
1188
1189 async fn from_proto(
1190 message: Self::ProtoRequest,
1191 _: ModelHandle<Project>,
1192 buffer: ModelHandle<Buffer>,
1193 mut cx: AsyncAppContext,
1194 ) -> Result<Self> {
1195 let position = message
1196 .position
1197 .and_then(deserialize_anchor)
1198 .ok_or_else(|| anyhow!("invalid position"))?;
1199 buffer
1200 .update(&mut cx, |buffer, _| {
1201 buffer.wait_for_version(deserialize_version(&message.version))
1202 })
1203 .await?;
1204 Ok(Self {
1205 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1206 })
1207 }
1208
1209 fn response_to_proto(
1210 response: Self::Response,
1211 _: &mut Project,
1212 _: PeerId,
1213 _: &clock::Global,
1214 _: &mut AppContext,
1215 ) -> proto::GetHoverResponse {
1216 if let Some(response) = response {
1217 let (start, end) = if let Some(range) = response.range {
1218 (
1219 Some(language::proto::serialize_anchor(&range.start)),
1220 Some(language::proto::serialize_anchor(&range.end)),
1221 )
1222 } else {
1223 (None, None)
1224 };
1225
1226 let contents = response
1227 .contents
1228 .into_iter()
1229 .map(|block| proto::HoverBlock {
1230 text: block.text,
1231 is_markdown: block.kind == HoverBlockKind::Markdown,
1232 language: if let HoverBlockKind::Code { language } = block.kind {
1233 Some(language)
1234 } else {
1235 None
1236 },
1237 })
1238 .collect();
1239
1240 proto::GetHoverResponse {
1241 start,
1242 end,
1243 contents,
1244 }
1245 } else {
1246 proto::GetHoverResponse {
1247 start: None,
1248 end: None,
1249 contents: Vec::new(),
1250 }
1251 }
1252 }
1253
1254 async fn response_from_proto(
1255 self,
1256 message: proto::GetHoverResponse,
1257 _: ModelHandle<Project>,
1258 buffer: ModelHandle<Buffer>,
1259 cx: AsyncAppContext,
1260 ) -> Result<Self::Response> {
1261 let contents: Vec<_> = message
1262 .contents
1263 .into_iter()
1264 .map(|block| HoverBlock {
1265 text: block.text,
1266 kind: if let Some(language) = block.language {
1267 HoverBlockKind::Code { language }
1268 } else if block.is_markdown {
1269 HoverBlockKind::Markdown
1270 } else {
1271 HoverBlockKind::PlainText
1272 },
1273 })
1274 .collect();
1275 if contents.is_empty() {
1276 return Ok(None);
1277 }
1278
1279 let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1280 let range = if let (Some(start), Some(end)) = (message.start, message.end) {
1281 language::proto::deserialize_anchor(start)
1282 .and_then(|start| language::proto::deserialize_anchor(end).map(|end| start..end))
1283 } else {
1284 None
1285 };
1286
1287 Ok(Some(Hover {
1288 contents,
1289 range,
1290 language,
1291 }))
1292 }
1293
1294 fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
1295 message.buffer_id
1296 }
1297}
1298
1299#[async_trait(?Send)]
1300impl LspCommand for GetCompletions {
1301 type Response = Vec<Completion>;
1302 type LspRequest = lsp::request::Completion;
1303 type ProtoRequest = proto::GetCompletions;
1304
1305 fn to_lsp(
1306 &self,
1307 path: &Path,
1308 _: &Buffer,
1309 _: &Arc<LanguageServer>,
1310 _: &AppContext,
1311 ) -> lsp::CompletionParams {
1312 lsp::CompletionParams {
1313 text_document_position: lsp::TextDocumentPositionParams::new(
1314 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1315 point_to_lsp(self.position),
1316 ),
1317 context: Default::default(),
1318 work_done_progress_params: Default::default(),
1319 partial_result_params: Default::default(),
1320 }
1321 }
1322
1323 async fn response_from_lsp(
1324 self,
1325 completions: Option<lsp::CompletionResponse>,
1326 _: ModelHandle<Project>,
1327 buffer: ModelHandle<Buffer>,
1328 _: LanguageServerId,
1329 cx: AsyncAppContext,
1330 ) -> Result<Vec<Completion>> {
1331 let completions = if let Some(completions) = completions {
1332 match completions {
1333 lsp::CompletionResponse::Array(completions) => completions,
1334 lsp::CompletionResponse::List(list) => list.items,
1335 }
1336 } else {
1337 Default::default()
1338 };
1339
1340 let completions = buffer.read_with(&cx, |buffer, _| {
1341 let language = buffer.language().cloned();
1342 let snapshot = buffer.snapshot();
1343 let clipped_position = buffer.clip_point_utf16(Unclipped(self.position), Bias::Left);
1344 let mut range_for_token = None;
1345 completions
1346 .into_iter()
1347 .filter_map(move |mut lsp_completion| {
1348 // For now, we can only handle additional edits if they are returned
1349 // when resolving the completion, not if they are present initially.
1350 if lsp_completion
1351 .additional_text_edits
1352 .as_ref()
1353 .map_or(false, |edits| !edits.is_empty())
1354 {
1355 return None;
1356 }
1357
1358 let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
1359 // If the language server provides a range to overwrite, then
1360 // check that the range is valid.
1361 Some(lsp::CompletionTextEdit::Edit(edit)) => {
1362 let range = range_from_lsp(edit.range);
1363 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
1364 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
1365 if start != range.start.0 || end != range.end.0 {
1366 log::info!("completion out of expected range");
1367 return None;
1368 }
1369 (
1370 snapshot.anchor_before(start)..snapshot.anchor_after(end),
1371 edit.new_text.clone(),
1372 )
1373 }
1374 // If the language server does not provide a range, then infer
1375 // the range based on the syntax tree.
1376 None => {
1377 if self.position != clipped_position {
1378 log::info!("completion out of expected range");
1379 return None;
1380 }
1381 let Range { start, end } = range_for_token
1382 .get_or_insert_with(|| {
1383 let offset = self.position.to_offset(&snapshot);
1384 let (range, kind) = snapshot.surrounding_word(offset);
1385 if kind == Some(CharKind::Word) {
1386 range
1387 } else {
1388 offset..offset
1389 }
1390 })
1391 .clone();
1392 let text = lsp_completion
1393 .insert_text
1394 .as_ref()
1395 .unwrap_or(&lsp_completion.label)
1396 .clone();
1397 (
1398 snapshot.anchor_before(start)..snapshot.anchor_after(end),
1399 text,
1400 )
1401 }
1402 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
1403 log::info!("unsupported insert/replace completion");
1404 return None;
1405 }
1406 };
1407
1408 let language = language.clone();
1409 LineEnding::normalize(&mut new_text);
1410 Some(async move {
1411 let mut label = None;
1412 if let Some(language) = language {
1413 language.process_completion(&mut lsp_completion).await;
1414 label = language.label_for_completion(&lsp_completion).await;
1415 }
1416 Completion {
1417 old_range,
1418 new_text,
1419 label: label.unwrap_or_else(|| {
1420 language::CodeLabel::plain(
1421 lsp_completion.label.clone(),
1422 lsp_completion.filter_text.as_deref(),
1423 )
1424 }),
1425 lsp_completion,
1426 }
1427 })
1428 })
1429 });
1430
1431 Ok(futures::future::join_all(completions).await)
1432 }
1433
1434 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCompletions {
1435 let anchor = buffer.anchor_after(self.position);
1436 proto::GetCompletions {
1437 project_id,
1438 buffer_id: buffer.remote_id(),
1439 position: Some(language::proto::serialize_anchor(&anchor)),
1440 version: serialize_version(&buffer.version()),
1441 }
1442 }
1443
1444 async fn from_proto(
1445 message: proto::GetCompletions,
1446 _: ModelHandle<Project>,
1447 buffer: ModelHandle<Buffer>,
1448 mut cx: AsyncAppContext,
1449 ) -> Result<Self> {
1450 let version = deserialize_version(&message.version);
1451 buffer
1452 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
1453 .await?;
1454 let position = message
1455 .position
1456 .and_then(language::proto::deserialize_anchor)
1457 .map(|p| {
1458 buffer.read_with(&cx, |buffer, _| {
1459 buffer.clip_point_utf16(Unclipped(p.to_point_utf16(buffer)), Bias::Left)
1460 })
1461 })
1462 .ok_or_else(|| anyhow!("invalid position"))?;
1463 Ok(Self { position })
1464 }
1465
1466 fn response_to_proto(
1467 completions: Vec<Completion>,
1468 _: &mut Project,
1469 _: PeerId,
1470 buffer_version: &clock::Global,
1471 _: &mut AppContext,
1472 ) -> proto::GetCompletionsResponse {
1473 proto::GetCompletionsResponse {
1474 completions: completions
1475 .iter()
1476 .map(language::proto::serialize_completion)
1477 .collect(),
1478 version: serialize_version(&buffer_version),
1479 }
1480 }
1481
1482 async fn response_from_proto(
1483 self,
1484 message: proto::GetCompletionsResponse,
1485 _: ModelHandle<Project>,
1486 buffer: ModelHandle<Buffer>,
1487 mut cx: AsyncAppContext,
1488 ) -> Result<Vec<Completion>> {
1489 buffer
1490 .update(&mut cx, |buffer, _| {
1491 buffer.wait_for_version(deserialize_version(&message.version))
1492 })
1493 .await?;
1494
1495 let language = buffer.read_with(&cx, |buffer, _| buffer.language().cloned());
1496 let completions = message.completions.into_iter().map(|completion| {
1497 language::proto::deserialize_completion(completion, language.clone())
1498 });
1499 futures::future::try_join_all(completions).await
1500 }
1501
1502 fn buffer_id_from_proto(message: &proto::GetCompletions) -> u64 {
1503 message.buffer_id
1504 }
1505}
1506
1507#[async_trait(?Send)]
1508impl LspCommand for GetCodeActions {
1509 type Response = Vec<CodeAction>;
1510 type LspRequest = lsp::request::CodeActionRequest;
1511 type ProtoRequest = proto::GetCodeActions;
1512
1513 fn check_capabilities(&self, capabilities: &ServerCapabilities) -> bool {
1514 match &capabilities.code_action_provider {
1515 None => false,
1516 Some(lsp::CodeActionProviderCapability::Simple(false)) => false,
1517 _ => true,
1518 }
1519 }
1520
1521 fn to_lsp(
1522 &self,
1523 path: &Path,
1524 buffer: &Buffer,
1525 language_server: &Arc<LanguageServer>,
1526 _: &AppContext,
1527 ) -> lsp::CodeActionParams {
1528 let relevant_diagnostics = buffer
1529 .snapshot()
1530 .diagnostics_in_range::<_, usize>(self.range.clone(), false)
1531 .map(|entry| entry.to_lsp_diagnostic_stub())
1532 .collect();
1533 lsp::CodeActionParams {
1534 text_document: lsp::TextDocumentIdentifier::new(
1535 lsp::Url::from_file_path(path).unwrap(),
1536 ),
1537 range: range_to_lsp(self.range.to_point_utf16(buffer)),
1538 work_done_progress_params: Default::default(),
1539 partial_result_params: Default::default(),
1540 context: lsp::CodeActionContext {
1541 diagnostics: relevant_diagnostics,
1542 only: language_server.code_action_kinds(),
1543 ..lsp::CodeActionContext::default()
1544 },
1545 }
1546 }
1547
1548 async fn response_from_lsp(
1549 self,
1550 actions: Option<lsp::CodeActionResponse>,
1551 _: ModelHandle<Project>,
1552 _: ModelHandle<Buffer>,
1553 server_id: LanguageServerId,
1554 _: AsyncAppContext,
1555 ) -> Result<Vec<CodeAction>> {
1556 Ok(actions
1557 .unwrap_or_default()
1558 .into_iter()
1559 .filter_map(|entry| {
1560 if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
1561 Some(CodeAction {
1562 server_id,
1563 range: self.range.clone(),
1564 lsp_action,
1565 })
1566 } else {
1567 None
1568 }
1569 })
1570 .collect())
1571 }
1572
1573 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetCodeActions {
1574 proto::GetCodeActions {
1575 project_id,
1576 buffer_id: buffer.remote_id(),
1577 start: Some(language::proto::serialize_anchor(&self.range.start)),
1578 end: Some(language::proto::serialize_anchor(&self.range.end)),
1579 version: serialize_version(&buffer.version()),
1580 }
1581 }
1582
1583 async fn from_proto(
1584 message: proto::GetCodeActions,
1585 _: ModelHandle<Project>,
1586 buffer: ModelHandle<Buffer>,
1587 mut cx: AsyncAppContext,
1588 ) -> Result<Self> {
1589 let start = message
1590 .start
1591 .and_then(language::proto::deserialize_anchor)
1592 .ok_or_else(|| anyhow!("invalid start"))?;
1593 let end = message
1594 .end
1595 .and_then(language::proto::deserialize_anchor)
1596 .ok_or_else(|| anyhow!("invalid end"))?;
1597 buffer
1598 .update(&mut cx, |buffer, _| {
1599 buffer.wait_for_version(deserialize_version(&message.version))
1600 })
1601 .await?;
1602
1603 Ok(Self { range: start..end })
1604 }
1605
1606 fn response_to_proto(
1607 code_actions: Vec<CodeAction>,
1608 _: &mut Project,
1609 _: PeerId,
1610 buffer_version: &clock::Global,
1611 _: &mut AppContext,
1612 ) -> proto::GetCodeActionsResponse {
1613 proto::GetCodeActionsResponse {
1614 actions: code_actions
1615 .iter()
1616 .map(language::proto::serialize_code_action)
1617 .collect(),
1618 version: serialize_version(&buffer_version),
1619 }
1620 }
1621
1622 async fn response_from_proto(
1623 self,
1624 message: proto::GetCodeActionsResponse,
1625 _: ModelHandle<Project>,
1626 buffer: ModelHandle<Buffer>,
1627 mut cx: AsyncAppContext,
1628 ) -> Result<Vec<CodeAction>> {
1629 buffer
1630 .update(&mut cx, |buffer, _| {
1631 buffer.wait_for_version(deserialize_version(&message.version))
1632 })
1633 .await?;
1634 message
1635 .actions
1636 .into_iter()
1637 .map(language::proto::deserialize_code_action)
1638 .collect()
1639 }
1640
1641 fn buffer_id_from_proto(message: &proto::GetCodeActions) -> u64 {
1642 message.buffer_id
1643 }
1644}
1645
1646#[async_trait(?Send)]
1647impl LspCommand for OnTypeFormatting {
1648 type Response = Option<Transaction>;
1649 type LspRequest = lsp::request::OnTypeFormatting;
1650 type ProtoRequest = proto::OnTypeFormatting;
1651
1652 fn check_capabilities(&self, server_capabilities: &lsp::ServerCapabilities) -> bool {
1653 let Some(on_type_formatting_options) = &server_capabilities.document_on_type_formatting_provider else { return false };
1654 on_type_formatting_options
1655 .first_trigger_character
1656 .contains(&self.trigger)
1657 || on_type_formatting_options
1658 .more_trigger_character
1659 .iter()
1660 .flatten()
1661 .any(|chars| chars.contains(&self.trigger))
1662 }
1663
1664 fn to_lsp(
1665 &self,
1666 path: &Path,
1667 _: &Buffer,
1668 _: &Arc<LanguageServer>,
1669 _: &AppContext,
1670 ) -> lsp::DocumentOnTypeFormattingParams {
1671 lsp::DocumentOnTypeFormattingParams {
1672 text_document_position: lsp::TextDocumentPositionParams::new(
1673 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(path).unwrap()),
1674 point_to_lsp(self.position),
1675 ),
1676 ch: self.trigger.clone(),
1677 options: lsp_formatting_options(self.options.tab_size),
1678 }
1679 }
1680
1681 async fn response_from_lsp(
1682 self,
1683 message: Option<Vec<lsp::TextEdit>>,
1684 project: ModelHandle<Project>,
1685 buffer: ModelHandle<Buffer>,
1686 server_id: LanguageServerId,
1687 mut cx: AsyncAppContext,
1688 ) -> Result<Option<Transaction>> {
1689 if let Some(edits) = message {
1690 let (lsp_adapter, lsp_server) =
1691 language_server_for_buffer(&project, &buffer, server_id, &mut cx)?;
1692 Project::deserialize_edits(
1693 project,
1694 buffer,
1695 edits,
1696 self.push_to_history,
1697 lsp_adapter,
1698 lsp_server,
1699 &mut cx,
1700 )
1701 .await
1702 } else {
1703 Ok(None)
1704 }
1705 }
1706
1707 fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::OnTypeFormatting {
1708 proto::OnTypeFormatting {
1709 project_id,
1710 buffer_id: buffer.remote_id(),
1711 position: Some(language::proto::serialize_anchor(
1712 &buffer.anchor_before(self.position),
1713 )),
1714 trigger: self.trigger.clone(),
1715 version: serialize_version(&buffer.version()),
1716 }
1717 }
1718
1719 async fn from_proto(
1720 message: proto::OnTypeFormatting,
1721 _: ModelHandle<Project>,
1722 buffer: ModelHandle<Buffer>,
1723 mut cx: AsyncAppContext,
1724 ) -> Result<Self> {
1725 let position = message
1726 .position
1727 .and_then(deserialize_anchor)
1728 .ok_or_else(|| anyhow!("invalid position"))?;
1729 buffer
1730 .update(&mut cx, |buffer, _| {
1731 buffer.wait_for_version(deserialize_version(&message.version))
1732 })
1733 .await?;
1734
1735 let tab_size = buffer.read_with(&cx, |buffer, cx| {
1736 language_settings(buffer.language(), buffer.file(), cx).tab_size
1737 });
1738
1739 Ok(Self {
1740 position: buffer.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
1741 trigger: message.trigger.clone(),
1742 options: lsp_formatting_options(tab_size.get()).into(),
1743 push_to_history: false,
1744 })
1745 }
1746
1747 fn response_to_proto(
1748 response: Option<Transaction>,
1749 _: &mut Project,
1750 _: PeerId,
1751 _: &clock::Global,
1752 _: &mut AppContext,
1753 ) -> proto::OnTypeFormattingResponse {
1754 proto::OnTypeFormattingResponse {
1755 transaction: response
1756 .map(|transaction| language::proto::serialize_transaction(&transaction)),
1757 }
1758 }
1759
1760 async fn response_from_proto(
1761 self,
1762 message: proto::OnTypeFormattingResponse,
1763 _: ModelHandle<Project>,
1764 _: ModelHandle<Buffer>,
1765 _: AsyncAppContext,
1766 ) -> Result<Option<Transaction>> {
1767 let Some(transaction) = message.transaction else { return Ok(None) };
1768 Ok(Some(language::proto::deserialize_transaction(transaction)?))
1769 }
1770
1771 fn buffer_id_from_proto(message: &proto::OnTypeFormatting) -> u64 {
1772 message.buffer_id
1773 }
1774}