Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18376 from Veykril/veykril/push-ptmnsoqzsmqk
feat: Add text edits to more inlay hints
Lukas Wirth 2024-10-23
parent c286786 · parent b837ea4 · commit af7c97f
-rw-r--r--crates/ide/src/inlay_hints.rs13
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs57
-rw-r--r--crates/ide/src/inlay_hints/binding_mode.rs72
-rw-r--r--crates/ide/src/inlay_hints/discriminant.rs11
-rw-r--r--crates/ide/src/inlay_hints/implicit_static.rs3
5 files changed, 93 insertions, 63 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index fcf262877d..b6e46c3202 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -410,19 +410,6 @@ impl 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> {
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
}
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index ab44d8c3b5..0e0d50b1f3 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,6 +3,8 @@
//! let _: u32 = /* <never-to-any> */ loop {};
//! let _: &u32 = /* &* */ &mut 0;
//! ```
+use std::ops::Not;
+
use either::Either;
use hir::{
Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
@@ -15,6 +17,7 @@ use syntax::{
ast::{self, make, AstNode},
ted,
};
+use text_edit::TextEditBuilder;
use crate::{
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())?;
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 }] =
- &*adjustments
- {
- // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
- if source == target {
- return None;
- }
+ // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
+ if matches!(
+ &*adjustments,
+ [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }]
+ if source == target
+ ) {
+ 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 mut allow_edit = !postfix;
for Adjustment { source, target, kind } in iter {
if source == target {
cov_mark::hit!(same_type_adjustment);
@@ -110,6 +114,7 @@ pub(super) fn hints(
// FIXME: Add some nicer tooltips to each of these
let (text, coercion) = match kind {
Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
("<never-to-any>", "never to any")
}
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
// handling everything as a prefix expr makes the `(` and `)` insertion easier
Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+ allow_edit = false;
match cast {
PointerCast::ReifyFnPointer => {
("<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) {
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() {
- acc.push(post);
+ if allow_edit {
+ 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(())
}
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index beba2ad748..e38450b73f 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -9,6 +9,7 @@ use ide_db::famous_defs::FamousDefs;
use span::EditionedFileId;
use syntax::ast::{self, AstNode};
+use text_edit::TextEditBuilder;
use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
@@ -23,16 +24,7 @@ pub(super) fn hints(
return None;
}
- let outer_paren_pat = pat
- .syntax()
- .ancestors()
- .skip(1)
- .map_while(ast::Pat::cast)
- .map_while(|pat| match pat {
- ast::Pat::ParenPat(pat) => Some(pat),
- _ => None,
- })
- .last();
+ let outer_paren_pat = pat.syntax().ancestors().skip(1).map_while(ast::ParenPat::cast).last();
let range = outer_paren_pat.as_ref().map_or_else(
|| match pat {
// 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.pad_right = was_mut_last;
- if !hint.label.parts.is_empty() {
- acc.push(hint);
- }
+ let acc_base = acc.len();
match pat {
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 = match bm {
- hir::BindingMode::Move => return None,
- hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
- hir::BindingMode::Ref(Mutability::Shared) => "ref",
+ hir::BindingMode::Move => None,
+ hir::BindingMode::Ref(Mutability::Mut) => Some("ref mut"),
+ hir::BindingMode::Ref(Mutability::Shared) => Some("ref"),
};
- acc.push(InlayHint {
- range: pat.syntax().text_range(),
- kind: InlayKind::BindingMode,
- label: bm.into(),
- text_edit: None,
- position: InlayHintPosition::Before,
- pad_left: false,
- pad_right: true,
- resolve_parent: Some(pat.syntax().text_range()),
- });
+ if let Some(bm) = bm {
+ acc.push(InlayHint {
+ range: pat.syntax().text_range(),
+ kind: InlayKind::BindingMode,
+ label: bm.into(),
+ text_edit: None,
+ position: InlayHintPosition::Before,
+ pad_left: false,
+ pad_right: true,
+ resolve_parent: Some(pat.syntax().text_range()),
+ });
+ }
}
ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
- acc.push(InlayHint::opening_paren_before(
- InlayKind::BindingMode,
- pat.syntax().text_range(),
- ));
+ hint.label.append_str("(");
acc.push(InlayHint::closing_paren_after(
InlayKind::BindingMode,
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(())
}
@@ -154,11 +161,10 @@ fn __(
}
match &(0,) {
(x,) | (x,) => (),
- //^^^^^^^^^^^&
+ //^^^^^^^^^^^)
+ //^^^^^^^^^^^&(
//^ ref
//^ ref
- //^^^^^^^^^^^(
- //^^^^^^^^^^^)
((x,) | (x,)) => (),
//^^^^^^^^^^^^^&
//^ ref
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index 35b6287832..40d7367dba 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -8,6 +8,7 @@ use hir::Semantics;
use ide_db::{famous_defs::FamousDefs, RootDatabase};
use span::EditionedFileId;
use syntax::ast::{self, AstNode, HasName};
+use text_edit::TextEdit;
use crate::{
DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
@@ -65,11 +66,11 @@ fn variant_hints(
let eq_ = if eq_token.is_none() { " =" } else { "" };
let label = InlayHintLabel::simple(
match d {
- Ok(x) => {
- if x >= 10 {
- format!("{eq_} {x} ({x:#X})")
+ Ok(val) => {
+ if val >= 10 {
+ format!("{eq_} {val} ({val:#X})")
} else {
- format!("{eq_} {x}")
+ format!("{eq_} {val}")
}
}
Err(_) => format!("{eq_} ?"),
@@ -87,7 +88,7 @@ fn variant_hints(
},
kind: InlayKind::Discriminant,
label,
- text_edit: None,
+ text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
position: InlayHintPosition::After,
pad_left: false,
pad_right: false,
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index 8d422478cb..f15d19047c 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -9,6 +9,7 @@ use syntax::{
ast::{self, AstNode},
SyntaxKind,
};
+use text_edit::TextEdit;
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
@@ -38,7 +39,7 @@ pub(super) fn hints(
range: t.text_range(),
kind: InlayKind::Lifetime,
label: "'static".into(),
- text_edit: None,
+ text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
position: InlayHintPosition::After,
pad_left: false,
pad_right: true,