173 lines
5.2 KiB
Markdown
173 lines
5.2 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.
|
|
- A type-consistency warning when one key holds different value kinds in
|
|
different places in the same document, for example `close_price:num:100.00` in
|
|
most records and `close_price::200.00` in one. `k::32` is valid SRF and often
|
|
deliberate, so the check is not "this value looks numeric" but "this key is
|
|
typed differently elsewhere in this file", which the document itself evidences.
|
|
Kinds are compared by the `srf.Value` variant a hint produces, so an empty
|
|
hint, `string` and a byte count are all one kind. A uniformly mistyped document
|
|
has no minority and so gets no warning.
|
|
- 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.
|
|
- A string value that also parses as a number gets a one-line note that a
|
|
consumer coercing it to a numeric field needs `strings_to_numbers`.
|
|
- 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`.
|
|
|
|
### With nix
|
|
|
|
This repository is a flake. To add it to a `buildEnv`-style home profile:
|
|
|
|
```nix
|
|
inputs = {
|
|
srf-lsp.url = "git+https://git.lerch.org/lobo/srf-lsp.git";
|
|
# Optional: reuse your own nixpkgs instead of instantiating another one.
|
|
srf-lsp.inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
```
|
|
|
|
then add `srf-lsp.packages.${system}.default` to your package list. Or run it
|
|
directly:
|
|
|
|
```sh
|
|
nix run git+https://git.lerch.org/lobo/srf-lsp.git
|
|
```
|
|
|
|
`nix flake update srf-lsp` picks up a new version. The build runs the full test
|
|
suite in the sandbox, so a release that fails its tests will not install.
|
|
|
|
Bumping the `srf` dependency changes `build.zig.zon`, which invalidates the
|
|
`zigDeps` hash in `nix/package.nix`. To refresh it: set the hash to
|
|
`lib.fakeHash`, build, and paste the hash nix reports.
|
|
|
|
### Without nix
|
|
|
|
```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
|
|
```
|