mirror of
https://github.com/nix-community/nixvim.git
synced 2025-06-20 16:15:43 +02:00
nvim-lsp: Add settings for rust-analyzer (#113)
* nvim-lsp: Add settings for rust-analyzer Because the settings are quite complex they are auto-generated. This commit adds the script creating it & the generated options. * Update flake.nix Co-authored-by: Pedro Alves <pta2002@users.noreply.github.com>
This commit is contained in:
parent
5b84bbb513
commit
2f2f724f6a
5 changed files with 1846 additions and 2 deletions
43
flake.nix
43
flake.nix
|
@ -35,10 +35,49 @@
|
|||
(system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
extractRustAnalyzer = { stdenv, pkgs }: stdenv.mkDerivation {
|
||||
pname = "extract_rust_analyzer";
|
||||
version = "master";
|
||||
|
||||
dontUnpack = true;
|
||||
dontBuild = true;
|
||||
|
||||
buildInputs = [ pkgs.python3 ];
|
||||
|
||||
installPhase = ''
|
||||
ls -la
|
||||
mkdir -p $out/bin
|
||||
cp ${./helpers/extract_rust_analyzer.py} $out/bin/extract_rust_analyzer.py
|
||||
'';
|
||||
};
|
||||
extractRustAnalyzerPkg = pkgs.callPackage extractRustAnalyzer { };
|
||||
in
|
||||
{
|
||||
packages.docs = pkgs.callPackage (import ./docs.nix) {
|
||||
modules = nixvimModules;
|
||||
packages = {
|
||||
docs = pkgs.callPackage (import ./docs.nix) {
|
||||
modules = nixvimModules;
|
||||
};
|
||||
runUpdates = pkgs.callPackage
|
||||
({ pkgs, stdenv }: stdenv.mkDerivation {
|
||||
pname = "run-updates";
|
||||
version = pkgs.rust-analyzer.version;
|
||||
|
||||
src = pkgs.rust-analyzer.src;
|
||||
|
||||
nativeBuildInputs = with pkgs; [extractRustAnalyzerPkg alejandra nixpkgs-fmt];
|
||||
|
||||
buildPhase = ''
|
||||
extract_rust_analyzer.py editors/code/package.json |
|
||||
alejandra --quiet |
|
||||
nixpkgs-fmt > rust-analyzer-config.nix
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/share
|
||||
cp rust-analyzer-config.nix $out/share
|
||||
'';
|
||||
})
|
||||
{ };
|
||||
};
|
||||
legacyPackages = rec {
|
||||
makeNixvimWithModule = import ./wrappers/standalone.nix pkgs modules;
|
||||
|
|
229
helpers/extract_rust_analyzer.py
Executable file
229
helpers/extract_rust_analyzer.py
Executable file
|
@ -0,0 +1,229 @@
|
|||
#!/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)
|
|
@ -197,6 +197,9 @@ let
|
|||
name = "rust-analyzer";
|
||||
description = "Enable rust-analyzer, for Rust.";
|
||||
serverName = "rust_analyzer";
|
||||
|
||||
extraOptions = import ./rust-analyzer-config.nix lib;
|
||||
settings = cfg: { rust-analyzer = cfg; };
|
||||
}
|
||||
{
|
||||
name = "sumneko-lua";
|
||||
|
|
1560
plugins/nvim-lsp/rust-analyzer-config.nix
Normal file
1560
plugins/nvim-lsp/rust-analyzer-config.nix
Normal file
File diff suppressed because it is too large
Load diff
13
plugins/nvim-lsp/update_ra.md
Normal file
13
plugins/nvim-lsp/update_ra.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# 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