New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling eglot in files outside current project after following xrefs #76

Open
mkcms opened this Issue Aug 18, 2018 · 5 comments

Comments

Projects
None yet
3 participants
@mkcms
Contributor

mkcms commented Aug 18, 2018

When I find a definition outside current project, eglot is either not enabled or enabled, but using a different server. I'd like to have it enabled and using the same server where it came from, unless I explicitly started it with eglot or there was already a server managing this buffer started with eglot-ensure, but not in a transient project.

@joaotavora

This comment has been minimized.

Show comment
Hide comment
@joaotavora

joaotavora Aug 19, 2018

Owner

When I find a definition outside current project

The solution here would be to teach project.el that the file you visited is actually in the same project that you came from. Isn't that possible?

Owner

joaotavora commented Aug 19, 2018

When I find a definition outside current project

The solution here would be to teach project.el that the file you visited is actually in the same project that you came from. Isn't that possible?

@mkcms

This comment has been minimized.

Show comment
Hide comment
@mkcms

mkcms Aug 20, 2018

Contributor

The solution here would be to teach project.el

Can you give me a simple example how to do that? Assuming that the found files are in system paths like /usr/include.

Contributor

mkcms commented Aug 20, 2018

The solution here would be to teach project.el

Can you give me a simple example how to do that? Assuming that the found files are in system paths like /usr/include.

@joaotavora

This comment has been minimized.

Show comment
Hide comment
@joaotavora

joaotavora Aug 20, 2018

Owner

You could start by adding some mkcms/try-to-find-related-java-project to project-find-functions. This would slightly abuse the semantics that a project is supposed to "contain" a file of the given buffer where you call project-current, but I don't see any problem in that.

At some point though , you would of course have to make a decision in mkcms/try-to-find-related-java-project as to which project to pick, because there may be more than one. Eventually that function may become eglot-setup-finding-related-java-projects which we add to eglot.el and suggest that users add to java-mode-hook just like we suggest to add eglot-ensure there.

Another interesting generic function is project-external-roots. In project.el "external roots" are defined thusly

It's the list of directories outside of the project that are
still related to it.  If the project deals with source code then,
depending on the languages used, this list should include the
headers search path, load path, class path, and so on.

The rule of thumb for whether to include a directory here, and
not in `project-roots', is whether its contents are meant to be
edited together with the rest of the project.

This seems to fit nicely with the /usr/include example, but the implementation is kinda sketchy (still?). Still, if you could configure them (perhaps using project-vc-external-roots-function) then eglot-setup-finding-related-java-projectscould possibly become eglot-setup-search-for-projects, and in this case we could make it a defcustom.

Am I explaining myself here?

Owner

joaotavora commented Aug 20, 2018

You could start by adding some mkcms/try-to-find-related-java-project to project-find-functions. This would slightly abuse the semantics that a project is supposed to "contain" a file of the given buffer where you call project-current, but I don't see any problem in that.

At some point though , you would of course have to make a decision in mkcms/try-to-find-related-java-project as to which project to pick, because there may be more than one. Eventually that function may become eglot-setup-finding-related-java-projects which we add to eglot.el and suggest that users add to java-mode-hook just like we suggest to add eglot-ensure there.

Another interesting generic function is project-external-roots. In project.el "external roots" are defined thusly

It's the list of directories outside of the project that are
still related to it.  If the project deals with source code then,
depending on the languages used, this list should include the
headers search path, load path, class path, and so on.

The rule of thumb for whether to include a directory here, and
not in `project-roots', is whether its contents are meant to be
edited together with the rest of the project.

This seems to fit nicely with the /usr/include example, but the implementation is kinda sketchy (still?). Still, if you could configure them (perhaps using project-vc-external-roots-function) then eglot-setup-finding-related-java-projectscould possibly become eglot-setup-search-for-projects, and in this case we could make it a defcustom.

Am I explaining myself here?

@MaskRay

This comment has been minimized.

Show comment
Hide comment
@MaskRay

MaskRay Aug 22, 2018

Contributor

For references outside of the project, the action itself has the characteristic of "dynamic binding".

