Skip to content

Commit 0ffb361

Browse files
committed
feat: adds hover hint to ".." in record pattern
currently only works with struct pattern
1 parent 791cb87 commit 0ffb361

File tree

2 files changed

+58
-3
lines changed

2 files changed

+58
-3
lines changed

crates/ide/src/hover.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub struct HoverResult {
8787
// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
8888
// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
8989
//
90-
// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
90+
// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif
9191
pub(crate) fn hover(
9292
db: &RootDatabase,
9393
FileRange { file_id, range }: FileRange,
@@ -268,7 +268,10 @@ fn hover_type_fallback(
268268
}
269269
};
270270

271-
let res = render::type_info(sema, config, &expr_or_pat)?;
271+
let res =
272+
render::type_info(sema, config, &expr_or_pat)
273+
.or_else(|| render::struct_rest_pat(sema, config, &expr_or_pat))?;
274+
272275
let range = sema
273276
.original_range_opt(&node)
274277
.map(|frange| frange.range)

crates/ide/src/hover/render.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ide_db::{
1414
use itertools::Itertools;
1515
use stdx::format_to;
1616
use syntax::{
17-
algo, ast, match_ast, AstNode, Direction,
17+
algo, ast::{self, RecordPat}, match_ast, AstNode, Direction,
1818
SyntaxKind::{LET_EXPR, LET_STMT},
1919
SyntaxToken, T,
2020
};
@@ -250,6 +250,58 @@ pub(super) fn keyword(
250250
Some(HoverResult { markup, actions })
251251
}
252252

253+
pub(super) fn struct_rest_pat(
254+
sema: &Semantics<'_, RootDatabase>,
255+
config: &HoverConfig,
256+
expr_or_pat: &Either<ast::Expr, ast::Pat>,
257+
) -> Option<HoverResult> {
258+
let pat = expr_or_pat.as_ref().right()?;
259+
260+
let mut ancestors = sema.ancestors_with_macros(pat.syntax().clone());
261+
let _record_pat_field_list = ancestors.next()?;
262+
let record_pat = ancestors.next()?;
263+
let pattern = sema
264+
.find_nodes_at_offset_with_descend::<RecordPat>(
265+
&record_pat,
266+
record_pat.text_range().start())
267+
.next()?;
268+
269+
let missing_fields = sema.record_pattern_missing_fields(&pattern);
270+
271+
// if there are no missing fields, the end result is a hover that shows ".."
272+
// should be left in to indicate that there are no more fields in the pattern
273+
// example, S {a: 1, b: 2, ..} when struct S {a: u32, b: u32}
274+
275+
let mut res = HoverResult::default();
276+
let mut targets: Vec<hir::ModuleDef> = Vec::new();
277+
let mut push_new_def = |item: hir::ModuleDef| {
278+
if !targets.contains(&item) {
279+
targets.push(item);
280+
}
281+
};
282+
for (_, t) in &missing_fields {
283+
walk_and_push_ty(sema.db, &t, &mut push_new_def);
284+
}
285+
286+
res.markup = {
287+
let mut s = String::from(".., ");
288+
for (f, _) in &missing_fields {
289+
s += f.display(sema.db).to_string().as_ref();
290+
s += ", ";
291+
}
292+
// get rid of trailing comma
293+
if s.len() > 0 {s.truncate(s.len() - 2);}
294+
295+
if config.markdown() {
296+
Markup::fenced_block(&s)
297+
} else {
298+
s.into()
299+
}
300+
};
301+
res.actions.push(HoverAction::goto_type_from_targets(sema.db, targets));
302+
Some(res)
303+
}
304+
253305
pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<HoverResult> {
254306
let (path, tt) = attr.as_simple_call()?;
255307
if !tt.syntax().text_range().contains(token.text_range().start()) {

0 commit comments

Comments
 (0)