mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-22 07:09:54 +00:00
bfb486d802
* doc/misc/eglot.texi (Extending Eglot): Simplify. Copyright-paperwork-exempt: yes
1596 lines
64 KiB
Plaintext
1596 lines
64 KiB
Plaintext
\input texinfo @c -*-texinfo-*-
|
|
@c %**start of header
|
|
@setfilename ../../eglot.info
|
|
@settitle Eglot: The Emacs Client for the Language Server Protocol
|
|
@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--2024 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.
|
|
|
|
@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
|
|
* 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 with 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. Alternatively, install one or more servers
|
|
of your choice and add them to the value of
|
|
@code{eglot-server-programs}, as described in @ref{Setting Up LSP
|
|
Servers}.
|
|
|
|
@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
|
|
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{Eglot 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::
|
|
* Eglot Variables::
|
|
@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 at or near a symbol or an
|
|
identifier, the information about the symbol/identifier, such as the
|
|
signature of a function or class method and server-generated
|
|
diagnostics, is made available via the ElDoc package
|
|
(@pxref{Programming Language Doc,,, emacs, GNU Emacs Manual}). This
|
|
allows major modes to provide extensive help and documentation about
|
|
the program identifiers.
|
|
|
|
@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 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 language-server 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
|
|
Automatic reformatting of source code as you type it. This is similar
|
|
to what the @code{eglot-format} command does (see below), but is
|
|
activated automatically as you type.
|
|
|
|
@item
|
|
If a completion package such as @code{company-mode}, a popular
|
|
third-party completion package (or any other completion package), is
|
|
installed, Eglot enhances it by providing completion candidates based
|
|
on the language-server analysis of the source code.
|
|
(@code{company-mode} can be installed from GNU ELPA.)
|
|
|
|
@item
|
|
If @code{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
|
|
@code{yasnippet}. (@code{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
|
|
some features via user options (@pxref{Customizing Eglot}) and a 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 the
|
|
language-server 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, it performs several background
|
|
activities on behalf of the project and its buffers:
|
|
|
|
@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.
|
|
|
|
@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.
|
|
|
|
@vindex eglot-managed-mode-hook
|
|
@vindex eglot-managed-p
|
|
@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,
|
|
and also arranges for other Emacs features supported by Eglot
|
|
(@pxref{Eglot Features}) to receive information from the language
|
|
server, by changing the settings of these features. Unlike other
|
|
minor-modes, this special minor mode is not activated manually by the
|
|
user, but automatically, as the result of starting an Eglot session
|
|
for the buffer. However, this minor mode provides a hook variable
|
|
@code{eglot-managed-mode-hook} that can be used to customize the Eglot
|
|
management of the buffer. This hook is run both when the minor mode
|
|
is turned on and when it's turned off; use the variable
|
|
@code{eglot-managed-p} to tell if current buffer is still being
|
|
managed or not. When Eglot stops managing the buffer, this minor mode
|
|
is turned off, and all the settings that Eglot changed are restored to
|
|
their original values.
|
|
|
|
@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.
|
|
@end itemize
|
|
|
|
@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.
|
|
@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 Eglot Variables
|
|
@section Eglot 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)
|
|
@end lisp
|
|
|
|
@end vtable
|
|
|
|
Additional variables, which are relevant for customizing the server
|
|
connections, are documented in @ref{Customizing Eglot}.
|
|
|
|
@node Customizing Eglot
|
|
@chapter Customizing Eglot
|
|
@cindex customizing Eglot
|
|
|
|
Eglot itself has a relatively small number of customization options.
|
|
A large part of customizing Eglot to your needs and preferences should
|
|
actually be done via options of the Emacs packages and features which
|
|
Eglot supports and enhances (@pxref{Eglot Features}). For example:
|
|
|
|
@itemize @bullet
|
|
@item
|
|
To configure the face used for server-derived errors and warnings,
|
|
customize the Flymake faces @code{flymake-error} and
|
|
@code{flymake-warning}.
|
|
|
|
@item
|
|
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}.
|
|
|
|
@item
|
|
To completely change how ElDoc displays the at-point documentation
|
|
destination, customize the ElDoc variable
|
|
@code{eldoc-display-functions}.
|
|
@end itemize
|
|
|
|
For this reason, this manual describes only how to customize
|
|
Eglot's own operation, which mainly has to do with the server
|
|
connections and the server features to be used by Eglot.
|
|
|
|
@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.
|
|
|
|
@vindex eglot-connect-hook
|
|
@item eglot-connect-hook
|
|
A hook run after connection to the server is successfully
|
|
established. @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.
|
|
|
|
@vindex eglot-report-progress
|
|
@cindex progress
|
|
@item eglot-report-progress
|
|
Set this variable to true if you'd like progress notifications coming
|
|
from the language server to be handled as Emacs's progress reporting
|
|
facilities.
|
|
@end table
|
|
|
|
@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
|
|
This sets the value of @code{eglot-workspace-configuration} in all the
|
|
buffers inside the project; each server will use only the section of
|
|
the parameters intended for that server, and ignore the rest. Note
|
|
how alists are used for associating Emacs mode names with alists
|
|
associating variable names with variable values. Then notice how
|
|
plists are used inside the value of
|
|
@code{eglot-workspace-configuration}.
|
|
|
|
This 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 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. 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 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{Eglot 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. 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}).
|
|
|
|
@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
|
|
Describe how to setup a @emph{minimal} project directory where Eglot
|
|
should be started for the problem to happen. Describe each file's
|
|
name and its contents. 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. Some major modes (Go, Rust, etc.)
|
|
are provided by ELPA packages. It's sometimes easy to miss these,
|
|
since they are usually implicitly loaded when visiting a file in that
|
|
language.
|
|
|
|
ELPA packages usually live 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
|