mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-22 08:53:28 +02:00
plugins/lsp: Extract rust-analyzer options from the source directly (#562)
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.
This commit is contained in:
parent
26626aa1b1
commit
33cffcb0fd
7 changed files with 152 additions and 2239 deletions
1
.github/workflows/update.yml
vendored
1
.github/workflows/update.yml
vendored
|
@ -24,7 +24,6 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
git checkout update_flake_lock_action
|
git checkout update_flake_lock_action
|
||||||
nix build .#autogenerated-configs
|
nix build .#autogenerated-configs
|
||||||
cp result/rust-analyzer-config.nix ./plugins/lsp/language-servers/rust-analyzer-config.nix
|
|
||||||
cp result/efmls-configs-tools.json ./plugins/lsp/language-servers/efmls-configs-tools.json
|
cp result/efmls-configs-tools.json ./plugins/lsp/language-servers/efmls-configs-tools.json
|
||||||
git add ./plugins
|
git add ./plugins
|
||||||
git commit -m "autogenerated: Update options"
|
git commit -m "autogenerated: Update options"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
pkgs: rec {
|
pkgs: rec {
|
||||||
rust-analyzer-config = pkgs.callPackage ./rust-analyzer {};
|
|
||||||
efmls-configs-tools = pkgs.callPackage ./efmls-configs {};
|
efmls-configs-tools = pkgs.callPackage ./efmls-configs {};
|
||||||
autogenerated-configs = pkgs.callPackage ({stdenv}:
|
autogenerated-configs = pkgs.callPackage ({stdenv}:
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
|
@ -11,7 +10,6 @@ pkgs: rec {
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
cp ${rust-analyzer-config}/share/* $out
|
|
||||||
cp ${efmls-configs-tools}/share/* $out
|
cp ${efmls-configs-tools}/share/* $out
|
||||||
'';
|
'';
|
||||||
}) {};
|
}) {};
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
stdenv,
|
|
||||||
python3,
|
|
||||||
rust-analyzer,
|
|
||||||
alejandra,
|
|
||||||
}: let
|
|
||||||
extract = stdenv.mkDerivation {
|
|
||||||
pname = "extract_rust_analyzer";
|
|
||||||
version = "1";
|
|
||||||
|
|
||||||
src = ./extract.py;
|
|
||||||
|
|
||||||
dontUnpack = true;
|
|
||||||
dontBuild = true;
|
|
||||||
|
|
||||||
buildInputs = [python3];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp $src $out/bin/extract_rust_analyzer.py
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
pname = "rust-analyzer-config";
|
|
||||||
inherit (rust-analyzer) version src;
|
|
||||||
|
|
||||||
nativeBuildInputs = [alejandra extract];
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
extract_rust_analyzer.py editors/code/package.json |
|
|
||||||
alejandra --quiet > rust-analyzer-config.nix
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/share
|
|
||||||
cp rust-analyzer-config.nix $out/share
|
|
||||||
'';
|
|
||||||
}
|
|
|
@ -1,229 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
|
|
||||||
ra_package_json = sys.argv[1]
|
|
||||||
with open(ra_package_json) as f:
|
|
||||||
ra_package = json.load(f)
|
|
||||||
|
|
||||||
config = ra_package["contributes"]["configuration"]["properties"]
|
|
||||||
|
|
||||||
config_dict = {}
|
|
||||||
|
|
||||||
in_common_block = False
|
|
||||||
|
|
||||||
|
|
||||||
def py_to_nix(obj):
|
|
||||||
if obj is None:
|
|
||||||
return "null"
|
|
||||||
|
|
||||||
if obj is False:
|
|
||||||
return "false"
|
|
||||||
|
|
||||||
if obj is True:
|
|
||||||
return "true"
|
|
||||||
|
|
||||||
if isinstance(obj, str):
|
|
||||||
s = f'"{obj}"'
|
|
||||||
if "${" in s:
|
|
||||||
s = s.replace("${", "$\\{")
|
|
||||||
return s
|
|
||||||
|
|
||||||
if isinstance(obj, int):
|
|
||||||
return f"{obj}"
|
|
||||||
|
|
||||||
if isinstance(obj, dict):
|
|
||||||
val = "{"
|
|
||||||
for key in obj:
|
|
||||||
key_val = py_to_nix(obj[key])
|
|
||||||
val += f'"{key}" = {key_val};\n'
|
|
||||||
val += "}"
|
|
||||||
|
|
||||||
return val
|
|
||||||
|
|
||||||
if isinstance(obj, list):
|
|
||||||
return "[" + " ".join(py_to_nix(val) for val in obj) + "]"
|
|
||||||
|
|
||||||
print(f"Unhandled value: {obj}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def ty_to_nix(ty):
|
|
||||||
if ty == "boolean":
|
|
||||||
return "types.bool"
|
|
||||||
|
|
||||||
if ty == "string":
|
|
||||||
return "types.str"
|
|
||||||
|
|
||||||
# This is an object without any additional properties
|
|
||||||
if ty == "object":
|
|
||||||
return "types.attrsOf types.anything"
|
|
||||||
|
|
||||||
if isinstance(ty, list) and ty[0] == "null":
|
|
||||||
if len(ty) > 2:
|
|
||||||
print("Unhandled type", ty)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
nullable_ty = ty_to_nix(ty[1])
|
|
||||||
return f"types.nullOr ({nullable_ty})"
|
|
||||||
|
|
||||||
if isinstance(ty, list):
|
|
||||||
either_types = (ty_to_nix(t) for t in ty)
|
|
||||||
either_types = " ".join(f"({t})" for t in either_types)
|
|
||||||
return f"types.oneOf ([{either_types}])"
|
|
||||||
|
|
||||||
print(f"Unhandled type: {ty}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def prop_ty_to_nix(prop_info):
|
|
||||||
if "type" in prop_info:
|
|
||||||
if "enum" in prop_info:
|
|
||||||
enum = "[" + " ".join(f'"{member}"' for member in prop_info["enum"]) + "]"
|
|
||||||
if prop_info["type"] == "string":
|
|
||||||
return f"types.enum {enum}"
|
|
||||||
|
|
||||||
print("TODO: with unknown enum type", prop_info["type"])
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if "additionalProperties" in prop_info or "properties" in prop_info:
|
|
||||||
print("TODO: with (additional)Properties", prop_info)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if "minimum" in prop_info or "maximum" in prop_info:
|
|
||||||
can_be_null = False
|
|
||||||
if "null" in prop_info["type"]:
|
|
||||||
can_be_null = True
|
|
||||||
if len(prop_info["type"]) > 2:
|
|
||||||
print("Unhandled int type", prop_info["type"])
|
|
||||||
sys.exit()
|
|
||||||
prop_info["type"] = prop_info["type"][1]
|
|
||||||
|
|
||||||
if prop_info["type"] == "number":
|
|
||||||
int_ty = "types.number"
|
|
||||||
elif prop_info["type"] == "integer":
|
|
||||||
int_ty = "types.int"
|
|
||||||
else:
|
|
||||||
print("Unhandled int type", prop_info["type"])
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if "minimum" in prop_info and "maximum" in prop_info:
|
|
||||||
min = prop_info["minimum"]
|
|
||||||
max = prop_info["maximum"]
|
|
||||||
int_ty = f"{int_ty}s.between {min} {max}"
|
|
||||||
elif "minimum" in prop_info:
|
|
||||||
min = prop_info["minimum"]
|
|
||||||
int_ty = f"types.addCheck {int_ty} (x: x >= {min})"
|
|
||||||
else:
|
|
||||||
print("TODO: max number", prop_info)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
if can_be_null:
|
|
||||||
return f"types.nullOr ({int_ty})"
|
|
||||||
else:
|
|
||||||
return int_ty
|
|
||||||
|
|
||||||
if "array" in prop_info["type"] or prop_info["type"] == "array":
|
|
||||||
if "items" not in prop_info:
|
|
||||||
print("Array without items")
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
items_ty = prop_ty_to_nix(prop_info["items"])
|
|
||||||
array_ty = f"types.listOf ({items_ty})"
|
|
||||||
if prop_info["type"] == "array":
|
|
||||||
return array_ty
|
|
||||||
elif prop_info["type"] == ["null", "array"]:
|
|
||||||
return f"types.nullOr ({array_ty})"
|
|
||||||
else:
|
|
||||||
print("Unhandled array type", prop_info)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
return ty_to_nix(prop_info["type"])
|
|
||||||
elif "anyOf" in prop_info:
|
|
||||||
can_be_null = False
|
|
||||||
if {"type": "null"} in prop_info["anyOf"]:
|
|
||||||
can_be_null = True
|
|
||||||
prop_info["anyOf"].remove({"type": "null"})
|
|
||||||
|
|
||||||
types = (prop_ty_to_nix(prop) for prop in prop_info["anyOf"])
|
|
||||||
one_of = " ".join(f"({ty})" for ty in types)
|
|
||||||
one_of_ty = f"types.oneOf ([{one_of}])"
|
|
||||||
|
|
||||||
if can_be_null:
|
|
||||||
return f"types.nullOr ({one_of_ty})"
|
|
||||||
else:
|
|
||||||
return one_of_ty
|
|
||||||
else:
|
|
||||||
print("TODO: no *type*", prop_info)
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
|
|
||||||
for opt in config:
|
|
||||||
if opt.startswith("$"):
|
|
||||||
in_common_block = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if not in_common_block:
|
|
||||||
continue
|
|
||||||
|
|
||||||
opt_path = opt.split(".")
|
|
||||||
if opt_path[0] != "rust-analyzer":
|
|
||||||
print("ERROR: expected all options to start with 'rust-analyzer'")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
path = opt_path[1:-1]
|
|
||||||
option = opt_path[-1]
|
|
||||||
|
|
||||||
top_dict = config_dict
|
|
||||||
|
|
||||||
for p in path:
|
|
||||||
if not p in top_dict:
|
|
||||||
top_dict[p] = {}
|
|
||||||
top_dict = top_dict[p]
|
|
||||||
|
|
||||||
prop_info = config[opt]
|
|
||||||
|
|
||||||
is_optional = False
|
|
||||||
|
|
||||||
ty = prop_ty_to_nix(prop_info)
|
|
||||||
|
|
||||||
default = py_to_nix(prop_info["default"])
|
|
||||||
|
|
||||||
if "markdownDescription" in prop_info:
|
|
||||||
desc = prop_info["markdownDescription"]
|
|
||||||
else:
|
|
||||||
desc = prop_info["description"]
|
|
||||||
|
|
||||||
desc += f"\n\ndefault value is: \n```nix\n {default}\n```"
|
|
||||||
|
|
||||||
top_dict[
|
|
||||||
option
|
|
||||||
] = """
|
|
||||||
mkOption {{
|
|
||||||
type = types.nullOr ({ty});
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
{desc}
|
|
||||||
'';
|
|
||||||
}}
|
|
||||||
""".format(
|
|
||||||
ty=ty, default=default, desc=desc
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def print_dict(d):
|
|
||||||
print("{")
|
|
||||||
for key in d:
|
|
||||||
print(f'"{key}" = ')
|
|
||||||
if isinstance(d[key], str):
|
|
||||||
print(d[key])
|
|
||||||
else:
|
|
||||||
print_dict(d[key])
|
|
||||||
print(";")
|
|
||||||
print("}")
|
|
||||||
|
|
||||||
|
|
||||||
print("# THIS FILE IS AUTOGENERATED DO NOT EDIT")
|
|
||||||
print("lib: with lib;")
|
|
||||||
print_dict(config_dict)
|
|
|
@ -130,7 +130,7 @@ in {
|
||||||
setting it to false may improve startup time
|
setting it to false may improve startup time
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
// (import ../lsp/language-servers/rust-analyzer-config.nix lib));
|
// (import ../lsp/language-servers/rust-analyzer-config.nix lib pkgs));
|
||||||
};
|
};
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
extraPlugins = with pkgs.vimPlugins; [nvim-lspconfig cfg.package];
|
extraPlugins = with pkgs.vimPlugins; [nvim-lspconfig cfg.package];
|
||||||
|
|
|
@ -467,7 +467,7 @@ with lib; let
|
||||||
description = "Enable rust-analyzer, for Rust.";
|
description = "Enable rust-analyzer, for Rust.";
|
||||||
serverName = "rust_analyzer";
|
serverName = "rust_analyzer";
|
||||||
|
|
||||||
settingsOptions = import ./rust-analyzer-config.nix lib;
|
settingsOptions = import ./rust-analyzer-config.nix lib pkgs;
|
||||||
settings = cfg: {rust-analyzer = cfg;};
|
settings = cfg: {rust-analyzer = cfg;};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue