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