mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Allow multi-part inlay hint labels with location links
This commit is contained in:
parent
ab068f120b
commit
241807dbf9
4 changed files with 179 additions and 46 deletions
|
@ -1,3 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
use either::Either;
|
||||
use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
|
||||
use ide_db::{
|
||||
|
@ -69,7 +71,7 @@ pub enum InlayKind {
|
|||
pub struct InlayHint {
|
||||
pub range: TextRange,
|
||||
pub kind: InlayKind,
|
||||
pub label: String,
|
||||
pub label: InlayHintLabel,
|
||||
pub tooltip: Option<InlayTooltip>,
|
||||
}
|
||||
|
||||
|
@ -80,6 +82,78 @@ pub enum InlayTooltip {
|
|||
HoverOffset(FileId, TextSize),
|
||||
}
|
||||
|
||||
pub struct InlayHintLabel {
|
||||
pub parts: Vec<InlayHintLabelPart>,
|
||||
}
|
||||
|
||||
impl InlayHintLabel {
|
||||
pub fn as_simple_str(&self) -> Option<&str> {
|
||||
match &*self.parts {
|
||||
[part] => part.as_simple_str(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepend_str(&mut self, s: &str) {
|
||||
match &mut *self.parts {
|
||||
[part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
|
||||
_ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_str(&mut self, s: &str) {
|
||||
match &mut *self.parts {
|
||||
[.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
|
||||
_ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for InlayHintLabel {
|
||||
fn from(s: String) -> Self {
|
||||
Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InlayHintLabel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InlayHintLabel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(&self.parts).finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InlayHintLabelPart {
|
||||
pub text: String,
|
||||
pub linked_location: Option<FileRange>,
|
||||
}
|
||||
|
||||
impl InlayHintLabelPart {
|
||||
pub fn as_simple_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self { text, linked_location: None } => Some(text),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InlayHintLabelPart {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.as_simple_str() {
|
||||
Some(string) => string.fmt(f),
|
||||
None => f
|
||||
.debug_struct("InlayHintLabelPart")
|
||||
.field("text", &self.text)
|
||||
.field("linked_location", &self.linked_location)
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Feature: Inlay Hints
|
||||
//
|
||||
// rust-analyzer shows additional information inline with the source code.
|
||||
|
@ -281,7 +355,7 @@ fn closing_brace_hints(
|
|||
acc.push(InlayHint {
|
||||
range: closing_token.text_range(),
|
||||
kind: InlayKind::ClosingBraceHint,
|
||||
label,
|
||||
label: label.into(),
|
||||
tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)),
|
||||
});
|
||||
|
||||
|
@ -311,7 +385,7 @@ fn implicit_static_hints(
|
|||
acc.push(InlayHint {
|
||||
range: t.text_range(),
|
||||
kind: InlayKind::LifetimeHint,
|
||||
label: "'static".to_owned(),
|
||||
label: "'static".to_owned().into(),
|
||||
tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
|
||||
});
|
||||
}
|
||||
|
@ -329,10 +403,10 @@ fn fn_lifetime_fn_hints(
|
|||
return None;
|
||||
}
|
||||
|
||||
let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
|
||||
let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
|
||||
range: t.text_range(),
|
||||
kind: InlayKind::LifetimeHint,
|
||||
label,
|
||||
label: label.into(),
|
||||
tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
|
||||
};
|
||||
|
||||
|
@ -486,7 +560,8 @@ fn fn_lifetime_fn_hints(
|
|||
"{}{}",
|
||||
allocated_lifetimes.iter().format(", "),
|
||||
if is_empty { "" } else { ", " }
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
|
||||
});
|
||||
}
|
||||
|
@ -535,7 +610,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()),
|
||||
.unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
|
||||
.into(),
|
||||
tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
|
||||
});
|
||||
Some(())
|
||||
|
@ -562,7 +638,7 @@ fn reborrow_hints(
|
|||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::ImplicitReborrowHint,
|
||||
label: label.to_string(),
|
||||
label: label.to_string().into(),
|
||||
tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
|
||||
});
|
||||
Some(())
|
||||
|
@ -620,9 +696,9 @@ fn chaining_hints(
|
|||
acc.push(InlayHint {
|
||||
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()
|
||||
}),
|
||||
label: hint_iterator(sema, &famous_defs, config, &ty)
|
||||
.unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
|
||||
.into(),
|
||||
tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
|
||||
});
|
||||
}
|
||||
|
@ -674,7 +750,7 @@ fn param_name_hints(
|
|||
InlayHint {
|
||||
range,
|
||||
kind: InlayKind::ParameterHint,
|
||||
label: param_name,
|
||||
label: param_name.into(),
|
||||
tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
|
||||
}
|
||||
});
|
||||
|
@ -705,7 +781,7 @@ fn binding_mode_hints(
|
|||
acc.push(InlayHint {
|
||||
range,
|
||||
kind: InlayKind::BindingModeHint,
|
||||
label: r.to_string(),
|
||||
label: r.to_string().into(),
|
||||
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
||||
});
|
||||
});
|
||||
|
@ -720,7 +796,7 @@ fn binding_mode_hints(
|
|||
acc.push(InlayHint {
|
||||
range,
|
||||
kind: InlayKind::BindingModeHint,
|
||||
label: bm.to_string(),
|
||||
label: bm.to_string().into(),
|
||||
tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
|
||||
});
|
||||
}
|
||||
|
@ -772,7 +848,7 @@ fn bind_pat_hints(
|
|||
None => pat.syntax().text_range(),
|
||||
},
|
||||
kind: InlayKind::TypeHint,
|
||||
label,
|
||||
label: label.into(),
|
||||
tooltip: pat
|
||||
.name()
|
||||
.map(|it| it.syntax().text_range())
|
||||
|
@ -2223,7 +2299,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 147..172,
|
||||
kind: ChainingHint,
|
||||
label: "B",
|
||||
label: [
|
||||
"B",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2236,7 +2314,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 147..154,
|
||||
kind: ChainingHint,
|
||||
label: "A",
|
||||
label: [
|
||||
"A",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2294,7 +2374,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 143..190,
|
||||
kind: ChainingHint,
|
||||
label: "C",
|
||||
label: [
|
||||
"C",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2307,7 +2389,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 143..179,
|
||||
kind: ChainingHint,
|
||||
label: "B",
|
||||
label: [
|
||||
"B",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2350,7 +2434,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 246..283,
|
||||
kind: ChainingHint,
|
||||
label: "B<X<i32, bool>>",
|
||||
label: [
|
||||
"B<X<i32, bool>>",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2363,7 +2449,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 246..265,
|
||||
kind: ChainingHint,
|
||||
label: "A<X<i32, bool>>",
|
||||
label: [
|
||||
"A<X<i32, bool>>",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2408,7 +2496,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 174..241,
|
||||
kind: ChainingHint,
|
||||
label: "impl Iterator<Item = ()>",
|
||||
label: [
|
||||
"impl Iterator<Item = ()>",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2421,7 +2511,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 174..224,
|
||||
kind: ChainingHint,
|
||||
label: "impl Iterator<Item = ()>",
|
||||
label: [
|
||||
"impl Iterator<Item = ()>",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2434,7 +2526,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 174..206,
|
||||
kind: ChainingHint,
|
||||
label: "impl Iterator<Item = ()>",
|
||||
label: [
|
||||
"impl Iterator<Item = ()>",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2447,7 +2541,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 174..189,
|
||||
kind: ChainingHint,
|
||||
label: "&mut MyIter",
|
||||
label: [
|
||||
"&mut MyIter",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2489,7 +2585,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 124..130,
|
||||
kind: TypeHint,
|
||||
label: "Struct",
|
||||
label: [
|
||||
"Struct",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2502,7 +2600,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 145..185,
|
||||
kind: ChainingHint,
|
||||
label: "Struct",
|
||||
label: [
|
||||
"Struct",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2515,7 +2615,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 145..168,
|
||||
kind: ChainingHint,
|
||||
label: "Struct",
|
||||
label: [
|
||||
"Struct",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverRanged(
|
||||
FileId(
|
||||
|
@ -2528,7 +2630,9 @@ fn main() {
|
|||
InlayHint {
|
||||
range: 222..228,
|
||||
kind: ParameterHint,
|
||||
label: "self",
|
||||
label: [
|
||||
"self",
|
||||
],
|
||||
tooltip: Some(
|
||||
HoverOffset(
|
||||
FileId(
|
||||
|
|
|
@ -82,8 +82,8 @@ pub use crate::{
|
|||
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
||||
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
|
||||
inlay_hints::{
|
||||
ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip,
|
||||
LifetimeElisionHints, ReborrowHints,
|
||||
ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
|
||||
InlayTooltip, LifetimeElisionHints, ReborrowHints,
|
||||
},
|
||||
join_lines::JoinLinesConfig,
|
||||
markup::Markup,
|
||||
|
|
|
@ -1362,7 +1362,7 @@ pub(crate) fn handle_inlay_hints(
|
|||
.map(|it| {
|
||||
to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
|
||||
})
|
||||
.collect(),
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,9 @@ use ide::{
|
|||
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
|
||||
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
|
||||
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
|
||||
InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity,
|
||||
SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
|
||||
InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
|
||||
Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
|
||||
TextSize,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use serde_json::to_value;
|
||||
|
@ -426,9 +427,16 @@ pub(crate) fn inlay_hint(
|
|||
snap: &GlobalStateSnapshot,
|
||||
line_index: &LineIndex,
|
||||
render_colons: bool,
|
||||
inlay_hint: InlayHint,
|
||||
) -> lsp_types::InlayHint {
|
||||
lsp_types::InlayHint {
|
||||
mut inlay_hint: InlayHint,
|
||||
) -> Result<lsp_types::InlayHint> {
|
||||
match inlay_hint.kind {
|
||||
InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
|
||||
InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
|
||||
InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(lsp_types::InlayHint {
|
||||
position: match inlay_hint.kind {
|
||||
// before annotated thing
|
||||
InlayKind::ParameterHint
|
||||
|
@ -459,15 +467,9 @@ pub(crate) fn inlay_hint(
|
|||
| InlayKind::ImplicitReborrowHint
|
||||
| InlayKind::TypeHint
|
||||
| InlayKind::ClosingBraceHint => false,
|
||||
InlayKind::BindingModeHint => inlay_hint.label != "&",
|
||||
InlayKind::BindingModeHint => inlay_hint.label.to_string() != "&",
|
||||
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
||||
}),
|
||||
label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
|
||||
InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
|
||||
InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
|
||||
InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label),
|
||||
_ => inlay_hint.label.clone(),
|
||||
}),
|
||||
kind: match inlay_hint.kind {
|
||||
InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
|
||||
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
|
||||
|
@ -506,9 +508,36 @@ pub(crate) fn inlay_hint(
|
|||
})(),
|
||||
tooltip: Some(match inlay_hint.tooltip {
|
||||
Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
|
||||
_ => lsp_types::InlayHintTooltip::String(inlay_hint.label),
|
||||
_ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
|
||||
}),
|
||||
}
|
||||
label: inlay_hint_label(snap, inlay_hint.label)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn inlay_hint_label(
|
||||
snap: &GlobalStateSnapshot,
|
||||
label: InlayHintLabel,
|
||||
) -> Result<lsp_types::InlayHintLabel> {
|
||||
Ok(match label.as_simple_str() {
|
||||
Some(s) => lsp_types::InlayHintLabel::String(s.into()),
|
||||
None => lsp_types::InlayHintLabel::LabelParts(
|
||||
label
|
||||
.parts
|
||||
.into_iter()
|
||||
.map(|part| {
|
||||
Ok(lsp_types::InlayHintLabelPart {
|
||||
value: part.text,
|
||||
tooltip: None,
|
||||
location: part
|
||||
.linked_location
|
||||
.map(|range| location(snap, range))
|
||||
.transpose()?,
|
||||
command: None,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
|
||||
|
|
Loading…
Reference in a new issue