mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-21 16:39:00 +02:00
This directly reads the package.json file in pkgs.rust-analyzer.src in order to generate the list of options for rust-analyzer. This avoids the need for a generator script, and makes sure that it is always in sync.
163 lines
4.5 KiB
Nix
163 lines
4.5 KiB
Nix
lib: pkgs:
|
|
# Future improvements:
|
|
# - extra documentation from anyOf types, they can have `enumDescriptions` that are valuable
|
|
with lib; 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;
|
|
};
|
|
|
|
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
|
|
if minimum != null && maximum != null
|
|
then types.numbers.between minimum maximum
|
|
else if minimum != null
|
|
then types.addCheck types.number (x: x >= minimum)
|
|
else if maximum != null
|
|
then types.addCheck types.number (x: x <= maximum)
|
|
else types.number
|
|
else if type == "integer"
|
|
then
|
|
if minimum != null && maximum != null
|
|
then types.ints.between minimum maximum
|
|
else if minimum != null
|
|
then types.addCheck types.int (x: x >= minimum)
|
|
else if maximum != null
|
|
then types.addCheck types.int (x: x <= maximum)
|
|
else types.int
|
|
else throw "unhandled type `${builtins.toJSON type}` (in ${opt})";
|
|
|
|
mkRustAnalyzerOption = opt: {
|
|
default,
|
|
markdownDescription,
|
|
type ? null,
|
|
anyOf ? null,
|
|
# Enum types
|
|
enum ? null,
|
|
enumDescriptions ? null,
|
|
# Int types
|
|
minimum ? null,
|
|
maximum ? null,
|
|
# List types
|
|
items ? null,
|
|
uniqueItems ? false,
|
|
}:
|
|
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}
|
|
```
|
|
'';
|
|
};
|
|
|
|
nixOptions = builtins.mapAttrs mkRustAnalyzerOption rustAnalyzerOptions;
|
|
|
|
nestOpt = opt: value: let
|
|
parts = strings.splitString "." opt;
|
|
in
|
|
builtins.foldl' (current: segment: {${segment} = current;}) value (lists.reverseList parts);
|
|
|
|
nestedNixOptions = attrsets.mapAttrsToList nestOpt nixOptions;
|
|
in
|
|
(builtins.foldl' attrsets.recursiveUpdate {} nestedNixOptions).rust-analyzer
|