summary refs log tree commit diff
path: root/lib/modules.nix
diff options
context:
space:
mode:
authorJade Lovelace <software@lfcode.ca>2022-12-28 23:39:05 +0100
committerJade Lovelace <software@lfcode.ca>2023-09-08 11:48:40 +0200
commita1d38823079bdf7836dd44392e5e1029087d8c85 (patch)
tree8aaea0a9751c780533df6c784565864196bb89ee /lib/modules.nix
parent450d6437aeda4c90bb948f6f1f7d25a005ab9bb2 (diff)
downloadnixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar.gz
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar.bz2
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar.lz
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar.xz
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.tar.zst
nixpkgs-a1d38823079bdf7836dd44392e5e1029087d8c85.zip
nixos/modules: Add declarationPositions
What it does: line and column level *declaration* position information:

$ nix repl .
nix-repl> :p nixosConfigurations.micro.options.environment.systemPackages.declarationPositions
[ { column = 7; file = "/nix/store/24aj3k7fgqv3ly7qkbf98qvphasrw9nb-source/nixos/modules/config/system-path.nix"; line = 63; } ]

Use cases:
- ctags over NixOS options, as will be presented at NixCon 2023 ;)
- improving the documentation pages to go to the exact line of the
  declarations.

Related work:
- https://github.com/NixOS/nixpkgs/pull/65024

  This one does it for all *definitions* rather than declarations, and
  it was not followed through with due to performance worries.
- https://github.com/NixOS/nixpkgs/pull/208173

  The basis for this change. This change is just a rebase of that one.
  I split it out to add the capability before adding users of it, in
  order to simplify review. However, the ctags script in there is a
  sample user of this feature.

Benchmarks: conducted by evaluating my own reasonably complex NixOS
configuration with the command:
`hyperfine -S none -w 1 -- "nix eval .#nixosConfigurations.snowflake.config.system.build.toplevel.outPath"`

```
Benchmark 1: nix eval .#nixosConfigurations.snowflake.config.system.build.toplevel.outPath
  Time (mean ± σ):      8.971 s ±  0.254 s    [User: 5.872 s, System: 1.388 s]
  Range (min … max):    8.574 s …  9.327 s    10 runs

Benchmark 1: nix eval .#nixosConfigurations.snowflake.config.system.build.toplevel.outPath
  Time (mean ± σ):      8.766 s ±  0.160 s    [User: 5.873 s, System: 1.346 s]
  Range (min … max):    8.496 s …  9.033 s    10 runs
```

Summary of results: it seems to be in the noise, this does not cause any
visible regression in times.
Diffstat (limited to 'lib/modules.nix')
-rw-r--r--lib/modules.nix15
1 files changed, 11 insertions, 4 deletions
diff --git a/lib/modules.nix b/lib/modules.nix
index 4966619f663..a6f8b77deb2 100644
--- a/lib/modules.nix
+++ b/lib/modules.nix
@@ -537,7 +537,7 @@ let
     mergeModules' prefix modules
       (concatMap (m: map (config: { file = m._file; inherit config; }) (pushDownProperties m.config)) modules);
 
-  mergeModules' = prefix: options: configs:
+  mergeModules' = prefix: modules: configs:
     let
       # an attrset 'name' => list of submodules that declare ‘name’.
       declsByName =
@@ -554,11 +554,11 @@ let
               else
                 mapAttrs
                   (n: option:
-                    [{ inherit (module) _file; options = option; }]
+                    [{ inherit (module) _file; pos = builtins.unsafeGetAttrPos n subtree; options = option; }]
                   )
                   subtree
               )
-            options);
+            modules);
 
       # The root of any module definition must be an attrset.
       checkedConfigs =
@@ -730,9 +730,16 @@ let
             else res.options;
         in opt.options // res //
           { declarations = res.declarations ++ [opt._file];
+            # In the case of modules that are generated dynamically, we won't
+            # have exact declaration lines; fall back to just the file being
+            # evaluated.
+            declarationPositions = res.declarationPositions
+              ++ (if opt.pos != null
+                then [opt.pos]
+                else [{ file = opt._file; line = null; column = null; }]);
             options = submodules;
           } // typeSet
-    ) { inherit loc; declarations = []; options = []; } opts;
+    ) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
 
   /* Merge all the definitions of an option to produce the final
      config value. */