What I did in lsp-ui is to populate the current workspace information to the newly opened buffer, if the latter does not have an indefinite project root.

https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-peek.el#L472

(defun lsp-ui-peek--goto-xref (&optional x other-window)
.......
            (unless lsp--cur-workspace
              (setq lsp--cur-workspace current-workspace))
            (unless lsp-mode
              (lsp-mode 1)
              (lsp-on-open))
// hit textDocument/definition on the include line
#include <stdio.h>

/usr/include/stdio.h will be opened (cquery would fail to do so if it was on Arch Linux, details omitted).

I have (setq projectile-require-project-root t), so that (projectile-project-root) will return nil. Then lsp--cur-workspace of the current buffer will be populated to the new one.

Another example. ccls has switched to pure Clang/llvm C++ API (while cquery is fully libclang based).
When I hit textDocument/definition in a ccls buffer and it takes me to some llvm/tools/clang/**/*.cpp buffer, I wish the buffer belongs to llvm, not ccls. The following scheme meets my needs best.

  • (locate-dominating-file default-directory ".ccls-root") if it exists
  • (projectile-project-root) otherwise. Make sure you have (setq projectile-require-project-root t)
  • fallback to lsp--cur-workspace of the current buffer (jumped-from buffer)

Sorry if I mentioned ccls too many times in these comments.

Contributor

MaskRay commented Aug 22, 2018

For references outside of the project, the action itself has the characteristic of "dynamic binding".

What I did in lsp-ui is to populate the current workspace information to the newly opened buffer, if the latter does not have an indefinite project root.

https://github.com/emacs-lsp/lsp-ui/blob/master/lsp-ui-peek.el#L472

(defun lsp-ui-peek--goto-xref (&optional x other-window)
.......
            (unless lsp--cur-workspace
              (setq lsp--cur-workspace current-workspace))
            (unless lsp-mode
              (lsp-mode 1)
              (lsp-on-open))
// hit textDocument/definition on the include line
#include <stdio.h>

/usr/include/stdio.h will be opened (cquery would fail to do so if it was on Arch Linux, details omitted).

I have (setq projectile-require-project-root t), so that (projectile-project-root) will return nil. Then lsp--cur-workspace of the current buffer will be populated to the new one.

Another example. ccls has switched to pure Clang/llvm C++ API (while cquery is fully libclang based).
When I hit textDocument/definition in a ccls buffer and it takes me to some llvm/tools/clang/**/*.cpp buffer, I wish the buffer belongs to llvm, not ccls. The following scheme meets my needs best.

  • (locate-dominating-file default-directory ".ccls-root") if it exists
  • (projectile-project-root) otherwise. Make sure you have (setq projectile-require-project-root t)
  • fallback to lsp--cur-workspace of the current buffer (jumped-from buffer)

Sorry if I mentioned ccls too many times in these comments.

@mkcms

This comment has been minimized.

Show comment
Hide comment
@mkcms

mkcms Aug 27, 2018

Contributor

@joaotavora I think I get the idea, but how can I know with which "real" project (i.e. the one which generated xrefs) the project I found is associated? I could modify project-external-roots by hand to point to projects I know, but for a big project spanning multiple directories it would be a lot of work. Also, some setups will have external projects in nondeterministic locations, for example python projects using pipenv, because pipenv puts all dependencies in subdirs of, for example ~/.virtualenvs/test-hxkKlP5o/ (the directory changes for every project).

Would you accept a PR that makes this automatic by hooking to xref-after-jump-hook?

Contributor

mkcms commented Aug 27, 2018

@joaotavora I think I get the idea, but how can I know with which "real" project (i.e. the one which generated xrefs) the project I found is associated? I could modify project-external-roots by hand to point to projects I know, but for a big project spanning multiple directories it would be a lot of work. Also, some setups will have external projects in nondeterministic locations, for example python projects using pipenv, because pipenv puts all dependencies in subdirs of, for example ~/.virtualenvs/test-hxkKlP5o/ (the directory changes for every project).

Would you accept a PR that makes this automatic by hooking to xref-after-jump-hook?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment