Skip to content

Commit 1b1bb64

Browse files
Bryan C. Millsdmitshur
Bryan C. Mills
authored andcommitted
gopls/doc/emacs.md: describe configuration for eglot
Now that joaotavora/eglot#367 is fixed, I think we should recommend it as a serious alternative to LSP mode. This change describes both packages, summarizes their different philosophies, and simplifies the example LSP Mode configuration to avoid relying on another unnecessary third-party package. Users who need more detail on alternative configurations should consult the LSP client vendors' pages — we don't need to recapitulate all of that detail here. Change-Id: If125fbde6d609e223ce44936504cc4b08b84dc3d Reviewed-on: https://go-review.googlesource.com/c/tools/+/278774 Reviewed-by: Muir Manders <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]> Trust: Bryan C. Mills <[email protected]>
1 parent 7905cea commit 1b1bb64

File tree

1 file changed

+149
-40
lines changed

1 file changed

+149
-40
lines changed

gopls/doc/emacs.md

+149-40
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,69 @@
11
# Emacs
22

3-
Use [lsp-mode]. gopls is built in as a client. You first must install `gopls` and put it somewhere in your `PATH`. Here is a basic config to get you started (assuming you are using [use-package]):
3+
## Installing `gopls`
44

5-
```lisp
6-
(use-package lsp-mode
7-
:ensure t
8-
:commands (lsp lsp-deferred)
9-
:hook (go-mode . lsp-deferred))
5+
To use `gopls` with Emacs, you must first
6+
[install the `gopls` binary](user.md#installation) and ensure that the directory
7+
containing the resulting binary (either `$(go env GOBIN)` or `$(go env
8+
GOPATH)/bin`) is in your `PATH`.
9+
10+
## Choosing an Emacs LSP client
11+
12+
To use `gopls` with Emacs, you will need to choose and install an Emacs LSP
13+
client package. Two popular client packages are [LSP Mode] and [Eglot].
14+
15+
LSP Mode takes a batteries-included approach, with many integrations enabled
16+
“out of the box” and several additional behaviors provided by `lsp-mode` itself.
17+
18+
Eglot takes a minimally-intrusive approach, focusing on smooth integration with
19+
other established packages. It provides a few of its own `eglot-` commands but
20+
no additional keybindings by default.
21+
22+
Once you have selected which client you want to use, install it per the packages
23+
instructions: see [Eglot 1-2-3](https://github.com/joaotavora/eglot#1-2-3) or
24+
[LSP Mode Installation](https://emacs-lsp.github.io/lsp-mode/page/installation/).
25+
26+
## Common configuration
27+
28+
Both Eglot and LSP Mode can integrate with popular packages in the Emacs
29+
ecosystem:
30+
31+
* The built-in [`xref`] package provides cross-references.
32+
33+
* The built-in [Flymake] package provides an on-the-fly diagnostic overlay.
34+
35+
* [Company] mode displays code completion candidates (with a richer UI than
36+
the built-in [`completion-at-point`]).
37+
38+
Eglot provides documentation using the built-in [ElDoc] minor mode, while LSP
39+
Mode by default provides documentation using its own [`lsp-ui`] mode.
40+
41+
Eglot by default locates the project root using the [`project`] package. In LSP
42+
Mode, this behavior can be configured using the `lsp-auto-guess-root` setting.
43+
44+
## Configuring LSP Mode
45+
46+
### Loading LSP Mode in `.emacs`
47+
48+
```elisp
49+
(require 'lsp-mode)
50+
(add-hook 'go-mode-hook #'lsp-deferred)
1051
1152
;; Set up before-save hooks to format buffer and add/delete imports.
1253
;; Make sure you don't have other gofmt/goimports hooks enabled.
1354
(defun lsp-go-install-save-hooks ()
1455
(add-hook 'before-save-hook #'lsp-format-buffer t t)
1556
(add-hook 'before-save-hook #'lsp-organize-imports t t))
1657
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
17-
18-
;; Optional - provides fancier overlays.
19-
(use-package lsp-ui
20-
:ensure t
21-
:commands lsp-ui-mode)
22-
23-
;; Company mode is a standard completion package that works well with lsp-mode.
24-
(use-package company
25-
:ensure t
26-
:config
27-
;; Optionally enable completion-as-you-type behavior.
28-
(setq company-idle-delay 0)
29-
(setq company-minimum-prefix-length 1))
30-
31-
;; Optional - provides snippet support.
32-
(use-package yasnippet
33-
:ensure t
34-
:commands yas-minor-mode
35-
:hook (go-mode . yas-minor-mode))
3658
```
3759

38-
lsp-mode integrates with xref. By default `lsp-find-definition` is bound to `M-.`. To go back, use `M-,`. Explore other `lsp-*` commands (not everything is supported by gopls).
60+
### Configuring `gopls` via LSP Mode
3961

40-
## Gopls Configuration
62+
See [settings] for information about available gopls settings.
4163

42-
Stable gopls settings have first-class support in [lsp-mode]. For example, `(setq lsp-gopls-use-placeholders nil)` will disable placeholders in completion snippets. See [lsp-go] for a list of available variables.
64+
Stable gopls settings have corresponding configuration variables in `lsp-mode`.
65+
For example, `(setq lsp-gopls-use-placeholders nil)` will disable placeholders
66+
in completion snippets. See [`lsp-go`] for a list of available variables.
4367

4468
Experimental settings can be configured via `lsp-register-custom-settings`:
4569

@@ -49,22 +73,107 @@ Experimental settings can be configured via `lsp-register-custom-settings`:
4973
("gopls.staticcheck" t t)))
5074
```
5175

52-
See [settings] for information about gopls settings.
76+
Note that after changing settings you must restart gopls using e.g. `M-x
77+
lsp-restart-workspace`.
78+
79+
## Configuring Eglot
80+
81+
### Configuring `project` for Go modules in `.emacs`
82+
83+
Eglot uses the built-in `project` package to identify the LSP workspace for a
84+
newly-opened buffer. The `project` package does not natively know about `GOPATH`
85+
or Go modules. Fortunately, you can give it a custom hook to tell it to look for
86+
the nearest parent `go.mod` file (that is, the root of the Go module) as the
87+
project root.
88+
89+
```elisp
90+
(require 'project)
91+
92+
(defun project-find-go-module (dir)
93+
(when-let ((root (locate-dominating-file dir "go.mod")))
94+
(cons 'go-module root)))
95+
96+
(cl-defmethod project-root ((project (head go-module)))
97+
(cdr project))
98+
99+
(add-hook 'project-find-functions #'project-find-go-module)
100+
```
101+
102+
### Loading Eglot in `.emacs`
103+
104+
```elisp
105+
;; Optional: load other packages before eglot to enable eglot integrations.
106+
(require 'company)
107+
(require 'yasnippet)
53108
54-
Note that after changing settings you must restart gopls using e.g. `M-x lsp-restart-workspace`.
109+
(require 'go-mode)
110+
(require 'eglot)
111+
(add-hook 'go-mode-hook 'eglot-ensure)
112+
113+
;; Optional: install eglot-format-buffer as a save hook.
114+
;; The depth of -10 places this before eglot's willSave notification,
115+
;; so that that notification reports the actual contents that will be saved.
116+
(defun eglot-format-buffer-on-save ()
117+
(add-hook 'before-save-hook #'eglot-format-buffer -10 t))
118+
(add-hook 'go-mode-hook #'eglot-format-buffer-on-save)
119+
```
120+
121+
### Configuring `gopls` via Eglot
122+
123+
See [settings] for information about available gopls settings.
124+
125+
LSP server settings are controlled by the `eglot-workspace-configuration`
126+
variable, which can be set either globally in `.emacs` (as below) or in a
127+
`.dir-locals.el` file in the project root.
128+
129+
```elisp
130+
(setq-default eglot-workspace-configuration
131+
'((:gopls .
132+
((staticcheck . t)
133+
(matcher . "CaseSensitive")))))
134+
```
135+
136+
### Organizing imports with Eglot
137+
138+
`gopls` provides the import-organizing functionality of `goimports` as an LSP
139+
code action, which you can invoke as needed by running `M-x eglot-code-actions`
140+
(or a key of your choice bound to the `eglot-code-actions` function) and
141+
selecting `Organize Imports` at the prompt.
142+
143+
Eglot does not currently support a standalone function to execute a specific
144+
code action (see
145+
[joaotavora/eglot#411](https://github.com/joaotavora/eglot/issues/411)), nor an
146+
option to organize imports as a `before-save-hook` (see
147+
[joaotavora/eglot#574](https://github.com/joaotavora/eglot/issues/574)). In the
148+
meantime, see those issues for discussion and possible workarounds.
55149

56150
## Troubleshooting
57151

58152
Common errors:
59-
- When prompted by Emacs for your project folder, if you are using modules you must select the module's root folder (i.e. the directory with the "go.mod"). If you are using GOPATH, select your $GOPATH as your folder.
60-
- Emacs must have your environment set properly (PATH, GOPATH, etc). You can run `M-x getenv <RET> PATH <RET>` to see if your PATH is set in Emacs. If not, you can try starting Emacs from your terminal, using [this package][exec-path-from-shell], or moving your shell config from .bashrc into .bashenv (or .zshenv).
61-
- Make sure `lsp-mode` and `lsp-ui` are up-to-date, also make sure `lsp-go` and `company-lsp` are _not_ installed.
62-
- Look for errors in the `*lsp-log*` buffer.
63-
- Ask for help in the #emacs channel on the [Gophers slack].
64-
65-
[lsp-mode]: https://github.com/emacs-lsp/lsp-mode
66-
[use-package]: https://github.com/jwiegley/use-package
67-
[exec-path-from-shell]: https://github.com/purcell/exec-path-from-shell
153+
154+
- When prompted by Emacs for your project folder, if you are using modules you
155+
must select the module's root folder (i.e. the directory with the "go.mod").
156+
If you are using GOPATH, select your $GOPATH as your folder.
157+
- Emacs must have your environment set properly (PATH, GOPATH, etc). You can
158+
run `M-x getenv <RET> PATH <RET>` to see if your PATH is set in Emacs. If
159+
not, you can try starting Emacs from your terminal, using [this
160+
package][exec-path-from-shell], or moving your shell config from `.bashrc`
161+
into `.profile` and logging out and back in.
162+
- Make sure only one LSP client mode is installed. (For example, if using
163+
`lsp-mode`, ensure that you are not _also_ enabling `eglot`.)
164+
- Look for errors in the `*lsp-log*` buffer or run `M-x eglot-events-buffer`.
165+
- Ask for help in the `#emacs` channel on the [Gophers slack].
166+
167+
[LSP Mode]: https://emacs-lsp.github.io/lsp-mode/
168+
[Eglot]: https://github.com/joaotavora/eglot/blob/master/README.md
169+
[`xref`]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html
170+
[Flymake]: https://www.gnu.org/software/emacs/manual/html_node/flymake/Using-Flymake.html#Using-Flymake
171+
[Company]: https://company-mode.github.io/
172+
[`completion-at-point`]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html
173+
[ElDoc]: https://elpa.gnu.org/packages/eldoc.html
174+
[`lsp-ui`]: https://emacs-lsp.github.io/lsp-ui/
175+
[`lsp-go`]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el
176+
[`use-package`]: https://github.com/jwiegley/use-package
177+
[`exec-path-from-shell`]: https://github.com/purcell/exec-path-from-shell
68178
[settings]: settings.md
69-
[lsp-go]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el
70179
[Gophers slack]: https://invite.slack.golangbridge.org/

0 commit comments

Comments
 (0)