# 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 1. Ensure Go is installed and `GOPATH` is set 2. Open your Go project: ```bash nvim /path/to/project ``` 3. gopls will auto-start when you open a `.go` file ### Module Initialization If starting fresh: ```bash 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 | |-----|--------| | `ca` | Code actions | | `cr` | Rename symbol | | `cf` | Format (gofmt) | ### Go-Specific Actions Press `ca` for: - Add import - Organize imports - Extract function - Extract variable - Generate interface stubs - Add struct tags - Fill struct ### Diagnostics | Key | Action | |-----|--------| | `cd` | Line diagnostics | | `]d` / `[d` | Next/prev diagnostic | | `xx` | Toggle trouble | ## Testing ### Running Tests | Key | Action | |-----|--------| | `tt` | Run test at cursor | | `tf` | Run file tests | | `ta` | Run all tests | | `tl` | Re-run last test | ### Test File Convention Go tests live in `*_test.go` files: ```go // 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 ``` ts Toggle test summary to Show test output tO Toggle output panel ]t / [t Jump to failed tests ``` ### Table-Driven Tests Common Go pattern - cursor on any test case runs it: ```go 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) { // 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 ``` td Debug test at cursor ``` ## Debugging with Delve ### Prerequisites Install delve: ```bash go install github.com/go-delve/delve/cmd/dlv@latest ``` ### Setting Breakpoints | Key | Action | |-----|--------| | `db` | Toggle breakpoint | | `dB` | Conditional breakpoint | ### Running Debugger | Key | Action | |-----|--------| | `dc` | Continue/Start | | `di` | Step into | | `do` | Step over | | `dO` | Step out | | `dt` | Terminate | ### DAP UI ``` du Toggle DAP UI de Evaluate expression ``` ### launch.json For custom debug configs, create `.vscode/launch.json`: ```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: ``` 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: ``` xx Toggle trouble (all diagnostics) ``` ### Struct Tags Generate/modify struct tags via code actions: ```go type User struct { Name string // ca → "Add json tag" Email string } ``` Result: ```go type User struct { Name string `json:"name"` Email string `json:"email"` } ``` ## AI Assistance | Key | Action | |-----|--------| | `ka` | Ask opencode | | `ke` | Explain code | | `kR` | Refactor selection | | `kt` | Generate tests | | `kd` | Generate comments | ### Generate Tests 1. Select function in visual mode 2. `kt` 3. Review generated table-driven tests ## Common Workflows ### Starting New Feature 1. Create/open `.go` file 2. `H` - Mark with harpoon 3. Write code, LSP handles imports 4. `tt` - Test as you go ### Implementing Interface 1. Write struct 2. `ca` → "Generate interface stubs" 3. Select interface to implement 4. Fill in method bodies ### Debugging 1. `db` - Set breakpoint 2. `dc` - Start debugger 3. Use step commands to navigate 4. `de` - Evaluate expressions 5. `dt` - Terminate when done ### Error Handling Common Go pattern - AI can help: 1. Write function that returns error 2. `ka` - "Add proper error handling" 3. Or use snippet (if configured): ```go if err != nil { return err } ``` ## Project Structure ### Standard Layout ``` myproject/ ├── cmd/ │ └── myapp/ │ └── main.go ├── internal/ │ └── pkg/ ├── pkg/ │ └── public/ ├── go.mod └── go.sum ``` ### go.mod ```go 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: ``` Brs Set command: go run . 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 - `K` on any symbol shows docs - Works with standard library - Shows function signatures ## Troubleshooting ### gopls Not Starting 1. `:LspInfo` - Check status 2. Verify gopls is installed: ```bash go install golang.org/x/tools/gopls@latest ``` 3. Check `go.mod` exists in project root ### Imports Not Working 1. Check gopls is running: `:LspInfo` 2. Verify `goimports` is installed: ```bash go install golang.org/x/tools/cmd/goimports@latest ``` ### Debugger Issues 1. Verify delve is installed: ```bash go install github.com/go-delve/delve/cmd/dlv@latest ``` 2. Check `:DapShowLog` for errors 3. Ensure code is compiled (not just source) ### Slow LSP 1. Check for large generated files 2. Add to `.gopls.json`: ```json { "build.directoryFilters": ["-vendor", "-node_modules"] } ```