Auto merge of #12263 - andylizi:hide-type-hint-closure, r=Veykril
feat: hide type inlay hints for initializations of closures  This PR adds an option to hide the inlay hints for `let IDENT_PAT = CLOSURE_EXPR;`, which is a somewhat common coding pattern. Currently the inlay hints for the assigned variable and the closure expression itself are both displayed, making it rather repetitive. In order to be consistent with closure return type hints, only closures with block bodies will be hid by this option. Personally I'd feel comfortable making it always enabled (or at least when closure return type hints are enabled), but considering the precedent set in #10761, I introduced an off-by-default option for this. changelog feature: option to hide type inlay hints for initializations of closures
This commit is contained in:
commit
41388bf81a
5 changed files with 90 additions and 5 deletions
|
|
@ -26,6 +26,7 @@ pub struct InlayHintsConfig {
|
|||
pub lifetime_elision_hints: LifetimeElisionHints,
|
||||
pub param_names_for_lifetime_elision_hints: bool,
|
||||
pub hide_named_constructor_hints: bool,
|
||||
pub hide_closure_initialization_hints: bool,
|
||||
pub max_length: Option<usize>,
|
||||
pub closing_brace_hints_min_lines: Option<usize>,
|
||||
}
|
||||
|
|
@ -467,10 +468,11 @@ fn closure_ret_hints(
|
|||
return None;
|
||||
}
|
||||
|
||||
let param_list = match closure.body() {
|
||||
Some(ast::Expr::BlockExpr(_)) => closure.param_list()?,
|
||||
_ => return None,
|
||||
};
|
||||
if !closure_has_block_body(&closure) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let param_list = closure.param_list()?;
|
||||
|
||||
let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
|
||||
let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
|
||||
|
|
@ -693,7 +695,7 @@ fn bind_pat_hints(
|
|||
let desc_pat = descended.as_ref().unwrap_or(pat);
|
||||
let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
|
||||
|
||||
if should_not_display_type_hint(sema, pat, &ty) {
|
||||
if should_not_display_type_hint(sema, config, pat, &ty) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -848,6 +850,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir
|
|||
|
||||
fn should_not_display_type_hint(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
config: &InlayHintsConfig,
|
||||
bind_pat: &ast::IdentPat,
|
||||
pat_ty: &hir::Type,
|
||||
) -> bool {
|
||||
|
|
@ -863,6 +866,18 @@ fn should_not_display_type_hint(
|
|||
}
|
||||
}
|
||||
|
||||
if config.hide_closure_initialization_hints {
|
||||
if let Some(parent) = bind_pat.syntax().parent() {
|
||||
if let Some(it) = ast::LetStmt::cast(parent.clone()) {
|
||||
if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
|
||||
if closure_has_block_body(&closure) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for node in bind_pat.syntax().ancestors() {
|
||||
match_ast! {
|
||||
match node {
|
||||
|
|
@ -889,6 +904,10 @@ fn should_not_display_type_hint(
|
|||
false
|
||||
}
|
||||
|
||||
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
||||
matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
|
||||
}
|
||||
|
||||
fn should_hide_param_name_hint(
|
||||
sema: &Semantics<RootDatabase>,
|
||||
callable: &hir::Callable,
|
||||
|
|
@ -1083,6 +1102,7 @@ mod tests {
|
|||
reborrow_hints: ReborrowHints::Always,
|
||||
binding_mode_hints: false,
|
||||
hide_named_constructor_hints: false,
|
||||
hide_closure_initialization_hints: false,
|
||||
param_names_for_lifetime_elision_hints: false,
|
||||
max_length: None,
|
||||
closing_brace_hints_min_lines: None,
|
||||
|
|
@ -2034,6 +2054,53 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_closure_type_hints() {
|
||||
check_with_config(
|
||||
InlayHintsConfig {
|
||||
type_hints: true,
|
||||
hide_closure_initialization_hints: true,
|
||||
..DISABLED_CONFIG
|
||||
},
|
||||
r#"
|
||||
//- minicore: fn
|
||||
fn main() {
|
||||
let multiple_2 = |x: i32| { x * 2 };
|
||||
|
||||
let multiple_2 = |x: i32| x * 2;
|
||||
// ^^^^^^^^^^ |i32| -> i32
|
||||
|
||||
let (not) = (|x: bool| { !x });
|
||||
// ^^^ |bool| -> bool
|
||||
|
||||
let (is_zero, _b) = (|x: usize| { x == 0 }, false);
|
||||
// ^^^^^^^ |usize| -> bool
|
||||
// ^^ bool
|
||||
|
||||
let plus_one = |x| { x + 1 };
|
||||
// ^ u8
|
||||
foo(plus_one);
|
||||
|
||||
let add_mul = bar(|x: u8| { x + 1 });
|
||||
// ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
|
||||
|
||||
let closure = if let Some(6) = add_mul(2).checked_sub(1) {
|
||||
// ^^^^^^^ fn(i32) -> i32
|
||||
|x: i32| { x * 2 }
|
||||
} else {
|
||||
|x: i32| { x * 3 }
|
||||
};
|
||||
}
|
||||
|
||||
fn foo(f: impl FnOnce(u8) -> u8) {}
|
||||
|
||||
fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
|
||||
move |x: u8| f(x) * 2
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hint_truncation() {
|
||||
check_with_config(
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ impl StaticIndex<'_> {
|
|||
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
|
||||
reborrow_hints: crate::ReborrowHints::Never,
|
||||
hide_named_constructor_hints: false,
|
||||
hide_closure_initialization_hints: false,
|
||||
param_names_for_lifetime_elision_hints: false,
|
||||
binding_mode_hints: false,
|
||||
max_length: Some(25),
|
||||
|
|
|
|||
|
|
@ -281,6 +281,9 @@ config_data! {
|
|||
inlayHints_renderColons: bool = "true",
|
||||
/// Whether to show inlay type hints for variables.
|
||||
inlayHints_typeHints_enable: bool = "true",
|
||||
/// Whether to hide inlay type hints for `let` statements that initialize to a closure.
|
||||
/// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
|
||||
inlayHints_typeHints_hideClosureInitialization: bool = "false",
|
||||
/// Whether to hide inlay type hints for constructors.
|
||||
inlayHints_typeHints_hideNamedConstructor: bool = "false",
|
||||
|
||||
|
|
@ -1000,6 +1003,9 @@ impl Config {
|
|||
LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
|
||||
},
|
||||
hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
|
||||
hide_closure_initialization_hints: self
|
||||
.data
|
||||
.inlayHints_typeHints_hideClosureInitialization,
|
||||
reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
|
||||
ReborrowHintsDef::Always => ide::ReborrowHints::Always,
|
||||
ReborrowHintsDef::Never => ide::ReborrowHints::Never,
|
||||
|
|
|
|||
|
|
@ -407,6 +407,12 @@ Whether to render leading colons for type hints, and trailing colons for paramet
|
|||
--
|
||||
Whether to show inlay type hints for variables.
|
||||
--
|
||||
[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`)::
|
||||
+
|
||||
--
|
||||
Whether to hide inlay type hints for `let` statements that initialize to a closure.
|
||||
Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
|
||||
--
|
||||
[[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`)::
|
||||
+
|
||||
--
|
||||
|
|
|
|||
|
|
@ -868,6 +868,11 @@
|
|||
"default": true,
|
||||
"type": "boolean"
|
||||
},
|
||||
"rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
|
||||
"markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
|
||||
"markdownDescription": "Whether to hide inlay type hints for constructors.",
|
||||
"default": false,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue