6.9 KiB
6.9 KiB
Go Development Workflow
This guide covers Go development in Neovim with gopls, testing, and debugging.
Overview
Your config includes:
- LSP: gopls (via LazyVim go extra)
- Linting: golangci-lint
- Testing: go test via neotest
- Debugging: delve via DAP
- Formatting: gofmt/goimports
Getting Started
Project Setup
-
Ensure Go is installed and
GOPATHis set -
Open your Go project:
nvim /path/to/project -
gopls will auto-start when you open a
.gofile
Module Initialization
If starting fresh:
go mod init myproject
LSP Features
Navigation
| Key | Action |
|---|---|
gd |
Go to definition |
gr |
Go to references |
gI |
Go to implementation |
gy |
Go to type definition |
K |
Hover documentation |
Code Actions
| Key | Action |
|---|---|
<leader>ca |
Code actions |
<leader>cr |
Rename symbol |
<leader>cf |
Format (gofmt) |
Go-Specific Actions
Press <leader>ca for:
- Add import
- Organize imports
- Extract function
- Extract variable
- Generate interface stubs
- Add struct tags
- Fill struct
Diagnostics
| Key | Action |
|---|---|
<leader>cd |
Line diagnostics |
]d / [d |
Next/prev diagnostic |
<leader>xx |
Toggle trouble |
Testing
Running Tests
| Key | Action |
|---|---|
<leader>tt |
Run test at cursor |
<leader>tf |
Run file tests |
<leader>ta |
Run all tests |
<leader>tl |
Re-run last test |
Test File Convention
Go tests live in *_test.go files:
// math_test.go
package math
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("expected 5, got %d", result)
}
}
Test Output
<leader>ts Toggle test summary
<leader>to Show test output
<leader>tO Toggle output panel
]t / [t Jump to failed tests
Table-Driven Tests
Common Go pattern - cursor on any test case runs it:
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -1, -1, -2},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// <leader>tt here runs this specific case
if got := Add(tt.a, tt.b); got != tt.expected {
t.Errorf("got %d, want %d", got, tt.expected)
}
})
}
}
Debugging Tests
<leader>td Debug test at cursor
Debugging with Delve
Prerequisites
Install delve:
go install github.com/go-delve/delve/cmd/dlv@latest
Setting Breakpoints
| Key | Action |
|---|---|
<leader>db |
Toggle breakpoint |
<leader>dB |
Conditional breakpoint |
Running Debugger
| Key | Action |
|---|---|
<leader>dc |
Continue/Start |
<leader>di |
Step into |
<leader>do |
Step over |
<leader>dO |
Step out |
<leader>dt |
Terminate |
DAP UI
<leader>du Toggle DAP UI
<leader>de Evaluate expression
launch.json
For custom debug configs, create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Package",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${fileDirname}"
},
{
"name": "Debug Main",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}/cmd/myapp"
},
{
"name": "Attach to Process",
"type": "go",
"request": "attach",
"mode": "local",
"processId": 0
}
]
}
Code Quality
Formatting
Go code is auto-formatted on save. Manual format:
<leader>cf Format with gofmt
Imports
goimports manages imports automatically:
- Adds missing imports on save
- Removes unused imports
- Sorts imports
Linting
golangci-lint runs automatically. View issues:
<leader>xx Toggle trouble (all diagnostics)
Struct Tags
Generate/modify struct tags via code actions:
type User struct {
Name string // <leader>ca → "Add json tag"
Email string
}
Result:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
AI Assistance
| Key | Action |
|---|---|
<leader>ka |
Ask opencode |
<leader>ke |
Explain code |
<leader>kR |
Refactor selection |
<leader>kt |
Generate tests |
<leader>kd |
Generate comments |
Generate Tests
- Select function in visual mode
<leader>kt- Review generated table-driven tests
Common Workflows
Starting New Feature
- Create/open
.gofile <leader>H- Mark with harpoon- Write code, LSP handles imports
<leader>tt- Test as you go
Implementing Interface
- Write struct
<leader>ca→ "Generate interface stubs"- Select interface to implement
- Fill in method bodies
Debugging
<leader>db- Set breakpoint<leader>dc- Start debugger- Use step commands to navigate
<leader>de- Evaluate expressions<leader>dt- Terminate when done
Error Handling
Common Go pattern - AI can help:
- Write function that returns error
<leader>ka- "Add proper error handling"- Or use snippet (if configured):
if err != nil { return err }
Project Structure
Standard Layout
myproject/
├── cmd/
│ └── myapp/
│ └── main.go
├── internal/
│ └── pkg/
├── pkg/
│ └── public/
├── go.mod
└── go.sum
go.mod
module github.com/user/myproject
go 1.21
require (
github.com/some/dependency v1.0.0
)
Tips
Quick Run
:!go run . Run current package
:!go run main.go Run specific file
Or use executor:
<leader>Brs Set command: go run .
<leader>Brr Run it
Build
:!go build . Build current package
Generate
:!go generate ./... Run go generate
Module Commands
:!go mod tidy Clean up go.mod
:!go mod download Download dependencies
Documentation
Kon any symbol shows docs- Works with standard library
- Shows function signatures
Troubleshooting
gopls Not Starting
:LspInfo- Check status- Verify gopls is installed:
go install golang.org/x/tools/gopls@latest - Check
go.modexists in project root
Imports Not Working
- Check gopls is running:
:LspInfo - Verify
goimportsis installed:go install golang.org/x/tools/cmd/goimports@latest
Debugger Issues
- Verify delve is installed:
go install github.com/go-delve/delve/cmd/dlv@latest - Check
:DapShowLogfor errors - Ensure code is compiled (not just source)
Slow LSP
- Check for large generated files
- Add to
.gopls.json:{ "build.directoryFilters": ["-vendor", "-node_modules"] }