bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#70408: 30.0.50; Eglot and Project integration


From: Ergus
Subject: bug#70408: 30.0.50; Eglot and Project integration
Date: Tue, 16 Apr 2024 18:02:10 +0200

On Tue, Apr 16, 2024 at 02:51:10PM +0100, João Távora wrote:
On Tue, Apr 16, 2024 at 1:56 PM Dmitry Gutov <dmitry@gutov.dev> wrote:

IIUC Ergus's request is primarily about a situation where an
"out-of-tree" build is used. Meaning, the directory for build artefacts
is not a subdirectory of the project root, but -- apparently -- some
sibling directory of it (e.g. "../build"). So it's somewhat atypical,
although I suppose the solution from the link above might work with it too.

Ah, I know about that.  That's where compile-commands.json is generated
by CMake.  But using that './build' as the project root passed via LSP
to clangd
(and likely any other server) will most likely fail: that's not  the
project root
and it doesn't have any versioned source files  (only auto-generated ones).

Because of this, C++ projects usually have sth like:

 ln -sf build/compile_commands.json compile_commands.json

as a build step.

Alternatively, you invoke clangd with `--compile-commands-dir=build`.
I don't think there's anything project.el or Eglot can do or should do
about this case.

What my POC workaround does is basically call a hook that updates
`eglot-workspace-configuration` as a root's directory-local variable
the first time project-current is called within a project.


```
(defun project-multi--set-eglot (plist)
  "Set the eglot variables in root's PLIST when possible."
  (when-let* ((compile-dir (project-extra-info (project-current) :compile-dir))
              (file-exists-p (expand-file-name "compile_commands.json" 
compile-dir)))

    (let* ((symvars (intern (format "eglot-multi--%s" compile-dir)))
           (eglot-complete (project-multi--merge-plist ;; merge with new values
                            (bound-and-true-p eglot-workspace-configuration)
                            `(:clangd (:initializationOptions
                                       (:compilationDatabasePath 
,compile-dir))))))

      ;; set the dir local variables, they will apply automatically to
      ;; all buffers open in the future within the project root
      (dir-locals-set-class-variables
       symvars
       `((nil . ((eglot-workspace-configuration . ,eglot-complete)))))

      (dir-locals-set-directory-class (project-root (project-current)) symvars)

      ;; set the variable manually in all the already opened buffers
      ;; TODO: JAM check if the variable is not already set in the other 
buffers??
      ;; Probably override only the value instead of replacing the whole 
variable?
      (mapc (lambda (buffer)
              (with-current-buffer buffer
                (setq-local eglot-workspace-configuration eglot-complete)))
            (project-buffers (project-current))))))
```

project-multi--merge-plist is just a hack function to merge the
eglot-workspace-configuration value without overriding the existing
sub-values if already set (in case the user sets some sub-values in the
dir locals then those takes precedence)

Then this restarts eglot

IIUC this is equivalent to call `--compile-commands-dir=build` and at
the moment is working for me.


This bug is split off from an emacs-devel discussion, where I posted a
draft solution of mine:
https://lists.gnu.org/archive/html/emacs-devel/2024-04/msg00279.html
I'm curious for any feedback - like would that be good enough for this
and related cases, or maybe if someone has an even simpler approach in mind.

I'll pass, but wish you luck.  I've stated in the past that I think
project.el should
allow subprojects inside larger projects, and let users of
project-current (direct
or indirect) specify if they're interesting in the innermost,
outermost, or intermediate
projects when searching for projects to act on, via a combination of prefix
arguments, arguments, customized special variables or let-bound special
variables.

At the moment I assume the outer most only; which is the simpler one to
setup and implement woth the current project.el support. The main goal I
have is OOSC, not nested projects.

João




reply via email to

[Prev in Thread] Current Thread [Next in Thread]