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