# 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 ```