A tiny language server that makes git log -p and unified-diff buffers
navigable in editors that speak LSP (built for helix).
It provides two things the diff tree-sitter grammar cannot:
textDocument/documentSymbol— acommit → file → hunkoutline (orfile → hunkfor a plain diff). In helix this powers<space>s.textDocument/definition— jump from a diff path / hunk line to the real source file at the corresponding line. In helix this isgd.
Highlighting and ]f/]t/]c motions come from the companion grammar
tree-sitter-git-log; the two are complementary (see "Why an LSP and not
just a grammar" below).
tree-sitter-diff is flat — no node wraps a whole file or hunk, and nothing
expresses the commit envelope of git log -p. The nested outline therefore has
to be computed by something that parses the text directly. Unified diff is
line-oriented and trivial to parse, so this server hand-rolls it with no parser
dependency. It works on stock helix (the LSP documentSymbol path needs no
recent build).
It speaks standard LSP over stdio (documentSymbol, definition), so any LSP
client can drive it — Neovim (nvim-lspconfig), VS Code, Emacs (eglot),
Sublime, Zed. helix is the reference client the examples below target; the only
editor-specific part is the wiring snippet.
Requires Rust 1.85+ (the dependency tree, via lsp-types → url → idna,
pulls crates that use edition 2024). The server's own code is far more
conservative — the floor comes from the lockfile.
cargo build --release
# binary: target/release/git-diff-language-serverInstall it onto PATH, e.g.:
cargo install --path .In your helix languages.toml:
[language-server.git-diff-lsp]
command = "git-diff-language-server"
[[language]]
name = "diff"
language-servers = ["git-diff-lsp"]Then in a diff / git log -p buffer: <space>s opens the commit→file→hunk
outline, and gd on a path or hunk line opens the real file. Generate the diffs
with --no-prefix (so paths are repo-relative) for gd to resolve them directly.
git log -p --no-prefix -3 > /tmp/sample.diff
# open /tmp/sample.diff in helix, press <space>s| Capability | Status |
|---|---|
documentSymbol (commit → file → hunk) |
✅ |
definition (diff line → real file + line) |
✅ |
foldingRange |
✗ — helix 23.10 has no code folding |
hover |
✗ — out of v1 scope |
- Combined/merge diffs (
@@@,diff --cc):gdjumps to the hunk start rather than an exact line (the two-column format isn't walked). gdreturns nothing (LSP null) when the cursor isn't on a file/hunk line, or when the resolved file doesn't exist on disk (e.g. an old commit's path that since moved/deleted) — it will not open a phantom buffer.- The server logs surprising misses to stderr with a
[git-diff-ls]prefix (non-file buffer URI, unresolvable path, stale-document parse failures). Editors capture server stderr into their LSP log — grep there whengd/<space>smisbehaves.
- Path resolution walks up from the diff document's directory to the
.gitroot, then joins the diff-relative path. Handles--no-prefixanda/,b/-prefixed diffs;/dev/nullsides (add/delete) fall back to the other side. - Hunk line mapping counts new-side lines (context + additions) from the
@@header to the cursor; deletions map to the next new-side line. - All parsing / mapping lives in the std-only library (
src/parser.rs,src/resolve.rs) and is unit-tested;src/main.rsis thinlsp-serverglue with an end-to-end test intests/integration.rs.
MPL-2.0 (matching helix). Copyright (c) 2026 YAGEO Corporation and contributors.