nixd icon indicating copy to clipboard operation
nixd copied to clipboard

goto definition for a file path

Open crabdancing opened this issue 1 year ago • 9 comments

Is your feature request related to a problem? Please describe.

It's awkward to navigate between related source files (e.g., source files that import other source files).

Describe the solution you'd like

LSP go-to on file path would ideally open that path.

Describe alternatives you've considered

I've tried to setup multi-LSP support and have nil do it, but it doesn't seem to work.

Additional context

In nil, if you 'go to' a path, it will open that file path. E.g., 'go to ./module.nix' will open ./module.nix. After switching to nixd, I am loving a lot of the cross-file analysis, but I really miss being able to hop between source files.

crabdancing avatar Jul 30 '24 06:07 crabdancing

Did you mean "go to definition" for file paths?

AFAIK, Ctrl + Click works as a part of "documentLink" on vscode, I guess your editor may not provide such linking.

inclyc avatar Jul 30 '24 07:07 inclyc

Yeah, I believe 'go to definition' is what it is. In Helix, it triggered when I hit g d, which is probably the exact same thing as Ctrl+Click in VSCode. The nixlang-relevant part of my config for Helix (setup via home-manager) is as follows:

languages = {
  language-server.nixd = {
    command = "nixd";
    formatting = {
      command = ["alejandra"];
    };
    options.nixos = {
      expr = "(builtins.getFlake \"/etc/nixos\").nixosConfigurations.core.options";
    };
  };
  language = [
    {
      name = "nix";
      auto-format = true;
      language-servers = ["nixd" "nil"];
      formatter.command = "${pkgs.alejandra}/bin/alejandra";
    }
  ];
};

If I select g d on an import path, it just says No definition found.

crabdancing avatar Jul 30 '24 19:07 crabdancing

I see, seems to be reasonable to integrate it.

inclyc avatar Jul 30 '24 20:07 inclyc

If it helps, I looked into it and figured out how to get a log of the Helix LSP thread's interactions with nixd. The output is here.

As a point of comparison, here is Helix interacting with nil to open a file by path via go-to-definition.

crabdancing avatar Jul 30 '24 20:07 crabdancing

If it helps, I looked into it and figured out how to get a log of the Helix LSP thread's interactions with nixd. The output is here.

As a point of comparison, here is Helix interacting with nil to open a file by path via go-to-definition.

Thanks for the detailed information; Acked. I also wanted to note that the feature document link behaves differently across editors. In vscode, document links become Ctrl + Click-able, which conflicts with the goto definition shortcut. That's why I didn't initially include it, as this project was primarily tested on vscode.

However, I believe it's important to enhance the user experience across all editors, so I'm happy to add this feature.

inclyc avatar Jul 31 '24 01:07 inclyc

Thanks for that! I really appreciate it. ^w^

crabdancing avatar Aug 01 '24 20:08 crabdancing

(Please let me know if I'm misunderstanding the issue):

In Helix, g f is "Goto files/URLs in selections" and g d is "Goto definition". In the video I press g f followed by g d:

https://github.com/user-attachments/assets/446be114-eab6-4961-89de-20961f7f2802

Relevant snippet from HM config for Helix:

languages = {
  language = [
    {
      name = "nix";
      auto-format = true;
      language-servers = [ "nixd" ];
      formatter.command = "nixfmt";
    }
  ];
  language-server = {
    nixd = {
      command = "nixd";
      config = {
        nixpkgs.expr = "import (builtins.getFlake \"/home/brisingr05/nixos-config\").inputs.nixpkgs { }";
        formatting.command = [ "nixfmt" ]; # Currently doesn't work
        options.nixos.expr = "(builtins.getFlake \"/home/brisingr05/nixos-config\").nixosConfigurations.hpaio.options";
      };
    };
  }
}

Brisingr05 avatar Aug 08 '24 04:08 Brisingr05

That's nifty, @Brisingr05! I actually was just thinking of g f as a fuzzy finder opener, since that's what it does if no file path is selected in the editor.

Regardless, the concern still remains. Other editors will seemingly often roll the go-to-file and go-to-definition logic into a single user-facing action, but Helix does not. In Helix, you would need to train separate reflexes for both use cases. This is unpleasant if you're used to nil, which is able to trigger opening the file path on g d.

I also believe there is a logical separation here, too. g f will work on arbitrary strings/tokens. I hit g f on "24.05" and it will happily open a nonsense myworkdirectory/24.05 file that was never even a path by Nix's reckoning. This makes accidents easy and workflow unpleasant. Go-to-definition ought to have no such issue. If I see a ./mythingy.nix import, I ought to be able to jump to that as if it were an invocation of a previously declared variable, with the 'declaration' being the file in the path. If I hit g d on a string, however, it would not go to that file path because that is not the lang server's understanding of the token. This is a more correctness focused approach.

This also has precedence as a more 'intelligent' go-to-file behavior (as opposed to the raw behavior) -- which is why I'd prefer to keep my muscle memory trained on g d instead of g f for things like module/include paths.

E.g., in Rust, if you g d on mod mymodule. rust-analyzer + helix will take you to src/mymodule.rs, not just a file named mymodule. If you try using g f, it will just dump you in a nonexistent mymodule file. This sort of thing makes it my opinion that g f ought to be a last resort, rather than the recommended solution for this use case. g d has more universally intelligent behavior that can adapt itself to different languages.

crabdancing avatar Aug 09 '24 00:08 crabdancing

Just tested it, and it also works in clang in the context of C projects.

g d in Helix takes you to definition for e.g. #include <stdio.h>. I think it's reasonable to say that this behavior is fairly well standardized, at least for static analysis of systems programming languages. :P

Edit:

It also works for Bash!

Hitting g d on ./bash2.sh in the context of source ./bash2.sh opens bash2.sh. Notably, this happens even if I hit g d on the source part. If I hit g f on the source token, it just dumps me in a nonexistent file named source. Notably, am using bash-language-server for this test.

crabdancing avatar Aug 09 '24 01:08 crabdancing