diff --git a/.gitignore b/.gitignore index bb3ed6e..a77a4f4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ transient/ var/ .cache/ .lsp-session* +gotools/ diff --git a/doc/modules/go.md b/doc/modules/go.md new file mode 100644 index 0000000..7999b7e --- /dev/null +++ b/doc/modules/go.md @@ -0,0 +1,87 @@ +# Prelude Go + +This module builds on top of the shared [Programming](programming.md) +module, as well as the [Prelude-LSP](lsp.md) module. + +The following keybindings are set by default, which are not present in +each mode's default bindings: + +* C-c a (`go-test-current-project`) +* C-c m (`go-test-current-file`) +* C-c . (`go-test-current-test`) +* C-c b (`go-run`) +* C-h f (`godoc-at-point`) + +Run C-h m for all the key bindings and other documentation. + +There are two ways to manage projects in Go: `$GOPATH` and with Go +modules. Modules are the newer, recommended method. Read [Using Go +Modules](https://go.dev/blog/using-go-modules) to learn about this, if +you are unfamiliar with the subject. Many of the tools used by Prelude +Go may provide functions that are broken with modules. There is +usually another function that will work properly; when in doubt, use a +function provided by `lsp-mode` which is documented below. + +Generics were added to Go in 1.18. `gopls`, the backend for `lsp-mode` +setup herein, supports generics as long as `gopls` itself was built +with 1.18+. Other minor modes may not support generics yet. + +## Go Mode + +`prelude-go` builds on several useful Go tools, and establishes sensible +defaults. The major mode is `go-mode`. Documentation is available at [github.com/dominikh/go-mode.el](https://github.com/dominikh/go-mode.el) + +## Go Projectile + +[Projectile](https://github.com/bbatsov/projectile) integration is +provided by [go-projectile](https://github.com/dougm/go-projectile). + +This provides: + +* Projectile integration +* Switching GOPATH if desired per project (customizable via + `customize`) +* Ability to download all commonly used `go` tools via M-x + go-projectile-install-tools and update them via M-x + go-projectile-update-tools +* Very basic refactoring via `go-projectile-rewrite` (uses `gofmt -r`) +* Support for `go get` and `go get -u` via `go-projectile-get` and + `go-projectile-update`. + +See its documentation for details. + +## LSP Mode and LSP UI + +[LSP](https://microsoft.github.io/language-server-protocol/) (Language +Server Protocol) is a protocol that allows editors to use an external +"language server" to provide features like autocompletion, +documentation, and code navigation rather than implementing these +features separately in each editor. Emacs supports LSP via +`lsp-mode`. The language server used is +[gopls](https://github.com/golang/tools/tree/master/gopls). + +To install `gopls`, change to a directory outside of `$GOPATH` or any +module (e.g., `/tmp`) and execute: + +``` +go install golang.org/x/tools/gopls@latest +``` + +Ensure that `gopls` is in your `$PATH`. + +Excellent documentation for `lsp-mode` and `lsp-ui` are provided at [emacs-lsp.github.io/lsp-mode/](https://emacs-lsp.github.io/lsp-mode/) + +If a feature, such as documentation, refactoring, indenting, etc. is +provided by `lsp`, you should use it instead of calling to another +tool. `gopls` is the officially maintained tool that supercedes +functionality in other tools, like `gocode`, and works properly with +modules and generics. + +Company support is automatically added that works with `lsp`. + +## GoTest + +[gotest](https://github.com/nlamirault/gotest.el) is also provided +while editing Go files in order to run tests more easily. The bindings +provided by `prelude-go` are listed at the top because `gotest` does +not set any. diff --git a/modules/prelude-go.el b/modules/prelude-go.el index 40277b9..13116c5 100644 --- a/modules/prelude-go.el +++ b/modules/prelude-go.el @@ -29,11 +29,13 @@ ;;; Code: (require 'prelude-programming) +(require 'prelude-lsp) (prelude-require-packages '(go-mode - company-go - go-eldoc go-projectile + lsp-mode + lsp-ui + company gotest)) (require 'go-projectile) @@ -58,23 +60,25 @@ (when goimports (setq gofmt-command goimports))) - ;; gofmt on save - (add-hook 'before-save-hook 'gofmt-before-save nil t) - ;; stop whitespace being highlighted (whitespace-toggle-options '(tabs)) - ;; Company mode settings - (set (make-local-variable 'company-backends) '(company-go)) - - ;; El-doc for Go - (go-eldoc-setup) - ;; CamelCase aware editing operations (subword-mode +1)) - (setq prelude-go-mode-hook 'prelude-go-mode-defaults) + ;; if yas is present, this enables yas-global-mode + ;; which provides completion via company + (if (fboundp 'yas-global-mode) + (yas-global-mode)) + ;; configure lsp for go + (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) + (add-hook 'go-mode-hook #'lsp-deferred) + + (setq prelude-go-mode-hook 'prelude-go-mode-defaults) (add-hook 'go-mode-hook (lambda () (run-hooks 'prelude-go-mode-hook))))