nix-community / nixd

Nix language server, based on nix libraries [maintainer=@inclyc,@Aleksanaa]
https://github.com/nix-community/nixd
GNU Lesser General Public License v3.0
867 stars 28 forks source link

Feature request: Teach nixd custom args to functions #480

Open andrewhamon opened 5 months ago

andrewhamon commented 5 months ago

Hey there! I asked about this on matrix and I was directed to open an issue.

I am a readTree user, so my repo consists of lots of files that are simple functions which accept arguments of my choosing. They look sort of like nixos modules, but i control all inputs, and there isn't any particular output schema like with nixos modules.

It would be amazing if it were possible to configure nixd to understand this structure. I imagine it would need a few pieces of information:

I think this issue is somewhat similar to what it would take to support completion on specialArgs in nixos modules (not sure if that is supported already). Conceptually I think this feature request is equivalent to "support specialArgs on arbitrary files that aren't nixos modules" if that makes it any less confusing.

andrewhamon commented 5 months ago

I made a minimal example of how readTree is used here: https://github.com/andrewhamon/readTreeExample

So basically, i want to teach nixd that the result of this expression:

(import (./.)).args

is what gets passed in to each of my files:

{ pkgs, root, ... }: # <- provide autocompletions for these args using the expression above
pkgs.writeShellScriptBin "hello2" ''
  ${root.packages.hello}/bin/hello
  ${root.packages.hello}/bin/hello
''
inclyc commented 5 months ago

Ironic thing: allowing arbitrary args were landed before. That's exactly legacy nixd. You can read more details at:

https://github.com/nix-community/nixd/issues/471#issuecomment-2081332365

inclyc commented 5 months ago

I am a readTree user, so my repo consists of lots of files that are simple functions which accept arguments of my choosing. They look sort of like nixos modules, but i control all inputs, and there isn't any particular output schema like with nixos modules.

Then that will be difficult do deal with. 'Eval' a whole config by each workspace editing (i.e. edit any file, just a typing), approximately consumes 30s and 600M memory. People cannot accept this at all. That is a curse in nix community.

It would be amazing if it were possible to configure nixd to understand this structure. I imagine it would need a few pieces of information:

The only way to 'support' this is, allowing you write some sort of type annotations and builtin-integrate the logic.

I think this issue is somewhat similar to what it would take to support completion on specialArgs in nixos modules (not sure if that is supported already). Conceptually I think this feature request is equivalent to "support specialArgs on arbitrary files that aren't nixos modules" if that makes it any less confusing.

This feature is excatly the removed 'eval' section between 2.0 and 1.x.

The reason is: performance.

Yes, we can do this precise eval. But people don't like to configure it. And it is relatively slow.

andrewhamon commented 5 months ago

I would definitely be willing to accept stale completion info in exchange for better performance.

Also, I wonder if the eval could be done incrementally/more lazily.

For example, in my readTree example, If i typed this in my editor:

root.packages.h # <- expect completion right here

Then it would only take traversing the next level below root.packages.

For example:

time nix eval --impure --expr 'builtins.attrNames (import ./.).args.root.packages'
[ "__readTree" "__readTreeChildren" "hello" "hello2" ]
nix eval --impure --expr 'builtins.attrNames (import ./.).args.root.packages'  0.01s user 0.01s system 82% cpu 0.022 total

In 22ms we could supply hello and hello2 as completions.

inclyc commented 5 months ago

I would definitely be willing to accept stale completion info in exchange for better performance.

Yes. That's actually work-in-progress. However:

https://github.com/nix-community/nixd/issues/471#issuecomment-2081331297

For a long time C++ part in this project has only one developer

It's hard to get all these stuff implemented by one person. This project needs to be sponsored & joint work.

Also, I wonder if the eval could be done incrementally/more lazily.

Yes. But this is non-trivial. I was thinking about introducing a delayed eval system by performing real evaluation on libnixf but values coming from function args will be resolved later, via IPC. And thus keep the IPC worker immutable, just calculate workspace changes. Challenge again:

For a long time C++ part in this project has only one developer