1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
# Gopls: Using Emacs
## Installing `gopls`
To use `gopls` with Emacs, you must first
[install the `gopls` binary](../README.md#installation) and ensure that the directory
containing the resulting binary (either `$(go env GOBIN)` or `$(go env
GOPATH)/bin`) is in your `PATH`.
## Choosing an Emacs LSP client
To use `gopls` with Emacs, you will need to choose and install an Emacs LSP
client package. Two popular client packages are [LSP Mode] and [Eglot].
LSP Mode takes a batteries-included approach, with many integrations enabled
“out of the box” and several additional behaviors provided by `lsp-mode` itself.
Eglot takes a minimally-intrusive approach, focusing on smooth integration with
other established packages. It provides a few of its own `eglot-` commands but
no additional keybindings by default.
Once you have selected which client you want to use, install it per the packages
instructions: see [Eglot 1-2-3](https://github.com/joaotavora/eglot#1-2-3) or
[LSP Mode Installation](https://emacs-lsp.github.io/lsp-mode/page/installation/).
## Common configuration
Both Eglot and LSP Mode can integrate with popular packages in the Emacs
ecosystem:
* The built-in [`xref`] package provides cross-references.
* The built-in [Flymake] package provides an on-the-fly diagnostic overlay.
* [Company] mode displays code completion candidates (with a richer UI than
the built-in [`completion-at-point`]).
Eglot provides documentation using the built-in [ElDoc] minor mode, while LSP
Mode by default provides documentation using its own [`lsp-ui`] mode.
Eglot by default locates the project root using the [`project`] package. In LSP
Mode, this behavior can be configured using the `lsp-auto-guess-root` setting.
## Configuring LSP Mode
### Loading LSP Mode in `.emacs`
```elisp
(require 'lsp-mode)
(add-hook 'go-mode-hook #'lsp-deferred)
;; Set up before-save hooks to format buffer and add/delete imports.
;; Make sure you don't have other gofmt/goimports hooks enabled.
(defun lsp-go-install-save-hooks ()
(add-hook 'before-save-hook #'lsp-format-buffer t t)
(add-hook 'before-save-hook #'lsp-organize-imports t t))
(add-hook 'go-mode-hook #'lsp-go-install-save-hooks)
```
### Configuring `gopls` via LSP Mode
See [settings] for information about available gopls settings.
Stable gopls settings have corresponding configuration variables 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.
Experimental settings can be configured via `lsp-register-custom-settings`:
```lisp
(lsp-register-custom-settings
'(("gopls.completeUnimported" t t)
("gopls.staticcheck" t t)))
```
Note that after changing settings you must restart gopls using e.g. `M-x
lsp-restart-workspace`.
## Configuring Eglot
### Configuring `project` for Go modules in `.emacs`
Eglot uses the built-in `project` package to identify the LSP workspace for a
newly-opened buffer. The `project` package does not natively know about `GOPATH`
or Go modules. Fortunately, you can give it a custom hook to tell it to look for
the nearest parent `go.mod` file (that is, the root of the Go module) as the
project root.
```elisp
(require 'project)
(defun project-find-go-module (dir)
(when-let ((root (locate-dominating-file dir "go.mod")))
(cons 'go-module root)))
(cl-defmethod project-root ((project (head go-module)))
(cdr project))
(add-hook 'project-find-functions #'project-find-go-module)
```
### Loading Eglot in `.emacs`
```elisp
;; Optional: load other packages before eglot to enable eglot integrations.
(require 'company)
(require 'yasnippet)
(require 'go-mode)
(require 'eglot)
(add-hook 'go-mode-hook 'eglot-ensure)
;; Optional: install eglot-format-buffer as a save hook.
;; The depth of -10 places this before eglot's willSave notification,
;; so that that notification reports the actual contents that will be saved.
(defun eglot-format-buffer-before-save ()
(add-hook 'before-save-hook #'eglot-format-buffer -10 t))
(add-hook 'go-mode-hook #'eglot-format-buffer-before-save)
```
Use `M-x eglot-upgrade-eglot` to upgrade to the latest version of
Eglot.
### Configuring `gopls` via Eglot
See [settings] for information about available gopls settings.
LSP server settings are controlled by the `eglot-workspace-configuration`
variable, which can be set either globally in `.emacs` or in a `.dir-locals.el` file in the project root.
`.emacs`:
```elisp
(setq-default eglot-workspace-configuration
'((:gopls .
((staticcheck . t)
(matcher . "CaseSensitive")))))
```
`.dir-locals.el`:
```elisp
((nil (eglot-workspace-configuration . ((gopls . ((staticcheck . t)
(matcher . "CaseSensitive")))))))
```
### Organizing imports with Eglot
`gopls` provides the import-organizing functionality of `goimports` as an LSP
code action, which you can invoke as needed by running `M-x eglot-code-actions`
(or a key of your choice bound to the `eglot-code-actions` function) and
selecting `Organize Imports` at the prompt.
To automatically organize imports before saving, add a hook:
```elisp
(add-hook 'before-save-hook
(lambda ()
(call-interactively 'eglot-code-action-organize-imports))
nil t)
```
## Troubleshooting
Common errors:
* 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.
* 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 `.profile` and logging out and back in.
* Make sure only one LSP client mode is installed. (For example, if using
`lsp-mode`, ensure that you are not _also_ enabling `eglot`.)
* Look for errors in the `*lsp-log*` buffer or run `M-x eglot-events-buffer`.
* Ask for help in the `#emacs` channel on the [Gophers slack].
[LSP Mode]: https://emacs-lsp.github.io/lsp-mode/
[Eglot]: https://github.com/joaotavora/eglot/blob/master/README.md
[`xref`]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html
[Flymake]: https://www.gnu.org/software/emacs/manual/html_node/flymake/Using-Flymake.html#Using-Flymake
[Company]: https://company-mode.github.io/
[`completion-at-point`]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html
[ElDoc]: https://elpa.gnu.org/packages/eldoc.html
[`lsp-ui`]: https://emacs-lsp.github.io/lsp-ui/
[`lsp-go`]: https://github.com/emacs-lsp/lsp-mode/blob/master/clients/lsp-go.el
[`use-package`]: https://github.com/jwiegley/use-package
[`exec-path-from-shell`]: https://github.com/purcell/exec-path-from-shell
[settings]: settings.md
[Gophers slack]: https://invite.slack.golangbridge.org/
|