Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
-rw-r--r--crates/ide/src/inlay_hints.rs162
1 files changed, 127 insertions, 35 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d3ce350f9b..bf82e83822 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,7 +8,8 @@ use itertools::Itertools;
use stdx::to_lower_snake_case;
use syntax::{
ast::{self, AstNode, HasArgList, HasGenericParams, HasName, UnaryOp},
- match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, TextRange, T,
+ match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
+ TextSize, T,
};
use crate::FileId;
@@ -56,11 +57,19 @@ pub enum InlayKind {
TypeHint,
}
+// FIXME: This should live somewhere more general
+#[derive(Debug)]
+pub enum RangeOrOffset {
+ Range(TextRange),
+ Offset(TextSize),
+}
+
#[derive(Debug)]
pub struct InlayHint {
pub range: TextRange,
pub kind: InlayKind,
- pub label: SmolStr,
+ pub label: String,
+ pub hover_trigger: Option<RangeOrOffset>,
}
// Feature: Inlay Hints
@@ -164,8 +173,10 @@ fn closing_brace_hints(
) -> Option<()> {
let min_lines = config.closing_brace_hints_min_lines?;
+ let name = |it: ast::Name| it.syntax().text_range().start();
+
let mut closing_token;
- let label = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
+ let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
closing_token = item_list.r_curly_token()?;
let parent = item_list.syntax().parent()?;
@@ -176,13 +187,13 @@ fn closing_brace_hints(
let ty = imp.self_ty(sema.db);
let trait_ = imp.trait_(sema.db);
- match trait_ {
+ (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)),
- }
+ }, None)
},
ast::Trait(tr) => {
- format!("trait {}", tr.name()?)
+ (format!("trait {}", tr.name()?), tr.name().map(name))
},
_ => return None,
}
@@ -191,7 +202,7 @@ fn closing_brace_hints(
closing_token = list.r_curly_token()?;
let module = ast::Module::cast(list.syntax().parent()?)?;
- format!("mod {}", module.name()?)
+ (format!("mod {}", module.name()?), module.name().map(name))
} else if let Some(block) = ast::BlockExpr::cast(node.clone()) {
closing_token = block.stmt_list()?.r_curly_token()?;
@@ -201,14 +212,14 @@ fn closing_brace_hints(
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()?)
+ (format!("fn {}", it.name()?), it.name().map(name))
},
- ast::Static(it) => format!("static {}", it.name()?),
+ ast::Static(it) => (format!("static {}", it.name()?), it.name().map(name)),
ast::Const(it) => {
if it.underscore_token().is_some() {
- "const _".into()
+ ("const _".into(), None)
} else {
- format!("const {}", it.name()?)
+ (format!("const {}", it.name()?), it.name().map(name))
}
},
_ => return None,
@@ -221,7 +232,10 @@ fn closing_brace_hints(
}
closing_token = last_token;
- format!("{}!", mac.path()?)
+ (
+ format!("{}!", mac.path()?),
+ mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
+ )
} else {
return None;
};
@@ -248,7 +262,8 @@ fn closing_brace_hints(
acc.push(InlayHint {
range: closing_token.text_range(),
kind: InlayKind::ClosingBraceHint,
- label: label.into(),
+ label,
+ hover_trigger: name_offset.map(RangeOrOffset::Offset),
});
None
@@ -262,6 +277,14 @@ fn lifetime_fn_hints(
if config.lifetime_elision_hints == LifetimeElisionHints::Never {
return None;
}
+
+ let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
+ range: t.text_range(),
+ kind: InlayKind::LifetimeHint,
+ label,
+ hover_trigger: None,
+ };
+
let param_list = func.param_list()?;
let generic_param_list = func.generic_param_list();
let ret_type = func.ret_type();
@@ -378,11 +401,7 @@ fn lifetime_fn_hints(
ast::Type::RefType(ty) if ty.lifetime().is_none() => {
if let Some(amp) = ty.amp_token() {
is_trivial = false;
- acc.push(InlayHint {
- range: amp.text_range(),
- kind: InlayKind::LifetimeHint,
- label: output_lt.clone(),
- });
+ acc.push(mk_lt_hint(amp, output_lt.to_string()));
}
}
_ => (),
@@ -398,8 +417,8 @@ fn lifetime_fn_hints(
for (_, amp_token, _, is_elided) in potential_lt_refs {
if is_elided {
let t = amp_token?;
- let lt = a.next()?.clone();
- acc.push(InlayHint { range: t.text_range(), kind: InlayKind::LifetimeHint, label: lt });
+ let lt = a.next()?;
+ acc.push(mk_lt_hint(t, lt.to_string()));
}
}
@@ -409,21 +428,20 @@ fn lifetime_fn_hints(
(Some(gpl), allocated_lifetimes) => {
let angle_tok = gpl.l_angle_token()?;
let is_empty = gpl.generic_params().next().is_none();
- acc.push(InlayHint {
- range: angle_tok.text_range(),
- kind: InlayKind::GenericParamListHint,
- label: format!(
+ acc.push(mk_lt_hint(
+ angle_tok,
+ format!(
"{}{}",
allocated_lifetimes.iter().format(", "),
if is_empty { "" } else { ", " }
- )
- .into(),
- });
+ ),
+ ));
}
(None, allocated_lifetimes) => acc.push(InlayHint {
range: func.name()?.syntax().text_range(),
kind: InlayKind::GenericParamListHint,
label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
+ hover_trigger: None,
}),
}
Some(())
@@ -456,7 +474,8 @@ fn closure_ret_hints(
range: param_list.syntax().text_range(),
kind: InlayKind::ClosureReturnTypeHint,
label: hint_iterator(sema, &famous_defs, config, &ty)
- .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string().into()),
+ .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()),
+ hover_trigger: None,
});
Some(())
}
@@ -482,7 +501,8 @@ fn reborrow_hints(
acc.push(InlayHint {
range: expr.syntax().text_range(),
kind: InlayKind::ImplicitReborrowHint,
- label: SmolStr::new_inline(label),
+ label: label.to_string(),
+ hover_trigger: None,
});
Some(())
}
@@ -539,8 +559,9 @@ fn chaining_hints(
range: expr.syntax().text_range(),
kind: InlayKind::ChainingHint,
label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
- ty.display_truncated(sema.db, config.max_length).to_string().into()
+ ty.display_truncated(sema.db, config.max_length).to_string()
}),
+ hover_trigger: Some(RangeOrOffset::Range(expr.syntax().text_range())),
});
}
}
@@ -581,6 +602,8 @@ fn param_name_hints(
range,
kind: InlayKind::ParameterHint,
label: param_name.into(),
+ // FIXME: Show hover for parameter
+ hover_trigger: None,
});
acc.extend(hints);
@@ -609,7 +632,8 @@ fn binding_mode_hints(
acc.push(InlayHint {
range,
kind: InlayKind::BindingModeHint,
- label: SmolStr::new_inline(r),
+ label: r.to_string(),
+ hover_trigger: None,
});
});
match pat {
@@ -623,7 +647,8 @@ fn binding_mode_hints(
acc.push(InlayHint {
range,
kind: InlayKind::BindingModeHint,
- label: SmolStr::new_inline(bm),
+ label: bm.to_string(),
+ hover_trigger: None,
});
}
_ => (),
@@ -663,7 +688,7 @@ fn bind_pat_hints(
{
return None;
}
- ty_name.into()
+ ty_name
}
};
@@ -674,6 +699,7 @@ fn bind_pat_hints(
},
kind: InlayKind::TypeHint,
label,
+ hover_trigger: pat.name().map(|it| it.syntax().text_range()).map(RangeOrOffset::Range),
});
Some(())
@@ -738,7 +764,7 @@ fn hint_iterator(
famous_defs: &FamousDefs,
config: &InlayHintsConfig,
ty: &hir::Type,
-) -> Option<SmolStr> {
+) -> Option<String> {
let db = sema.db;
let strukt = ty.strip_references().as_adt()?;
let krate = strukt.module(db).krate();
@@ -775,7 +801,7 @@ fn hint_iterator(
)
.to_string()
});
- return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END).into());
+ return Some(format!("{}{}{}", LABEL_START, ty_display, LABEL_END));
}
}
@@ -1986,11 +2012,21 @@ fn main() {
range: 147..172,
kind: ChainingHint,
label: "B",
+ hover_trigger: Some(
+ Range(
+ 147..172,
+ ),
+ ),
},
InlayHint {
range: 147..154,
kind: ChainingHint,
label: "A",
+ hover_trigger: Some(
+ Range(
+ 147..154,
+ ),
+ ),
},
]
"#]],
@@ -2041,11 +2077,21 @@ fn main() {
range: 143..190,
kind: ChainingHint,
label: "C",
+ hover_trigger: Some(
+ Range(
+ 143..190,
+ ),
+ ),
},
InlayHint {
range: 143..179,
kind: ChainingHint,
label: "B",
+ hover_trigger: Some(
+ Range(
+ 143..179,
+ ),
+ ),
},
]
"#]],
@@ -2081,11 +2127,21 @@ fn main() {
range: 246..283,
kind: ChainingHint,
label: "B<X<i32, bool>>",
+ hover_trigger: Some(
+ Range(
+ 246..283,
+ ),
+ ),
},
InlayHint {
range: 246..265,
kind: ChainingHint,
label: "A<X<i32, bool>>",
+ hover_trigger: Some(
+ Range(
+ 246..265,
+ ),
+ ),
},
]
"#]],
@@ -2123,21 +2179,41 @@ fn main() {
range: 174..241,
kind: ChainingHint,
label: "impl Iterator<Item = ()>",
+ hover_trigger: Some(
+ Range(
+ 174..241,
+ ),
+ ),
},
InlayHint {
range: 174..224,
kind: ChainingHint,
label: "impl Iterator<Item = ()>",
+ hover_trigger: Some(
+ Range(
+ 174..224,
+ ),
+ ),
},
InlayHint {
range: 174..206,
kind: ChainingHint,
label: "impl Iterator<Item = ()>",
+ hover_trigger: Some(
+ Range(
+ 174..206,
+ ),
+ ),
},
InlayHint {
range: 174..189,
kind: ChainingHint,
label: "&mut MyIter",
+ hover_trigger: Some(
+ Range(
+ 174..189,
+ ),
+ ),
},
]
"#]],
@@ -2172,21 +2248,37 @@ fn main() {
range: 124..130,
kind: TypeHint,
label: "Struct",
+ hover_trigger: Some(
+ Range(
+ 124..130,
+ ),
+ ),
},
InlayHint {
range: 145..185,
kind: ChainingHint,
label: "Struct",
+ hover_trigger: Some(
+ Range(
+ 145..185,
+ ),
+ ),
},
InlayHint {
range: 145..168,
kind: ChainingHint,
label: "Struct",
+ hover_trigger: Some(
+ Range(
+ 145..168,
+ ),
+ ),
},
InlayHint {
range: 222..228,
kind: ParameterHint,
label: "self",
+ hover_trigger: None,
},
]
"#]],