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.

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"

How Rune finds your Go project

Go code is organized into modules. A module is a folder tree whose root contains a go.mod file, a small manifest that names the project and records its dependencies. If a project does not have one yet, running go mod init <name> in a terminal at the project root creates it.

Rune uses that manifest to decide where a Go project starts and to root the language server there. Three marker files count: go.mod, go.sum, and go.work.

  • Workspace root. If the folder you open as your workspace contains one of the markers, the language server starts right away, rooted at the workspace.
  • Nested projects. Markers deeper in the workspace work too. When you open a .go file, Rune walks up from that file to the nearest enclosing folder that carries a marker and starts a language server rooted at that folder. In a monorepo with several modules, each module gets its own language server the first time you open one of its files, and that server is reused for every other file in the module.

A .go file with no marker in any folder between it and the workspace root gets no code intelligence, because there is no project to root a server at. Create a go.mod with go mod init and reopen the file.

info

Nested-module discovery is driven by opens. If an external tool, like Rune's agent wants to run semantic queries for a module you have never opened, and no enclosing module already has a server running, that module's server does not start until you open one of its files, so code intelligence there stays unavailable until then. Opening any .go file in the module brings the server up. Modules that sit under a workspace-root module are already covered by the root server, so this only affects standalone modules with no enclosing root.

Working across several modules in one repository? See the Monorepos guide for how per-module discovery and workspace-wide search fit together.

GOPATH projects are not supported

Before modules, Go located projects by their placement under a special directory tree ($GOPATH/src/...) with no marker file in the project itself. This legacy layout is known as GOPATH mode, and Rune's code intelligence does not support it. If your project has no go.mod, run go mod init <module-name> once at its root to convert it; everything in this guide works from there.

Code intelligence

Go to definition, find references, diagnostics, hover, rename, and formatting all run through the cross-language lsp command. For the full command list, the query-by-name workflow, and the default keys, see the Code Intelligence guide. The rest of this page covers what is specific to Go.

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-p>):

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.
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.

Key bindings

The shared code-intelligence keys (lsp hover, definition, references, implementation, rename, format, diagnostics, and completion) are listed in the Code Intelligence guide. Go-specific commands are not bound by the editor presets. Run them from the command prompt or add bindings to your existing command.key_bindings map.

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