Merge pull request #18376 from Veykril/veykril/push-ptmnsoqzsmqk
feat: Add text edits to more inlay hints
This commit is contained in:
commit
bde2000a98
@ -410,19 +410,6 @@ fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
|
|
||||||
InlayHint {
|
|
||||||
range,
|
|
||||||
kind,
|
|
||||||
label: InlayHintLabel::from("("),
|
|
||||||
text_edit: None,
|
|
||||||
position: InlayHintPosition::Before,
|
|
||||||
pad_left: false,
|
|
||||||
pad_right: false,
|
|
||||||
resolve_parent: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn needs_resolve(&self) -> Option<TextRange> {
|
pub fn needs_resolve(&self) -> Option<TextRange> {
|
||||||
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
|
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
//! let _: u32 = /* <never-to-any> */ loop {};
|
//! let _: u32 = /* <never-to-any> */ loop {};
|
||||||
//! let _: &u32 = /* &* */ &mut 0;
|
//! let _: &u32 = /* &* */ &mut 0;
|
||||||
//! ```
|
//! ```
|
||||||
|
use std::ops::Not;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{
|
||||||
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
|
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
|
||||||
@ -15,6 +17,7 @@
|
|||||||
ast::{self, make, AstNode},
|
ast::{self, make, AstNode},
|
||||||
ted,
|
ted,
|
||||||
};
|
};
|
||||||
|
use text_edit::TextEditBuilder;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
|
AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
|
||||||
@ -51,13 +54,13 @@ pub(super) fn hints(
|
|||||||
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
|
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
|
||||||
|
|
||||||
if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
|
if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
|
||||||
if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
|
// Don't show unnecessary reborrows for these, they will just repeat the inner ones again
|
||||||
&*adjustments
|
if matches!(
|
||||||
{
|
&*adjustments,
|
||||||
// Don't show unnecessary reborrows for these, they will just repeat the inner ones again
|
[Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }]
|
||||||
if source == target {
|
if source == target
|
||||||
return None;
|
) {
|
||||||
}
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +104,7 @@ pub(super) fn hints(
|
|||||||
};
|
};
|
||||||
let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
|
let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
|
||||||
|
|
||||||
|
let mut allow_edit = !postfix;
|
||||||
for Adjustment { source, target, kind } in iter {
|
for Adjustment { source, target, kind } in iter {
|
||||||
if source == target {
|
if source == target {
|
||||||
cov_mark::hit!(same_type_adjustment);
|
cov_mark::hit!(same_type_adjustment);
|
||||||
@ -110,6 +114,7 @@ pub(super) fn hints(
|
|||||||
// FIXME: Add some nicer tooltips to each of these
|
// FIXME: Add some nicer tooltips to each of these
|
||||||
let (text, coercion) = match kind {
|
let (text, coercion) = match kind {
|
||||||
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
|
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
|
||||||
|
allow_edit = false;
|
||||||
("<never-to-any>", "never to any")
|
("<never-to-any>", "never to any")
|
||||||
}
|
}
|
||||||
Adjust::Deref(None) => ("*", "dereference"),
|
Adjust::Deref(None) => ("*", "dereference"),
|
||||||
@ -130,6 +135,7 @@ pub(super) fn hints(
|
|||||||
// some of these could be represented via `as` casts, but that's not too nice and
|
// some of these could be represented via `as` casts, but that's not too nice and
|
||||||
// handling everything as a prefix expr makes the `(` and `)` insertion easier
|
// handling everything as a prefix expr makes the `(` and `)` insertion easier
|
||||||
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
|
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
|
||||||
|
allow_edit = false;
|
||||||
match cast {
|
match cast {
|
||||||
PointerCast::ReifyFnPointer => {
|
PointerCast::ReifyFnPointer => {
|
||||||
("<fn-item-to-fn-pointer>", "fn item to fn pointer")
|
("<fn-item-to-fn-pointer>", "fn item to fn pointer")
|
||||||
@ -170,12 +176,41 @@ pub(super) fn hints(
|
|||||||
if needs_outer_parens || (!postfix && needs_inner_parens) {
|
if needs_outer_parens || (!postfix && needs_inner_parens) {
|
||||||
post.label.append_str(")");
|
post.label.append_str(")");
|
||||||
}
|
}
|
||||||
if !pre.label.parts.is_empty() {
|
|
||||||
acc.push(pre);
|
let mut pre = pre.label.parts.is_empty().not().then_some(pre);
|
||||||
|
let mut post = post.label.parts.is_empty().not().then_some(post);
|
||||||
|
if pre.is_none() && post.is_none() {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
if !post.label.parts.is_empty() {
|
if allow_edit {
|
||||||
acc.push(post);
|
let edit = {
|
||||||
|
let mut b = TextEditBuilder::default();
|
||||||
|
if let Some(pre) = &pre {
|
||||||
|
b.insert(
|
||||||
|
pre.range.start(),
|
||||||
|
pre.label.parts.iter().map(|part| &*part.text).collect::<String>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if let Some(post) = &post {
|
||||||
|
b.insert(
|
||||||
|
post.range.end(),
|
||||||
|
post.label.parts.iter().map(|part| &*part.text).collect::<String>(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
b.finish()
|
||||||
|
};
|
||||||
|
match (&mut pre, &mut post) {
|
||||||
|
(Some(pre), Some(post)) => {
|
||||||
|
pre.text_edit = Some(edit.clone());
|
||||||
|
post.text_edit = Some(edit);
|
||||||
|
}
|
||||||
|
(Some(pre), None) => pre.text_edit = Some(edit),
|
||||||
|
(None, Some(post)) => post.text_edit = Some(edit),
|
||||||
|
(None, None) => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
acc.extend(pre);
|
||||||
|
acc.extend(post);
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
use span::EditionedFileId;
|
use span::EditionedFileId;
|
||||||
use syntax::ast::{self, AstNode};
|
use syntax::ast::{self, AstNode};
|
||||||
|
use text_edit::TextEditBuilder;
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
|
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
|
||||||
|
|
||||||
@ -23,16 +24,7 @@ pub(super) fn hints(
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let outer_paren_pat = pat
|
let outer_paren_pat = pat.syntax().ancestors().skip(1).map_while(ast::ParenPat::cast).last();
|
||||||
.syntax()
|
|
||||||
.ancestors()
|
|
||||||
.skip(1)
|
|
||||||
.map_while(ast::Pat::cast)
|
|
||||||
.map_while(|pat| match pat {
|
|
||||||
ast::Pat::ParenPat(pat) => Some(pat),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.last();
|
|
||||||
let range = outer_paren_pat.as_ref().map_or_else(
|
let range = outer_paren_pat.as_ref().map_or_else(
|
||||||
|| match pat {
|
|| match pat {
|
||||||
// for ident patterns that @ bind a name, render the un-ref patterns in front of the inner pattern
|
// for ident patterns that @ bind a name, render the un-ref patterns in front of the inner pattern
|
||||||
@ -70,33 +62,30 @@ pub(super) fn hints(
|
|||||||
hint.label.append_str(r);
|
hint.label.append_str(r);
|
||||||
});
|
});
|
||||||
hint.pad_right = was_mut_last;
|
hint.pad_right = was_mut_last;
|
||||||
if !hint.label.parts.is_empty() {
|
let acc_base = acc.len();
|
||||||
acc.push(hint);
|
|
||||||
}
|
|
||||||
match pat {
|
match pat {
|
||||||
ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
|
ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
|
||||||
let bm = sema.binding_mode_of_pat(pat)?;
|
let bm = sema.binding_mode_of_pat(pat)?;
|
||||||
let bm = match bm {
|
let bm = match bm {
|
||||||
hir::BindingMode::Move => return None,
|
hir::BindingMode::Move => None,
|
||||||
hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
|
hir::BindingMode::Ref(Mutability::Mut) => Some("ref mut"),
|
||||||
hir::BindingMode::Ref(Mutability::Shared) => "ref",
|
hir::BindingMode::Ref(Mutability::Shared) => Some("ref"),
|
||||||
};
|
};
|
||||||
acc.push(InlayHint {
|
if let Some(bm) = bm {
|
||||||
range: pat.syntax().text_range(),
|
acc.push(InlayHint {
|
||||||
kind: InlayKind::BindingMode,
|
range: pat.syntax().text_range(),
|
||||||
label: bm.into(),
|
kind: InlayKind::BindingMode,
|
||||||
text_edit: None,
|
label: bm.into(),
|
||||||
position: InlayHintPosition::Before,
|
text_edit: None,
|
||||||
pad_left: false,
|
position: InlayHintPosition::Before,
|
||||||
pad_right: true,
|
pad_left: false,
|
||||||
resolve_parent: Some(pat.syntax().text_range()),
|
pad_right: true,
|
||||||
});
|
resolve_parent: Some(pat.syntax().text_range()),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
|
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
|
||||||
acc.push(InlayHint::opening_paren_before(
|
hint.label.append_str("(");
|
||||||
InlayKind::BindingMode,
|
|
||||||
pat.syntax().text_range(),
|
|
||||||
));
|
|
||||||
acc.push(InlayHint::closing_paren_after(
|
acc.push(InlayHint::closing_paren_after(
|
||||||
InlayKind::BindingMode,
|
InlayKind::BindingMode,
|
||||||
pat.syntax().text_range(),
|
pat.syntax().text_range(),
|
||||||
@ -104,6 +93,24 @@ pub(super) fn hints(
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
if !hint.label.parts.is_empty() {
|
||||||
|
acc.push(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let hints @ [_, ..] = &mut acc[acc_base..] {
|
||||||
|
let mut edit = TextEditBuilder::default();
|
||||||
|
for h in &mut *hints {
|
||||||
|
edit.insert(
|
||||||
|
match h.position {
|
||||||
|
InlayHintPosition::Before => h.range.start(),
|
||||||
|
InlayHintPosition::After => h.range.end(),
|
||||||
|
},
|
||||||
|
h.label.parts.iter().map(|p| &*p.text).collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let edit = edit.finish();
|
||||||
|
hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
@ -154,11 +161,10 @@ fn __(
|
|||||||
}
|
}
|
||||||
match &(0,) {
|
match &(0,) {
|
||||||
(x,) | (x,) => (),
|
(x,) | (x,) => (),
|
||||||
//^^^^^^^^^^^&
|
//^^^^^^^^^^^)
|
||||||
|
//^^^^^^^^^^^&(
|
||||||
//^ ref
|
//^ ref
|
||||||
//^ ref
|
//^ ref
|
||||||
//^^^^^^^^^^^(
|
|
||||||
//^^^^^^^^^^^)
|
|
||||||
((x,) | (x,)) => (),
|
((x,) | (x,)) => (),
|
||||||
//^^^^^^^^^^^^^&
|
//^^^^^^^^^^^^^&
|
||||||
//^ ref
|
//^ ref
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
use ide_db::{famous_defs::FamousDefs, RootDatabase};
|
use ide_db::{famous_defs::FamousDefs, RootDatabase};
|
||||||
use span::EditionedFileId;
|
use span::EditionedFileId;
|
||||||
use syntax::ast::{self, AstNode, HasName};
|
use syntax::ast::{self, AstNode, HasName};
|
||||||
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
|
DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
|
||||||
@ -65,11 +66,11 @@ fn variant_hints(
|
|||||||
let eq_ = if eq_token.is_none() { " =" } else { "" };
|
let eq_ = if eq_token.is_none() { " =" } else { "" };
|
||||||
let label = InlayHintLabel::simple(
|
let label = InlayHintLabel::simple(
|
||||||
match d {
|
match d {
|
||||||
Ok(x) => {
|
Ok(val) => {
|
||||||
if x >= 10 {
|
if val >= 10 {
|
||||||
format!("{eq_} {x} ({x:#X})")
|
format!("{eq_} {val} ({val:#X})")
|
||||||
} else {
|
} else {
|
||||||
format!("{eq_} {x}")
|
format!("{eq_} {val}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => format!("{eq_} ?"),
|
Err(_) => format!("{eq_} ?"),
|
||||||
@ -87,7 +88,7 @@ fn variant_hints(
|
|||||||
},
|
},
|
||||||
kind: InlayKind::Discriminant,
|
kind: InlayKind::Discriminant,
|
||||||
label,
|
label,
|
||||||
text_edit: None,
|
text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
};
|
};
|
||||||
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
|
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ pub(super) fn hints(
|
|||||||
range: t.text_range(),
|
range: t.text_range(),
|
||||||
kind: InlayKind::Lifetime,
|
kind: InlayKind::Lifetime,
|
||||||
label: "'static".into(),
|
label: "'static".into(),
|
||||||
text_edit: None,
|
text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user