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