diff --git a/plugins/languages/rust/rust-tools.nix b/plugins/languages/rust/rust-tools.nix index 3b1bbd6e..b73ea5e4 100644 --- a/plugins/languages/rust/rust-tools.nix +++ b/plugins/languages/rust/rust-tools.nix @@ -123,7 +123,7 @@ in standalone file support setting it to false may improve startup time ''; - }; # // (import ../../lsp/language-servers/rust-analyzer-config.nix lib pkgs); + } // (import ../../lsp/language-servers/rust-analyzer-config.nix lib helpers); }; config = mkIf cfg.enable { extraPlugins = with pkgs.vimPlugins; [ diff --git a/plugins/languages/rust/rustaceanvim/settings-options.nix b/plugins/languages/rust/rustaceanvim/settings-options.nix index 45fe0b30..b135ca46 100644 --- a/plugins/languages/rust/rustaceanvim/settings-options.nix +++ b/plugins/languages/rust/rustaceanvim/settings-options.nix @@ -257,8 +257,7 @@ with lib; settings = helpers.mkNullOrStrLuaFnOr (types.submodule { - # options = import ../../../lsp/language-servers/rust-analyzer-config.nix lib pkgs; - options = { }; + options = import ../../../lsp/language-servers/rust-analyzer-config.nix lib helpers; freeformType = with types; attrsOf anything; }) '' diff --git a/plugins/lsp/language-servers/default.nix b/plugins/lsp/language-servers/default.nix index 693bf7f2..ec15c618 100644 --- a/plugins/lsp/language-servers/default.nix +++ b/plugins/lsp/language-servers/default.nix @@ -488,7 +488,7 @@ let description = "rust-analyzer for Rust"; serverName = "rust_analyzer"; - # settingsOptions = import ./rust-analyzer-config.nix lib pkgs; + settingsOptions = import ./rust-analyzer-config.nix lib helpers; settings = cfg: { rust-analyzer = cfg; }; } { diff --git a/plugins/lsp/language-servers/rust-analyzer-config.nix b/plugins/lsp/language-servers/rust-analyzer-config.nix index 80f2f61b..17362cc4 100644 --- a/plugins/lsp/language-servers/rust-analyzer-config.nix +++ b/plugins/lsp/language-servers/rust-analyzer-config.nix @@ -1,167 +1,69 @@ -lib: pkgs: -# Future improvements: -# - extra documentation from anyOf types, they can have `enumDescriptions` that are valuable -with lib; +# TODO: make all the types support raw lua +lib: helpers: let - packageJson = "${pkgs.rust-analyzer.src}/editors/code/package.json"; - - options = (trivial.importJSON packageJson).contributes.configuration.properties; - - packageJsonTxt = strings.splitString "\n" (builtins.readFile packageJson); - vscodeStart = lists.findFirstIndex ( - x: x == " \"configuration\": {" - ) (throw "no configuration") packageJsonTxt; - vscodeEnd = - lists.findFirstIndex (strings.hasInfix "generated-start") (throw "no generated start") - packageJsonTxt; - vscodeOptions = lists.sublist vscodeStart (vscodeEnd - vscodeStart) packageJsonTxt; - - vscodeOptionNames = builtins.map ( - x: strings.removeSuffix "\": {" (strings.removePrefix " \"" x) - ) (lists.filter (strings.hasPrefix " \"rust-analyzer.") vscodeOptions); - - rustAnalyzerOptions = builtins.removeAttrs options ( - vscodeOptionNames - ++ [ - "\$generated-start" - "\$generated-end" - ] - ); - - nullType = mkOptionType { - name = "nullType"; - description = "null"; - descriptionClass = "noun"; - merge = mergeEqualOption; - check = e: e == null; - }; + rustAnalyzerOptions = import ../../../generated/rust-analyzer.nix; mkRustAnalyzerType = - opt: - { - type, - enum ? null, - minimum ? null, - maximum ? null, - items ? null, - anyOf ? null, - uniqueItems ? null, - # unused, but for exhaustivness - enumDescriptions ? null, - }@def: - if enum != null then - types.enum enum - else if anyOf != null then - types.oneOf (builtins.map (mkRustAnalyzerType opt) anyOf) - else if builtins.isList type then - if builtins.length type == 2 && builtins.head type == "null" then - types.nullOr (mkRustAnalyzerType opt (def // { type = builtins.elemAt type 1; })) - else - types.oneOf (builtins.map (t: mkRustAnalyzerType opt (def // { type = t; })) type) - else if type == "boolean" then - types.bool - else if type == "object" then - types.attrsOf types.anything - else if type == "string" then - types.str - else if type == "null" then - nullType - else if type == "array" then - types.listOf ( - mkRustAnalyzerType "${opt}-items" ( - if items == null then throw "null items with array type (in ${opt})" else items - ) - ) - else if type == "number" then + { kind, ... }@typeInfo: + if kind == "enum" then + lib.types.enum typeInfo.values + else if kind == "oneOf" then + lib.types.oneOf (lib.map mkRustAnalyzerType typeInfo.subTypes) + else if kind == "list" then + lib.types.listOf (mkRustAnalyzerType typeInfo.item) + else if kind == "number" then + let + inherit (typeInfo) minimum maximum; + in if minimum != null && maximum != null then - types.numbers.between minimum maximum + lib.types.numbers.between minimum maximum else if minimum != null then - types.addCheck types.number (x: x >= minimum) + lib.types.addCheck lib.types.number (x: x >= minimum) else if maximum != null then - types.addCheck types.number (x: x <= maximum) + lib.types.addCheck lib.types.number (x: x <= maximum) else - types.number - else if type == "integer" then + lib.types.number + else if kind == "integer" then + let + inherit (typeInfo) minimum maximum; + in if minimum != null && maximum != null then - types.ints.between minimum maximum + lib.types.ints.between minimum maximum else if minimum != null then - types.addCheck types.int (x: x >= minimum) + lib.types.addCheck lib.types.int (x: x >= minimum) else if maximum != null then - types.addCheck types.int (x: x <= maximum) + lib.types.addCheck lib.types.int (x: x <= maximum) else - types.int + lib.types.int + else if kind == "object" then + lib.types.attrsOf lib.types.anything + else if kind == "string" then + lib.types.str + else if kind == "boolean" then + lib.types.bool else - throw "unhandled type `${builtins.toJSON type}` (in ${opt})"; + throw "Unknown type: ${kind}"; - mkRustAnalyzerOption = - opt: + mkNixOption = { - default, - markdownDescription, - type ? null, - anyOf ? null, - # Enum types - enum ? null, - enumDescriptions ? null, - # Int types - minimum ? null, - maximum ? null, - # List types - items ? null, - uniqueItems ? false, + description, + pluginDefault, + type, }: - mkOption { - type = types.nullOr ( - mkRustAnalyzerType opt { - inherit - type - enum - minimum - maximum - items - anyOf - uniqueItems - ; - } - ); - default = null; - description = - if enum != null then - let - valueDesc = builtins.map ({ fst, snd }: ''- ${fst}: ${snd}'') ( - lists.zipLists enum enumDescriptions - ); - in - '' - ${markdownDescription} - - Values: - ${builtins.concatStringsSep "\n" valueDesc} - - ```nix - ${generators.toPretty { } default} - ``` - '' - else - '' - ${markdownDescription} - - default: - ```nix - ${generators.toPretty { } default} - ``` - ''; + helpers.defaultNullOpts.mkNullable' { + inherit description pluginDefault; + type = mkRustAnalyzerType type; }; - nixOptions = builtins.mapAttrs mkRustAnalyzerOption rustAnalyzerOptions; - nestOpt = opt: value: let - parts = strings.splitString "." opt; + parts = lib.strings.splitString "." opt; in - builtins.foldl' (current: segment: { ${segment} = current; }) value (lists.reverseList parts); + lib.setAttrByPath parts value; - nestedNixOptions = attrsets.mapAttrsToList nestOpt nixOptions; + nestedNixOptions = lib.attrsets.mapAttrsToList ( + name: value: nestOpt name (mkNixOption value) + ) rustAnalyzerOptions; in -(builtins.foldl' attrsets.recursiveUpdate { } nestedNixOptions).rust-analyzer +(builtins.foldl' lib.attrsets.recursiveUpdate { } nestedNixOptions).rust-analyzer