mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-20 16:15:43 +02:00
This changes how we think about this directory; it does not need to be exclusively for scripts related to updates, but should be a place for any scripts intended to be run by CI workflows. This mindset should make it easier to develop and test the business logic of workflows, without always needing to test "in production" on the nixvim repo or a fork.
234 lines
7.1 KiB
Nix
234 lines
7.1 KiB
Nix
#
|
|
# 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,
|
|
pandoc,
|
|
runCommand,
|
|
}:
|
|
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: property:
|
|
let
|
|
inner =
|
|
{
|
|
type ? null,
|
|
enum ? null,
|
|
minimum ? null,
|
|
maximum ? null,
|
|
items ? null,
|
|
anyOf ? null,
|
|
properties ? 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
|
|
(
|
|
assert lib.assertMsg (type != null) "property is neither anyOf nor enum, it must have a type";
|
|
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 type == "object" && properties != null then
|
|
{
|
|
kind = "submodule";
|
|
options = lib.mapAttrs (
|
|
name: value: mkRustAnalyzerOptionType false "${property_name}.${name}" value
|
|
) properties;
|
|
}
|
|
else if
|
|
lib.elem type [
|
|
"object"
|
|
"string"
|
|
"boolean"
|
|
]
|
|
then
|
|
{ kind = type; }
|
|
else
|
|
throw "Unhandled value in ${property_name}: ${lib.generators.toPretty { } property}"
|
|
);
|
|
in
|
|
builtins.addErrorContext "While creating type for ${property_name}:\n${lib.generators.toPretty { } property}" (
|
|
inner 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
|
|
filteredMarkdownDesc =
|
|
# If there is a risk that the string contains an heading filter it out
|
|
if lib.hasInfix "# " markdownDescription then
|
|
builtins.readFile (
|
|
runCommand "filtered-documentation" { inherit markdownDescription; } ''
|
|
${lib.getExe pandoc} -o $out -t markdown \
|
|
--lua-filter=${./heading_filter.lua} <<<"$markdownDescription"
|
|
''
|
|
)
|
|
else
|
|
markdownDescription;
|
|
|
|
enumDesc =
|
|
values: descriptions:
|
|
let
|
|
valueDesc = builtins.map ({ fst, snd }: ''- ${fst}: ${snd}'') (
|
|
lib.lists.zipLists values descriptions
|
|
);
|
|
in
|
|
''
|
|
${filteredMarkdownDesc}
|
|
|
|
Values:
|
|
${builtins.concatStringsSep "\n" valueDesc}
|
|
'';
|
|
in
|
|
{
|
|
type = mkRustAnalyzerOptionType true property_name {
|
|
inherit
|
|
type
|
|
enum
|
|
minimum
|
|
maximum
|
|
items
|
|
anyOf
|
|
enumDescriptions
|
|
;
|
|
};
|
|
pluginDefault = default;
|
|
description =
|
|
let
|
|
globalDescription = ''
|
|
${filteredMarkdownDesc}
|
|
'';
|
|
in
|
|
if
|
|
enum == null && (anyOf == null || builtins.all (subProp: !(lib.hasAttr "enum" subProp)) anyOf)
|
|
then
|
|
globalDescription
|
|
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
|
|
if subEnum ? enumDescriptions then
|
|
enumDesc subEnum.enum subEnum.enumDescriptions
|
|
else
|
|
globalDescription;
|
|
|
|
};
|
|
|
|
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))
|
|
)
|