1use anyhow::Context as _;
2use gpui::{Context, View, ViewContext, VisualContext, WindowContext};
3use language::Language;
4use multi_buffer::MultiBuffer;
5use project::lsp_ext_command::ExpandMacro;
6use text::ToPointUtf16;
7
8use crate::{
9 element::register_action, lsp_ext::find_specific_language_server_in_selection, Editor,
10 ExpandMacroRecursively,
11};
12
13const RUST_ANALYZER_NAME: &str = "rust-analyzer";
14
15fn is_rust_language(language: &Language) -> bool {
16 language.name() == "Rust".into()
17}
18
19pub fn apply_related_actions(editor: &View<Editor>, cx: &mut WindowContext) {
20 if editor
21 .update(cx, |e, cx| {
22 find_specific_language_server_in_selection(e, cx, is_rust_language, RUST_ANALYZER_NAME)
23 })
24 .is_some()
25 {
26 register_action(editor, cx, expand_macro_recursively);
27 }
28}
29
30pub fn expand_macro_recursively(
31 editor: &mut Editor,
32 _: &ExpandMacroRecursively,
33 cx: &mut ViewContext<'_, Editor>,
34) {
35 if editor.selections.count() == 0 {
36 return;
37 }
38 let Some(project) = &editor.project else {
39 return;
40 };
41 let Some(workspace) = editor.workspace() else {
42 return;
43 };
44
45 let Some((trigger_anchor, rust_language, server_to_query, buffer)) =
46 find_specific_language_server_in_selection(
47 editor,
48 cx,
49 is_rust_language,
50 RUST_ANALYZER_NAME,
51 )
52 else {
53 return;
54 };
55
56 let project = project.clone();
57 let buffer_snapshot = buffer.read(cx).snapshot();
58 let position = trigger_anchor.text_anchor.to_point_utf16(&buffer_snapshot);
59 let expand_macro_task = project.update(cx, |project, cx| {
60 project.request_lsp(
61 buffer,
62 project::LanguageServerToQuery::Other(server_to_query),
63 ExpandMacro { position },
64 cx,
65 )
66 });
67 cx.spawn(|_editor, mut cx| async move {
68 let macro_expansion = expand_macro_task.await.context("expand macro")?;
69 if macro_expansion.is_empty() {
70 log::info!("Empty macro expansion for position {position:?}");
71 return Ok(());
72 }
73
74 let buffer = project
75 .update(&mut cx, |project, cx| project.create_buffer(cx))?
76 .await?;
77 workspace.update(&mut cx, |workspace, cx| {
78 buffer.update(cx, |buffer, cx| {
79 buffer.edit([(0..0, macro_expansion.expansion)], None, cx);
80 buffer.set_language(Some(rust_language), cx)
81 });
82 let multibuffer = cx.new_model(|cx| {
83 MultiBuffer::singleton(buffer, cx).with_title(macro_expansion.name)
84 });
85 workspace.add_item_to_active_pane(
86 Box::new(
87 cx.new_view(|cx| Editor::for_multibuffer(multibuffer, Some(project), true, cx)),
88 ),
89 None,
90 true,
91 cx,
92 );
93 })
94 })
95 .detach_and_log_err(cx);
96}