Files
Andy Kopra ef77f03584 Klammerset: the @@@klammerset construct, its search path, and const correctness
The @@@klammerset system command formally declares a klammerset — a
named, logically related group of klammer definitions — with an
operative, idempotent declaration (:requires and :files load in order
at the declaration point, relative to the declaring file). A bare
symbol given to ktext -k, kdesc --input, or :requires resolves to
x/x.k on the search path: the document's directory, then
KLAMMERTEXT_KLAMMERSETS, then KLAMMERTEXT_HOME; kdesc --klammerset
lists the available sets. sks/sks.k is the first declared klammerset,
so `-k sks` loads the SKS by name. The engine's lookup classes were
renamed *_set → *_registry to keep the two concepts apart, and the
whole C++ tree now follows standard const-correctness conventions.
tst/ gains klammerset_test.sh (18 cases).

(from dev 64b1abf23e56)
2026-07-30 23:50:07 +02:00
..

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.