"Life is all about sharing. If we are good at something, pass it on." - Mary Berry

How to create snippets in Helix?

2023-07-31

Categories: Development Environment

Helix currently does not support snippets. However, there is a workaround to insert snippets using :insert-output to run a shell command. Still, this might not feel like the most natural way to work with snippets.

For instance, in GoLand, a similar feature called live templates allows you to type err and expand it into the following:

1if err != nil {
2  
3}

I wonder if I can archieve the same functionality in Helix by creating a simple language server using the Language Server Protocol.

After exploring different SDKs for the LSP I decided to give go-lsp a try, as I am most familiar with Golang.

Here’s what I came up with. Initially, I encountered and error during the first attempt:

 1{
 2  "jsonrpc": "",
 3  "id": 0,
 4  "result": {
 5    "capabilities": {
 6      "textDocumentSync": 1,
 7      "completionProvider": {
 8        "triggerCharacters": [
 9          "."
10        ]
11      }
12    }
13  },
14  "error": null
15}
12023-07-31T17:12:56.162 helix_lsp::transport [ERROR] snippets-ls err: <- Parse(Error("data did not match any variant of untagged enum ServerMessage", line: 0, column: 0))

However, I was able to resolve the issue by passing the jsonrpc version in the response.

To test this feature, you can create a configuration file like this:

1main: |-
2  func main() {
3      $1
4  }  
5
6err: |-
7  if err != nil {
8      $1
9  }  

Then add the following into ~/.config/helix/languages.toml:

1[[language]]
2name = "go"
3formatter = { command = "goimports"}
4language-servers = ["gopls", "snippets-ls"]
5
6[language-server.snippets-ls]
7args = ["-config", "/Users/quantong/.config/helix/go-snippets.yaml"]
8command="snippets-ls"

Now, when we open a .go file in Helix, the editor forks a process to start the language server:

1$ pstree -p 818
2-+= 00001 root /sbin/launchd
3 \-+= 00440 quantong /Applications/WezTerm.app/Contents/MacOS/wezterm-gui
4   \-+= 00487 quantong -fish
5     \-+= 00818 quantong hx .
6       |--- 00855 quantong /opt/homebrew/bin/gopls
7       \--- 00856 quantong /Users/quantong/go/bin/snippets-ls -config /Users/quantong/.config/helix/go-snippets.yaml

Next, you can type err and press tab, Helix will send a textDocument/completion request to the language server:

 1{
 2  "jsonrpc": "2.0",
 3  "method": "textDocument/completion",
 4  "params": {
 5    "position": {
 6      "character": 2,
 7      "line": 25
 8    },
 9    "textDocument": {
10      "uri": "file:///Users/quantong/Code/personal/snippets-ls/main.go"
11    }
12  },
13  "id": 3
14}

and the server will respond with the result:

 1{
 2  "jsonrpc": "2.0",
 3  "id": 3,
 4  "result": [
 5    {
 6      "label": "main",
 7      "kind": 15,
 8      "insertText": "func main() {\n    $1\n}"
 9    },
10    {
11      "label": "err",
12      "kind": 15,
13      "insertText": "if err != nil {\n    $1\n}"
14    }
15  ],
16  "error": null
17}

With this setup, you should be able to use snippets in Helix just like in GoLand, enhancing your coding productivity.

Tags: helix lsp golang

Edit on GitHub

Related Posts: