Skip to content

Commit f9db48f

Browse files
committed
Consider interleaving hover kinds
1 parent b0e7ef4 commit f9db48f

File tree

2 files changed

+95
-84
lines changed

2 files changed

+95
-84
lines changed

src/tools/rust-analyzer/crates/ide/src/hover.rs

+94-83
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub enum HoverDocFormat {
5858
PlainText,
5959
}
6060

61-
#[derive(Debug, Clone)]
61+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
6262
pub enum HoverAction {
6363
Runnable(Runnable),
6464
Implementation(FilePosition),
@@ -97,7 +97,7 @@ pub struct HoverGotoTypeData {
9797
}
9898

9999
/// Contains the results when hovering over an item
100-
#[derive(Debug, Default)]
100+
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
101101
pub struct HoverResult {
102102
pub markup: Markup,
103103
pub actions: Vec<HoverAction>,
@@ -200,21 +200,24 @@ fn hover_simple(
200200
| ((no_tt_parent as usize) << 3)
201201
});
202202

203-
// TODO: WE should not try these step by step, instead to accommodate for macros we should run
204-
// all of these in "parallel" and rank their results
205-
let result = None
206-
// try lint hover
207-
.or_else(|| {
208-
descended().find_map(|token| {
209-
// FIXME: Definition should include known lints and the like instead of having this special case here
210-
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
211-
render::try_for_lint(&attr, token)
212-
})
213-
})
214-
// try definitions
215-
.or_else(|| {
216-
descended()
217-
.filter_map(|token| {
203+
let mut res = vec![];
204+
// let mut merge_result = |next: HoverResult| {
205+
// res.markup = Markup::from(format!("{}\n---\n{}", res.markup, next.markup));
206+
// res.actions.extend(next.actions);
207+
// };
208+
for token in descended {
209+
let lint_hover = (|| {
210+
// FIXME: Definition should include known lints and the like instead of having this special case here
211+
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
212+
render::try_for_lint(&attr, &token)
213+
})();
214+
if let Some(lint_hover) = lint_hover {
215+
res.push(lint_hover);
216+
continue;
217+
}
218+
let definitions = (|| {
219+
Some(
220+
'a: {
218221
let node = token.parent()?;
219222

220223
// special case macro calls, we wanna render the invoked arm index
@@ -229,11 +232,11 @@ fn hover_simple(
229232
.and_then(ast::MacroCall::cast)
230233
{
231234
if let Some(macro_) = sema.resolve_macro_call(&macro_call) {
232-
return Some(vec![(
235+
break 'a vec![(
233236
Definition::Macro(macro_),
234237
sema.resolve_macro_call_arm(&macro_call),
235238
node,
236-
)]);
239+
)];
237240
}
238241
}
239242
}
@@ -242,88 +245,96 @@ fn hover_simple(
242245
match IdentClass::classify_node(sema, &node)? {
243246
// It's better for us to fall back to the keyword hover here,
244247
// rendering poll is very confusing
245-
IdentClass::Operator(OperatorClass::Await(_)) => None,
248+
IdentClass::Operator(OperatorClass::Await(_)) => return None,
246249

247250
IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand {
248251
decl,
249252
..
250-
}) => Some(vec![(Definition::ExternCrateDecl(decl), None, node)]),
253+
}) => {
254+
vec![(Definition::ExternCrateDecl(decl), None, node)]
255+
}
251256

252-
class => Some(
257+
class => {
253258
multizip((class.definitions(), iter::repeat(None), iter::repeat(node)))
254-
.collect::<Vec<_>>(),
255-
),
259+
.collect::<Vec<_>>()
260+
}
256261
}
257-
})
258-
.flatten()
262+
}
263+
.into_iter()
259264
.unique_by(|&(def, _, _)| def)
260265
.map(|(def, macro_arm, node)| {
261266
hover_for_definition(sema, file_id, def, &node, macro_arm, config, edition)
262267
})
263-
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
264-
acc.actions.extend(actions);
265-
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
266-
acc
267-
})
268-
})
269-
// try keywords
270-
.or_else(|| descended().find_map(|token| render::keyword(sema, config, token, edition)))
271-
// try _ hovers
272-
.or_else(|| descended().find_map(|token| render::underscore(sema, config, token, edition)))
273-
// try rest pattern hover
274-
.or_else(|| {
275-
descended().find_map(|token| {
276-
if token.kind() != DOT2 {
277-
return None;
278-
}
268+
.collect::<Vec<_>>(),
269+
)
270+
})();
271+
if let Some(definitions) = definitions {
272+
res.extend(definitions);
273+
continue;
274+
}
275+
let keywords = || render::keyword(sema, config, &token, edition);
276+
let underscore = || render::underscore(sema, config, &token, edition);
277+
let rest_pat = || {
278+
if token.kind() != DOT2 {
279+
return None;
280+
}
279281

280-
let rest_pat = token.parent().and_then(ast::RestPat::cast)?;
281-
let record_pat_field_list =
282-
rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?;
282+
let rest_pat = token.parent().and_then(ast::RestPat::cast)?;
283+
let record_pat_field_list =
284+
rest_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast)?;
283285

284-
let record_pat =
285-
record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?;
286+
let record_pat =
287+
record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?;
286288

287-
Some(render::struct_rest_pat(sema, config, &record_pat, edition))
288-
})
289-
})
290-
// try () call hovers
291-
.or_else(|| {
292-
descended().find_map(|token| {
293-
if token.kind() != T!['('] && token.kind() != T![')'] {
294-
return None;
295-
}
296-
let arg_list = token.parent().and_then(ast::ArgList::cast)?.syntax().parent()?;
297-
let call_expr = syntax::match_ast! {
298-
match arg_list {
299-
ast::CallExpr(expr) => expr.into(),
300-
ast::MethodCallExpr(expr) => expr.into(),
301-
_ => return None,
302-
}
303-
};
304-
render::type_info_of(sema, config, &Either::Left(call_expr), edition)
305-
})
306-
})
307-
// try closure
308-
.or_else(|| {
309-
descended().find_map(|token| {
310-
if token.kind() != T![|] {
311-
return None;
289+
Some(render::struct_rest_pat(sema, config, &record_pat, edition))
290+
};
291+
let call = || {
292+
if token.kind() != T!['('] && token.kind() != T![')'] {
293+
return None;
294+
}
295+
let arg_list = token.parent().and_then(ast::ArgList::cast)?.syntax().parent()?;
296+
let call_expr = syntax::match_ast! {
297+
match arg_list {
298+
ast::CallExpr(expr) => expr.into(),
299+
ast::MethodCallExpr(expr) => expr.into(),
300+
_ => return None,
312301
}
313-
let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
314-
render::closure_expr(sema, config, c, edition)
315-
})
316-
})
317-
// tokens
318-
.or_else(|| {
302+
};
303+
render::type_info_of(sema, config, &Either::Left(call_expr), edition)
304+
};
305+
let closure = || {
306+
if token.kind() != T![|] {
307+
return None;
308+
}
309+
let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?;
310+
render::closure_expr(sema, config, c, edition)
311+
};
312+
let literal = || {
319313
render::literal(sema, original_token.clone(), edition)
320314
.map(|markup| HoverResult { markup, actions: vec![] })
321-
});
315+
};
316+
if let Some(result) = keywords()
317+
.or_else(underscore)
318+
.or_else(rest_pat)
319+
.or_else(call)
320+
.or_else(closure)
321+
.or_else(literal)
322+
{
323+
res.push(result)
324+
}
325+
}
322326

323-
result.map(|mut res: HoverResult| {
324-
res.actions = dedupe_or_merge_hover_actions(res.actions);
325-
RangeInfo::new(original_token.text_range(), res)
326-
})
327+
res.into_iter()
328+
.unique()
329+
.reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
330+
acc.actions.extend(actions);
331+
acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
332+
acc
333+
})
334+
.map(|mut res: HoverResult| {
335+
res.actions = dedupe_or_merge_hover_actions(res.actions);
336+
RangeInfo::new(original_token.text_range(), res)
337+
})
327338
}
328339

329340
fn hover_ranged(

src/tools/rust-analyzer/crates/ide/src/markup.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! what is used by LSP, so let's keep it simple.
66
use std::fmt;
77

8-
#[derive(Default, Debug)]
8+
#[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
99
pub struct Markup {
1010
text: String,
1111
}

0 commit comments

Comments
 (0)