about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-05-04 15:19:00 +0200
committerLukas Wirth <lukastw97@gmail.com>2022-05-04 15:29:25 +0200
commit73df43f69a819e82ecf101719c19c939b3d10209 (patch)
tree427a0729ee5bbbb01ac7264eb390c753d86923f6
parent291f94e22e4ef3a9c61dbd40728c9f8cef34f886 (diff)
downloadrust-73df43f69a819e82ecf101719c19c939b3d10209.tar.gz
rust-73df43f69a819e82ecf101719c19c939b3d10209.zip
Implement old to new config patching
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/config/patch_old_style.rs115
2 files changed, 118 insertions, 0 deletions
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 75c1a31e934..4d7db826c54 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -35,6 +35,8 @@ use crate::{
     lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
 };
 
+mod patch_old_style;
+
 // Conventions for configuration keys to preserve maximal extendability without breakage:
 //  - Toggles (be it binary true/false or with more options in-between) should almost always suffix as `_enable`
 //    This has the benefit of namespaces being extensible, and if the suffix doesn't fit later it can be changed without breakage.
@@ -592,6 +594,7 @@ impl Config {
                 .into_iter()
                 .map(AbsPathBuf::assert)
                 .collect();
+        patch_old_style::patch_json_for_outdated_configs(&mut json);
         self.data = ConfigData::from_json(json, &mut errors);
         self.snippets.clear();
         for (name, def) in self.data.completion_snippets_custom.iter() {
diff --git a/crates/rust-analyzer/src/config/patch_old_style.rs b/crates/rust-analyzer/src/config/patch_old_style.rs
new file mode 100644
index 00000000000..277364cefa0
--- /dev/null
+++ b/crates/rust-analyzer/src/config/patch_old_style.rs
@@ -0,0 +1,115 @@
+//! See [`patch_json_for_outdated_configs`]
+use serde_json::{json, Value};
+
+/// This function patches the json config to the new expected keys.
+/// That is we try to load old known config keys here and convert them to the new ones.
+/// See https://github.com/rust-lang/rust-analyzer/pull/12010
+pub(super) fn patch_json_for_outdated_configs(json: &mut Value) {
+    let copy = json.clone();
+
+    macro_rules! patch {
+        ($(
+            $($src:ident).+ -> $($dst:ident).+ ;
+        )+) => { $(
+            if let Some(it) = copy.pointer(concat!($("/", stringify!($src)),+)).cloned() {
+                let mut last = it;
+                for segment in [$(stringify!($dst)),+].into_iter().rev() {
+                    last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_string(), last))));
+                }
+
+                merge(json, last);
+            }
+        )+ };
+    }
+
+    patch! {
+        assist.allowMergingIntoGlobImports -> imports.merge.glob;
+        assist.exprFillDefault -> assist.expressionFillDefault;
+        assist.importEnforceGranularity -> imports.granularity.enforce;
+        assist.importGranularity -> imports.granularity.group;
+        assist.importMergeBehavior -> imports.granularity.group;
+        assist.importMergeBehaviour -> imports.granularity.group;
+        assist.importGroup -> imports.group.enable;
+        assist.importPrefix -> imports.prefix;
+        cache.warmup -> primeCaches.enable;
+        cargo.loadOutDirsFromCheck -> cargo.buildScripts.enable;
+        cargo.runBuildScripts -> cargo.runBuildScripts.overrideCommand;
+        cargo.runBuildScriptsCommand -> cargo.runBuildScripts.overrideCommand;
+        cargo.useRustcWrapperForBuildScripts -> cargo.runBuildScripts.useRustcWrapper;
+        completion.snippets -> completion.snippets.custom;
+        diagnostics.enableExperimental -> diagnostics.experimental.enable;
+        experimental.procAttrMacros -> procMacro.attributes.enable;
+        highlighting.strings -> semanticHighlighting.strings.enable;
+        highlightRelated.breakPoints -> semanticHighlighting.breakPoints.enable;
+        highlightRelated.exitPoints -> semanticHighlighting.exitPoints.enable;
+        highlightRelated.yieldPoints -> semanticHighlighting.yieldPoints.enable;
+        highlightRelated.references -> semanticHighlighting.references.enable;
+        hover.documentation -> hover.documentation.enable;
+        hover.linksInHover -> hover.links.enable;
+        hoverActions.linksInHover -> hover.links.enable;
+        hoverActions.debug -> hoverActions.debug.enable;
+        hoverActions.enable -> hoverActions.enable.enable;
+        hoverActions.gotoTypeDef -> hoverActions.gotoTypeDef.enable;
+        hoverActions.implementations -> hoverActions.implementations.enable;
+        hoverActions.references -> hoverActions.references.enable;
+        hoverActions.run -> hoverActions.run.enable;
+        inlayHints.chainingHints -> inlayHints.chainingHints.enable;
+        inlayHints.closureReturnTypeHints -> inlayHints.closureReturnTypeHints.enable;
+        inlayHints.hideNamedConstructorHints -> inlayHints.typeHints.hideNamedConstructorHints;
+        inlayHints.parameterHints -> inlayHints.parameterHints.enable;
+        inlayHints.reborrowHints -> inlayHints.reborrowHints.enable;
+        inlayHints.typeHints -> inlayHints.typeHints.enable;
+        lruCapacity -> lru.capacity;
+        runnables.cargoExtraArgs -> runnables.extraArgs ;
+        runnables.overrideCargo -> runnables.command ;
+        rustcSource -> rustc.source;
+        rustfmt.enableRangeFormatting -> rustfmt.rangeFormatting.enable;
+    }
+
+    // callInfo_full -> signatureInfo_detail, signatureInfo_documentation_enable
+    if let Some(Value::Bool(b)) = copy.pointer("/callInfo/full") {
+        let sig_info = match b {
+            true => json!({ "signatureInfo": {
+                "documentation": {"enable": true}},
+                "detail": "full"
+            }),
+            false => json!({ "signatureInfo": {
+                "documentation": {"enable": false}},
+                "detail": "parameters"
+            }),
+        };
+        merge(json, sig_info);
+    }
+
+    // cargo_allFeatures, cargo_features -> cargo_features
+    if let Some(Value::Bool(true)) = copy.pointer("/cargo/allFeatures") {
+        merge(json, json!({ "cargo": { "features": "all" } }));
+    }
+
+    // checkOnSave_allFeatures, checkOnSave_features -> checkOnSave_features
+    if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") {
+        merge(json, json!({ "checkOnSave": { "features": "all" } }));
+    }
+
+    // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets
+    let res = match (
+        copy.pointer("/completion/addCallArgumentSnippets"),
+        copy.pointer("/completion/addCallParenthesis"),
+    ) {
+        (Some(Value::Bool(true)), Some(Value::Bool(true))) => json!("fill_arguments"),
+        (Some(Value::Bool(true)), _) => json!("add_parentheses"),
+        (_, _) => json!(null),
+    };
+    merge(json, json!({ "completion": { "callable": {"snippets": res }} }));
+}
+
+fn merge(dst: &mut Value, src: Value) {
+    match (dst, src) {
+        (Value::Object(dst), Value::Object(src)) => {
+            for (k, v) in src {
+                merge(dst.entry(k).or_insert(v.clone()), v)
+            }
+        }
+        (dst, src) => *dst = src,
+    }
+}