branch: externals/eglot commit 1db95974a7082a9915ad1c14bb17c49253efcc56 Author: João Távora <joaotav...@gmail.com> Commit: João Távora <joaotav...@gmail.com>
Per #967: eglot-workspace-configuration can be a function * README.md (Workspace configuration): Renamed from per-project configuration. Rework. * NEWS.md: Mention change. * eglot.el (eglot-workspace-configuration): Overhaul. (eglot-signal-didChangeConfiguration): Use new eglot-workspace-configuration. --- NEWS.md | 6 +++++- README.md | 47 ++++++++++++++++++++++++++++++++++------------- eglot.el | 18 ++++++++++++++---- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/NEWS.md b/NEWS.md index 156fe761bb..47450927ba 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,8 @@ # (upcoming) -##### C-u M-. lists and completes arbitrary workspace symbols [#131][github#131]) +##### `eglot-workspace-configuration` can be a function ([#967][github#967]) + +##### C-u M-. lists and completes arbitrary workspace symbols ([#131][github#131]) A very old request, now made possible by a relatively recent change to the `workspace/symbol` RPC method. @@ -322,6 +324,7 @@ and now said bunch of references--> [github#121]: https://github.com/joaotavora/eglot/issues/121 [github#124]: https://github.com/joaotavora/eglot/issues/124 [github#126]: https://github.com/joaotavora/eglot/issues/126 +[github#131]: https://github.com/joaotavora/eglot/issues/131 [github#138]: https://github.com/joaotavora/eglot/issues/138 [github#144]: https://github.com/joaotavora/eglot/issues/144 [github#154]: https://github.com/joaotavora/eglot/issues/154 @@ -383,3 +386,4 @@ and now said bunch of references--> [github#901]: https://github.com/joaotavora/eglot/issues/901 [github#905]: https://github.com/joaotavora/eglot/issues/905 [github#922]: https://github.com/joaotavora/eglot/issues/922 +[github#967]: https://github.com/joaotavora/eglot/issues/967 diff --git a/README.md b/README.md index 8a54156882..2314eb2d32 100644 --- a/README.md +++ b/README.md @@ -128,14 +128,14 @@ it be started as a server. Notice the `:autoport` symbol in there: it is replaced dynamically by a local port believed to be vacant, so that the ensuing TCP connection finds a listening server. -## Per-project server configuration +## Workspace configuration Most servers can guess good defaults and will operate nicely out-of-the-box, but some need to be configured specially via LSP interfaces. Additionally, in some situations, you may also want a particular server to operate differently across different projects. -Per-project settings are realized with Emacs's _directory variables_ +Per-project settings are realized with Emacs's _directory variables and the Elisp variable `eglot-workspace-configuration`. To make a particular Python project always enable Pyls's snippet support, put a file named `.dir-locals.el` in the project's root: @@ -147,15 +147,17 @@ file named `.dir-locals.el` in the project's root: ``` This tells Emacs that any `python-mode` buffers in that directory -should have a particular buffer-local value of -`eglot-workspace-configuration`. That variable's value should be -_association list_ of _parameter sections_ which are presumably -understood by the server. In this example, we associate section -`pyls` with the parameters object `(:plugins (:jedi_completion -(:include_params t)))`. - -Now, supposing that you also had some Go code in the very same -project, you can configure the Gopls server in the same file. Adding +should have a particular value of `eglot-workspace-configuration`. +That variable's value should be _association list_ of _parameter +sections_ which are presumably understood by the server. + +In this above, we associated the _section_ `:pyls` with the parameters +object `(:plugins (:jedi_completion (:include_params t)))`. + +### Multiple workspace configuration for multiple servers + +Suppose you also had some Go code in the very same project, you can +configure the Gopls server in the same `.dir-locals.el' file. Adding a section for `go-mode`, the file's contents become: ```lisp @@ -167,9 +169,28 @@ a section for `go-mode`, the file's contents become: . ((:gopls . (:usePlaceholders t))))))) ``` +As a matter of taste, you might prefer this equivalent setup. + +```lisp +((nil + . ((eglot-workspace-configuration + . ((:pyls . (:plugins (:jedi_completion (:include_params t)))) + (:gopls . (:usePlaceholders t))))))) +``` + +### Setting up without `.dir-locals.el` + If you can't afford an actual `.dir-locals.el` file, or if managing -these files becomes cumbersome, the Emacs manual teaches you -programmatic ways to leverage per-directory local variables. +this file becomes cumbersome, the Emacs manual (49.2.5 Per-Directory +Local Variables) teaches you programmatic ways to leverage +per-directory local variables. Look for the functions +`dir-locals-set-directory-class` and `dir-locals-set-class-variables`. + +### Setting a dynamic `eglot-workspace-configuration` dynamically + +If you need to decide `eglot-workspace-configuration` can be a function, too. It is passed +the `eglot-lsp-server` instance and runs with `default-directory` set +to the root of your project. ## Handling quirky servers diff --git a/eglot.el b/eglot.el index 0b64cd2301..582ad1fdee 100644 --- a/eglot.el +++ b/eglot.el @@ -2199,12 +2199,22 @@ Records BEG, END and PRE-CHANGE-LENGTH locally." (defvar-local eglot-workspace-configuration () "Alist of (SECTION . VALUE) entries configuring the LSP server. -SECTION should be a keyword or a string, value can be anything -that can be converted to JSON.") +SECTION should be a keyword or a string. VALUE is a +plist or a primitive type converted to JSON. + +The value of this variable can also be a unary function of a +`eglot-lsp-server' instance, the server connection requesting the +configuration. It should return an alist of the format described +above.") ;;;###autoload (put 'eglot-workspace-configuration 'safe-local-variable 'listp) +(defun eglot--workspace-configuration (server) + (if (functionp eglot-workspace-configuration) + (funcall eglot-workspace-configuration server) + eglot-workspace-configuration)) + (defun eglot-signal-didChangeConfiguration (server) "Send a `:workspace/didChangeConfiguration' signal to SERVER. When called interactively, use the currently active server" @@ -2213,7 +2223,7 @@ When called interactively, use the currently active server" server :workspace/didChangeConfiguration (list :settings - (or (cl-loop for (section . v) in eglot-workspace-configuration + (or (cl-loop for (section . v) in (eglot--workspace-configuration server) collect (if (keywordp section) section (intern (format ":%s" section))) @@ -2235,7 +2245,7 @@ When called interactively, use the currently active server" (project-root (eglot--project server))))) (setq-local major-mode (eglot--major-mode server)) (hack-dir-local-variables-non-file-buffer) - (alist-get section eglot-workspace-configuration + (alist-get section (eglot--workspace-configuration server) nil nil (lambda (wsection section) (string=