Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r--crates/ide/src/hover.rs112
1 files changed, 61 insertions, 51 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c46c1c1cd1..4a76ac9320 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -86,30 +86,38 @@ pub struct HoverResult {
// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
pub(crate) fn hover(
db: &RootDatabase,
- file_range: FileRange,
+ frange @ FileRange { file_id, range }: FileRange,
config: &HoverConfig,
) -> Option<RangeInfo<HoverResult>> {
let sema = &hir::Semantics::new(db);
- let mut res = hover_impl(sema, file_range, config)?;
+ let file = sema.parse(file_id).syntax().clone();
+ let mut res = if range.is_empty() {
+ hover_simple(sema, FilePosition { file_id, offset: range.start() }, file, config)
+ } else {
+ hover_ranged(sema, frange, file, config)
+ }?;
+
if let HoverDocFormat::PlainText = config.format {
res.info.markup = remove_markdown(res.info.markup.as_str()).into();
}
Some(res)
}
-fn hover_impl(
+fn hover_simple(
sema: &Semantics<'_, RootDatabase>,
- FileRange { file_id, range }: FileRange,
+ FilePosition { file_id, offset }: FilePosition,
+ file: SyntaxNode,
config: &HoverConfig,
) -> Option<RangeInfo<HoverResult>> {
- let file = sema.parse(file_id).syntax().clone();
- if !range.is_empty() {
- return hover_ranged(&file, range, sema, config);
- }
- let offset = range.start();
-
let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
- IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4,
+ IDENT
+ | INT_NUMBER
+ | LIFETIME_IDENT
+ | T![self]
+ | T![super]
+ | T![crate]
+ | T![Self]
+ | T![_] => 4,
// index and prefix ops
T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
kind if kind.is_keyword() => 2,
@@ -142,19 +150,18 @@ fn hover_impl(
} else {
sema.descend_into_macros_with_same_text(original_token.clone())
};
+ let descended = || descended.iter();
- // try lint hover
- let result = descended
- .iter()
+ let result = descended()
+ // try lint hover
.find_map(|token| {
// FIXME: Definition should include known lints and the like instead of having this special case here
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
render::try_for_lint(&attr, token)
})
- // try item definitions
+ // try definitions
.or_else(|| {
- descended
- .iter()
+ descended()
.filter_map(|token| {
let node = token.parent()?;
let class = IdentClass::classify_token(sema, token)?;
@@ -175,10 +182,12 @@ fn hover_impl(
})
})
// try keywords
- .or_else(|| descended.iter().find_map(|token| render::keyword(sema, config, token)))
- // try rest item hover
+ .or_else(|| descended().find_map(|token| render::keyword(sema, config, token)))
+ // try _ hovers
+ .or_else(|| descended().find_map(|token| render::underscore(sema, config, token)))
+ // try rest pattern hover
.or_else(|| {
- descended.iter().find_map(|token| {
+ descended().find_map(|token| {
if token.kind() != DOT2 {
return None;
}
@@ -201,39 +210,13 @@ fn hover_impl(
})
// fallback to type hover if there aren't any other suggestions
// this finds its own range instead of using the closest token's range
- .or_else(|| {
- descended.iter().find_map(|token| hover_type_fallback(sema, config, token, token))
- })
-}
-
-pub(crate) fn hover_for_definition(
- sema: &Semantics<'_, RootDatabase>,
- file_id: FileId,
- definition: Definition,
- node: &SyntaxNode,
- config: &HoverConfig,
-) -> Option<HoverResult> {
- let famous_defs = match &definition {
- Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
- _ => None,
- };
- render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| {
- HoverResult {
- markup: render::process_markup(sema.db, definition, &markup, config),
- actions: show_implementations_action(sema.db, definition)
- .into_iter()
- .chain(show_fn_references_action(sema.db, definition))
- .chain(runnable_action(sema, definition, file_id))
- .chain(goto_type_action_for_def(sema.db, definition))
- .collect(),
- }
- })
+ .or_else(|| descended().find_map(|token| hover_type_fallback(sema, config, token, token)))
}
fn hover_ranged(
- file: &SyntaxNode,
- range: syntax::TextRange,
sema: &Semantics<'_, RootDatabase>,
+ FileRange { range, .. }: FileRange,
+ file: SyntaxNode,
config: &HoverConfig,
) -> Option<RangeInfo<HoverResult>> {
// FIXME: make this work in attributes
@@ -248,7 +231,7 @@ fn hover_ranged(
}
_ => None,
};
- let res = res.or_else(|| render::type_info(sema, config, &expr_or_pat));
+ let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat));
res.map(|it| {
let range = match expr_or_pat {
Either::Left(it) => it.syntax().text_range(),
@@ -258,6 +241,33 @@ fn hover_ranged(
})
}
+pub(crate) fn hover_for_definition(
+ sema: &Semantics<'_, RootDatabase>,
+ file_id: FileId,
+ definition: Definition,
+ node: &SyntaxNode,
+ config: &HoverConfig,
+) -> Option<HoverResult> {
+ let famous_defs = match &definition {
+ Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
+ _ => None,
+ };
+ render::definition(sema.db, definition, famous_defs.as_ref(), config).map(|markup| {
+ HoverResult {
+ markup: render::process_markup(sema.db, definition, &markup, config),
+ actions: [
+ show_implementations_action(sema.db, definition),
+ show_fn_references_action(sema.db, definition),
+ runnable_action(sema, definition, file_id),
+ goto_type_action_for_def(sema.db, definition),
+ ]
+ .into_iter()
+ .flatten()
+ .collect(),
+ }
+ })
+}
+
fn hover_type_fallback(
sema: &Semantics<'_, RootDatabase>,
config: &HoverConfig,
@@ -282,7 +292,7 @@ fn hover_type_fallback(
}
};
- let res = render::type_info(sema, config, &expr_or_pat)?;
+ let res = render::type_info_of(sema, config, &expr_or_pat)?;
let range = sema
.original_range_opt(&node)