Unnamed repository; edit this file 'description' to name the repository.
| -rw-r--r-- | crates/ide/src/hover.rs | 7 | ||||
| -rw-r--r-- | crates/ide/src/hover/render.rs | 54 |
2 files changed, 58 insertions, 3 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 838fb18c3d..966daad135 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -87,7 +87,7 @@ pub struct HoverResult { // Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code. // Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. // -// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[] +// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif pub(crate) fn hover( db: &RootDatabase, FileRange { file_id, range }: FileRange, @@ -268,7 +268,10 @@ fn hover_type_fallback( } }; - let res = render::type_info(sema, config, &expr_or_pat)?; + let res = + render::type_info(sema, config, &expr_or_pat) + .or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?; + let range = sema .original_range_opt(&node) .map(|frange| frange.range) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index d109c07691..3b561f65da 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -14,7 +14,7 @@ use ide_db::{ use itertools::Itertools; use stdx::format_to; use syntax::{ - algo, ast, match_ast, AstNode, Direction, + algo, ast::{self, RecordPat}, match_ast, AstNode, Direction, SyntaxKind::{LET_EXPR, LET_STMT}, SyntaxToken, T, }; @@ -250,6 +250,58 @@ pub(super) fn keyword( Some(HoverResult { markup, actions }) } +pub(super) fn struct_rest_pat( + sema: &Semantics<'_, RootDatabase>, + config: &HoverConfig, + expr_or_pat: &Either<ast::Expr, ast::Pat>, +) -> Option<HoverResult> { + let pat = expr_or_pat.as_ref().right()?; + + let mut ancestors = sema.ancestors_with_macros(pat.syntax().clone()); + let _record_pat_field_list = ancestors.next()?; + let record_pat = ancestors.next()?; + let pattern = sema + .find_nodes_at_offset_with_descend::<RecordPat>( + &record_pat, + record_pat.text_range().start()) + .next()?; + + let missing_fields = sema.record_pattern_missing_fields(&pattern); + + // if there are no missing fields, the end result is a hover that shows ".." + // should be left in to indicate that there are no more fields in the pattern + // example, S {a: 1, b: 2, ..} when struct S {a: u32, b: u32} + + let mut res = HoverResult::default(); + let mut targets: Vec<hir::ModuleDef> = Vec::new(); + let mut push_new_def = |item: hir::ModuleDef| { + if !targets.contains(&item) { + targets.push(item); + } + }; + for (_, t) in &missing_fields { + walk_and_push_ty(sema.db, &t, &mut push_new_def); + } + + res.markup = { + let mut s = String::from(".., "); + for (f, _) in &missing_fields { + s += f.display(sema.db).to_string().as_ref(); + s += ", "; + } + // get rid of trailing comma + if s.len() > 0 {s.truncate(s.len() - 2);} + + if config.markdown() { + Markup::fenced_block(&s) + } else { + s.into() + } + }; + res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets)); + Some(res) +} + pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> { let (path, tt) = attr.as_simple_call()?; if !tt.syntax().text_range().contains(token.text_range().start()) { |