mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-21 00:25:42 +02:00
update-script/rust-analyzer: Filter out headers from option descriptions
Headers are not allowed in nixpkgs option descriptions.
This commit is contained in:
parent
ad704ddba7
commit
dbf6f7bc99
4 changed files with 44 additions and 24 deletions
217
update-scripts/rust-analyzer/default.nix
Normal file
217
update-scripts/rust-analyzer/default.nix
Normal file
|
@ -0,0 +1,217 @@
|
|||
#
|
||||
# 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:
|
||||
{
|
||||
type,
|
||||
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 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}";
|
||||
|
||||
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 =
|
||||
if
|
||||
enum == null && (anyOf == null || builtins.all (subProp: !(lib.hasAttr "enum" subProp)) anyOf)
|
||||
then
|
||||
''
|
||||
${filteredMarkdownDesc}
|
||||
''
|
||||
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))
|
||||
)
|
3
update-scripts/rust-analyzer/heading_filter.lua
Normal file
3
update-scripts/rust-analyzer/heading_filter.lua
Normal file
|
@ -0,0 +1,3 @@
|
|||
function Header(elem)
|
||||
return pandoc.Strong(elem.content)
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue