oxalica / nil

NIx Language server, an incremental analysis assistant for writing in Nix.
Apache License 2.0
1.32k stars 40 forks source link

Code actions: convert `with lib;` to `let inherit (lib) ...;`, add unknown symbols to inherit #145

Open max-privatevoid opened 1 month ago

max-privatevoid commented 1 month ago

When writing module options, one ends up using various lib functions, such that using with lib; becomes tempting. Since large-scale with usage is generally considered bad practice, people sometimes opt for an alternative like this:

{ lib, ... }:

let
  inherit (lib) mkOption;
  inherit (lib.types) attrsOf str;
in

{
  options.example = mkOption {
    type = attrsOf str;
    default = { };
  };
}

Since it's annoying to type this out by hand, it would be really nice if nil offered a code action to turn a with into this kind of let-inherit-in construct. It won't be perfect in the case of nested withs, but I think it'll still be worth it for the 80% case.

On top of that, nil could offer a code action similar to the "add to imports" of LSPs in other languages, to easily add new things to the construct. On every unknown symbol, provide code actions such as Inherit this symbol from lib, Inherit this symbol from lib.types for every inherit (from) expression in scope:

{ lib, ... }:

let
  inherit (lib) mkOption;
  inherit (lib.types) attrsOf;
in

{
  options.example = mkOption {
    type = attrsOf str; # <- unknown symbol "str"
    default = { }; # --[ Inherit "str" from lib       ]
  };               # ->[ Inherit "str" from lib.types ]
}