Contents
- Install — Cargo, distro packages
- Quick Start — smoke test
- Why this approach? — design rationale
- Surface — LSP methods supported
- Editor configuration — VS Code, Zed, Neovim, Helix, Sublime
- Examples — JSON-RPC scripts
- Performance — formatter cost
- When not to use noyalib-lsp
- Documentation
- License
Install
Pre-built binaries for every target the workspace ships are
attached to each GitHub Release; each is signed with cosign
keyless. See the
install matrix in the workspace README
for distro-package paths — noyalib-lsp is bundled into the
top-level noyalib package on every channel (Homebrew, AUR,
Scoop, Nix, GHCR).
MSRV: Rust 1.85.0. The transitive LSP transport stack
(litemap, uuid) requires recent stables; the noyalib core
library itself stays at 1.75.
Quick Start
# Smoke test — drives a one-shot LSP handshake over stdio.
# As a child process spawned by your editor (the typical path).
# See "Editor configuration" below for VS Code / Zed / Neovim /
# Helix / Sublime examples.
Why this approach?
The market has two YAML language servers (yaml-language-server,
taplo-style hybrids) and both make tradeoffs noyalib-lsp avoids:
- Byte-faithful formatting.
textDocument/formattingruns through noyalib's lossless CST. An already-canonical document produces an emptyTextEdit[]— your editor doesn't churn whitespace on save. Comments stay where they were; indent width follows the file's dominant style; only quoting and inter-key whitespace normalise. - Real diagnostics. Parse errors flow through
textDocument/publishDiagnosticswith line / column locations the editor's gutter can highlight directly. No best-effort parsers, no recovery hand-waving. - Schema-aware hover. When a JSON Schema is attached, hover surfaces the resolved field type. Schema descriptions land in the hover card in a follow-up.
- Stdio transport. Standard
Content-Length-framed JSON-RPC 2.0. Works with every LSP-compliant client; no client-specific protocol extensions. - Pure-Rust, zero
unsafe. Same#![forbid(unsafe_code)]guarantee as the noyalib core library.
The whole thing is ~5 KLOC of Rust; the heavy lifting is in the
noyalib library, the LSP wrapper just bridges JSON-RPC to the
library's CST + parser surface.
Surface
| LSP method | What it does |
|---|---|
initialize / initialized / shutdown / exit |
Full LSP lifecycle handshake. |
textDocument/didOpen / didChange / didClose |
Full-text document sync (TextDocumentSyncKind = 1). |
textDocument/publishDiagnostics |
Parse-error diagnostics emitted on every open + change. Line / column locations. |
textDocument/formatting |
Full-document TextEdit[] from the CST formatter. Empty array when the document is already canonical. |
textDocument/hover |
Markdown card with cursor position + document type. Schema-driven descriptions tracked for follow-up. |
Server capabilities response includes textDocumentSync = 1,
documentFormattingProvider = true, hoverProvider = true.
Future capabilities (rangeFormatting, documentSymbols,
codeActions) are gated behind the same lossless-CST surface
in the library.
Editor configuration
Visual Studio Code
The bundled experience ships through the noyalib VS Code extension; no manual config needed. To point at a system-installed binary instead of the bundled one:
Zed
~/.config/zed/settings.json:
Neovim (via nvim-lspconfig)
require. =
require..
Helix
~/.config/helix/languages.toml:
[[]]
= "yaml"
= ["noyalib-lsp"]
= true
[]
= "noyalib-lsp"
Sublime Text (via LSP package)
~/.config/sublime-text/Packages/User/LSP.sublime-settings:
Examples
Editor-driving demos under
crates/noyalib-lsp/examples/:
| Script | What it shows |
|---|---|
handshake.sh |
One-shot initialize / initialized / shutdown / exit round-trip. Smoke test for protocol compliance. |
format-on-save.sh |
didOpen → textDocument/formatting. Returns the TextEdit[] an editor would apply on save. |
hover-cursor.sh |
didOpen → textDocument/hover at a specific (line, column). |
Each script pipes a sequence of Content-Length-framed JSON-RPC
messages into noyalib-lsp over stdio and prints the response
stream. POSIX-shell only — no jq, no node dependencies.
Performance
textDocument/formatting for a 1 MiB YAML document on Apple
M-series ≈ 12 ms (the same wall-clock as noyafmt --write
since both share the CST). For per-keystroke formatting under
human-perceivable latency, the server returns an empty
TextEdit[] when the document is already canonical, so the
editor avoids a round-trip on every didChange after a save.
textDocument/publishDiagnostics runs on every didChange;
parse cost on a freshly-edited buffer is dominated by the byte
range that changed, not the buffer size.
When not to use noyalib-lsp
- You want OpenAPI / AsyncAPI / Kubernetes-CRD hover docs out
of the box. That comes from the JSON Schema attached to
the buffer. noyalib-lsp doesn't ship a schema registry; you
point it at a schema explicitly via the
yaml.schemas(style) settings exposed by your editor. - You need WebDAV-style multi-document operations
(
workspace/applyEditfor cross-file refactor). Not implemented yet; tracked as a v0.1.x capability extension.
Documentation
- Engineering policies (MSRV, SemVer, security, performance, concurrency, platform support, feature flags):
doc/POLICIES.md - Security policy:
SECURITY.md - API reference: https://docs.rs/noyalib-lsp
- Editor setup (VS Code, Neovim, Emacs, Helix, Zed, Sublime):
doc/editor-setup.md - Protocol coverage (which LSP methods are implemented):
doc/protocol-coverage.md - Workspace README: https://github.com/sebastienrousseau/noyalib#readme
- LSP specification: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
License
Dual-licensed under Apache 2.0 or MIT, at your option.