mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-30 02:33:03 -07:00
* doc/misc/woman.texi: * doc/misc/wisent.texi: * doc/misc/widget.texi: * doc/misc/vtable.texi: * doc/misc/viper.texi: * doc/misc/vhdl-mode.texi: * doc/misc/use-package.texi: * doc/misc/url.texi: * doc/misc/tramp.texi: * doc/misc/todo-mode.texi: * doc/misc/srecode.texi: * doc/misc/speedbar.texi: * doc/misc/smtpmail.texi: * doc/misc/sieve.texi: * doc/misc/ses.texi: * doc/misc/semantic.texi: * doc/misc/sc.texi: * doc/misc/sasl.texi: * doc/misc/remember.texi: * doc/misc/reftex.texi: * doc/misc/rcirc.texi: * doc/misc/pgg.texi: * doc/misc/pcl-cvs.texi: * doc/misc/octave-mode.texi: * doc/misc/nxml-mode.texi: * doc/misc/newsticker.texi: * doc/misc/mh-e.texi: * doc/misc/message.texi: * doc/misc/mairix-el.texi: * doc/misc/info.texi: * doc/misc/ido.texi: * doc/misc/idlwave.texi: * doc/misc/htmlfontify.texi: * doc/misc/gnus.texi: * doc/misc/forms.texi: * doc/misc/flymake.texi: * doc/misc/eww.texi: * doc/misc/eudc.texi: * doc/misc/eshell.texi: * doc/misc/ert.texi: * doc/misc/erc.texi: * doc/misc/epa.texi: * doc/misc/emacs-gnutls.texi: * doc/misc/eieio.texi: * doc/misc/eglot.texi: * doc/misc/efaq-w32.texi: * doc/misc/efaq.texi: * doc/misc/edt.texi: * doc/misc/ediff.texi: * doc/misc/ede.texi: * doc/misc/ebrowse.texi: * doc/misc/dired-x.texi: * doc/misc/dbus.texi: * doc/misc/cl.texi: * doc/misc/cc-mode.texi: * doc/misc/calc.texi: * doc/misc/bovine.texi: * doc/misc/autotype.texi: * doc/misc/auth.texi: * doc/lispintro/emacs-lisp-intro.texi: * doc/lispref/elisp.texi: * doc/emacs/emacs.texi: Add @documentlanguage where it was missing. This makes the language explicit given the change in behavior expected in Texinfo 7.3.
1992 lines
81 KiB
Text
1992 lines
81 KiB
Text
\input texinfo @c -*-texinfo-*-
|
|
@c %**start of header
|
|
@setfilename ../../eglot.info
|
|
@settitle Eglot: The Emacs Client for the Language Server Protocol
|
|
@documentlanguage en
|
|
@include docstyle.texi
|
|
@syncodeindex vr cp
|
|
@syncodeindex fn cp
|
|
@c %**end of header
|
|
|
|
@copying
|
|
This manual is for Eglot, the Emacs LSP client.
|
|
|
|
Copyright @copyright{} 2022--2026 Free Software Foundation, Inc.
|
|
|
|
@quotation
|
|
Permission is granted to copy, distribute and/or modify this document
|
|
under the terms of the GNU Free Documentation License, Version 1.3 or
|
|
any later version published by the Free Software Foundation; with no
|
|
Invariant Sections, with the Front-Cover Texts being ``A GNU Manual'',
|
|
and with the Back-Cover Texts as in (a) below. A copy of the license is
|
|
included in the section entitled ``GNU Free Documentation License''.
|
|
|
|
(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
|
|
modify this GNU manual.''
|
|
@end quotation
|
|
@end copying
|
|
|
|
@dircategory Emacs misc features
|
|
@direntry
|
|
* Eglot: (eglot). Language Server Protocol client for Emacs.
|
|
@end direntry
|
|
|
|
@titlepage
|
|
@sp 4
|
|
@c The title is printed in a large font.
|
|
@center @titlefont{User's Guide}
|
|
@sp 1
|
|
@center @titlefont{to}
|
|
@sp 1
|
|
@center @titlefont{Eglot: The Emacs LSP Client}
|
|
@ignore
|
|
@sp 2
|
|
@center release 1.8
|
|
@c -release-
|
|
@end ignore
|
|
@sp 3
|
|
@center Jo@~ao T@'avora & Eli Zaretskii
|
|
@c -date-
|
|
|
|
@page
|
|
@vskip 0pt plus 1filll
|
|
@insertcopying
|
|
@end titlepage
|
|
|
|
@contents
|
|
|
|
@ifnottex
|
|
@node Top
|
|
@top Eglot
|
|
|
|
@cindex LSP
|
|
@cindex language server protocol
|
|
Eglot is the Emacs client for the @dfn{Language Server Protocol}
|
|
(@acronym{LSP}). The name ``Eglot'' is an acronym that stands for
|
|
@ifhtml
|
|
``@emph{E}macs Poly@emph{glot}''.
|
|
@end ifhtml
|
|
@ifnothtml
|
|
``Emacs polyGLOT''.
|
|
@end ifnothtml
|
|
@footnote{ A @dfn{polyglot} is a person who is able to use several
|
|
languages. } Eglot provides infrastructure and a set of commands for
|
|
enriching the source code editing capabilities of Emacs via LSP@. LSP
|
|
is a standardized communications protocol between source code editors
|
|
(such as Emacs) and language servers---programs external to Emacs which
|
|
analyze the source code on behalf of Emacs. The protocol allows Emacs
|
|
to receive various source code services from the server, such as
|
|
description and location of function calls, types of variables, class
|
|
definitions, syntactic errors, etc. This way, Emacs doesn't need to
|
|
implement the language-specific parsing and analysis capabilities in its
|
|
own code, but is still capable of providing sophisticated editing
|
|
features that rely on such capabilities, such as automatic code
|
|
completion, go-to definition of function/class, documentation of symbol
|
|
at-point, refactoring, on-the-fly diagnostics, and more.
|
|
|
|
Eglot itself is completely language-agnostic, but it can support any
|
|
programming language for which there is a language server and an Emacs
|
|
major mode.
|
|
|
|
This manual documents how to configure, use, and customize Eglot. To
|
|
read this manual from within Emacs, type @kbd{M-x eglot-manual
|
|
@key{RET}}.
|
|
|
|
@insertcopying
|
|
|
|
@menu
|
|
* Quick Start:: For the impatient.
|
|
* Eglot and LSP Servers:: How to work with language servers.
|
|
* Using Eglot:: Important Eglot commands and variables.
|
|
* Customizing Eglot:: Eglot customization and advanced features.
|
|
* Advanced server configuration:: Fine-tune a specific language server
|
|
* Multi-server support:: Use more than one server in a buffer
|
|
* Extending Eglot:: Writing Eglot extensions in Elisp
|
|
* Troubleshooting Eglot:: Troubleshooting and reporting bugs.
|
|
* GNU Free Documentation License:: The license for this manual.
|
|
* Index::
|
|
@end menu
|
|
@end ifnottex
|
|
|
|
@node Quick Start
|
|
@chapter Quick Start
|
|
@cindex quick start
|
|
|
|
This chapter provides concise instructions for setting up and using
|
|
Eglot with your programming project in common usage scenarios. For more
|
|
detailed instructions regarding Eglot setup, @pxref{Eglot and LSP
|
|
Servers}. @xref{Using Eglot}, for detailed description of using Eglot,
|
|
and see @ref{Customizing Eglot}, for adapting Eglot to less common use
|
|
patterns.
|
|
|
|
Here's how to start using Eglot with your programming project:
|
|
|
|
@enumerate
|
|
@item
|
|
Select and install a language server.
|
|
|
|
Eglot comes pre-configured for many popular language servers, see the
|
|
value of @code{eglot-server-programs}. If the server(s) mentioned there
|
|
satisfy your needs for the programming language(s) with which you want
|
|
to use Eglot, you just need to make sure those servers are installed on
|
|
your system and Eglot can find them.
|
|
|
|
Alternatively, install one or more servers of your choice and tell Eglot
|
|
where to find them. To do that, you may add to the value of
|
|
@code{eglot-server-programs}, as described in @ref{Setting Up LSP
|
|
Servers} or have Eglot prompt you about it (@pxref{Eglot Commands}).
|
|
|
|
@item
|
|
Turn on Eglot for your project.
|
|
|
|
To start using Eglot for a project, type @kbd{M-x eglot @key{RET}} in a
|
|
buffer visiting any file that belongs to the project. This starts the
|
|
language server configured for the programming language of that buffer,
|
|
and causes Eglot to start @dfn{managing} file-visiting buffers related
|
|
to that programming language. This includes files that are already
|
|
visited at the time the @code{eglot} command is invoked, as well as any
|
|
files visited after this invocation.
|
|
|
|
The notion of a ``project'' used by Eglot is the same Emacs uses
|
|
(@pxref{Projects,,, emacs, GNU Emacs Manual}): in the simplest case, the
|
|
``project'' is the single file you are editing, but it can also be all
|
|
the files in a single directory or a directory tree under some version
|
|
control system, such as Git.
|
|
|
|
There are alternate ways of starting Eglot; see @ref{Starting Eglot}
|
|
for details.
|
|
|
|
@item
|
|
Use Eglot.
|
|
|
|
Most Eglot facilities are integrated into Emacs features, such as ElDoc,
|
|
Flymake, Xref, and Imenu. However, Eglot also provides commands of its
|
|
own, mainly to perform tasks by the language server, such as @kbd{M-x
|
|
eglot-rename} (to rename an identifier across the entire project),
|
|
@kbd{M-x eglot-format} (to reformat and reindent code), and some others.
|
|
@xref{Eglot Commands}, for the detailed list of Eglot commands.
|
|
|
|
@item
|
|
That's it!
|
|
@end enumerate
|
|
|
|
@node Eglot and LSP Servers
|
|
@chapter Eglot and LSP Servers
|
|
|
|
This chapter describes how to set up Eglot for your needs, and how to
|
|
start it.
|
|
|
|
@menu
|
|
* Setting Up LSP Servers:: How to configure LSP servers for your needs.
|
|
* Starting Eglot:: Ways of starting Eglot for your project.
|
|
* Shutting Down LSP Servers::
|
|
@end menu
|
|
|
|
@node Setting Up LSP Servers
|
|
@section Setting Up LSP Servers
|
|
@cindex setting up LSP server for Eglot
|
|
@cindex LSP server for Eglot, setting up
|
|
@cindex language server for Eglot
|
|
|
|
For Eglot to be useful, it must first be combined with a suitable
|
|
language server. Usually, that means running the server program locally
|
|
as a child process of Emacs (@pxref{Processes,,, elisp, GNU Emacs Lisp
|
|
Reference Manual}) and communicating with it via the standard input and
|
|
output streams.
|
|
|
|
The language server program must be installed separately, and is not
|
|
further discussed in this manual; refer to the documentation of the
|
|
particular server(s) you want to install.
|
|
|
|
To use a language server, Eglot must know how to start it and which
|
|
programming languages each server supports. This information is
|
|
commonly provided by the variable @code{eglot-server-programs}.
|
|
|
|
@defvar eglot-server-programs
|
|
This variable associates major modes with names and command-line
|
|
arguments of the language server programs corresponding to the
|
|
programming language of each major mode. It provides all the
|
|
information that Eglot needs to know about the programming language of
|
|
the source you are editing.
|
|
|
|
The value of the variable is an alist, whose elements are of the form
|
|
@w{@code{(@var{major-mode} . @var{server})}}.
|
|
|
|
The @var{major-mode} of the alist elements can be either a symbol of an
|
|
Emacs major mode or a list of the form @w{@code{(@var{mode} :language-id
|
|
@var{id})}}, with @var{mode} being a major-mode symbol and @var{id} a
|
|
string that identifies the language to the server (if Eglot cannot by
|
|
itself convert the major-mode to the language identifier string required
|
|
by the server). In addition, @var{major-mode} can be a list of several
|
|
major modes specified in one of the above forms -- this means a running
|
|
instance of the associated server is responsible for files of multiple
|
|
major modes or languages in the project.
|
|
|
|
The @var{server} part of the alist elements can be one of the following:
|
|
|
|
@table @code
|
|
@item (@var{program} @var{args}@dots{})
|
|
This says to invoke @var{program} with zero or more arguments
|
|
@var{args}; the program is expected to communicate with Emacs via the
|
|
standard input and standard output streams.
|
|
|
|
@item (@var{program} @var{args}@dots{} :initializationOptions @var{options}@dots{})
|
|
@var{program} is invoked with @var{args} but @var{options} specifies how
|
|
to construct the @samp{:initializationOptions} JSON object to pass the
|
|
server on during the LSP handshake (@pxref{Advanced server
|
|
configuration}).
|
|
|
|
@item (@var{host} @var{port} @var{args}@dots{})
|
|
Here @var{host} is a string and @var{port} is a positive integer
|
|
specifying a TCP connection to a remote server. The @var{args} are
|
|
passed to @code{open-network-stream}, e.g.@: if the connection needs to
|
|
use encryption or other non-default parameters (@pxref{Network,,, elisp,
|
|
GNU Emacs Lisp Reference Manual}).
|
|
|
|
@item (@var{program} @var{args}@dots{} :autoport @var{moreargs}@dots{})
|
|
@var{program} is started with a command line constructed from @var{args}
|
|
followed by an available server port and the rest of arguments in
|
|
@var{moreargs}; Eglot then establishes a TCP connection with the server
|
|
via that port on the local host.
|
|
|
|
@item @var{function}
|
|
This should be a function of a single argument: non-@code{nil} if the
|
|
connection was requested interactively (e.g., by the @code{eglot}
|
|
command), otherwise @code{nil}. The function should return a value of
|
|
any of the forms described above. This allows interaction with the user
|
|
for determining the program to start and its command-line arguments.
|
|
@end table
|
|
|
|
@end defvar
|
|
|
|
Eglot comes with a fairly complete set of associations of major-modes to
|
|
popular language servers predefined. If you need to add server
|
|
associations to the default list, use @code{add-to-list}. For example,
|
|
if there is a hypothetical language server program @command{fools} for
|
|
the language @code{Foo} which is supported by an Emacs major-mode
|
|
@code{foo-mode}, you can add it to the alist like this:
|
|
|
|
@lisp
|
|
(with-eval-after-load 'eglot
|
|
(add-to-list 'eglot-server-programs
|
|
'(foo-mode . ("fools" "--stdio"))))
|
|
@end lisp
|
|
|
|
This will invoke the program @command{fools} with the command-line
|
|
argument @option{--stdio} in support of editing source files for which
|
|
Emacs turns on @code{foo-mode}, and will communicate with the program
|
|
via the standard streams. As usual with invoking programs, the
|
|
executable file @file{fools} should be in one of the directories
|
|
mentioned by the @code{exec-path} variable (@pxref{Subprocess
|
|
Creation,,, elisp, GNU Emacs Lisp Reference Manual}), for Eglot to be
|
|
able to find it.
|
|
|
|
Sometimes, multiple servers are acceptable alternatives for handling a
|
|
given major-mode. In those cases, you may combine the helper function
|
|
@code{eglot-alternatives} with the functional form of
|
|
@code{eglot-server-programs}.
|
|
|
|
@lisp
|
|
(with-eval-after-load 'eglot
|
|
(add-to-list 'eglot-server-programs
|
|
`(foo-mode . ,(eglot-alternatives
|
|
'(("fools" "--stdio")
|
|
("phewls" "--fast"))))))
|
|
@end lisp
|
|
|
|
If you have @command{fools} and @command{phewls} installed, the function
|
|
produced by @code{eglot-alternatives} will prompt for the server to use
|
|
in @code{foo-mode} buffers. Else it will use whichever is available.
|
|
|
|
@node Starting Eglot
|
|
@section Starting Eglot
|
|
@cindex starting Eglot
|
|
@cindex activating Eglot for a project
|
|
|
|
@findex eglot
|
|
The most common way to start Eglot is to simply visit a source file of a
|
|
given language and use the command @kbd{M-x eglot}. This starts the
|
|
language server suitable for the visited file's major-mode, and attempts
|
|
to connect to it. If the connection to the language server is
|
|
successful, you will see the @code{[eglot:@var{project}]} indicator on
|
|
the mode line which reflects the server that was started. If the server
|
|
program couldn't be started or connection to it failed, you will see an
|
|
error message; in that case, try to troubleshoot the problem as
|
|
described in @ref{Troubleshooting Eglot}. Once a language server was
|
|
successfully started and Eglot connected to it, you can immediately
|
|
start using the Emacs features supported by Eglot, as described in
|
|
@ref{Eglot Features}.
|
|
|
|
A single Eglot session for a certain major-mode usually serves all the
|
|
buffers under that mode which visit files from the same project, so you
|
|
don't need to invoke @kbd{M-x eglot} again when you visit another file
|
|
from the same project which is edited using the same major-mode. This
|
|
is because Eglot uses the Emacs project infrastructure, as described in
|
|
@ref{Eglot and Buffers}, and this knows about files that belong to the
|
|
same project. Thus, after starting an Eglot session for some buffer,
|
|
that session is automatically reused when visiting files in the same
|
|
project with the same major-mode.
|
|
|
|
@findex eglot-ensure
|
|
Alternatively, you could configure Eglot to start automatically for one
|
|
or more major-modes from the respective mode hooks. Here's an example
|
|
for a hypothetical @code{foo-mode}:
|
|
|
|
@lisp
|
|
(add-hook 'foo-mode-hook 'eglot-ensure)
|
|
@end lisp
|
|
|
|
@noindent
|
|
The function @code{eglot-ensure} will start an Eglot session for each
|
|
buffer in which @code{foo-mode} is turned on, if there isn't already an
|
|
Eglot session that handles the buffer. Note that this variant of
|
|
starting an Eglot session is non-interactive, so it should be used only
|
|
when you are confident that Eglot can be started reliably for any file
|
|
which may be visited with the major-mode in question.
|
|
|
|
Note that it's often difficult to establish this confidence fully, so it
|
|
may be wise to use the interactive command @code{eglot} instead. You
|
|
only need to invoke it once per project, as all other files visited
|
|
within the same project will automatically be managed with no further
|
|
user intervention needed.
|
|
|
|
When Eglot connects to a language server for the first time in an Emacs
|
|
session, it runs the hook @code{eglot-connect-hook} (@pxref{Other
|
|
Variables}).
|
|
|
|
@node Shutting Down LSP Servers
|
|
@section Shutting Down LSP Servers
|
|
@cindex shutting down LSP server
|
|
|
|
When Eglot is turned on, it arranges for turning itself off
|
|
automatically if the language server process terminates. Turning off
|
|
Eglot means that it shuts down the server connection, ceases its
|
|
management of all the buffers that use the server connection which was
|
|
terminated, deactivates its minor mode, and restores the original values
|
|
of the Emacs variables that Eglot changed when it was turned on.
|
|
@xref{Eglot and Buffers}, for more details of what Eglot management of a
|
|
buffer entails.
|
|
|
|
@findex eglot-shutdown
|
|
You can also shut down a language server manually, by using the command
|
|
@kbd{M-x eglot-shutdown}. This prompts for the server (unless there's
|
|
only one connection and it's used in the current buffer), and then shuts
|
|
it down. By default, it also kills the server's events buffer
|
|
(@pxref{Troubleshooting Eglot}), but a prefix argument prevents that.
|
|
|
|
Alternatively, you can customize the variable @code{eglot-autoshutdown}
|
|
to a non-@code{nil} value, in which case Eglot will automatically shut
|
|
down the language server process when the last buffer served by that
|
|
language server is killed. The default of this variable is @code{nil},
|
|
so that visiting another file would automatically activate Eglot even
|
|
when the project which started Eglot with the server no longer has any
|
|
buffer associated with it. This default allows you to start a server
|
|
only once in each Emacs session.
|
|
|
|
@node Using Eglot
|
|
@chapter Using Eglot
|
|
|
|
This chapter describes in detail the features that Eglot provides and
|
|
how it does that. It also provides reference sections for Eglot
|
|
commands and variables.
|
|
|
|
@menu
|
|
* Eglot Features::
|
|
* Eglot and Buffers::
|
|
* Eglot Commands::
|
|
@end menu
|
|
|
|
@node Eglot Features
|
|
@section Eglot Features
|
|
@cindex features in buffers supported by Eglot
|
|
|
|
While Eglot is enabled in a buffer, it is said to be @dfn{managing} it,
|
|
using LSP and the specific capabilities of the language server to
|
|
activate and enhance modern IDE features in Emacs. Some of these
|
|
features are provided via other Emacs packages, and some via Eglot
|
|
directly (@pxref{Eglot Commands}).
|
|
|
|
Here's an overview of the main features that Eglot provides:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
At-point documentation: when point is near a symbol or an identifier,
|
|
information about the identifier's significance in the program (its
|
|
function or method signature, its type, its custom documentation string,
|
|
etc.) is made available via the ElDoc package (@pxref{Programming
|
|
Language Doc,,, emacs, GNU Emacs Manual}).
|
|
|
|
@item
|
|
On-the-fly diagnostic annotations, via the Flymake package
|
|
(@pxref{Top,,, Flymake, GNU Flymake manual}). Eglot's Flymake backend
|
|
replaces other Flymake backends while it is managing a buffer, and
|
|
enhances diagnostics with interactive server-suggested fixes (so-called
|
|
@dfn{code actions}, @pxref{Eglot Commands}).
|
|
|
|
@item
|
|
Finding definitions and uses of identifiers, via Xref (@pxref{Xref,,,
|
|
emacs, GNU Emacs Manual}). Eglot provides a backend for the Xref
|
|
capabilities which uses the language server's understanding of the
|
|
program source. In particular, it eliminates the need to generate tags
|
|
tables (@pxref{Tags tables,,, emacs, GNU Emacs Manual}) for languages
|
|
which are only supported by the @code{etags} backend.
|
|
|
|
@item
|
|
Buffer navigation by name of function, class, method, etc., via Imenu
|
|
(@pxref{Imenu,,, emacs, GNU Emacs Manual}). Eglot provides its own
|
|
variant of @code{imenu-create-index-function}, which generates the index
|
|
for the buffer based on the language server's program source analysis.
|
|
|
|
@item
|
|
Enhanced completion of symbol at point by the @code{completion-at-point}
|
|
command (@pxref{Symbol Completion,,, emacs, GNU Emacs Manual}). This
|
|
uses the language server's parser data for the completion candidates.
|
|
|
|
@item
|
|
Server-suggested code refactorings. The ElDoc package is also leveraged
|
|
to retrieve so-called @dfn{code actions} nearby point. When such
|
|
suggestions are available they are annotated with a special indication
|
|
and can be easily invoked by the user with the @code{eglot-code-action}
|
|
command (@pxref{Eglot Commands}).
|
|
|
|
@item
|
|
On-the-fly succinct informative annotations, so-called @dfn{inlay
|
|
hints}. Eglot adds special intangible text nearby certain identifiers,
|
|
be it the type of a variable, or the name of a formal parameter in a
|
|
function call. @xref{Eglot Commands}, and the
|
|
@code{eglot-inlay-hints-mode} minor mode.
|
|
|
|
@item
|
|
Enhanced source code fontification via LSP @dfn{semantic tokens}. Eglot
|
|
can leverage the language server's understanding of the role and meaning
|
|
of identifiers in the code to provide more accurate syntax highlighting.
|
|
@xref{Eglot Commands}, and the @code{eglot-semantic-tokens-mode} minor
|
|
mode.
|
|
|
|
@item
|
|
Display of function call and type hierarchies via the
|
|
@code{eglot-show-call-hierarchy} and @code{eglot-show-type-hierarchy}
|
|
commands (@pxref{Eglot Commands}).
|
|
|
|
@item
|
|
Code reformatting via the @code{eglot-format} and related commands
|
|
(@pxref{Eglot Commands}). Automatic reformatting of source code is also
|
|
supported and is activated automatically as you type.
|
|
|
|
@item
|
|
If a completion package such as the Company package (a popular
|
|
third-party completion package providing @code{company-mode}), is
|
|
installed, Eglot enhances it by providing completion candidates based on
|
|
the language server's analysis of the source code. (Company can be
|
|
installed from GNU ELPA.)
|
|
|
|
@item
|
|
If YASnippet, a popular third-party package for automatic insertion of
|
|
code templates (snippets), is installed, and the language server
|
|
supports snippet completion candidates, Eglot arranges for the
|
|
completion package to instantiate these snippets using YASnippet.
|
|
(YASnippet can be installed from GNU ELPA.)
|
|
|
|
@item
|
|
If the popular third-party package @code{markdown-mode} is installed,
|
|
and the server provides at-point documentation formatted as Markdown in
|
|
addition to plain text, Eglot arranges for the ElDoc package to enrich
|
|
this text with fontifications and other nice formatting before
|
|
displaying it to the user. This makes the documentation shown by ElDoc
|
|
look nicer on display.
|
|
|
|
@item
|
|
In addition to enabling and enhancing other features and packages, Eglot
|
|
also provides a number of user commands based on the capabilities of
|
|
language servers. Examples include renaming symbols with
|
|
@kbd{eglot-rename} and asking to automatically correct problems with
|
|
@kbd{eglot-code-actions}. @xref{Eglot Commands}.
|
|
@end itemize
|
|
|
|
Not all servers support the full set of LSP capabilities, but most of
|
|
them support enough to enable the basic set of features mentioned above.
|
|
|
|
Conversely, some servers offer capabilities for which no equivalent
|
|
Emacs package exists yet, and so Eglot cannot (yet) expose these
|
|
capabilities to Emacs users. However, @xref{Extending Eglot}.
|
|
|
|
Finally, it's worth noting that, by default, Eglot generally turns on
|
|
all features that it @emph{can} turn on. It's possible to opt out of
|
|
features via the @code{eglot-ignored-server-capabilities} user option
|
|
(@pxref{Customizing Eglot}) and the @code{eglot-managed-mode-hook} hook
|
|
that runs after Eglot starts managing a buffer (@pxref{Eglot and
|
|
Buffers}).
|
|
|
|
@node Eglot and Buffers
|
|
@section Buffers, Projects, and Eglot
|
|
@cindex buffers managed by Eglot
|
|
@cindex projects and Eglot
|
|
|
|
@cindex workspace
|
|
One of the main strong points of using a language server is that a
|
|
language server has a broad view of the program: it considers more than
|
|
just the single source file you are editing. Ideally, the language
|
|
server should know about all the source files of your program which are
|
|
written in the language supported by the server. In LSP parlance, the
|
|
set of the source files of a program is known as a @dfn{workspace}. The
|
|
Emacs equivalent of a workspace is a @dfn{project} (@pxref{Projects,,,
|
|
emacs, GNU Emacs Manual}). Eglot fully supports Emacs projects, and
|
|
considers the file in whose buffer Eglot is turned on as belonging to a
|
|
project. In the simplest case, that file is the entire project, i.e.@:
|
|
your project consists of a single file. But there are other more
|
|
complex projects:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
A single-directory project: several source files in a single common
|
|
directory.
|
|
|
|
@item
|
|
A VC project: source files in a directory hierarchy under some VCS,
|
|
e.g.@: a VCS repository (@pxref{Version Control,,, emacs, GNU Emacs
|
|
Manual}).
|
|
|
|
@item
|
|
An EDE project: source files in a directory hierarchy managed via the
|
|
Emacs Development Environment (@pxref{EDE,,, emacs, GNU Emacs
|
|
Manual}).
|
|
@end itemize
|
|
|
|
Eglot uses Emacs's project management infrastructure to figure out which
|
|
files and buffers belong to what project, so any kind of project
|
|
supported by that infrastructure is automatically supported by Eglot.
|
|
|
|
When Eglot starts a server program, it does so in the project's root
|
|
directory, which is usually the top-level directory of the project's
|
|
directory hierarchy. This ensures the language server has the same
|
|
comprehensive view of the project's files as you do.
|
|
|
|
For example, if you visit the file @file{~/projects/fooey/lib/x.foo} and
|
|
@file{x.foo} belongs to a project rooted at @file{~/projects/fooey}
|
|
(perhaps because a @file{.git} directory exists there), then @kbd{M-x
|
|
eglot} causes the server program to start with that root as the current
|
|
working directory. The server then will analyze not only the file
|
|
@file{lib/x.foo} you visited, but likely also all the other @file{*.foo}
|
|
files under the @file{~/projects/fooey} directory.
|
|
|
|
In some cases, additional information specific to a given project will
|
|
need to be provided to the language server when starting it. The
|
|
variable @code{eglot-workspace-configuration} (@pxref{Customizing
|
|
Eglot}) exists for that purpose. It specifies the parameters and their
|
|
values to communicate to each language server which needs that.
|
|
|
|
When Eglot is active for a project, the project's buffers are treated
|
|
specially in several ways:
|
|
|
|
@itemize @bullet
|
|
@cindex mode-line indication of language server
|
|
@cindex mouse clicks on mode-line, and Eglot
|
|
@vindex eglot-menu
|
|
@item
|
|
All of the project's file-visiting buffers under the same major-mode are
|
|
served by a single language server connection. (If the project uses
|
|
several programming languages, there will usually be a separate server
|
|
connection for each group of files written in the same language and
|
|
using the same Emacs major-mode.) Eglot adds the
|
|
@samp{[eglot:@var{project}]} indication to the mode line of each such
|
|
buffer, where @var{server} is the name of the server and @var{project}
|
|
identifies the project by its root directory. Clicking the mouse on the
|
|
Eglot mode-line indication activates a menu with server-specific items.
|
|
The layout of the Eglot mode-line can be changed by customizing
|
|
@code{eglot-mode-line-format} (@pxref{Customization Variables}).
|
|
|
|
@item
|
|
For each buffer in which Eglot is active, it notifies the language
|
|
server that Eglot is @dfn{managing} the file visited by that buffer.
|
|
This tells the language server that the file's contents on disk may no
|
|
longer be up-to-date due to unsaved edits. Eglot reports to the server
|
|
any changes in the text of each managed buffer, to make the server aware
|
|
of unsaved changes. This includes your editing of the buffer and also
|
|
changes done automatically by other Emacs features and commands.
|
|
Killing a buffer relinquishes its management by Eglot and notifies the
|
|
server that the file on disk is up-to-date.
|
|
|
|
@item
|
|
When you visit a file under the same project, whether an existing or a
|
|
new file, its buffer is automatically added to the set of buffers
|
|
managed by Eglot, and the server which supports the buffer's major-mode
|
|
is notified about that. Thus, visiting a non-existent file
|
|
@file{/home/joe/projects/fooey/lib/y.foo} in the above example will
|
|
notify the server of the @file{*.foo} files' language that a new file
|
|
was added to the project, even before the file appears on disk. The
|
|
special Eglot minor mode is also turned on automatically in the buffer
|
|
visiting the file.
|
|
|
|
@item
|
|
Eglot turns on a special minor mode in each buffer it manages. This
|
|
minor mode ensures the server is notified about files Eglot manages.
|
|
Unlike other minor-modes, this special minor mode is @emph{not}
|
|
activated manually by the user, but automatically, as the result of
|
|
starting an Eglot session for the buffer. When Eglot stops managing the
|
|
buffer, the minor mode is turned off, and all the settings that Eglot
|
|
changed are restored to their original values.
|
|
|
|
@vindex eglot-managed-mode-hook
|
|
@vindex eglot-managed-p
|
|
@item
|
|
The minor mode's main job is to ``hook up'' Eglot to other Emacs
|
|
functionality, i.e. arrange for these features to receive information
|
|
from the language server, by changing special variables controlling
|
|
these features. @xref{Eglot Features}.
|
|
|
|
@item
|
|
To customize this, Eglot's special minor mode provides a hook variable
|
|
@code{eglot-managed-mode-hook} specifically to alter Eglot's interaction
|
|
with these variables in each buffer. This hook is run both when the
|
|
minor mode is turned on and when it's turned off; use the function
|
|
@code{eglot-managed-p} to tell if current buffer is still being managed
|
|
or not.
|
|
@end itemize
|
|
|
|
For example, to turn off @dfn{inlay hints} and @dfn{semantic tokens} by
|
|
default but still retain the ability to turn them on again
|
|
interactively use this:
|
|
|
|
@lisp
|
|
(add-hook 'eglot-managed-mode-hook
|
|
(lambda ()
|
|
(eglot-inlay-hints-mode -1)
|
|
(eglot-semantic-tokens-mode -1)))
|
|
@end lisp
|
|
|
|
@node Eglot Commands
|
|
@section Eglot Commands
|
|
@cindex commands, Eglot
|
|
|
|
This section provides a reference for the most commonly used Eglot
|
|
commands:
|
|
|
|
@ftable @code
|
|
@item M-x eglot
|
|
This command adds the current buffer and the file it visits to the group
|
|
of buffers and files managed by Eglot on behalf of a suitable language
|
|
server. If a language server for the buffer's @code{major-mode}
|
|
(@pxref{Major Modes,,, emacs, GNU Emacs Manual}) is not yet running, it
|
|
will be started; otherwise the buffer and its file will be added to
|
|
those managed by an existing server session.
|
|
|
|
The command attempts to figure out the buffer's major mode and the
|
|
suitable language server; in case it fails, it might prompt for the
|
|
major mode to use and for the server program to start. If invoked with
|
|
@kbd{C-u}, it always prompts for the server program, and if invoked with
|
|
@kbd{C-u C-u}, it also prompts for the major mode.
|
|
|
|
If the language server is successfully started and contacted, this
|
|
command arranges for any other buffers belonging to the same project and
|
|
using the same major mode to use the same language server session. That
|
|
includes any buffers created by visiting files after this command
|
|
succeeds to connect to a language server.
|
|
|
|
All the Emacs features that are capable of using Eglot services
|
|
(@pxref{Eglot Features}) are automatically configured by this command to
|
|
start using the language server via Eglot. To customize which Emacs
|
|
features will be configured to use Eglot, use the
|
|
@code{eglot-stay-out-of} option (@pxref{Customizing Eglot}).
|
|
|
|
@item M-x eglot-reconnect
|
|
This command shuts down the current connection to the language server
|
|
and immediately restarts it using the same options used originally.
|
|
This can sometimes be useful to unclog a partially malfunctioning server
|
|
connection.
|
|
|
|
@item M-x eglot-shutdown
|
|
This command shuts down a language server. It prompts for a language
|
|
server to shut down (unless there's only one server session, and it
|
|
manages the current buffer). Then the command shuts down the server and
|
|
stops managing the buffers the server was used for. Emacs features
|
|
(@pxref{Eglot Features}) that Eglot configured to work with the language
|
|
server are restored back to their original configuration.
|
|
|
|
Normally, this command kills the buffers used for communicating with the
|
|
language server, but if invoked with a prefix argument @kbd{C-u}, the
|
|
command doesn't kill those buffers, allowing them to be used for
|
|
diagnostics and problem reporting (@pxref{Troubleshooting Eglot}).
|
|
|
|
@item M-x eglot-shutdown-all
|
|
This command shuts down all the language servers active in the current
|
|
Emacs session. As with @code{eglot-shutdown}, invoking this command
|
|
with a prefix argument avoids killing the buffers used for
|
|
communications with the language servers.
|
|
|
|
@item M-x eglot-rename
|
|
This command renames the program symbol (a.k.a.@: @dfn{identifier}) at
|
|
point to another name. It prompts for the new name of the symbol, and
|
|
then modifies all the files in the project which are managed by the
|
|
language server of the current buffer to implement the renaming.
|
|
|
|
@item M-x eglot-format
|
|
This command reformats the active region according to the
|
|
language server rules. If no region is active, it reformats the entire
|
|
current buffer.
|
|
|
|
@item M-x eglot-format-buffer
|
|
This command reformats the current buffer, in the same manner as
|
|
@code{eglot-format} does.
|
|
|
|
@cindex code actions
|
|
@item M-x eglot-code-actions
|
|
@itemx M-x eglot-code-action-organize-imports
|
|
@itemx M-x eglot-code-action-quickfix
|
|
@itemx M-x eglot-code-action-extract
|
|
@itemx M-x eglot-code-action-inline
|
|
@itemx M-x eglot-code-action-rewrite
|
|
These commands allow you to invoke the so-called @dfn{code actions}:
|
|
requests for the language server to provide editing commands for
|
|
correcting, refactoring or beautifying your code. These commands may
|
|
affect more than one visited file belonging to the project.
|
|
|
|
The command @code{eglot-code-actions} asks the server if there are any
|
|
code actions for any point in the buffer or contained in the active
|
|
region. If there are, you have the choice to execute one of them via
|
|
the minibuffer.
|
|
|
|
A common use of code actions is fixing the Flymake error diagnostics
|
|
issued by Eglot (@pxref{Top,,, Flymake, GNU Flymake manual}). Clicking
|
|
on a diagnostic with @kbd{mouse-2} invokes
|
|
@code{eglot-code-actions-at-mouse} which pops up a menu of available
|
|
code actions. The variable @code{eglot-diagnostics-map} can be used to
|
|
control the mouse binding.
|
|
|
|
Other commands execute a specific code action. For example,
|
|
@code{eglot-code-action-organize-imports} rearranges the program's
|
|
@dfn{imports}---declarations of modules whose capabilities the program
|
|
uses.
|
|
|
|
@cindex inlay hints
|
|
@item M-x eglot-inlay-hints-mode
|
|
This command toggles LSP @dfn{inlay hints} on and off for the current
|
|
buffer. Inlay hints are small text annotations to specific parts of the
|
|
whole buffer, not unlike diagnostics, but designed to help readability
|
|
instead of indicating problems. For example, a C++ language server can
|
|
serve hints about positional parameter names in function calls and a
|
|
variable's automatically deduced type. Inlay hints help the user not
|
|
have to remember these things by heart.
|
|
|
|
@cindex momentary inlay hints
|
|
@item eglot-momentary-inlay-hints
|
|
When bound to a single key in @code{eglot-mode-map}
|
|
(@pxref{Customization Variables}), this will arrange for inlay hints to
|
|
be displayed as long as the key is held down, and then hidden shortly
|
|
after it is released. The best way to set it up is something like this:
|
|
|
|
@lisp
|
|
(define-key eglot-mode-map [f7] 'eglot-momentary-inlay-hints)
|
|
@end lisp
|
|
|
|
@noindent
|
|
Note that Emacs doesn't support binding to \"key up\" events, so this
|
|
command offers an approximation by estimating your system keyboard delay
|
|
and repeat rate.
|
|
|
|
@cindex semantic tokens
|
|
@item M-x eglot-semantic-tokens-mode
|
|
This command toggles LSP @dfn{semantic tokens} fontification on and off
|
|
for the current buffer. Semantic tokens provide enhanced syntax
|
|
highlighting based on the language server's semantic analysis of the
|
|
code, going beyond traditional regular-expression-based fontification.
|
|
For example, the server can distinguish between different kinds of
|
|
variables (parameters, local variables, fields) or indicate whether a
|
|
function is being declared or called.
|
|
|
|
@vindex eglot-semantic-token-types
|
|
@vindex eglot-semantic-token-modifiers
|
|
The @code{eglot-semantic-faces} customization group contains the user
|
|
options @code{eglot-semantic-token-types} and
|
|
@code{eglot-semantic-token-modifiers}, which control which semantic
|
|
token types and modifiers reported by the language server Eglot should
|
|
consider when fontifying. For performance reasons, the server
|
|
connection has to be restarted before changes take effect.
|
|
|
|
@cindex semantic token faces
|
|
The @code{eglot-semantic-faces} customization group also contains the
|
|
face definitions for controlling the appearance of each token.
|
|
|
|
@cindex type hierarchy
|
|
@item M-x eglot-show-type-hierarchy
|
|
Pop up a special buffer showing a interactive tree which represents a
|
|
hierarchy of subtypes and supertypes for the symbol at point.
|
|
|
|
@cindex call hierarchy
|
|
@item M-x eglot-call-type-hierarchy
|
|
Pop up a special buffer showing a interactive tree which represents a
|
|
hierarchy of callers and callee for the symbol at point.
|
|
@end ftable
|
|
|
|
The following Eglot commands are used less commonly, mostly for
|
|
diagnostic and troubleshooting purposes:
|
|
|
|
@ftable @code
|
|
@item M-x eglot-events-buffer
|
|
This command pops up the events buffer used for communication with the
|
|
language server of the current buffer.
|
|
|
|
@item M-x eglot-stderr-buffer
|
|
This command pops up the buffer with the debug info printed by the
|
|
language server to its standard error stream.
|
|
|
|
@item M-x eglot-forget-pending-continuations
|
|
Forget pending requests for the server of the current buffer.
|
|
@c FIXME: Better description of the need.
|
|
|
|
@item M-x eglot-signal-didChangeConfiguration
|
|
This command updates the language server configuration according to the
|
|
current value of the variable @code{eglot-workspace-configuration}
|
|
(@pxref{Customizing Eglot}).
|
|
|
|
@item M-x eglot-clear-status
|
|
Clear the last JSONRPC error for the server of the current buffer.
|
|
Eglot keeps track of erroneous situations encountered by the server in
|
|
its mode-line indication so that the user may inspect the communication
|
|
leading up to it (@pxref{Troubleshooting Eglot}). If the situation is
|
|
deemed uninteresting or temporary, this command can be used to
|
|
``forget'' the error. Note that the command @code{M-x eglot-reconnect}
|
|
can sometimes be used to unclog a temporarily malfunctioning server.
|
|
@end ftable
|
|
|
|
As described in @ref{Eglot Features} most features associated with Eglot
|
|
are actually provided by other Emacs packages and features, and Eglot
|
|
only enhances them by allowing them to use the information coming from
|
|
the language servers. For completeness, here's the list of commands of
|
|
those other packages that are very commonly used in Eglot-managed
|
|
buffers:
|
|
|
|
@c Not @ftable, because the index entries should mention Eglot
|
|
@table @code
|
|
@cindex ElDoc, and Eglot
|
|
@cindex documentation using Eglot
|
|
@item M-x eldoc
|
|
Ask the ElDoc system for help at point.
|
|
|
|
@cindex Flymake, and Eglot
|
|
@cindex on-the-fly diagnostics using Eglot
|
|
@item M-x flymake-show-buffer-diagnostics
|
|
Ask Flymake system to display diagnostics for the current buffer.
|
|
|
|
@item M-x flymake-show-project-diagnostics
|
|
Ask Flymake to list diagnostics for all the files in the current
|
|
project.
|
|
|
|
@cindex xref, and Eglot
|
|
@cindex finding definitions of identifiers using Eglot
|
|
@item M-x xref-find-definitions
|
|
Ask Xref to go the definition of the identifier at point.
|
|
|
|
@cindex imenu navigation using Eglot
|
|
@item M-x imenu
|
|
Let the user navigate the program source code using buffer index,
|
|
categorizing program elements by syntactic class (class, method,
|
|
variable, etc.) and offering completion.
|
|
|
|
@cindex symbol completion using Eglot
|
|
@item M-x completion-at-point
|
|
Request completion of the symbol at point.
|
|
@end table
|
|
|
|
@node Customizing Eglot
|
|
@chapter Customizing Eglot
|
|
@cindex customizing Eglot
|
|
|
|
To have Eglot behave like you want it, sometimes it suffices to
|
|
customize Emacs packages and features that Eglot uses but to do so for
|
|
all of Emacs (regardless of Eglot) . For example, to configure the
|
|
amount of space taken up by documentation in the echo area, customize
|
|
the ElDoc variable @code{eldoc-echo-area-use-multiline-p}. To configure
|
|
Flymake faces used for errors and warnings, customize the
|
|
@code{flymake-error} and @code{flymake-warning} faces.
|
|
|
|
Compared to the breadth of its functionality, Eglot itself has a
|
|
relatively small number of customization variables. There is
|
|
additionally a set of variables that are usually set from Elisp snippets
|
|
(@pxref{Init File,,, emacs, The GNU Emacs Manual}).
|
|
|
|
Other times, it's necessary to have finer control of Eglot's interaction
|
|
with these features. @xref{More Customization}.
|
|
|
|
@menu
|
|
* Customization Variables::
|
|
* Other Variables::
|
|
* More Customization::
|
|
@end menu
|
|
|
|
@node Customization Variables
|
|
@section Customization Variables
|
|
@cindex variables, Eglot
|
|
|
|
This section provides a reference for the Eglot user options.
|
|
|
|
@vtable @code
|
|
@item eglot-autoreconnect
|
|
This option controls the ability to reconnect automatically to the
|
|
language server when Eglot detects that the server process terminated
|
|
unexpectedly. The default value @code{3} means to attempt reconnection
|
|
only if the previous successful connection lasted for more than that
|
|
number of seconds; a different positive value changes the minimal length
|
|
of the connection to trigger reconnection. A value of @code{t} means
|
|
always reconnect automatically, and @code{nil} means never reconnect (in
|
|
which case you will need to reconnect manually using @kbd{M-x eglot}).
|
|
|
|
@item eglot-connect-timeout
|
|
This specifies the number of seconds before connection attempt to a
|
|
language server times out. The value of @code{nil} means never time
|
|
out. The default is 30 seconds.
|
|
|
|
@item eglot-sync-connect
|
|
This setting is mainly important for connections which are slow to
|
|
establish. Whereas the variable @code{eglot-connect-timeout} controls
|
|
how long to wait for, this variable controls whether to block Emacs's
|
|
user interface while waiting. The default value is @code{3}; a positive
|
|
value means block for that many seconds, then wait for the connection in
|
|
the background. The value of @code{t} means block during the whole
|
|
waiting period. The value of @code{nil} or @code{0} means don't block
|
|
at all during the waiting period.
|
|
|
|
@item eglot-events-buffer-config
|
|
This configures the size and format of the Eglot events buffer.
|
|
@xref{Eglot Commands, eglot-events-buffer}, for how to access that
|
|
buffer. If the value is changed, the connection should be restarted
|
|
using @kbd{M-x eglot-reconnect} for the new value to take effect.
|
|
@c FIXME: Shouldn't the defcustom do this by itself using the :set
|
|
@c attribute? Maybe not because reconnecting is a complex task.
|
|
@xref{Troubleshooting Eglot}, for when this could be useful.
|
|
|
|
@item eglot-autoshutdown
|
|
If this is non-@code{nil}, Eglot shuts down a language server when the
|
|
last buffer managed by it is killed. @xref{Shutting Down LSP Servers}.
|
|
The default is @code{nil}; if you want to shut down a server, use
|
|
@kbd{M-x eglot-shutdown} (@pxref{Eglot Commands}).
|
|
|
|
@item eglot-confirm-server-edits
|
|
Various Eglot commands and code actions result in the language server
|
|
sending editing commands to Emacs. If this option's value is
|
|
non-@code{nil}, Eglot will ask for confirmation before performing edits
|
|
proposed by the language server. This option's value can be crafted to
|
|
require this confirmation for specific commands or only when the edit
|
|
affects files not yet visited by the user. Consult this option's
|
|
docstring for more information.
|
|
|
|
@item eglot-ignored-server-capabilities
|
|
This variable's value is a list of language server capabilities that
|
|
Eglot should not use. The default is @code{nil}: Eglot uses all of the
|
|
capabilities supported by each server.
|
|
|
|
@item eglot-extend-to-xref
|
|
If this is non-@code{nil}, and @kbd{M-.} (@code{xref-find-definitions})
|
|
lands you in a file outside of your project, such as a system-installed
|
|
library or header file, transiently consider that file as managed by the
|
|
same language server. That file is still outside your project
|
|
(i.e. @code{project-find-file} won't find it), but Eglot and the server
|
|
will consider it to be part of the workspace. The default is
|
|
@code{nil}.
|
|
|
|
@item eglot-mode-map
|
|
This variable is the keymap for binding Eglot-related command. It is in
|
|
effect only as long as the buffer is managed by Eglot. By default, it
|
|
is empty, with the single exception: @kbd{C-h .} is remapped to invoke
|
|
@code{eldoc-doc-buffer}. You can bind additional commands in this map.
|
|
For example:
|
|
|
|
@lisp
|
|
(define-key eglot-mode-map (kbd "C-c r") 'eglot-rename)
|
|
(define-key eglot-mode-map (kbd "C-c o") 'eglot-code-action-organize-imports)
|
|
(define-key eglot-mode-map (kbd "C-c h") 'eldoc)
|
|
(define-key eglot-mode-map (kbd "<f6>") 'xref-find-definitions)
|
|
(define-key eglot-mode-map (kbd "<f7>") 'eglot-momentary-inlay-hints)
|
|
@end lisp
|
|
|
|
@cindex progress
|
|
@item eglot-report-progress
|
|
Set this variable to non-nil if you'd like progress notifications coming
|
|
from the language server to be handled by Emacs's progress reporting
|
|
facilities. If the value is the symbol @code{messages} the message
|
|
buffer is used, else the progress is reported in the mode line.
|
|
|
|
@cindex request cancellation
|
|
@item eglot-advertise-cancellation
|
|
Setting this variable to true causes Eglot to send special cancellation
|
|
notification for certain stale client request. This may help some LSP
|
|
servers avoid doing costly but ultimately useless work on behalf of the
|
|
client, improving overall performance.
|
|
|
|
@item eglot-code-action-indications
|
|
This variable controls the indication of code actions available at
|
|
point. Value is a list of symbols, more than one can be specified:
|
|
|
|
@itemize @minus
|
|
@item
|
|
@code{eldoc-hint}: ElDoc is used to hint about at-point actions.
|
|
@item
|
|
@code{margin}: A special indicator appears in the margin of the line
|
|
that point is currently on.
|
|
@item
|
|
@code{nearby}: An interactive special indicator appears near point.
|
|
@item
|
|
@code{mode-line}: An interactive special indicator appears in the mode
|
|
line.
|
|
@end itemize
|
|
|
|
@code{margin} and @code{nearby} are incompatible. If the list is empty,
|
|
ElDoc will not hint about at-point actions.
|
|
|
|
@item eglot-code-action-indicator
|
|
This variable is a string determining what the special indicator looks
|
|
like.
|
|
|
|
@item eglot-mode-line-format
|
|
This variables controls the shape and look of Eglot's mode line. Its
|
|
value is a mode line ``construct'', generally a list of symbols and
|
|
strings. The following symbols are meaningful and useful for Eglot's
|
|
mode line:
|
|
@itemize @minus
|
|
@item
|
|
@code{eglot-mode-line-menu}: access Eglot's main menu. See also
|
|
@code{eglot-menu-string};
|
|
@item
|
|
@code{eglot-mode-line-session}: indicate current project and access
|
|
current session's menu;
|
|
@item
|
|
@code{eglot-mode-line-error}: an indication of recent LSP errors;
|
|
@item
|
|
@code{eglot-mode-line-pending-requests}: number of pending LSP requests;
|
|
@item
|
|
@code{eglot-mode-line-progress}: progress reporter widgets;
|
|
@item
|
|
@code{eglot-mode-line-action-suggestion}: LSP code actions at point.
|
|
@end itemize
|
|
@end vtable
|
|
|
|
@node Other Variables
|
|
@section Other Variables
|
|
|
|
This section provides a reference for Eglot variables that are meant to
|
|
be changed from Elisp snippets.
|
|
|
|
@c @table, not @vtable, because some of the variables are indexed
|
|
@c elsewhere
|
|
@table @code
|
|
@item eglot-server-programs
|
|
This variable determines which language server to start for each
|
|
supported major mode, and how to invoke that server's program.
|
|
@xref{Setting Up LSP Servers}, for the details.
|
|
|
|
@vindex eglot-strict-mode
|
|
@item eglot-strict-mode
|
|
This is @code{nil} by default, meaning that Eglot is generally lenient
|
|
about non-conforming servers. If you need to debug a server, set this
|
|
to @w{@code{(disallow-non-standard-keys enforce-required-keys)}}.
|
|
|
|
@vindex eglot-server-initialized-hook
|
|
@item eglot-server-initialized-hook
|
|
A hook run after the server object is successfully initialized (which
|
|
includes launching the process) but before any LSP communication is
|
|
attempted. Each function receives a @code{eglot-lsp-server} instance as
|
|
argument.
|
|
|
|
@vindex eglot-connect-hook
|
|
@item eglot-connect-hook
|
|
A hook run after the LSP connection to the server is successfully
|
|
established. Each function receives a @code{eglot-lsp-server} instance
|
|
as argument. @xref{Starting Eglot}.
|
|
|
|
@item eglot-managed-mode-hook
|
|
A hook run after Eglot started or stopped managing a buffer.
|
|
@xref{Eglot and Buffers}, for details of its usage.
|
|
|
|
@vindex eglot-stay-out-of
|
|
@item eglot-stay-out-of
|
|
This variable's value lists Emacs features that Eglot shouldn't
|
|
automatically try to manage on the user's behalf. It is useful, for
|
|
example, when you need to use non-LSP Flymake or Company back-ends. To
|
|
have Eglot stay away from some Emacs feature, add that feature's symbol
|
|
or a regexp that will match a symbol's name to the list: for example,
|
|
the symbol @code{xref} to leave Xref alone, or the string @samp{company}
|
|
to stay away from your Company customizations. Here's an example:
|
|
|
|
@lisp
|
|
(add-to-list 'eglot-stay-out-of 'flymake)
|
|
@end lisp
|
|
|
|
Note that you can still configure the excluded Emacs features manually
|
|
to use Eglot in your @code{eglot-managed-mode-hook} or via some other
|
|
mechanism.
|
|
@end table
|
|
|
|
@node More Customization
|
|
@section More Customization
|
|
|
|
As explained earlier (@pxref{Eglot and Buffers}), Eglot hooks onto
|
|
existing Emacs packages and features by setting special variables in its
|
|
special minor mode. To gain finer control of Eglot's operation, the
|
|
@code{eglot-managed-mode-hook} should be used to tweak, subdue or
|
|
completely override Eglot's setting of these variables.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Eglot hooks onto ElDoc's @code{eldoc-documentation-functions} variable,
|
|
adding a number of functions to it:
|
|
@itemize @minus
|
|
@item @code{eglot-hover-eldoc-function}, to display general information
|
|
about an identifier.
|
|
@item @code{eglot-signature-eldoc-function}, to display function
|
|
signature information.
|
|
@item @code{eglot-highlight-eldoc-function}, to highlight nearby
|
|
manifestations of an identifier.
|
|
@item @code{eglot-code-action-suggestion}, to retrieve relevant code
|
|
actions at point.
|
|
@end itemize
|
|
|
|
A simple tweak to remove at-point identifier information for
|
|
hypothetical language @code{Foo} may look like:
|
|
|
|
@lisp
|
|
(add-hook 'foo-mode-hook
|
|
(lambda ()
|
|
(add-hook 'eglot-managed-mode-hook
|
|
(lambda ()
|
|
(remove-hook 'eldoc-documentation-functions
|
|
'eglot-hover-eldoc-function
|
|
nil t))
|
|
nil t)))
|
|
@end lisp
|
|
|
|
For more sophisticated changes, we can take advantage of ElDoc's
|
|
well-defined protocols. @xref{Programming Language Doc,,, emacs, GNU
|
|
Emacs Manual}. For instance, the functions in
|
|
@code{eldoc-display-functions} control displays of the at-point
|
|
documentation produced by @code{eldoc-documentation-functions}. As an
|
|
example, to ensure that hover documentation specifically is never output
|
|
into the Echo area (in all programming modes):
|
|
|
|
@lisp
|
|
(require 'cl-lib)
|
|
|
|
(defun my/special-eglot-hover-function (cb &rest _ignored)
|
|
"Same as `eglot-hover-eldoc-function`, but skip the echo area."
|
|
(eglot-hover-eldoc-function (lambda (info &rest _ignore)
|
|
(funcall cb info :echo 'skip))))
|
|
|
|
;; substitute 'eldoc-hover-eldoc-function with our "fixed" variant.
|
|
(add-hook
|
|
'eglot-managed-mode-hook
|
|
(lambda ()
|
|
(setq-local eldoc-documentation-functions
|
|
(cl-substitute #'my/special-eglot-hover-function
|
|
'eglot-hover-eldoc-function
|
|
eldoc-documentation-functions))))
|
|
@end lisp
|
|
|
|
@item
|
|
Eglot hooks onto Flymake's @code{flymake-diagnostic-functions} variable,
|
|
completely replacing its value with Eglot's own
|
|
@code{eglot-flymake-backend} function. Additional backends may be added
|
|
to work alongside Eglot's.
|
|
|
|
@lisp
|
|
(add-hook 'foo-mode-hook
|
|
(lambda ()
|
|
(add-hook 'eglot-managed-mode-hook
|
|
(lambda ()
|
|
(add-hook 'flymake-diagnostic-functions
|
|
#'my/special-foo-mode-backend
|
|
nil t))
|
|
nil t)))
|
|
@end lisp
|
|
|
|
@item
|
|
Eglot hooks onto Xref's @code{xref-backend-functions} variable, adding
|
|
its own @code{eglot-xref-backend} function to it.
|
|
|
|
@item
|
|
Eglot hooks onto Imenu's @code{imenu-create-index-function}.
|
|
|
|
@item
|
|
Eglot hooks onto Emacs's @code{completion-at-point-functions}.
|
|
|
|
@item
|
|
Eglot hooks onto Company's @code{company-backends} variable, ensuring
|
|
only the @code{company-capf} backend lives there. This ensures the same
|
|
set of completions as regular @code{completion-at-point}.
|
|
|
|
@item
|
|
Eglot hooks onto YASnippet by automatically activating
|
|
@code{yas-minor-mode} when needed to expand server-provided snippets.
|
|
@end itemize
|
|
|
|
@node Advanced server configuration
|
|
@chapter Advanced server configuration
|
|
|
|
Though many language servers work well out-of-the-box, most allow
|
|
fine-grained control of their operation via specific configuration
|
|
options that are transmitted over the LSP protocol and vary from server
|
|
to server. A small number of servers require such special configuration
|
|
to work acceptably, or even to work at all.
|
|
|
|
After having setup a server executable program in
|
|
@code{eglot-server-programs} (@pxref{Setting Up LSP Servers}) and
|
|
ensuring Eglot can invoke it, you may want to take advantage of some of
|
|
these options. You should first distinguish two main kinds of server
|
|
configuration:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Project-specific, applying to a specific project;
|
|
|
|
@item
|
|
User-specific, applying to all projects the server is used for.
|
|
@end itemize
|
|
|
|
When you have decided which kind you need, the following sections
|
|
teach how Eglot's user variables can be used to achieve it:
|
|
|
|
@menu
|
|
* Project-specific configuration::
|
|
* User-specific configuration::
|
|
* JSONRPC objects in Elisp::
|
|
@end menu
|
|
|
|
It's important to note that not all servers allow both kinds of
|
|
configuration, nor is it guaranteed that user options can be copied over
|
|
to project options, and vice-versa. When in doubt, consult your
|
|
language server's documentation.
|
|
|
|
It's also worth noting that some language servers can read these
|
|
settings from configuration files in the user's @code{HOME} directory or
|
|
in a project's directory. For example, the @command{pylsp} Python
|
|
server reads the file @file{~/.config/pycodestyle} for user
|
|
configuration. The @command{clangd} C/C++ server reads both
|
|
@file{~/.config/clangd/config.yaml} for user configuration and
|
|
@file{.clangd} for project configuration. It may be advantageous to use
|
|
these mechanisms instead of Eglot's, as this will probably work with
|
|
other LSP clients and may be easier to debug than options riding on the
|
|
LSP wire.
|
|
|
|
@node Project-specific configuration
|
|
@section Project-specific configuration
|
|
@vindex eglot-workspace-configuration
|
|
@cindex workspace configuration
|
|
|
|
To set project-specific settings, which the LSP specification calls
|
|
@dfn{workspace configuration}, the variable
|
|
@code{eglot-workspace-configuration} may be used.
|
|
|
|
This variable is a directory-local variable (@pxref{Directory Variables,
|
|
, Per-directory Local Variables, emacs, The GNU Emacs Manual}). It's
|
|
important to recognize that this variable really only makes sense when
|
|
set directory-locally. It usually does not make sense to set it
|
|
file-locally or in a major-mode hook.
|
|
|
|
The most common way to set @code{eglot-workspace-configuration } is
|
|
using a @file{.dir-locals.el} file in the root of your project. If you
|
|
can't do that, you may also set it from Elisp code via the
|
|
@code{dir-locals-set-class-variables} function. (@pxref{Directory Local
|
|
Variables,,, elisp, GNU Emacs Lisp Reference Manual}).
|
|
|
|
However you choose to set it, the variable's value is a plist
|
|
(@pxref{Property Lists,,, elisp, GNU Emacs Lisp Reference Manual}) with
|
|
the following format:
|
|
|
|
@lisp
|
|
(@var{:server1} @var{plist1} @var{:server2} @var{plist2} @dots{})
|
|
@end lisp
|
|
|
|
@noindent
|
|
Here, @var{:server1} and @var{:server2} are keywords whose names
|
|
identify the LSP language servers to target. Consult server
|
|
documentation to find out what name to use. @var{plist1} and
|
|
@var{plist2} are plists of options, possibly nesting other plists.
|
|
|
|
@findex eglot-show-workspace-configuration
|
|
When experimenting with workspace settings, you can use the command
|
|
@kbd{M-x eglot-show-workspace-configuration} to inspect and debug the
|
|
value of this variable in its final JSON form, ready to be sent to the
|
|
server (@pxref{JSONRPC objects in Elisp}). This helper command works
|
|
even before actually connecting to the server.
|
|
|
|
These variable's value doesn't take effect immediately. That happens
|
|
upon establishing the connection, in response to an explicit query from
|
|
the server, or when issuing the command @kbd{M-x
|
|
eglot-signal-didChangeConfiguration} which notifies the server during an
|
|
ongoing Eglot session.
|
|
|
|
@subsection Examples
|
|
|
|
For some users, setting @code{eglot-workspace-configuration} is a
|
|
somewhat daunting task. One of the reasons is having to manage the
|
|
general Elisp syntax of per-mode directory-local variables, which uses
|
|
alists (@pxref{Association Lists,,, elisp, GNU Emacs Lisp Reference
|
|
Manual}), and the specific syntax of Eglot's variable, which uses
|
|
plists. Some examples are useful.
|
|
|
|
Let's say you want to configure two language servers to be used in a
|
|
project written in a combination of the Python and Go languages. You
|
|
want to use the @command{pylsp} and @command{gopls} languages servers.
|
|
In the documentation of the servers in question (or in some other
|
|
editor's configuration file, or in some blog article), you find the
|
|
following configuration options in informal dotted-notation syntax:
|
|
|
|
@example
|
|
pylsp.plugins.jedi_completion.include_params: true
|
|
pylsp.plugins.jedi_completion.fuzzy: true
|
|
pylsp.pylint.enabled: false
|
|
gopls.usePlaceholders: true
|
|
@end example
|
|
|
|
To apply this to Eglot, and assuming you chose the
|
|
@file{.dir-locals.el} file method, the contents of that file could be:
|
|
|
|
@lisp
|
|
((nil
|
|
. ((eglot-workspace-configuration
|
|
. (:pylsp (:plugins (:jedi_completion (:include_params t
|
|
:fuzzy t)
|
|
:pylint (:enabled :json-false)))
|
|
:gopls (:usePlaceholders t)))))
|
|
(python-base-mode . ((indent-tabs-mode . nil)))
|
|
(go-mode . ((indent-tabs-mode . t))))
|
|
@end lisp
|
|
|
|
@noindent
|
|
Note how alists are used for associating Emacs mode names with other
|
|
alists, associating variable names with variable values. Then, pay
|
|
special attention to how the value of
|
|
@code{eglot-workspace-configuration} is a plist and @emph{not} an alist.
|
|
|
|
The above form sets the value of @code{eglot-workspace-configuration} in
|
|
all the buffers inside the project; each language server will then use
|
|
only the section of the parameters intended for it, and ignore the rest.
|
|
In our example, @command{pylsp} and @command{gopls} are solely
|
|
interested in the @code{:pylsp} and @code{:gopls} parameter section
|
|
names, respectively. However, section names don't have to match the
|
|
server name and some servers may be even interested in multiple
|
|
sections: the @command{typescript-language-server} server is known to be
|
|
interested in the @code{:javascript} and @code{:typescript} section
|
|
names.
|
|
|
|
To avoid sending whole configuration sections to servers who are
|
|
decidedly not interested in them, the following form may also be used:
|
|
|
|
@lisp
|
|
((python-base-mode
|
|
. ((eglot-workspace-configuration
|
|
. (:pylsp (:plugins (:jedi_completion (:include_params t
|
|
:fuzzy t)
|
|
:pylint (:enabled :json-false)))))
|
|
(indent-tabs-mode . nil)))
|
|
(go-mode
|
|
. ((eglot-workspace-configuration
|
|
. (:gopls (:usePlaceholders t)))
|
|
(indent-tabs-mode . t))))
|
|
@end lisp
|
|
|
|
@noindent
|
|
This sets up the value of @code{eglot-workspace-configuration}
|
|
separately depending on the major mode of each of that project's
|
|
buffers. @code{python-base-mode} buffers will have the variable set to
|
|
@code{(:pylsp (:plugins ...))}. @code{go-mode} buffers will have the
|
|
variable set to @code{(:gopls (:usePlaceholders t))}.
|
|
|
|
Some servers will issue workspace configuration for specific source
|
|
files inside your project. For example, if you know @code{gopls} is
|
|
asking about specific files in the @code{src/imported} subdirectory and
|
|
you want to set a different option for @code{gopls.usePlaceholders} ,
|
|
you may use something like:
|
|
|
|
@lisp
|
|
((python-base-mode
|
|
. ((eglot-workspace-configuration
|
|
. (:pylsp (:plugins (:jedi_completion (:include_params t
|
|
:fuzzy t)
|
|
:pylint (:enabled :json-false)))))
|
|
(indent-tabs-mode nil)))
|
|
(go-mode
|
|
. ((eglot-workspace-configuration
|
|
. (:gopls (:usePlaceholders t)))
|
|
(indent-tabs-mode t)))
|
|
("src/imported"
|
|
. ((eglot-workspace-configuration
|
|
. (:gopls (:usePlaceholders nil))))))
|
|
@end lisp
|
|
|
|
Finally, if one needs to determine the workspace configuration based on
|
|
some dynamic context, @code{eglot-workspace-configuration} can be set to
|
|
a function instead of a plist. The function is called with the
|
|
@code{eglot-lsp-server} instance of the connected server (if any) and
|
|
with @code{default-directory} set to the root of the project. The
|
|
function should return a plist suitable for use as the variable's value.
|
|
|
|
@node User-specific configuration
|
|
@section User-specific configuration
|
|
@cindex initializationOptions
|
|
@cindex command-line arguments
|
|
|
|
This kind of configuration applies to all projects the server is used
|
|
for. Here, there are a number of ways to do this inside Eglot.
|
|
|
|
A common way is to pass command-line options to the server invocation
|
|
via @code{eglot-server-programs}. Let's say we want to configure where
|
|
the @command{clangd} server reads its @code{compile_commands.json} from.
|
|
This can be done like so:
|
|
|
|
@lisp
|
|
(with-eval-after-load 'eglot
|
|
(add-to-list 'eglot-server-programs
|
|
`(c++-mode . ("clangd" "--compile-commands-dir=/tmp"))))
|
|
|
|
@end lisp
|
|
|
|
@noindent
|
|
Another way is to have Eglot pass a JSON object to the server during the
|
|
LSP handshake. This is done using the @code{:initializationOptions}
|
|
syntax of @code{eglot-server-programs}:
|
|
|
|
@lisp
|
|
(with-eval-after-load 'eglot
|
|
(add-to-list 'eglot-server-programs
|
|
`(c++-mode . ("clangd" :initializationOptions
|
|
(:compilationDatabasePath "/tmp")))))
|
|
@end lisp
|
|
|
|
@noindent
|
|
The argument @code{(:compilationDatabasePath "/tmp")} is Emacs's
|
|
representation in plist format of a simple JSON object
|
|
@code{@{"compilationDatabasePath": "/tmp"@}}. To learn how to represent
|
|
more deeply nested options in this format, @pxref{JSONRPC objects in
|
|
Elisp}.
|
|
|
|
In this case, the two examples achieve exactly the same, but notice how
|
|
the option's name has changed between them.
|
|
|
|
@vindex eglot-workspace-configuration
|
|
Finally there is another way to do user-specific configuration of
|
|
language servers, which may be used if the methods above are not
|
|
supported. It consists of @emph{globally} setting
|
|
@code{eglot-workspace-configuration}, a variable originally intended for
|
|
project-specific configuration. This has the same effect as giving all
|
|
your projects a certain default configuration, as described in
|
|
@ref{Project-specific configuration}. Here is an example:
|
|
|
|
@lisp
|
|
(setq-default eglot-workspace-configuration
|
|
'(:pylsp (:plugins (:jedi_completion (:include_params t
|
|
:fuzzy t)
|
|
:pylint (:enabled :json-false)))
|
|
:gopls (:usePlaceholders t)))
|
|
@end lisp
|
|
|
|
Note that the global value of @code{eglot-workspace-configuration} is
|
|
always overridden if a directory-local value is detected.
|
|
|
|
@node JSONRPC objects in Elisp
|
|
@section JSONRPC objects in Elisp
|
|
|
|
Emacs's preferred way of representing JSON is via Lisp lists. In Eglot,
|
|
the syntax of this list is the simplest possible (the one with fewer
|
|
parenthesis), a plist (@pxref{Property Lists,,, elisp, GNU Emacs Lisp
|
|
Reference Manual}).
|
|
|
|
The plist may be arbitrarily complex, and generally containing other
|
|
keyword-value property sub-plists corresponding to JSON sub-objects.
|
|
|
|
For representing the JSON leaf values @code{true}, @code{false},
|
|
@code{null} and @code{@{@}}, you can use the Lisp values @code{t},
|
|
@code{:json-false}, @code{nil}, and @code{eglot-@{@}}, respectively.
|
|
JSON arrays are represented as Elisp vectors surrounded by square
|
|
brackets (@pxref{Vectors,,,elisp,GNU Emacs Lisp Reference Manual}).
|
|
|
|
For example, the plist
|
|
|
|
@lisp
|
|
(:pylsp (:plugins (:jedi_completion (:include_params t
|
|
:fuzzy t
|
|
:cache_for ["pandas" "numpy"])
|
|
:pylint (:enabled :json-false)))
|
|
:gopls (:usePlaceholders t))
|
|
@end lisp
|
|
|
|
@noindent
|
|
is serialized by Eglot to the following JSON text:
|
|
|
|
@example
|
|
@{
|
|
"pylsp": @{
|
|
"plugins": @{
|
|
"jedi_completion": @{
|
|
"include_params": true,
|
|
"fuzzy": true,
|
|
"cache_for": [ "pandas", "numpy" ]
|
|
@},
|
|
"pylint": @{
|
|
"enabled": false
|
|
@}
|
|
@}
|
|
@},
|
|
"gopls": @{
|
|
"usePlaceholders": true
|
|
@}
|
|
@}
|
|
@end example
|
|
|
|
@node Multi-server support
|
|
@chapter Multi-server support
|
|
@cindex multiple servers per buffer
|
|
@cindex LSP server multiplexer
|
|
@cindex per-buffer multiple servers
|
|
|
|
One of the most frequently requested features for Eglot in close to a
|
|
decade of existence is the ability to use more than one LSP server in a
|
|
single buffer. This is distinct from using multiple servers in a
|
|
project, where each server manages a disjoint set of files written in
|
|
different languages.
|
|
|
|
The latter case---multiple servers for different files---is
|
|
intrinsically supported by Eglot. For example, in a web project with
|
|
JavaScript, CSS, and Python files, Eglot can seamlessly manage separate
|
|
language servers for each file type within the same project
|
|
(@pxref{Starting Eglot}). Each buffer communicates with its appropriate
|
|
server, and this works out-of-the-box.
|
|
|
|
However, there are several scenarios where multiple servers per buffer
|
|
are useful:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
Combining a spell-checking language server like @command{codebook-lsp}
|
|
with language-specific servers for C++, Go, or Python files. The
|
|
spell-checker provides diagnostics for comments and strings, while the
|
|
language server handles syntax and semantics.
|
|
|
|
@item
|
|
One might want multiple servers to cover different aspects of the same
|
|
language. For Python, you might combine @command{ty} for type checking
|
|
with @command{ruff} for linting and formatting. For JavaScript, you
|
|
might use @command{typescript-language-server} for language features
|
|
together with @command{eslint} for linting.
|
|
|
|
@item
|
|
When working on multi-language files like Vue @file{.vue} files, which
|
|
contain JavaScript, CSS, and HTML embedded in a single file, multiple
|
|
servers can manage the different areas of the buffer.
|
|
@end itemize
|
|
|
|
These use cases are not directly supported by Eglot's architecture,
|
|
however, you can use a language-agnostic @dfn{LSP server multiplexer}
|
|
that sits between Eglot and the actual language servers. Eglot still
|
|
communicates with a single LSP server process in each buffer, but that
|
|
process mediates communication to multiple language-specific servers,
|
|
meaning that for practical purposes, it's @emph{as if} Eglot was
|
|
connected to them directly.
|
|
|
|
This approach is more powerful and user-friendly than current
|
|
workarounds that combine one LSP server in a buffer with additional
|
|
non-LSP mechanisms such as extra Flymake backends (@pxref{Top,,,
|
|
Flymake, GNU Flymake manual}) for the same buffer.
|
|
|
|
@menu
|
|
* Using Rassumfrassum:: Setup the @code{rass} LSP multiplexer
|
|
* Design rationale:: Benefits and drawbacks of LSP multiplexers
|
|
@end menu
|
|
|
|
@node Using Rassumfrassum
|
|
@section Using Rassumfrassum
|
|
|
|
@uref{https://github.com/joaotavora/rassumfrassum, Rassumfrassum} is an
|
|
LSP server multiplexer program that fits the bill. Like most language
|
|
servers, it must be installed separately since it is not bundled with
|
|
Emacs (at time of writing). The installation is similar to installing
|
|
any other language server, and usually amounts to making sure the
|
|
program executable is somewhere in @code{PATH} or @code{exec-path}.
|
|
|
|
The Rassumfrassum program, invoked via the @command{rass} command, works
|
|
by spawning multiple LSP server subprocesses and aggregating their
|
|
capabilities, requests, and responses into a single unified LSP
|
|
interface. From Eglot's perspective, it appears to be communicating with
|
|
a single server.
|
|
|
|
To use Rassumfrassum with Eglot, you can start it interactively with a
|
|
prefix argument to @code{eglot} and specify the @command{rass} command
|
|
followed by the actual servers you want to use, separated by @code{--}:
|
|
|
|
@example
|
|
C-u M-x eglot RET rass -- clangd -- codebook-lsp serve RET
|
|
@end example
|
|
|
|
@noindent
|
|
This starts @command{clangd} for C++ language support and
|
|
@command{codebook-lsp} for spell-checking in the same buffer.
|
|
|
|
For Python, you might use:
|
|
|
|
@example
|
|
C-u M-x eglot RET rass -- ty server -- ruff server RET
|
|
@end example
|
|
|
|
@noindent
|
|
or simply @kbd{C-u M-x eglot RET rass python}, using the ``preset''
|
|
feature. This combines @command{ty} for type checking with
|
|
@command{ruff} for linting and formatting.
|
|
|
|
These configurations can be integrated into the
|
|
@code{eglot-server-programs} variable (@pxref{Setting Up LSP Servers})
|
|
for automatic use:
|
|
|
|
@lisp
|
|
(with-eval-after-load 'eglot
|
|
(add-to-list 'eglot-server-programs
|
|
'(c-ts-base-mode . ("rass" "--" "clangd" "--"
|
|
"codebook-lsp" "serve")))
|
|
(add-to-list 'eglot-server-programs
|
|
'(python-mode . ("rass" "--" "ty" "server" "--"
|
|
"ruff" "server"))))
|
|
@end lisp
|
|
|
|
@node Design rationale
|
|
@section Design rationale
|
|
|
|
Using an LSP server multiplexer like @command{rass} relieves Eglot from
|
|
knowing about the specific characteristics of individual servers and the
|
|
complexity of managing multiple simultaneous server connections per
|
|
buffer. This helps preserve the essential features that distinguish
|
|
Eglot's code base from other LSP offers for Emacs: simple, performant
|
|
and mindful of the core tenet of LSP, which is for a client to be
|
|
language-agnostic.
|
|
|
|
This approach has an additional benefit: because the multiplexer
|
|
mediates all communication between Eglot and the servers, it can take
|
|
advantage of different optimization opportunities. For instance, at the
|
|
system level it may be multi-threaded to process different JSONRPC
|
|
streams in with true parallelism, something which is currently
|
|
impossible to do in plain Elisp. At the LSP-level it can merge server
|
|
responses intelligently, truncate unnecessarily large objects, and cache
|
|
significant amounts of information in efficient ways. In many cases,
|
|
this can reduce the amount of JSONRPC traffic exchanged with Emacs to
|
|
levels well below what would occur if a client connected to multiple
|
|
servers separately. Some of these optimizations may apply even when a
|
|
program like @command{rass} is mediating communication to a single
|
|
server.
|
|
|
|
The multiplexer approach is not without drawbacks. Since LSP is a
|
|
relatively large protocol with a decade of existence and many backward
|
|
compatibility concerns, combining the responses of servers using completely
|
|
different mechanisms of the protocol to respond to the same request
|
|
sometimes leads to complexity in covering the corner cases. However,
|
|
offloading this complexity to a completely separate layer has proven
|
|
very effective in practice.
|
|
|
|
@node Extending Eglot
|
|
@chapter Extending Eglot
|
|
|
|
Sometimes it may be useful to extend existing Eglot functionality using
|
|
Elisp its public methods. A good example of when this need may arise is
|
|
adding support for a custom LSP protocol extension only implemented by a
|
|
specific server.
|
|
|
|
The best source of documentation for this is probably Eglot source code
|
|
itself, particularly the section marked ``API''.
|
|
|
|
Most of the functionality is implemented with Common-Lisp style generic
|
|
functions (@pxref{Generics,,,eieio,EIEIO}) that can be easily extended
|
|
or overridden. The Eglot code itself is an example on how to do this.
|
|
|
|
The following is a relatively simple example that adds support for the
|
|
@code{inactiveRegions} experimental feature introduced in version 17 of
|
|
the @command{clangd} C/C++ language server++.
|
|
|
|
Summarily, the feature works by first having the server detect the
|
|
Eglot's advertisement of the @code{inactiveRegions} client capability
|
|
during startup, whereupon the language server will report a list of
|
|
regions of inactive code for each buffer. This is usually code
|
|
surrounded by C/C++ @code{#ifdef} macros that the preprocessor removes
|
|
based on compile-time information.
|
|
|
|
The language server reports the regions by periodically sending a
|
|
@code{textDocument/inactiveRegions} notification for each managed buffer
|
|
(@pxref{Eglot and Buffers}). Normally, unknown server notifications are
|
|
ignored by Eglot, but we're going change that.
|
|
|
|
Both the announcement of the client capability and the handling of the
|
|
new notification is done by adding methods to generic functions.
|
|
|
|
@itemize @bullet
|
|
@item
|
|
The first method extends @code{eglot-client-capabilities} using a simple
|
|
heuristic to detect if current server is @command{clangd} and enables
|
|
the @code{inactiveRegion} capability.
|
|
|
|
@lisp
|
|
(cl-defmethod eglot-client-capabilities :around (server)
|
|
(let ((base (cl-call-next-method)))
|
|
(when (cl-find "clangd" (process-command
|
|
(jsonrpc--process server))
|
|
:test #'string-match)
|
|
(setf (cl-getf (cl-getf base :textDocument)
|
|
:inactiveRegionsCapabilities)
|
|
'(:inactiveRegions t)))
|
|
base))
|
|
@end lisp
|
|
|
|
Notice we use an internal function of the @code{jsonrpc.el} library, and
|
|
a regexp search to detect @command{clangd}. An alternative would be to
|
|
define a new EIEIO subclass of @code{eglot-lsp-server}, maybe called
|
|
@code{eglot-clangd}, so that the method would be simplified:
|
|
|
|
@lisp
|
|
(cl-defmethod eglot-client-capabilities :around ((_s eglot-clangd))
|
|
(let ((base (cl-call-next-method)))
|
|
(setf (cl-getf (cl-getf base :textDocument)
|
|
:inactiveRegionsCapabilities)
|
|
'(:inactiveRegions t))))
|
|
@end lisp
|
|
|
|
However, this would require that users tweak @code{eglot-server-program}
|
|
to tell Eglot instantiate such sub-classes instead of the generic
|
|
@code{eglot-lsp-server} (@pxref{Setting Up LSP Servers}). For the
|
|
purposes of this particular demonstration, we're going to use the more
|
|
hacky regexp route which doesn't require that.
|
|
|
|
Note, however, that detecting server versions before announcing new
|
|
capabilities is generally not needed, as both server and client are
|
|
required by LSP to ignore unknown capabilities advertised by their
|
|
counterparts.
|
|
|
|
@item
|
|
The second method implements @code{eglot-handle-notification} to process
|
|
the server notification for the LSP method
|
|
@code{textDocument/inactiveRegions}. For each region received it
|
|
creates an overlay applying the @code{shadow} face to the region.
|
|
Overlays are recreated every time a new notification of this kind is
|
|
received.
|
|
|
|
To learn about how @command{clangd}'s special JSONRPC notification
|
|
message is structured in detail you could consult that server's
|
|
documentation. Another possibility is to evaluate the first
|
|
capability-announcing method, reconnect to the server and peek in the
|
|
events buffer (@pxref{Eglot Commands, eglot-events-buffer}). You could
|
|
find something like:
|
|
|
|
@lisp
|
|
[server-notification] Mon Sep 4 01:10:04 2023:
|
|
(:jsonrpc "2.0" :method "textDocument/inactiveRegions" :params
|
|
(:textDocument
|
|
(:uri "file:///path/to/file.cpp")
|
|
:regions
|
|
[(:start (:character 0 :line 18)
|
|
:end (:character 58 :line 19))
|
|
(:start (:character 0 :line 36)
|
|
:end (:character 1 :line 38))]))
|
|
@end lisp
|
|
|
|
This reveals that the @code{textDocument/inactiveRegions} notification
|
|
contains a @code{:textDocument} property to designate the managed buffer
|
|
and an array of LSP regions under the @code{:regions} property. Notice
|
|
how the message (originally in JSON format), is represented as Elisp
|
|
plists (@pxref{JSONRPC objects in Elisp}).
|
|
|
|
The Eglot generic function machinery will automatically destructure the
|
|
incoming message, so these two properties can simply be added to the new
|
|
method's lambda list as @code{&key} arguments. Also, the
|
|
@code{eglot-uri-to-path} and @code{eglot-range-region} may be used to
|
|
easily parse the LSP @code{:uri} and @code{:start ... :end ...} objects
|
|
to obtain Emacs objects for file names and positions.
|
|
|
|
The remainder of the implementation consists of standard Elisp
|
|
techniques to loop over arrays, manage buffers and overlays.
|
|
|
|
@lisp
|
|
(cl-defmethod eglot-handle-notification
|
|
(_server (_method (eql textDocument/inactiveRegions))
|
|
&key regions textDocument &allow-other-keys)
|
|
(if-let* ((path (expand-file-name (eglot-uri-to-path
|
|
(cl-getf textDocument :uri))))
|
|
(buffer (find-buffer-visiting path)))
|
|
(with-current-buffer buffer
|
|
(remove-overlays nil nil 'inactive-code t)
|
|
(cl-loop
|
|
for r across regions
|
|
for (beg . end) = (eglot-range-region r)
|
|
for ov = (make-overlay beg end)
|
|
do
|
|
(overlay-put ov 'face 'shadow)
|
|
(overlay-put ov 'inactive-code t)))))
|
|
@end lisp
|
|
|
|
@end itemize
|
|
|
|
After evaluating these two additions and reconnecting to the
|
|
@command{clangd} language server (version 17), the result will be that
|
|
all the inactive code in the buffer will be nicely grayed out using the
|
|
LSP server knowledge about current compile time preprocessor defines.
|
|
|
|
@node Troubleshooting Eglot
|
|
@chapter Troubleshooting Eglot
|
|
@cindex troubleshooting Eglot
|
|
|
|
This chapter documents commands and variables that can be used to
|
|
troubleshoot Eglot problems. It also provides guidelines for
|
|
reporting Eglot bugs in a way that facilitates their resolution.
|
|
|
|
When you encounter problems with Eglot, try first using the commands
|
|
@kbd{M-x eglot-events-buffer} and @kbd{M-x eglot-stderr-buffer}. They
|
|
pop up special buffers that can be used to inspect the communications
|
|
between the Eglot and language server. In many cases, this will
|
|
indicate the problems or at least provide a hint.
|
|
|
|
@menu
|
|
* Performance::
|
|
* Getting the latest version::
|
|
* Reporting bugs::
|
|
@end menu
|
|
|
|
@node Performance
|
|
@section Performance
|
|
@cindex performance problems, with Eglot
|
|
A common and easy-to-fix cause of performance problems in Eglot
|
|
(especially in older versions) is its events buffer, since it represents
|
|
additional work that Eglot must do (@pxref{Eglot Commands,
|
|
eglot-events-buffer}). If you find Eglot is operating correctly but
|
|
slowly, try to customize the variable @code{eglot-events-buffer-config}
|
|
(@pxref{Customization Variables}) and set its @code{:size} property to
|
|
0. This will disable recording any events and may speed things up.
|
|
|
|
In other situations, the cause of poor performance lies in the language
|
|
server itself. Some servers use aggressive caching and other techniques
|
|
to improve their performance. Often, this can be tweaked by changing
|
|
the server configuration (@pxref{Advanced server configuration}).
|
|
|
|
Another aspect that may cause performance degradation is the amount of
|
|
JSONRPC information exchanged with Emacs. Using an LSP program like
|
|
@ref{Using Rassumfrassum,Rassumfrassum} may alleviate such problems.
|
|
|
|
@node Getting the latest version
|
|
@section Getting the latest version
|
|
@cindex upgrading Eglot
|
|
|
|
To install the latest Eglot in an Emacs version that does not bundle
|
|
Eglot, use @kbd{M-x package-install}.
|
|
|
|
Often, a newer Eglot version exists that has fixed a longstanding bug,
|
|
has more LSP features, or just better supports a particular language
|
|
server. Recent Eglot versions can self-update via the command @kbd{M-x
|
|
eglot-upgrade-eglot}. This will replace any currently installed version
|
|
with the newest one available from the ELPA archives configured in
|
|
@code{package-archives}.
|
|
|
|
You can also update Eglot through other methods, such as
|
|
@code{use-package} (@pxref{Installing packages,,, use-package,
|
|
use-package User Manual}), @code{package-install}, @code{list-packages}
|
|
or the newer @code{package-upgrade} (@pxref{Packages,,, emacs, GNU Emacs
|
|
Manual}). However, do read the docstrings of the command you intend to
|
|
use before you use it, as some of them may not work in exactly the same
|
|
way across Emacs versions, meaning your configuration may be not
|
|
portable.
|
|
|
|
@node Reporting bugs
|
|
@section Reporting bugs
|
|
@cindex bug reports
|
|
|
|
If you think you have found a bug, we want to hear about it. Before
|
|
reporting a bug, keep in mind that interaction with language servers
|
|
represents a large quantity of unknown variables. Therefore, it is
|
|
generally both @emph{difficult} and @emph{absolutely essential} that the
|
|
maintainers reproduce bugs exactly as they happened to you, the user.
|
|
|
|
To report an Eglot bug, send e-mail to @email{bug-gnu-emacs@@gnu.org}.
|
|
|
|
To understand how to write this email, get acquainted with Emacs's bug
|
|
reporting guidelines (@pxref{Bugs,,, emacs, GNU Emacs Manual}). Then,
|
|
follow this Eglot-specific checklist:
|
|
|
|
@enumerate
|
|
@item
|
|
Include the transcript of JSONRPC events obtained from the buffer popped
|
|
up by @kbd{M-x eglot-events-buffer}. You may narrow down the transcript
|
|
if you are sure of where the problematic exchange is, but it's safer to
|
|
include the whole transcript, either attached or inline.
|
|
|
|
@item
|
|
If Emacs signaled an error (an error message was seen or heard), make
|
|
sure to repeat the process after turning on @code{debug-on-error} via
|
|
@kbd{M-x toggle-debug-on-error}. This normally produces a backtrace of
|
|
the error that should also be attached to the bug report.
|
|
|
|
@item
|
|
Include a description of how the maintainer should obtain, install, and
|
|
configure the language server you used. Maintainers usually have access
|
|
to GNU/Linux systems, though not necessarily the distribution that you
|
|
may be using. If possible, try to replicate the problem with the
|
|
C/C@t{++} or Python servers, as these are very easy to install.
|
|
|
|
@item
|
|
If using an LSP multiplexer server like @ref{Using Rassumfrassum,
|
|
Rassumfrassum}, first verify if the program replicates by using one of
|
|
the multiplexed servers directly. If it doesn't the problem lies in the
|
|
LSP multiplexer program and should be reported there.
|
|
|
|
@item
|
|
Include a description of a @emph{minimal} project directory where Eglot
|
|
should be started for the problem to happen. Describe each file's name
|
|
and its contents, or---sometimes better--- zip that project directory
|
|
completely and attach it. Alternatively, you can supply the address of
|
|
a public Git repository.
|
|
|
|
@item
|
|
Include versions of the software used. The Emacs version can be
|
|
obtained with @kbd{M-x emacs-version}.
|
|
|
|
We welcome bug reports about all Eglot versions, but it is helpful to
|
|
first check if the problem isn't already fixed in the latest version
|
|
(@pxref{Getting the latest version}).
|
|
|
|
It's also essential to include the version of ELPA packages that are
|
|
explicitly or implicitly loaded. The optional but popular Company or
|
|
Markdown packages are distributed as GNU ELPA packages, not to mention
|
|
Eglot itself in some situations. Prefer reproducing the problem with
|
|
built-in Treesit major modes like @code{go-ts-mode} or
|
|
@code{rust-ts-mode} since the non-ts modes for such languages are
|
|
usually provided by ELPA packages, and it's often easy to miss them.
|
|
|
|
If you can't reproduce your bug without ELPA packages, you may find the
|
|
ones you're using in @code{~/.emacs.d/elpa} (or what is in
|
|
@code{package-user-dir}). Including a listing of files in that
|
|
directory is a way to tell the maintainers about ELPA package versions.
|
|
|
|
@item
|
|
Include a recipe to replicate the problem with @emph{a clean Emacs run}.
|
|
The invocation @code{emacs -Q -f package-initialize} starts Emacs with
|
|
no configuration and initializes the ELPA packages. A very minimal
|
|
@file{.emacs} initialization file (10 lines or less) is also acceptable
|
|
and good means to describe changes to variables.
|
|
|
|
There is usually no need to include @code{require} statements in the
|
|
recipe, as Eglot's functionality uses autoloads.
|
|
|
|
Likewise, there is rarely the need to use things like @code{use-package}
|
|
or @code{eglot-ensure}. This just makes the recipe harder to follow.
|
|
Prefer setting variables with @code{setq} and adding to hooks with
|
|
@code{add-hook}. Prefer starting Eglot with @code{M-x eglot}.
|
|
|
|
@item
|
|
Make sure to double check all the above elements and re-run the recipe
|
|
to see that the problem is reproducible. Following the recipe should
|
|
produce event transcript and error backtraces that are very similar to
|
|
the ones you included. If the problem only happens sometimes, mention
|
|
this in your report.
|
|
@end enumerate
|
|
|
|
Please keep in mind that some problems reported against Eglot may
|
|
actually be bugs in the language server or the Emacs feature/package
|
|
that used Eglot to communicate with the language server. Eglot is, in
|
|
many cases, just a frontend to that functionality.
|
|
|
|
@node GNU Free Documentation License
|
|
@appendix GNU Free Documentation License
|
|
@include doclicense.texi
|
|
|
|
@node Index
|
|
@unnumbered Index
|
|
@printindex cp
|
|
|
|
@bye
|