Files
klammertext/doc/edit/README.md
Andy Kopra f855c5ccae Editor support generalized: shared core, language server, Vim and VS Code (from dev eb5baf9cbe59)
doc/edit/ now holds a shared Python implementation of the language's
structural layer (klammertext_edit.py) and a dependency-free language
server (klammertext_ls.py), with integrations for Emacs, Sublime Text,
Vim, and Visual Studio Code.  The editor test suite in tst/ covers the
core's API and CLI, the language server protocol, the VS Code
extension, headless Vim, and Emacs byte-equality.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 15:01:49 +02:00

4.8 KiB

Klammertext editor support

Editing support for Klammertext files (.kt documents and .k klammer definitions) in four editors, built around one shared implementation.

Directory Contents
shared/ The shared editor core (klammertext_edit.py) and the Klammertext language server (klammertext_ls.py). Everything structure-aware — indentation, table alignment, delimiter matching, delimiter diagnostics — implemented once, in dependency-free Python.
emacs/ Emacs major mode. An independent elisp implementation of the same algorithms (Emacs cannot call Python per keystroke), held byte-equal to the shared core by the test suite.
sublime/ Sublime Text package. Syntax file plus thin plugin wrappers that import the shared core directly (Sublime's plugin host is Python).
vim/ Vim plugin. Syntax/ftplugin files plus commands that run the shared core's CLI; with +python3, the core also runs in-process (= operator, live match highlighting).
vscode/ Visual Studio Code extension. TextMate grammar plus a dependency-free extension that spawns the language server and speaks LSP to it.

The architecture

Klammertext's structural layer — @-run tiers, bar-run dimension, ^-escapes, # removal, literal spans, nesting depth — is independent of both the Klammermachine and any klammer set, and every editor needs the same operations on it. Those operations live in shared/klammertext_edit.py:

  • Indentation — 2 spaces per nesting level; bar runs and closing delimiters sit at their opener's column; @document is transparent; verbatim/@eval/removed content is never touched. Explicit-only in every editor: whitespace is content in Klammertext.
  • Table alignment — pad a @table's rows so the depth-0 | separators line up (rows end with ||; cells over 30 characters or spanning lines opt their row out; over 100 columns the command declines; never a space inside a bar run).
  • Delimiter matching — open ↔ close for klammer applications, literal klammers matched by name with opaque content, everything else by depth.
  • Diagnostics — whole-buffer balance check over all three @-tiers: unclosed openings, extra closes, name and tier mismatches, unclosed literal spans and #[ blocks.
  • A CLI (indent | align | match | check over stdin/stdout) for editors that shell out (Vim), and for scripts.

shared/klammertext_ls.py puts a language server in front of the same core: JSON-RPC over stdio, no dependencies. It serves publishDiagnostics, document/range formatting (reindentation), documentHighlight and definition (the matcher), and a klammertext.alignTable command. The VS Code extension is its first client; any LSP client works — Neovim's built-in LSP, Emacs eglot, Sublime's LSP package — with a one-line configuration pointing at python3 klammertext_ls.py.

Syntax highlighting and cursor-latency features stay native in each editor (a tokenizer or a per-keystroke matcher cannot round-trip to Python), so each editor directory carries its own syntax artifact and, where relevant, its own thin glue.

Locating the shared core

The Sublime, Vim, and VS Code integrations find klammertext_edit.py (and VS Code additionally klammertext_ls.py) in this order: a copy at the integration's own root (the editing zip vendors one there, so each unpacked folder is self-contained), ../shared/ relative to the integration (this repository's layout — using an editor directory straight from a checkout just works), then $KLAMMERTEXT_HOME/doc/edit/shared/.

Keeping things in sync

klammertext_edit.py is the source of truth for the policy lists (LITERAL_KLAMMERS, TRANSPARENT_KLAMMERS, CODE_KLAMMERS, ALIGN_KLAMMERS) and limits (INDENT_OFFSET, CELL_MAX, ROW_MAX). Two kinds of artifact cannot read it and restate parts of it by hand:

  1. The Emacs mode — a full independent implementation with its own defcustoms, checked byte-for-byte against the shared core by tst/editor_test.sh.
  2. The static syntax files — the literal-klammer set (@code) appears in the Sublime .sublime-syntax, the Vim syntax/klammertext.vim, and the VS Code tmLanguage.json grammar (and the Emacs defcustom). When you add a literal klammer, change them together; each file's header carries the same SYNC note.

Testing

tst/editor_test.sh (run by dbg/rebuild.sh and make -C tst test) drives the fixture pairs in tst/editor/ through the shared core's API and CLI, checks idempotence, checks the Emacs implementation for byte-equality, runs the language server through a scripted LSP client (ls_test.py), exercises the VS Code extension against the real server under a stubbed VS Code API (vscode_ext_test.js), and runs the Vim plugin's commands headlessly. Emacs, Vim, and Node/VS Code halves skip gracefully where not installed.