mirror of
https://github.com/nix-community/nixvim.git
synced 2025-08-09 20:35:10 +02:00
dev: Add a script to generate rust-analyzer options
This commit is contained in:
parent
92e9f5466d
commit
8b6b2e5253
4 changed files with 205 additions and 13 deletions
|
@ -10,6 +10,7 @@
|
||||||
./templates.nix
|
./templates.nix
|
||||||
./tests.nix
|
./tests.nix
|
||||||
./wrappers.nix
|
./wrappers.nix
|
||||||
|
./updates
|
||||||
];
|
];
|
||||||
|
|
||||||
perSystem =
|
perSystem =
|
||||||
|
|
9
flake-modules/updates/default.nix
Normal file
9
flake-modules/updates/default.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
perSystem =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
packages = {
|
||||||
|
rust-analyzer-options = pkgs.callPackage ./rust-analyzer.nix { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
195
flake-modules/updates/rust-analyzer.nix
Normal file
195
flake-modules/updates/rust-analyzer.nix
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
#
|
||||||
|
# This derivation creates a Nix file that describes the Nix module that needs to be instantiated
|
||||||
|
#
|
||||||
|
# The create file is of the form:
|
||||||
|
#
|
||||||
|
# {
|
||||||
|
# "<rust-analyzer.option.name>" = {
|
||||||
|
# description = "<option description>";
|
||||||
|
# type = {
|
||||||
|
# kind = "<name of the type>";
|
||||||
|
# # Other values depending on the kind, like values for enum or subTypes for oneOf
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
rust-analyzer,
|
||||||
|
writeText,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
packageJSON = "${rust-analyzer.src}/editors/code/package.json";
|
||||||
|
options = (lib.importJSON packageJSON).contributes.configuration;
|
||||||
|
|
||||||
|
generatedStart = lib.lists.findFirstIndex (
|
||||||
|
e: e == { title = "$generated-start"; }
|
||||||
|
) (throw "missing generated start") options;
|
||||||
|
generatedEnd = lib.lists.findFirstIndex (
|
||||||
|
e: e == { title = "$generated-end"; }
|
||||||
|
) (throw "missing generated end") options;
|
||||||
|
|
||||||
|
# Extract only the generated properties, removing vscode specific options
|
||||||
|
rustAnalyzerProperties = lib.lists.sublist (generatedStart + 1) (
|
||||||
|
generatedEnd - generatedStart - 1
|
||||||
|
) options;
|
||||||
|
|
||||||
|
mkRustAnalyzerOptionType =
|
||||||
|
nullable: property_name:
|
||||||
|
{
|
||||||
|
type,
|
||||||
|
enum ? null,
|
||||||
|
minimum ? null,
|
||||||
|
maximum ? null,
|
||||||
|
items ? null,
|
||||||
|
anyOf ? null,
|
||||||
|
# Not used in the function, but anyOf values contain it
|
||||||
|
enumDescriptions ? null,
|
||||||
|
}@property:
|
||||||
|
if enum != null then
|
||||||
|
{
|
||||||
|
kind = "enum";
|
||||||
|
values = enum;
|
||||||
|
}
|
||||||
|
else if anyOf != null then
|
||||||
|
let
|
||||||
|
possibleTypes = lib.filter (sub: !(sub.type == "null" && nullable)) anyOf;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
kind = "oneOf";
|
||||||
|
subTypes = builtins.map (
|
||||||
|
t: mkRustAnalyzerOptionType nullable "${property_name}-sub" t
|
||||||
|
) possibleTypes;
|
||||||
|
}
|
||||||
|
else if lib.isList type then
|
||||||
|
(
|
||||||
|
if lib.head type == "null" then
|
||||||
|
assert lib.assertMsg (
|
||||||
|
lib.length type == 2
|
||||||
|
) "Lists starting with null are assumed to mean nullOr, so length 2";
|
||||||
|
let
|
||||||
|
innerType = property // {
|
||||||
|
type = lib.elemAt type 1;
|
||||||
|
};
|
||||||
|
inner = mkRustAnalyzerOptionType nullable "${property_name}-inner" innerType;
|
||||||
|
in
|
||||||
|
assert lib.assertMsg nullable "nullOr types are not yet handled";
|
||||||
|
inner
|
||||||
|
else
|
||||||
|
let
|
||||||
|
innerTypes = builtins.map (
|
||||||
|
t: mkRustAnalyzerOptionType nullable "${property_name}-inner" (property // { type = t; })
|
||||||
|
) type;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
kind = "oneOf";
|
||||||
|
subTypes = innerTypes;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else if type == "array" then
|
||||||
|
{
|
||||||
|
kind = "list";
|
||||||
|
item = mkRustAnalyzerOptionType false "${property_name}-item" items;
|
||||||
|
}
|
||||||
|
else if type == "number" || type == "integer" then
|
||||||
|
{
|
||||||
|
kind = type;
|
||||||
|
inherit minimum maximum;
|
||||||
|
}
|
||||||
|
else if
|
||||||
|
lib.elem type [
|
||||||
|
"object"
|
||||||
|
"string"
|
||||||
|
"boolean"
|
||||||
|
]
|
||||||
|
then
|
||||||
|
{ kind = type; }
|
||||||
|
else
|
||||||
|
throw "Unhandled value in ${property_name}: ${lib.generators.toPretty { } property}";
|
||||||
|
|
||||||
|
mkRustAnalyzerOption =
|
||||||
|
property_name:
|
||||||
|
{
|
||||||
|
# List all possible values so that we are sure no new values are introduced
|
||||||
|
default,
|
||||||
|
markdownDescription,
|
||||||
|
enum ? null,
|
||||||
|
enumDescriptions ? null,
|
||||||
|
anyOf ? null,
|
||||||
|
minimum ? null,
|
||||||
|
maximum ? null,
|
||||||
|
items ? null,
|
||||||
|
# TODO: add this in the documentation ?
|
||||||
|
uniqueItems ? null,
|
||||||
|
type ? null,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
enumDesc =
|
||||||
|
values: descriptions:
|
||||||
|
let
|
||||||
|
valueDesc = builtins.map ({ fst, snd }: ''- ${fst}: ${snd}'') (
|
||||||
|
lib.lists.zipLists values descriptions
|
||||||
|
);
|
||||||
|
in
|
||||||
|
''
|
||||||
|
${markdownDescription}
|
||||||
|
|
||||||
|
Values:
|
||||||
|
${builtins.concatStringsSep "\n" valueDesc}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
type = mkRustAnalyzerOptionType true property_name {
|
||||||
|
inherit
|
||||||
|
type
|
||||||
|
enum
|
||||||
|
minimum
|
||||||
|
maximum
|
||||||
|
items
|
||||||
|
anyOf
|
||||||
|
enumDescriptions
|
||||||
|
;
|
||||||
|
};
|
||||||
|
pluginDefault = default;
|
||||||
|
description =
|
||||||
|
if
|
||||||
|
enum == null && (anyOf == null || builtins.all (subProp: !(lib.hasAttr "enum" subProp)) anyOf)
|
||||||
|
then
|
||||||
|
''
|
||||||
|
${markdownDescription}
|
||||||
|
''
|
||||||
|
else if enum != null then
|
||||||
|
assert lib.assertMsg (anyOf == null) "enum + anyOf types are not yet handled";
|
||||||
|
enumDesc enum enumDescriptions
|
||||||
|
else
|
||||||
|
let
|
||||||
|
subEnums = lib.filter (lib.hasAttr "enum") anyOf;
|
||||||
|
subEnum =
|
||||||
|
assert lib.assertMsg (
|
||||||
|
lib.length subEnums == 1
|
||||||
|
) "anyOf types may currently only contain a single enum";
|
||||||
|
lib.head subEnums;
|
||||||
|
in
|
||||||
|
enumDesc subEnum.enum subEnum.enumDescriptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
rustAnalyzerOptions = builtins.map (
|
||||||
|
v:
|
||||||
|
let
|
||||||
|
props = lib.attrsToList v.properties;
|
||||||
|
prop =
|
||||||
|
assert lib.assertMsg (
|
||||||
|
lib.length props == 1
|
||||||
|
) "Rust analyzer configuration items are only supported with a single element";
|
||||||
|
lib.head props;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"${prop.name}" = mkRustAnalyzerOption prop.name prop.value;
|
||||||
|
}
|
||||||
|
) rustAnalyzerProperties;
|
||||||
|
in
|
||||||
|
writeText "rust-analyzer-options.nix" (
|
||||||
|
"# WARNING: DO NOT EDIT\n"
|
||||||
|
+ "# This file is generated with packages.<system>.rust-analyzer-options, which is run automatically by CI\n"
|
||||||
|
+ (lib.generators.toPretty { } (lib.mergeAttrsList rustAnalyzerOptions))
|
||||||
|
)
|
|
@ -1,13 +0,0 @@
|
||||||
# Updating rust-analyzer options
|
|
||||||
|
|
||||||
Because there a large number of rust-analyzer options it's difficult to handle them by hand.
|
|
||||||
|
|
||||||
The options can be fetched from the [rust-analyzer package.json](https://github.com/rust-lang/rust-analyzer/blob/master/editors/code/package.json).
|
|
||||||
|
|
||||||
There is a derivation on the top-level flake that allows to build it easily, you just have to run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix build .#rustAnalyzerOptions
|
|
||||||
```
|
|
||||||
|
|
||||||
You can then copy the `result/share/rust-analyzer-config.nix` to the correct location.
|
|
Loading…
Add table
Add a link
Reference in a new issue