Skip to main content

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:

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.

CommandArgumentWhat it doesDefault 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 completeShow completions at the cursor<ctrl-space>
lsp signature-helpShow the signature of the call at the cursor
lsp renameRename the symbol at the cursor everywhere<meta-f>
lsp formatFormat the file, or the selection if text is selected<alt-b>
lsp diagnosticsOpen 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:

KeyAction
<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 onYou get
A struct (concrete type)The interface(s) that the struct satisfies.
An interfaceThe struct(s) that satisfy the interface.
A method on a structThe interface method(s) that this method implements, i.e. which interface(s) it is part of.
A method on an interfaceThe 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

CommandWhat it does
go organize-importsRemove unused imports, add missing ones, and sort them. Bound to <alt-m> by default.
go add-importAdd a package import to the current file.
go eliminate-dot-importRemove a dot import and qualify all references with the package name.

Tests and benchmarks

CommandWhat it does
go test [<name>]Run the test or benchmark.
go add-testGenerate 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.

CommandWhat it does
go extract-functionReplace selected statements with a call to a new function.
go extract-methodLike above, but a method on the same receiver.
go extract-variableReplace the selected expression with a new local variable.
go extract-variable-allSame, replacing every occurrence of the expression.
go extract-constantReplace the selected constant expression with a named constant.
go extract-constant-allSame, replacing every occurrence.
go extract-to-new-fileMove selected top-level declarations to a new file in the package.
go inline-callReplace a function/method call with its body.
go inline-variableReplace references to a local variable with its initializer.
go invert-ifInvert an if-else, negating the condition and swapping branches.
go remove-unused-paramRemove an unused parameter and update all callers.
go move-param-leftMove the parameter at the cursor one position left, updating callers.
go move-param-rightMove the parameter at the cursor one position right, updating callers.
go fill-structFill missing fields of a struct literal with zero values or matching variables.
go fill-switchAdd the missing cases to a type or enum switch.
go add-tagsAdd JSON struct tags to the fields of the enclosing struct.
go remove-tagsClear struct tags on the fields of the enclosing struct.
go change-quoteToggle a string literal between raw backtick and double-quote form.
go split-linesSplit arguments or composite-literal fields onto separate lines.
go join-linesJoin multi-line arguments or composite-literal fields onto one line.

Source actions

CommandWhat it does
go fix-allApply every unambiguously safe fix in the file.
go docBrowse documentation for the current package.
go assemblyShow the compiler's assembly for the function at the cursor.
go free-symbolsReport symbols used in the selection but defined outside it.
go toggle-compiler-optToggle compiler optimization details (inlining, escape analysis) in diagnostics.

Module management

CommandWhat it does
go tidyRun go mod tidy so go.mod matches the source.
go vendorRun go mod vendor to create or refresh the vendor directory.
go upgrade-dependencyCheck for available upgrades of direct dependencies in go.mod.
go vulncheckRun govulncheck for known vulnerabilities reachable by the code.
go generateRun go generate for the //go:generate directive nearest the cursor.
go regenerate-cgoRe-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.

KeyCommand
<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
note

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.

Ask Rune Agent