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