srf-lsp/README.md

135 lines
3.7 KiB
Markdown

# srf-lsp
Language Server Protocol implementation for [SRF (Simple Record Format)](https://git.lerch.org/lobo/srf), written in Zig.
Provides real-time parse error diagnostics using the SRF library's parser directly.
## Features
- Parse error diagnostics on open and edit, using the SRF library's parser
directly: missing or duplicate `#!srfv1`, bad type hints, unparseable values,
data after `#!eof`, and so on.
- All errors from a parse are reported, not just the first.
- Length-prefix checking for the cases srf does not cover. A numeric type hint
declares an exact byte count. srf reports a wrong one in compact format, but in
long format it keeps the declared bytes and discards the rest of the line
without a word, and a count running past the end of the file fails with no
location at all. Both are detected here and reported on the offending bytes.
- Hover, covering every construct in the format:
- `#!srfv1` and each directive, explained.
- `#!expires`, `#!created` and `#!modified` render their Unix timestamp as a
UTC date, because nobody can read `1772589213`.
- Keys and values show the parsed interpretation: numbers, booleans, byte
counts for strings, and for `binary` values the decoded content when it is
text (`decoding to 5 bytes: "hello"`) or a note when it is not.
- Type hints are explained, including a numeric hint's length-prefix meaning.
- Position encoding is negotiated during `initialize` (`utf-8`, `utf-16` or
`utf-32`), so columns line up even on lines containing multi-byte characters.
- Full-document sync, which matches SRF's single-pass parser.
- stdio transport.
Value interpretation defers to the srf library rather than reimplementing its
rules, so hover and diagnostics cannot disagree about the same text.
Not implemented: completion, document symbols, formatting, goto definition,
semantic tokens, and pull diagnostics (`textDocument/diagnostic`). Requests for
them are answered with `MethodNotFound` rather than left unanswered, and none of
them are advertised as server capabilities.
## Requirements
Zig 0.16.0. Pinned in `.mise.toml`, along with the other tooling.
## Setup
```sh
mise install
```
## Build & Test
```sh
zig build
zig build test
```
The binary is at `zig-out/bin/srf-lsp`.
## Install
The Neovim config below expects `srf-lsp` on `PATH`:
```sh
zig build && install -m755 zig-out/bin/srf-lsp ~/.local/bin/srf-lsp
```
## Neovim Integration
Neovim 0.11 or newer. Add to your config:
```lua
vim.filetype.add({
extension = {
srf = "srf",
},
})
vim.lsp.config("srf_lsp", {
cmd = { "srf-lsp" },
filetypes = { "srf" },
root_markers = { ".git", "/" }, -- single file server
})
vim.lsp.enable("srf_lsp")
```
Check it attached with `:checkhealth vim.lsp` on a `.srf` buffer. Server logs go
to stderr, which Neovim captures in `:LspLog`.
## Combined Setup (with srf-tree-sitter)
For both syntax highlighting and error detection:
```lua
vim.filetype.add({
extension = {
srf = "srf",
},
})
-- Diagnostics
vim.lsp.config("srf_lsp", {
cmd = { "srf-lsp" },
filetypes = { "srf" },
root_markers = { ".git", "/" },
})
vim.lsp.enable("srf_lsp")
-- Syntax highlighting
vim.api.nvim_create_autocmd("User", {
pattern = "TSUpdate",
callback = function()
require("nvim-treesitter.parsers").srf = {
install_info = {
url = "https://github.com/elerch/srf-tree-sitter",
branch = "master",
queries = "queries",
},
}
end,
})
vim.api.nvim_create_autocmd("FileType", {
pattern = "srf",
callback = function(args)
pcall(vim.treesitter.start, args.buf)
end,
})
```
Then install the tree-sitter parser (`:TSInstall srf` no-ops if it is already
present, so use `:TSUpdate srf` to pick up a newer grammar):
```vim
:TSUpdate srf
```