Skip to content

Commit 1598740

Browse files
Reuse existing element rendering
1 parent 4c8edd0 commit 1598740

File tree

4 files changed

+74
-88
lines changed

4 files changed

+74
-88
lines changed

crates/completion/src/completions/magic.rs

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
33
use assists::utils::{insert_use, mod_path_to_ast, ImportScope};
44
use either::Either;
5-
use hir::{db::HirDatabase, MacroDef, ModuleDef};
5+
use hir::ScopeDef;
66
use ide_db::imports_locator;
77
use syntax::{algo, AstNode};
8-
use text_edit::TextEdit;
98

10-
use crate::{context::CompletionContext, item::CompletionKind, CompletionItem, CompletionItemKind};
9+
use crate::{
10+
context::CompletionContext,
11+
render::{render_resolution, RenderContext},
12+
};
1113

1214
use super::Completions;
1315

@@ -25,65 +27,49 @@ pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) ->
2527
let possible_imports =
2628
imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name)
2729
.filter_map(|import_candidate| {
28-
let use_path = match import_candidate {
29-
Either::Left(module_def) => current_module.find_use_path(ctx.db, module_def),
30-
Either::Right(macro_def) => current_module.find_use_path(ctx.db, macro_def),
31-
}?;
32-
Some((use_path, additional_completion(ctx.db, import_candidate)))
30+
Some(match import_candidate {
31+
Either::Left(module_def) => (
32+
current_module.find_use_path(ctx.db, module_def)?,
33+
ScopeDef::ModuleDef(module_def),
34+
),
35+
Either::Right(macro_def) => (
36+
current_module.find_use_path(ctx.db, macro_def)?,
37+
ScopeDef::MacroDef(macro_def),
38+
),
39+
})
3340
})
34-
.filter_map(|(mod_path, additional_completion)| {
35-
let mut builder = TextEdit::builder();
41+
.filter_map(|(mod_path, definition)| {
42+
let mut resolution_with_missing_import = render_resolution(
43+
RenderContext::new(ctx),
44+
mod_path.segments.last()?.to_string(),
45+
&definition,
46+
)?;
3647

37-
let correct_qualifier = format!(
38-
"{}{}",
39-
mod_path.segments.last()?,
40-
additional_completion.unwrap_or_default()
41-
);
42-
builder.replace(anchor.syntax().text_range(), correct_qualifier);
48+
let mut text_edits =
49+
resolution_with_missing_import.text_edit().to_owned().into_builder();
4350

4451
let rewriter =
4552
insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge);
4653
let old_ast = rewriter.rewrite_root()?;
47-
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut builder);
48-
49-
let completion_item: CompletionItem = CompletionItem::new(
50-
CompletionKind::Magic,
51-
ctx.source_range(),
52-
mod_path.to_string(),
53-
)
54-
.kind(CompletionItemKind::Struct)
55-
.text_edit(builder.finish())
56-
.into();
57-
Some(completion_item)
54+
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
55+
56+
resolution_with_missing_import.update_text_edit(text_edits.finish());
57+
58+
Some(resolution_with_missing_import)
5859
});
59-
acc.add_all(possible_imports);
6060

61+
acc.add_all(possible_imports);
6162
Some(())
6263
}
6364

64-
fn additional_completion(
65-
db: &dyn HirDatabase,
66-
import_candidate: Either<ModuleDef, MacroDef>,
67-
) -> Option<String> {
68-
match import_candidate {
69-
Either::Left(ModuleDef::Function(_)) => Some("()".to_string()),
70-
Either::Right(macro_def) => {
71-
let (left_brace, right_brace) =
72-
crate::render::macro_::guess_macro_braces(db, macro_def);
73-
Some(format!("!{}{}", left_brace, right_brace))
74-
}
75-
_ => None,
76-
}
77-
}
78-
7965
#[cfg(test)]
8066
mod tests {
8167
use crate::test_utils::check_edit;
8268

8369
#[test]
8470
fn function_magic_completion() {
8571
check_edit(
86-
"dep::io::stdin",
72+
"stdin",
8773
r#"
8874
//- /lib.rs crate:dep
8975
pub mod io {
@@ -99,7 +85,7 @@ fn main() {
9985
use dep::io::stdin;
10086
10187
fn main() {
102-
stdin()
88+
stdin()$0
10389
}
10490
"#,
10591
);
@@ -108,7 +94,7 @@ fn main() {
10894
#[test]
10995
fn macro_magic_completion() {
11096
check_edit(
111-
"dep::macro_with_curlies",
97+
"macro_with_curlies!",
11298
r#"
11399
//- /lib.rs crate:dep
114100
/// Please call me as macro_with_curlies! {}
@@ -126,7 +112,7 @@ fn main() {
126112
use dep::macro_with_curlies;
127113
128114
fn main() {
129-
macro_with_curlies! {}
115+
macro_with_curlies! {$0}
130116
}
131117
"#,
132118
);
@@ -135,7 +121,7 @@ fn main() {
135121
#[test]
136122
fn case_insensitive_magic_completion_works() {
137123
check_edit(
138-
"dep::some_module::ThirdStruct",
124+
"ThirdStruct",
139125
r#"
140126
//- /lib.rs crate:dep
141127
pub struct FirstStruct;

crates/completion/src/item.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ impl CompletionItem {
218218
&self.text_edit
219219
}
220220

221+
pub fn update_text_edit(&mut self, new_text_edit: TextEdit) {
222+
self.text_edit = new_text_edit;
223+
}
224+
221225
/// Short one-line additional information, like a type
222226
pub fn detail(&self) -> Option<&str> {
223227
self.detail.as_deref()

crates/completion/src/render/macro_.rs

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Renderer for macro invocations.
22
3-
use hir::{db::HirDatabase, Documentation, HasAttrs, HasSource};
3+
use hir::{Documentation, HasSource};
44
use syntax::display::macro_label;
55
use test_utils::mark;
66

@@ -27,48 +27,12 @@ struct MacroRender<'a> {
2727
ket: &'static str,
2828
}
2929

30-
pub fn guess_macro_braces(
31-
db: &dyn HirDatabase,
32-
macro_: hir::MacroDef,
33-
) -> (&'static str, &'static str) {
34-
let macro_name = match macro_.name(db) {
35-
Some(name) => name.to_string(),
36-
None => return ("(", ")"),
37-
};
38-
let macro_docs = macro_.docs(db);
39-
let macro_docs = macro_docs.as_ref().map(Documentation::as_str).unwrap_or("");
40-
41-
let mut votes = [0, 0, 0];
42-
for (idx, s) in macro_docs.match_indices(&macro_name) {
43-
let (before, after) = (&macro_docs[..idx], &macro_docs[idx + s.len()..]);
44-
// Ensure to match the full word
45-
if after.starts_with('!')
46-
&& !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
47-
{
48-
// It may have spaces before the braces like `foo! {}`
49-
match after[1..].chars().find(|&c| !c.is_whitespace()) {
50-
Some('{') => votes[0] += 1,
51-
Some('[') => votes[1] += 1,
52-
Some('(') => votes[2] += 1,
53-
_ => {}
54-
}
55-
}
56-
}
57-
58-
// Insert a space before `{}`.
59-
// We prefer the last one when some votes equal.
60-
let (_vote, (bra, ket)) = votes
61-
.iter()
62-
.zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
63-
.max_by_key(|&(&vote, _)| vote)
64-
.unwrap();
65-
(*bra, *ket)
66-
}
67-
6830
impl<'a> MacroRender<'a> {
6931
fn new(ctx: RenderContext<'a>, name: String, macro_: hir::MacroDef) -> MacroRender<'a> {
7032
let docs = ctx.docs(macro_);
71-
let (bra, ket) = guess_macro_braces(ctx.db(), macro_);
33+
let docs_str = docs.as_ref().map_or("", |s| s.as_str());
34+
let (bra, ket) = guess_macro_braces(&name, docs_str);
35+
7236
MacroRender { ctx, name, macro_, docs, bra, ket }
7337
}
7438

@@ -133,6 +97,34 @@ impl<'a> MacroRender<'a> {
13397
}
13498
}
13599

100+
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
101+
let mut votes = [0, 0, 0];
102+
for (idx, s) in docs.match_indices(&macro_name) {
103+
let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
104+
// Ensure to match the full word
105+
if after.starts_with('!')
106+
&& !before.ends_with(|c: char| c == '_' || c.is_ascii_alphanumeric())
107+
{
108+
// It may have spaces before the braces like `foo! {}`
109+
match after[1..].chars().find(|&c| !c.is_whitespace()) {
110+
Some('{') => votes[0] += 1,
111+
Some('[') => votes[1] += 1,
112+
Some('(') => votes[2] += 1,
113+
_ => {}
114+
}
115+
}
116+
}
117+
118+
// Insert a space before `{}`.
119+
// We prefer the last one when some votes equal.
120+
let (_vote, (bra, ket)) = votes
121+
.iter()
122+
.zip(&[(" {", "}"), ("[", "]"), ("(", ")")])
123+
.max_by_key(|&(&vote, _)| vote)
124+
.unwrap();
125+
(*bra, *ket)
126+
}
127+
136128
#[cfg(test)]
137129
mod tests {
138130
use test_utils::mark;

crates/text_edit/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ impl TextEdit {
4848
TextEditBuilder::default()
4949
}
5050

51+
pub fn into_builder(self) -> TextEditBuilder {
52+
TextEditBuilder { indels: self.indels }
53+
}
54+
5155
pub fn insert(offset: TextSize, text: String) -> TextEdit {
5256
let mut builder = TextEdit::builder();
5357
builder.insert(offset, text);

0 commit comments

Comments
 (0)