Go
Rune ships first-class Go support: code intelligence through a built-in
language client, and a dedicated go command that drives refactors,
tests, and module management. This guide works through every Go feature
from the commands you type down to what each one does.
On top of the cross-language lsp command, Go gets a dedicated go
command with refactorings, tests, and module tooling.
Rune also includes a built-in debugger, powered by (and with thanks to)
the Delve community, that you can use
to debug your Go programs. One thing to know up front: you launch a
debug session by passing the package to run, not the path to
main.go. For the full walkthrough, see the Debugger
guide.
Setup
The Go extension ships everything it needs; there is nothing to install separately. Rune provides its own language server for Go, so support works out of the box.
If you want to use your own language server binary, point Rune at it in
config.yaml:
- config.yaml
extensions:
go:
config:
lsp_path: "/path/to/your/binary"
Code intelligence starts inside a Go module, so opening a stray .go file
outside a module will not bring it up.
Code intelligence: the lsp command
lsp is the cross-language entry point for code intelligence. Run it as
lsp <subcommand>. Most subcommands act on the symbol under the cursor;
the navigation commands also accept an explicit symbol name as an
argument.
| Command | Argument | What it does | Default key |
|---|---|---|---|
lsp hover | [<symbol>] | Show docs, types, and signatures for the symbol | <alt-t> |
lsp definition | [<symbol>] | Jump to where the symbol is defined | <alt-d> |
lsp declaration | [<symbol>] | Jump to the symbol's declaration | |
lsp type-definition | [<symbol>] | Jump to the symbol's type definition | |
lsp implementation | [<symbol>] | List implementations of the symbol | <alt-i> |
lsp references | [<symbol>] | List every use of the symbol | <alt-r> |
lsp complete | Show completions at the cursor | <ctrl-space> | |
lsp signature-help | Show the signature of the call at the cursor | ||
lsp rename | Rename the symbol at the cursor everywhere | <meta-f> | |
lsp format | Format the file, or the selection if text is selected | <alt-b> | |
lsp diagnostics | Open a picker with every diagnostic in the file | <alt-shift-e> |
Query any symbol by name
This is one of the most powerful ways to move around a codebase. You can
query a symbol (a function, type, variable, struct, interface, or method)
by name, without first having to find where it lives. If you remember
what something is called but not where it is defined, press
<alt-shift-d>, type the name, and jump straight to its definition:
lsp definition NewServer
The default config binds a shifted variant for each query that pre-fills
the prompt with the command and leaves it open for you to type a name:
<alt-shift-t> (hover), <alt-shift-d> (definition), <alt-shift-r>
(references), and <alt-shift-i> (implementation). So <alt-shift-r>
lists every reference to a name, <alt-shift-i> finds what implements it,
and <alt-shift-t> reads its docs and signature, all by name, from
anywhere in the project.
Every query also works on the symbol under the cursor: for hover,
definition, declaration, type-definition, implementation, and
references, leaving the argument off uses whatever you are sitting on.
Diagnostics
lsp diagnostics (<alt-shift-e>) opens a location picker listing every
diagnostic gopls reports for the file. To step through them without the
picker, the default config binds:
| Key | Action |
|---|---|
<alt-j> | Jump to the next diagnostic |
<alt-k> | Jump to the previous diagnostic |
These are aliases for jumptolocation next lsp-diagnostics and
jumptolocation previous lsp-diagnostics.
Highlighting occurrences
There is no command for this: Rune automatically highlights other occurrences of the symbol under the cursor shortly after the cursor settles. Move off the symbol and the highlight clears.
Interesting queries
Some lsp queries are more powerful than they first appear. The
implementation query in particular is bidirectional; it answers "what
satisfies this?" and "what does this satisfy?" depending on where the
cursor is. In a language like Go where interface satisfaction is
implicit, this is the fastest way to discover the relationships the
compiler infers for you.
Place the cursor and run lsp implementation (or <alt-i>):
| Cursor on | You get |
|---|---|
| A struct (concrete type) | The interface(s) that the struct satisfies. |
| An interface | The struct(s) that satisfy the interface. |
| A method on a struct | The interface method(s) that this method implements, i.e. which interface(s) it is part of. |
| A method on an interface | The corresponding method on each struct that satisfies the interface. |
When a query has more than one answer, Rune opens a picker so you can jump to any of the results; with a single answer it jumps straight there.
This makes implicit relationships explorable in both directions:
- "What interfaces does this type implement?" → cursor on the struct.
- "What types implement this interface?" → cursor on the interface.
- "Which interface contract does this method fulfill?" → cursor on the struct's method.
- "Where is this interface method actually implemented?" → cursor on the interface's method.
Go-specific commands: the go command
The go command, powered by gopls, adds Go refactors, tests, and module
management on top of lsp. Run it as go <subcommand>. Most subcommands
act on the cursor position or the current selection; the command tells you
what to do when nothing applicable is under the cursor.
Imports
| Command | What it does |
|---|---|
go organize-imports | Remove unused imports, add missing ones, and sort them. Bound to <alt-m> by default. |
go add-import | Add a package import to the current file. |
go eliminate-dot-import | Remove a dot import and qualify all references with the package name. |
Tests and benchmarks
| Command | What it does |
|---|---|
go test [<name>] | Run the test or benchmark. |
go add-test | Generate a table-driven test for the function at the cursor. |
go test runs a single test or benchmark by name. You do not write a
regex or remember its line. Pass the exact function name and Rune runs
just that one:
go test TestNewServer
If the name starts with Benchmark, it is run as a benchmark instead.
Tab completion fuzzy-searches every Test, Benchmark, Fuzz, and
Example function in the whole workspace, so you can pull up any test
by name from anywhere and run it for a quick one-off check, without
opening its file first. With no argument at all, go test finds the test
or benchmark nearest the cursor and runs that one.
go test is the one Go command that executes through the real go
toolchain instead of the language server. The language server is still
used to locate the nearest test when you omit the name, but the run
itself happens in the file's package directory, streaming progress as
notifications.
Refactorings
All of these act on the cursor or the current selection.
| Command | What it does |
|---|---|
go extract-function | Replace selected statements with a call to a new function. |
go extract-method | Like above, but a method on the same receiver. |
go extract-variable | Replace the selected expression with a new local variable. |
go extract-variable-all | Same, replacing every occurrence of the expression. |
go extract-constant | Replace the selected constant expression with a named constant. |
go extract-constant-all | Same, replacing every occurrence. |
go extract-to-new-file | Move selected top-level declarations to a new file in the package. |
go inline-call | Replace a function/method call with its body. |
go inline-variable | Replace references to a local variable with its initializer. |
go invert-if | Invert an if-else, negating the condition and swapping branches. |
go remove-unused-param | Remove an unused parameter and update all callers. |
go move-param-left | Move the parameter at the cursor one position left, updating callers. |
go move-param-right | Move the parameter at the cursor one position right, updating callers. |
go fill-struct | Fill missing fields of a struct literal with zero values or matching variables. |
go fill-switch | Add the missing cases to a type or enum switch. |
go add-tags | Add JSON struct tags to the fields of the enclosing struct. |
go remove-tags | Clear struct tags on the fields of the enclosing struct. |
go change-quote | Toggle a string literal between raw backtick and double-quote form. |
go split-lines | Split arguments or composite-literal fields onto separate lines. |
go join-lines | Join multi-line arguments or composite-literal fields onto one line. |
Source actions
| Command | What it does |
|---|---|
go fix-all | Apply every unambiguously safe fix in the file. |
go doc | Browse documentation for the current package. |
go assembly | Show the compiler's assembly for the function at the cursor. |
go free-symbols | Report symbols used in the selection but defined outside it. |
go toggle-compiler-opt | Toggle compiler optimization details (inlining, escape analysis) in diagnostics. |
Module management
| Command | What it does |
|---|---|
go tidy | Run go mod tidy so go.mod matches the source. |
go vendor | Run go mod vendor to create or refresh the vendor directory. |
go upgrade-dependency | Check for available upgrades of direct dependencies in go.mod. |
go vulncheck | Run govulncheck for known vulnerabilities reachable by the code. |
go generate | Run go generate for the //go:generate directive nearest the cursor. |
go regenerate-cgo | Re-run cgo to regenerate Go declarations after editing C code. |
Default key bindings
The default editor config binds the most common code-intelligence and Go actions. See Key syntax for how the bindings are written.
| Key | Command |
|---|---|
<alt-t> | lsp hover |
<alt-shift-t> | lsp hover (prefilled prompt) |
<alt-d> | lsp definition |
<alt-shift-d> | lsp definition (prefilled prompt) |
<alt-r> | lsp references |
<alt-shift-r> | lsp references (prefilled prompt) |
<alt-i> | lsp implementation |
<alt-shift-i> | lsp implementation (prefilled prompt) |
<meta-f> | lsp rename |
<alt-b> | lsp format |
<alt-shift-e> | lsp diagnostics |
<alt-j> | Next diagnostic |
<alt-k> | Previous diagnostic |
<ctrl-space> | lsp complete |
<alt-m> | go organize-imports |
On macOS, <ctrl-space> is reserved for input source switching. To use it
for completion, go to System Settings → Keyboard → Keyboard Shortcuts →
Input Sources and uncheck both entries.
Everything bound to a key is also available from the command
prompt, so you can run any lsp or go
subcommand by name even when it has no binding.