Show Go Function Definition in Micro Editor

Show Go function definitions in Micro Editor. Definitions are only shown when you press F3, so they don't constantly pop on your face.

Backend uses Language Server Protocol (LSP), the same used by Sublime, neovim and VSCode.

Update: New LSP plugin has show signature (alt-k), definition (alt-d) and references (alt-r). It's just three line install - including Go language server and micro.

TL;DR for Busy Gurus

Ctrl-E, plugin install quickfix. Add to bindings.json:

	{ "F3": "command: fexec gopls definition {f}:#{o}" }

Now you can press F3 for function definition. Well done.

The rest of us can keep on reading.

Background

Many programmer's editors and IDEs need to show function definitions. Earlier, you needed a system for each language (Python, C, Go...) times each editor (vim, nano, micro, VSCode...). That's a lot of useless coding.

With LSP (Language Server Protocol), each language can have a single LSP Server. LSP Server creates the definitions and autocomplete suggestions. All editors can then use the same LSP Server.

Gopls is the only "show definition" tool that understands Go modules. GoGuru, my previous favourite, does not support modules, it's no longer a practical tool.

Despite it's non-stellar reputation, here Microsoft has done something nice. They started the LSP project as part of VSCode, then released as an open standard.

Caveats:

  • Vendor security: This article installs a lot of things from a lot of places, and their dependencies from even more places. Installation with a package manager (apt-get) would be safer, but these apps are not not packaged yet.
  • Possible shell injections in quickfix: You're responsible for the filenames and words you send to quickfix. The commands seem to be parsed in shell, so a bad filename could open a door to shell injection.

Install micro editor

For Debian Bullseye (testing), just

$ sudo apt-get update
$ sudo apt-get -y install micro

For Debian 10 Buster (stable), you have to enable backports before you can install micro.

$ echo "deb http://deb.debian.org/debian buster-backports main"|sudo tee /etc/apt/sources.list.d/buster-backports.list
$ sudo apt-get update
$ sudo apt-get -y install micro

Micro is also available for other operating systems. Download micro for for BSD, OSX, Windows and for other Linuxes..

Test

$ micro tero.txt

Type some text, like "See you at TeroKarvinen.com". Press Ctrl-Q to quit, and accept saving y.

Install Go (golang)

Current version in Debian 10 Buster is too old, it doesn't have proper module support.

So we have to install go according to official Go project instructions.

Install

$ wget https://golang.org/dl/go1.15.8.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.15.8.linux-amd64.tar.gz

Add Go command to our PATH so we can run it

$ echo "export PATH=$PATH:/usr/local/go/bin" >> $HOME/.bashrc
$ source $HOME/.bashrc

Test

$ go version
go version go1.15.8 linux/amd64

Install gopls - Go LSP Server

Gopls is the official Go project server for Language Server Protocol. Luckily, gopls has a CLI (command line interface), so it's easy to use without complicated support for JSON-RPC based support for LSP.

Download the latest release zip of gopls from official Go repository.

$ wget https://github.com/golang/tools/archive/gopls/v0.6.5.zip
$ unzip v0.6.5.zip
$ cd tools-gopls-v0.6.5/gopls/
$ go build

Yes, it downloads many dependencies. That's life outside package manager... Let's add it to a folder we previously added to our path

$ sudo cp gopls /usr/local/go/bin/

Test

$ gopls version
golang.org/x/tools/gopls v0.6.5
    golang.org/x/tools/gopls@(devel)

Install quickfix plugin

$ micro

Ctrl-E to open micro command line

> plugin install quickfix

A half height windows shows the result, "One or more plugins installed." Press Ctrl-Q to quit the half-height window, then press Ctrl-Q again to quit micro.

$ micro tero.txt

Optionally, you can check that quickfix is installed with Ctrl-E "plugin list".

Test, open micro command line with Ctrl-E

> fexec echo "Hello {f}"

The half-height window says Hello and shows current filename.

Quickfix provides these substitutions (as seen from Ctrl-E "help quickfix")

{w} -- current word
{s} -- current selection
{o} -- byte offset
{f} -- current file

Warning: commands to fexec are parsed in shell. To avoid shell injection, you must be careful to not have any dangerous characters in {w}, {s} or {f} you send to shell using quickfix fexec.

Show Go Function Definition

Write a quick "Hello world" in Go.

$ micro hello.go
package main

import "fmt"

func main() {
	fmt.Println("See you at TeroKarvinen.com!")
}

Now, move cursor over the function Println. Press Ctrl-E for micro command line.

> fexec gopls definition {f}:#{o}

And it shows the definition on a half-sized window.

Of course you could just press Ctrl-E and up arrow any time you want another definition. But a key binding might be more convenient.

Add Keybinding to "Define Keyword"

Micro's per-user configuration is in an obvious place in your home directory

$ micro .config/micro/bindings.json 

Add a new binding for F3. Remember to add comma on the previous line. Ctrl-S to save, Ctrl-Q to quit.

{
    "Alt-/": "lua:comment.comment",
    "CtrlUnderscore": "lua:comment.comment",
	"F3": "command: fexec gopls definition {f}:#{o}"
}

Test on the same file

$ micro hello.go

Move cursor over Println. Press F3. A half-sized window opens, showing your function definition.

Tips and tricks

Folding QuickFix Output with a Pipe

Quickfix fexec allows pipes. To nicely fold output at spaces (-s) at 79 chars (-79)

> fexec gopls definition {f}:#{o}|fold -s -79

goimports and gofmt with Go plugin

For quick access to other useful Go tools gofmt and goimports, Ctrl-E and

> plugin install go

Close and open micro

$ micro hello.go

Now remove some indentation, then Ctrl-E

> gofmt

Your file is formatted in place, and the indentation is correct again.

Goimports

Goimports automatically imports any libraries you use.

Install goimports

$ sudo apt-get -y install git
$ go get golang.org/x/tools/cmd/goimports

Add go build directory to our path so we can run goimports command

$ echo "export PATH=$PATH:$HOME/go/bin" >> $HOME/.bashrc
$ source $HOME/.bashrc

Test

$ goimports -h
usage: goimports [flags] [path ...]

Test importing with our sample file

$ micro hello.go

Remove the line 'import "fmt"'. Ctrl-E

> goimports

And your imports are added.

Well done, you now have nice Go development environment. Go in peace, gopher!