about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-12-21 15:00:05 +0000
committerMaybe Waffle <waffle.lapkin@gmail.com>2023-01-09 13:35:17 +0000
commit12b7f9f7bfb4d50ee29232d9d40430fa22db7157 (patch)
tree45b9a79b511a7c24b8f2d5b158faa8914226de59
parentb89c4f0a0529ca90dbe13d41fdd5e52331770900 (diff)
downloadrust-12b7f9f7bfb4d50ee29232d9d40430fa22db7157.tar.gz
rust-12b7f9f7bfb4d50ee29232d9d40430fa22db7157.zip
Add an option to minimize parentheses for adjustment hints
-rw-r--r--crates/ide/src/inlay_hints.rs14
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs111
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/ide/src/static_index.rs3
-rw-r--r--crates/rust-analyzer/src/config.rs35
-rw-r--r--docs/user/generated_config.adoc4
-rw-r--r--editors/code/package.json20
7 files changed, 162 insertions, 29 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 7315a37ebc7..48a7bbfecff 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -35,7 +35,7 @@ pub struct InlayHintsConfig {
     pub parameter_hints: bool,
     pub chaining_hints: bool,
     pub adjustment_hints: AdjustmentHints,
-    pub adjustment_hints_postfix: bool,
+    pub adjustment_hints_mode: AdjustmentHintsMode,
     pub adjustment_hints_hide_outside_unsafe: bool,
     pub closure_return_type_hints: ClosureReturnTypeHints,
     pub binding_mode_hints: bool,
@@ -75,6 +75,14 @@ pub enum AdjustmentHints {
     Never,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum AdjustmentHintsMode {
+    Prefix,
+    Postfix,
+    PreferPrefix,
+    PreferPostfix,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum InlayKind {
     BindingModeHint,
@@ -432,7 +440,7 @@ mod tests {
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
-    use crate::inlay_hints::AdjustmentHints;
+    use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
     use crate::DiscriminantHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
@@ -448,7 +456,7 @@ mod tests {
         lifetime_elision_hints: LifetimeElisionHints::Never,
         closure_return_type_hints: ClosureReturnTypeHints::Never,
         adjustment_hints: AdjustmentHints::Never,
-        adjustment_hints_postfix: false,
+        adjustment_hints_mode: AdjustmentHintsMode::Prefix,
         adjustment_hints_hide_outside_unsafe: false,
         binding_mode_hints: false,
         hide_named_constructor_hints: false,
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 367bd2f6619..47e854e4bd7 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -11,7 +11,7 @@ use syntax::{
     ted,
 };
 
-use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
+use crate::{AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -40,8 +40,8 @@ pub(super) fn hints(
     let desc_expr = descended.as_ref().unwrap_or(expr);
     let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
 
-    let (needs_outer_parens, needs_inner_parens) =
-        needs_parens_for_adjustment_hints(expr, config.adjustment_hints_postfix);
+    let (postfix, needs_outer_parens, needs_inner_parens) =
+        mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
 
     if needs_outer_parens {
         acc.push(InlayHint {
@@ -52,7 +52,7 @@ pub(super) fn hints(
         });
     }
 
-    if config.adjustment_hints_postfix && needs_inner_parens {
+    if postfix && needs_inner_parens {
         acc.push(InlayHint {
             range: expr.syntax().text_range(),
             kind: InlayKind::OpeningParenthesis,
@@ -68,7 +68,7 @@ pub(super) fn hints(
     }
 
     let (mut tmp0, mut tmp1);
-    let iter: &mut dyn Iterator<Item = _> = if config.adjustment_hints_postfix {
+    let iter: &mut dyn Iterator<Item = _> = if postfix {
         tmp0 = adjustments.into_iter();
         &mut tmp0
     } else {
@@ -112,20 +112,16 @@ pub(super) fn hints(
         };
         acc.push(InlayHint {
             range: expr.syntax().text_range(),
-            kind: if config.adjustment_hints_postfix {
+            kind: if postfix {
                 InlayKind::AdjustmentHintPostfix
             } else {
                 InlayKind::AdjustmentHint
             },
-            label: if config.adjustment_hints_postfix {
-                format!(".{}", text.trim_end()).into()
-            } else {
-                text.into()
-            },
+            label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() },
             tooltip: None,
         });
     }
-    if !config.adjustment_hints_postfix && needs_inner_parens {
+    if !postfix && needs_inner_parens {
         acc.push(InlayHint {
             range: expr.syntax().text_range(),
             kind: InlayKind::OpeningParenthesis,
@@ -150,6 +146,41 @@ pub(super) fn hints(
     Some(())
 }
 
+/// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`,
+/// if we are going to add (`postfix`) adjustments hints to it.
+fn mode_and_needs_parens_for_adjustment_hints(
+    expr: &ast::Expr,
+    mode: AdjustmentHintsMode,
+) -> (bool, bool, bool) {
+    use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
+
+    match mode {
+        Prefix | Postfix => {
+            let postfix = matches!(mode, Postfix);
+            let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix);
+            (postfix, inside, outside)
+        }
+        PreferPrefix | PreferPostfix => {
+            let prefer_postfix = matches!(mode, PreferPostfix);
+
+            let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false);
+            let prefix = (false, pre_inside, pre_outside);
+            let pre_count = pre_inside as u8 + pre_outside as u8;
+
+            let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true);
+            let postfix = (true, post_inside, post_outside);
+            let post_count = post_inside as u8 + post_outside as u8;
+
+            match pre_count.cmp(&post_count) {
+                Less => prefix,
+                Greater => postfix,
+                Equal if prefer_postfix => postfix,
+                Equal => prefix,
+            }
+        }
+    }
+}
+
 /// Returns whatever we need to add paretheses on the inside and/or outside of `expr`,
 /// if we are going to add (`postfix`) adjustments hints to it.
 fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
@@ -217,7 +248,7 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool,
 mod tests {
     use crate::{
         inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
-        AdjustmentHints, InlayHintsConfig,
+        AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
     };
 
     #[test]
@@ -333,7 +364,7 @@ impl Struct {
         check_with_config(
             InlayHintsConfig {
                 adjustment_hints: AdjustmentHints::Always,
-                adjustment_hints_postfix: true,
+                adjustment_hints_mode: AdjustmentHintsMode::Postfix,
                 ..DISABLED_CONFIG
             },
             r#"
@@ -420,6 +451,58 @@ impl Struct {
     }
 
     #[test]
+    fn adjustment_hints_prefer_prefix() {
+        check_with_config(
+            InlayHintsConfig {
+                adjustment_hints: AdjustmentHints::Always,
+                adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn main() {
+    let _: u32         = loop {};
+                       //^^^^^^^<never-to-any>
+
+    Struct.by_ref();
+  //^^^^^^.&
+
+    let (): () = return ();
+               //^^^^^^^^^<never-to-any>
+
+    struct Struct;
+    impl Struct { fn by_ref(&self) {} }
+}
+            "#,
+        )
+    }
+
+    #[test]
+    fn adjustment_hints_prefer_postfix() {
+        check_with_config(
+            InlayHintsConfig {
+                adjustment_hints: AdjustmentHints::Always,
+                adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn main() {
+    let _: u32         = loop {};
+                       //^^^^^^^.<never-to-any>
+
+    Struct.by_ref();
+  //^^^^^^.&
+
+    let (): () = return ();
+               //^^^^^^^^^<never-to-any>
+
+    struct Struct;
+    impl Struct { fn by_ref(&self) {} }
+}
+            "#,
+        )
+    }
+
+    #[test]
     fn never_to_never_is_never_shown() {
         check_with_config(
             InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 200958a4330..239456cb281 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -81,8 +81,8 @@ pub use crate::{
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
-        AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel,
-        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+        AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
+        InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index c6cca0d8698..a6b30ba1396 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -13,6 +13,7 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
 
 use crate::{
     hover::hover_for_definition,
+    inlay_hints::AdjustmentHintsMode,
     moniker::{def_to_moniker, MonikerResult},
     parent_module::crates_for,
     Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
@@ -115,7 +116,7 @@ impl StaticIndex<'_> {
                     closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
                     adjustment_hints: crate::AdjustmentHints::Never,
-                    adjustment_hints_postfix: false,
+                    adjustment_hints_mode: AdjustmentHintsMode::Prefix,
                     adjustment_hints_hide_outside_unsafe: false,
                     hide_named_constructor_hints: false,
                     hide_closure_initialization_hints: false,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 4d11a84091c..27a86db382d 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -333,8 +333,8 @@ config_data! {
         inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
         /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
         inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
-        /// Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc).
-        inlayHints_expressionAdjustmentHints_postfix: bool = "false",
+        /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
+        inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = "\"prefix\"",
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
         inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
         /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@@ -1254,7 +1254,12 @@ impl Config {
                 },
                 AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
             },
-            adjustment_hints_postfix: self.data.inlayHints_expressionAdjustmentHints_postfix,
+            adjustment_hints_mode: match self.data.inlayHints_expressionAdjustmentHints_mode {
+                AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
+                AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
+                AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
+                AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
+            },
             adjustment_hints_hide_outside_unsafe: self
                 .data
                 .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
@@ -1773,6 +1778,15 @@ enum DiscriminantHintsDef {
 
 #[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
+enum AdjustmentHintsModeDef {
+    Prefix,
+    Postfix,
+    PreferPrefix,
+    PreferPostfix,
+}
+
+#[derive(Deserialize, Debug, Clone)]
+#[serde(rename_all = "snake_case")]
 enum FilesWatcherDef {
     Client,
     Notify,
@@ -2104,6 +2118,21 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Only show discriminant hints on fieldless enum variants."
             ]
         },
+        "AdjustmentHintsModeDef" => set! {
+            "type": "string",
+            "enum": [
+                "prefix",
+                "postfix",
+                "prefer_prefix",
+                "prefer_postfix",
+            ],
+            "enumDescriptions": [
+                "Always show adjustment hints as prefix (`*expr`).",
+                "Always show adjustment hints as postfix (`expr.*`).",
+                "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
+                "Show prefix or postfix depending on which uses less parenthesis, prefering postfix.",
+            ]
+        },
         "CargoFeaturesDef" => set! {
             "anyOf": [
                 {
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 60c16ecadf5..0aaf07ebf38 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -469,10 +469,10 @@ Whether to show inlay hints for type adjustments.
 --
 Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
 --
-[[rust-analyzer.inlayHints.expressionAdjustmentHints.postfix]]rust-analyzer.inlayHints.expressionAdjustmentHints.postfix (default: `false`)::
+[[rust-analyzer.inlayHints.expressionAdjustmentHints.mode]]rust-analyzer.inlayHints.expressionAdjustmentHints.mode (default: `"prefix"`)::
 +
 --
-Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc).
+Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
 --
 [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index aeb1d97c5f6..5ffce2f5536 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1000,10 +1000,22 @@
                     "default": false,
                     "type": "boolean"
                 },
-                "rust-analyzer.inlayHints.expressionAdjustmentHints.postfix": {
-                    "markdownDescription": "Whether to show inlay hints for type adjustments as postfix ops (`.*` instead of `*`, etc).",
-                    "default": false,
-                    "type": "boolean"
+                "rust-analyzer.inlayHints.expressionAdjustmentHints.mode": {
+                    "markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).",
+                    "default": "prefix",
+                    "type": "string",
+                    "enum": [
+                        "prefix",
+                        "postfix",
+                        "prefer_prefix",
+                        "prefer_postfix"
+                    ],
+                    "enumDescriptions": [
+                        "Always show adjustment hints as prefix (`*expr`).",
+                        "Always show adjustment hints as postfix (`expr.*`).",
+                        "Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
+                        "Show prefix or postfix depending on which uses less parenthesis, prefering postfix."
+                    ]
                 },
                 "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
                     "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",