mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-01 07:48:45 +00:00
Auto merge of #12244 - jonas-schievink:closing-brace-hints, r=jonas-schievink
feat: Show inlay hints after a `}` to indicate the closed item Closes https://github.com/rust-lang/rust-analyzer/issues/7315 ![screenshot-2022-05-13-19:42:00](https://user-images.githubusercontent.com/1786438/168338713-4cedef50-3611-4667-aa6a-49e154ec16a7.png)
This commit is contained in:
commit
ee2cbe0ae8
6 changed files with 209 additions and 7 deletions
|
@ -26,6 +26,7 @@ pub struct InlayHintsConfig {
|
||||||
pub param_names_for_lifetime_elision_hints: bool,
|
pub param_names_for_lifetime_elision_hints: bool,
|
||||||
pub hide_named_constructor_hints: bool,
|
pub hide_named_constructor_hints: bool,
|
||||||
pub max_length: Option<usize>,
|
pub max_length: Option<usize>,
|
||||||
|
pub closing_brace_hints_min_lines: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -52,6 +53,7 @@ pub enum InlayKind {
|
||||||
LifetimeHint,
|
LifetimeHint,
|
||||||
ParameterHint,
|
ParameterHint,
|
||||||
TypeHint,
|
TypeHint,
|
||||||
|
ClosingBraceHint,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -104,7 +106,7 @@ pub(crate) fn inlay_hints(
|
||||||
NodeOrToken::Token(_) => return acc,
|
NodeOrToken::Token(_) => return acc,
|
||||||
NodeOrToken::Node(n) => n
|
NodeOrToken::Node(n) => n
|
||||||
.descendants()
|
.descendants()
|
||||||
.filter(|descendant| range.contains_range(descendant.text_range()))
|
.filter(|descendant| range.intersect(descendant.text_range()).is_some())
|
||||||
.for_each(hints),
|
.for_each(hints),
|
||||||
},
|
},
|
||||||
None => file.descendants().for_each(hints),
|
None => file.descendants().for_each(hints),
|
||||||
|
@ -124,6 +126,8 @@ fn hints(
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
closing_brace_hints(hints, sema, config, node.clone());
|
||||||
|
|
||||||
if let Some(expr) = ast::Expr::cast(node.clone()) {
|
if let Some(expr) = ast::Expr::cast(node.clone()) {
|
||||||
chaining_hints(hints, sema, &famous_defs, config, &expr);
|
chaining_hints(hints, sema, &famous_defs, config, &expr);
|
||||||
match expr {
|
match expr {
|
||||||
|
@ -147,6 +151,104 @@ fn hints(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn closing_brace_hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
sema: &Semantics<RootDatabase>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
node: SyntaxNode,
|
||||||
|
) -> Option<()> {
|
||||||
|
let min_lines = config.closing_brace_hints_min_lines?;
|
||||||
|
|
||||||
|
let mut closing_token;
|
||||||
|
let label = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
|
||||||
|
closing_token = item_list.r_curly_token()?;
|
||||||
|
|
||||||
|
let parent = item_list.syntax().parent()?;
|
||||||
|
match_ast! {
|
||||||
|
match parent {
|
||||||
|
ast::Impl(imp) => {
|
||||||
|
let imp = sema.to_def(&imp)?;
|
||||||
|
let ty = imp.self_ty(sema.db);
|
||||||
|
let trait_ = imp.trait_(sema.db);
|
||||||
|
|
||||||
|
match trait_ {
|
||||||
|
Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
|
||||||
|
None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::Trait(tr) => {
|
||||||
|
format!("trait {}", tr.name()?)
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(list) = ast::ItemList::cast(node.clone()) {
|
||||||
|
closing_token = list.r_curly_token()?;
|
||||||
|
|
||||||
|
let module = ast::Module::cast(list.syntax().parent()?)?;
|
||||||
|
format!("mod {}", module.name()?)
|
||||||
|
} else if let Some(block) = ast::BlockExpr::cast(node.clone()) {
|
||||||
|
closing_token = block.stmt_list()?.r_curly_token()?;
|
||||||
|
|
||||||
|
let parent = block.syntax().parent()?;
|
||||||
|
match_ast! {
|
||||||
|
match parent {
|
||||||
|
ast::Fn(it) => {
|
||||||
|
// FIXME: this could include parameters, but `HirDisplay` prints too much info
|
||||||
|
// and doesn't respect the max length either, so the hints end up way too long
|
||||||
|
format!("fn {}", it.name()?)
|
||||||
|
},
|
||||||
|
ast::Static(it) => format!("static {}", it.name()?),
|
||||||
|
ast::Const(it) => {
|
||||||
|
if it.underscore_token().is_some() {
|
||||||
|
"const _".into()
|
||||||
|
} else {
|
||||||
|
format!("const {}", it.name()?)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(mac) = ast::MacroCall::cast(node.clone()) {
|
||||||
|
let last_token = mac.syntax().last_token()?;
|
||||||
|
if last_token.kind() != T![;] && last_token.kind() != SyntaxKind::R_CURLY {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
closing_token = last_token;
|
||||||
|
|
||||||
|
format!("{}!", mac.path()?)
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut next) = closing_token.next_token() {
|
||||||
|
if next.kind() == T![;] {
|
||||||
|
if let Some(tok) = next.next_token() {
|
||||||
|
closing_token = next;
|
||||||
|
next = tok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !(next.kind() == SyntaxKind::WHITESPACE && next.text().contains('\n')) {
|
||||||
|
// Only display the hint if the `}` is the last token on the line
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut lines = 1;
|
||||||
|
node.text().for_each_chunk(|s| lines += s.matches('\n').count());
|
||||||
|
if lines < min_lines {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.push(InlayHint {
|
||||||
|
range: closing_token.text_range(),
|
||||||
|
kind: InlayKind::ClosingBraceHint,
|
||||||
|
label: label.into(),
|
||||||
|
});
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn lifetime_hints(
|
fn lifetime_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
|
@ -925,6 +1027,7 @@ mod tests {
|
||||||
hide_named_constructor_hints: false,
|
hide_named_constructor_hints: false,
|
||||||
param_names_for_lifetime_elision_hints: false,
|
param_names_for_lifetime_elision_hints: false,
|
||||||
max_length: None,
|
max_length: None,
|
||||||
|
closing_brace_hints_min_lines: None,
|
||||||
};
|
};
|
||||||
const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
||||||
type_hints: true,
|
type_hints: true,
|
||||||
|
@ -1422,10 +1525,10 @@ fn main() {
|
||||||
let foo = foo();
|
let foo = foo();
|
||||||
let foo = foo1();
|
let foo = foo1();
|
||||||
let foo = foo2();
|
let foo = foo2();
|
||||||
|
// ^^^ impl Fn(f64, f64)
|
||||||
let foo = foo3();
|
let foo = foo3();
|
||||||
// ^^^ impl Fn(f64, f64) -> u32
|
// ^^^ impl Fn(f64, f64) -> u32
|
||||||
let foo = foo4();
|
let foo = foo4();
|
||||||
// ^^^ &dyn Fn(f64, f64) -> u32
|
|
||||||
let foo = foo5();
|
let foo = foo5();
|
||||||
let foo = foo6();
|
let foo = foo6();
|
||||||
let foo = foo7();
|
let foo = foo7();
|
||||||
|
@ -2290,7 +2393,70 @@ fn __(
|
||||||
//^^^^ &mut
|
//^^^^ &mut
|
||||||
//^ ref mut
|
//^ ref mut
|
||||||
}
|
}
|
||||||
}
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hints_closing_brace() {
|
||||||
|
check_with_config(
|
||||||
|
InlayHintsConfig { closing_brace_hints_min_lines: Some(2), ..DISABLED_CONFIG },
|
||||||
|
r#"
|
||||||
|
fn a() {}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
} // no hint unless `}` is the last token on the line
|
||||||
|
|
||||||
|
fn g() {
|
||||||
|
}
|
||||||
|
//^ fn g
|
||||||
|
|
||||||
|
fn h<T>(with: T, arguments: u8, ...) {
|
||||||
|
}
|
||||||
|
//^ fn h
|
||||||
|
|
||||||
|
trait Tr {
|
||||||
|
fn f();
|
||||||
|
fn g() {
|
||||||
|
}
|
||||||
|
//^ fn g
|
||||||
|
}
|
||||||
|
//^ trait Tr
|
||||||
|
impl Tr for () {
|
||||||
|
}
|
||||||
|
//^ impl Tr for ()
|
||||||
|
impl dyn Tr {
|
||||||
|
}
|
||||||
|
//^ impl dyn Tr
|
||||||
|
|
||||||
|
static S0: () = 0;
|
||||||
|
static S1: () = {};
|
||||||
|
static S2: () = {
|
||||||
|
};
|
||||||
|
//^ static S2
|
||||||
|
const _: () = {
|
||||||
|
};
|
||||||
|
//^ const _
|
||||||
|
|
||||||
|
mod m {
|
||||||
|
}
|
||||||
|
//^ mod m
|
||||||
|
|
||||||
|
m! {}
|
||||||
|
m!();
|
||||||
|
m!(
|
||||||
|
);
|
||||||
|
//^ m!
|
||||||
|
|
||||||
|
m! {
|
||||||
|
}
|
||||||
|
//^ m!
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let v = vec![
|
||||||
|
];
|
||||||
|
}
|
||||||
|
//^ fn f
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,7 @@ impl StaticIndex<'_> {
|
||||||
param_names_for_lifetime_elision_hints: false,
|
param_names_for_lifetime_elision_hints: false,
|
||||||
binding_mode_hints: false,
|
binding_mode_hints: false,
|
||||||
max_length: Some(25),
|
max_length: Some(25),
|
||||||
|
closing_brace_hints_min_lines: Some(25),
|
||||||
},
|
},
|
||||||
file_id,
|
file_id,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -259,6 +259,11 @@ config_data! {
|
||||||
inlayHints_bindingModeHints_enable: bool = "false",
|
inlayHints_bindingModeHints_enable: bool = "false",
|
||||||
/// Whether to show inlay type hints for method chains.
|
/// Whether to show inlay type hints for method chains.
|
||||||
inlayHints_chainingHints_enable: bool = "true",
|
inlayHints_chainingHints_enable: bool = "true",
|
||||||
|
/// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
|
||||||
|
inlayHints_closingBraceHints_enable: bool = "true",
|
||||||
|
/// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
|
||||||
|
/// to always show them).
|
||||||
|
inlayHints_closingBraceHints_minLines: usize = "25",
|
||||||
/// Whether to show inlay type hints for return types of closures with blocks.
|
/// Whether to show inlay type hints for return types of closures with blocks.
|
||||||
inlayHints_closureReturnTypeHints_enable: bool = "false",
|
inlayHints_closureReturnTypeHints_enable: bool = "false",
|
||||||
/// Whether to show inlay type hints for elided lifetimes in function signatures.
|
/// Whether to show inlay type hints for elided lifetimes in function signatures.
|
||||||
|
@ -1005,6 +1010,11 @@ impl Config {
|
||||||
.data
|
.data
|
||||||
.inlayHints_lifetimeElisionHints_useParameterNames,
|
.inlayHints_lifetimeElisionHints_useParameterNames,
|
||||||
max_length: self.data.inlayHints_maxLength,
|
max_length: self.data.inlayHints_maxLength,
|
||||||
|
closing_brace_hints_min_lines: if self.data.inlayHints_closingBraceHints_enable {
|
||||||
|
Some(self.data.inlayHints_closingBraceHints_minLines)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,7 +426,8 @@ pub(crate) fn inlay_hint(
|
||||||
| InlayKind::TypeHint
|
| InlayKind::TypeHint
|
||||||
| InlayKind::ChainingHint
|
| InlayKind::ChainingHint
|
||||||
| InlayKind::GenericParamListHint
|
| InlayKind::GenericParamListHint
|
||||||
| InlayKind::LifetimeHint => position(line_index, inlay_hint.range.end()),
|
| InlayKind::LifetimeHint
|
||||||
|
| InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
|
||||||
},
|
},
|
||||||
label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
|
label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
|
||||||
InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
|
InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
|
||||||
|
@ -442,12 +443,13 @@ pub(crate) fn inlay_hint(
|
||||||
InlayKind::BindingModeHint
|
InlayKind::BindingModeHint
|
||||||
| InlayKind::GenericParamListHint
|
| InlayKind::GenericParamListHint
|
||||||
| InlayKind::LifetimeHint
|
| InlayKind::LifetimeHint
|
||||||
| InlayKind::ImplicitReborrowHint => None,
|
| InlayKind::ImplicitReborrowHint
|
||||||
|
| InlayKind::ClosingBraceHint => None,
|
||||||
},
|
},
|
||||||
tooltip: None,
|
tooltip: None,
|
||||||
padding_left: Some(match inlay_hint.kind {
|
padding_left: Some(match inlay_hint.kind {
|
||||||
InlayKind::TypeHint => !render_colons,
|
InlayKind::TypeHint => !render_colons,
|
||||||
InlayKind::ChainingHint => true,
|
InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
|
||||||
InlayKind::BindingModeHint
|
InlayKind::BindingModeHint
|
||||||
| InlayKind::ClosureReturnTypeHint
|
| InlayKind::ClosureReturnTypeHint
|
||||||
| InlayKind::GenericParamListHint
|
| InlayKind::GenericParamListHint
|
||||||
|
@ -460,7 +462,8 @@ pub(crate) fn inlay_hint(
|
||||||
| InlayKind::ClosureReturnTypeHint
|
| InlayKind::ClosureReturnTypeHint
|
||||||
| InlayKind::GenericParamListHint
|
| InlayKind::GenericParamListHint
|
||||||
| InlayKind::ImplicitReborrowHint
|
| InlayKind::ImplicitReborrowHint
|
||||||
| InlayKind::TypeHint => false,
|
| InlayKind::TypeHint
|
||||||
|
| InlayKind::ClosingBraceHint => false,
|
||||||
InlayKind::BindingModeHint => inlay_hint.label != "&",
|
InlayKind::BindingModeHint => inlay_hint.label != "&",
|
||||||
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -355,6 +355,17 @@ Whether to show inlay type hints for binding modes.
|
||||||
--
|
--
|
||||||
Whether to show inlay type hints for method chains.
|
Whether to show inlay type hints for method chains.
|
||||||
--
|
--
|
||||||
|
[[rust-analyzer.inlayHints.closingBraceHints.enable]]rust-analyzer.inlayHints.closingBraceHints.enable (default: `true`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
|
||||||
|
--
|
||||||
|
[[rust-analyzer.inlayHints.closingBraceHints.minLines]]rust-analyzer.inlayHints.closingBraceHints.minLines (default: `25`)::
|
||||||
|
+
|
||||||
|
--
|
||||||
|
Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
|
||||||
|
to always show them).
|
||||||
|
--
|
||||||
[[rust-analyzer.inlayHints.closureReturnTypeHints.enable]]rust-analyzer.inlayHints.closureReturnTypeHints.enable (default: `false`)::
|
[[rust-analyzer.inlayHints.closureReturnTypeHints.enable]]rust-analyzer.inlayHints.closureReturnTypeHints.enable (default: `false`)::
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
|
|
|
@ -792,6 +792,17 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"rust-analyzer.inlayHints.closingBraceHints.enable": {
|
||||||
|
"markdownDescription": "Whether to show inlay hints after a closing `}` to indicate what item it belongs to.",
|
||||||
|
"default": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"rust-analyzer.inlayHints.closingBraceHints.minLines": {
|
||||||
|
"markdownDescription": "Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1\nto always show them).",
|
||||||
|
"default": 25,
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
"rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
|
"rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
|
||||||
"markdownDescription": "Whether to show inlay type hints for return types of closures with blocks.",
|
"markdownDescription": "Whether to show inlay type hints for return types of closures with blocks.",
|
||||||
"default": false,
|
"default": false,
|
||||||
|
|
Loading…
Reference in a new issue