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