Files
klammertext/doc/edit/emacs/README.md
Andy Kopra 55be7e9619 fix(edit): require subr-x in klammertext-align.el (Emacs 27)
klammertext-align.el calls string-trim, string-blank-p, and
string-empty-p without requiring subr-x.  Newer Emacs has that library
loaded already; on Emacs 27 -- what Ubuntu 22.04 and Pop!_OS 22.04 ship
-- the symbols are void and table alignment fails with "Symbol's
function definition is void: string-blank-p".  The README now states
Emacs 27.1 as the supported floor.

(from dev 43a4ce7dea2a)
2026-07-28 23:59:39 +02:00

261 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Emacs mode for Klammertext
`klammertext-mode.el` is an Emacs major mode for editing Klammertext files. It
helps Klammertext authors see the structure of klammer application through
syntax highlighting.
Requires **Emacs 27.1 or newer** — the version Ubuntu 22.04 and Pop!_OS
22.04 ship, so it is the practical floor. Tested on 27.1 and 30.2.
## Install
Put the `emacs` directory somewhere on your system, then tell Emacs where it is
and load the mode. Add to `~/.emacs.d/init.el`:
```elisp
(add-to-list 'load-path "full-pathname-of-the-emacs-directory")
(require 'klammertext-mode)
(require 'klammertext-indent) ; optional, experimental: TAB indentation
(require 'klammertext-align) ; optional, experimental: table alignment
```
Replace `full-pathname-of-the-emacs-directory` with the full path to the
directory that contains `klammertext-mode.el`. The last two requires load
the experimental indentation and table-alignment support (see their sections
below); each is a separate unit — comment its line out to disable it
entirely.
The mode auto-activates for `.kt` and `.k` files. (The `.k` / `.kt` distinction
is a filing convention, not a lexical one — the same mode serves both.) You can
also switch to it manually with `M-x klammertext-mode`.
## What it highlights
**Text-removal ("ignore") constructs** — in two independently chosen colors,
one for the *removed content*, one for the *marker characters*:
| Construct | Meaning |
|--------------|----------------------------------|
| `#` ... | remove to end of line |
| `##` ... | remove to end of buffer |
| `#[ ... ]#` | remove enclosed text (nestable) |
**Klammer applications** — in two independent colors: one for *opening* a
klammer, one for *closing* it. The `@` and the name of an opening are one
syntactic unit and share the opening color; the close (named or bare) gets the
closing color, so you always have visual confirmation of where a klammer ends:
| Form | Color | Meaning |
|-----------|---------|----------------------------------|
| `@name` | opening | opening `@` + name (one unit) |
| `name@` | closing | named closing delimiter |
| `@` | closing | bare closing delimiter |
In the abbreviated form `@name-arg1-arg2` (equivalent to `@name arg1 | arg2 @`)
only the name is colored — the name ends at the first hyphen, and the
hyphen-separated arguments stay plain, just as `arg1`/`arg2` would be plain in
the long form.
Because a named closing carries the closing color across its name too, long
klammers that name their closing delimiter (`@document ... document@`) stand
out — which is exactly where naming the closing delimiter earns its keep
(accurate unmatched-delimiter error messages). Short bodies (`@i word @`) are
conventionally left with a bare `@` to keep the text uncluttered.
**Klammer definitions** (`@@`) are highlighted the same way, in their own pair
of colors — so definitions read as distinct from applications at a glance:
| Form | Color | Meaning |
|------------|---------|-----------------------------------|
| `@@name` | opening | opening `@@` + name (one unit) |
| `name@@` | closing | named closing delimiter |
| `@@` | closing | bare closing delimiter |
The name ends at the first non-name character, so a target suffix like
`@@name.html` colors only `@@name` and leaves `.html` plain. A definition's
body (between `@@name` and the closing `@@`) is highlighted like ordinary
Klammertext — e.g. an `@i … @` inside it shows as a normal application.
**System/target commands** (`@@@`) — `@@@target`, `@@@argtype`, `@@@state` — get
a third pair of colors, so the three `@`-levels (application, definition, system)
are visually distinct:
| Form | Color | Meaning |
|------------|---------|-----------------------------------|
| `@@@name` | opening | opening `@@@` + name (one unit) |
| `name@@@` | closing | named closing delimiter |
| `@@@` | closing | bare closing delimiter |
`@@@` commands do not nest, so each delimiter is colored independently; their
bodies (`| … |` option lists) are highlighted as ordinary Klammertext.
## The eight faces
All eight faces are defined by the `defconst klammertext--palette` at the
beginning of `klammertext-mode.el`.
| Face | Applies to |
|-----------------------------------|-------------------------------------|
| `klammertext-ignored-face` | removed content |
| `klammertext-marker-face` | `#`, `##`, `#[`, `]#` |
| `klammertext-klammer-open-face` | an application opening `@name` |
| `klammertext-klammer-close-face` | an application close `name@` or `@` |
| `klammertext-def-open-face` | a definition opening `@@name` |
| `klammertext-def-close-face` | a definition close `name@@` or `@@` |
| `klammertext-system-open-face` | a system opening `@@@name` |
| `klammertext-system-close-face` | a system close `name@@@` or `@@@` |
To experiment with a color (evaluate in `*scratch*`, or add to your init):
```elisp
(set-face-foreground 'klammertext-marker-face "cyan")
(set-face-foreground 'klammertext-system-close-face "chocolate4")
```
or `M-x customize-face RET klammertext-marker-face RET`.
## Matching delimiters (show-paren)
With `show-paren-mode` on (the default in Emacs 28+), placing point on a klammer
**application** delimiter highlights its partner, in both directions: on an
opening `@name` it highlights the closing `@`/`name@`, and on a close it
highlights the opening `@name`. Nesting is respected — in `@a @b x @ @`, the
outer `@a` matches the last `@`, not the first.
Matching covers applications only (`@`), not `@@`/`@@@`, since that is where
paired delimiters matter most. The matcher steps over `@@`/`@@@`, removed text,
other literal spans and escaped `^@`; the abbreviated `@name-arg` form has no
closing delimiter, so nothing is highlighted on it.
**Literal klammers** (those in `klammertext-literal-klammers`, e.g. `@code`) are
closed with the full `NAME@` form because their content is verbatim. These are
matched *by name*`@code``code@` — with the content treated as opaque, so a
stray `@` inside (`@code x @ y code@`) doesn't confuse the match, in either
direction. Register any klammer that declares a `literal` argument with
`(klammertext-add-literal-klammer "name")` in your init file so both its
highlighting and its delimiter matching work.
If a **named** close disagrees with its opening — e.g. `@doc … foo@` (should be
`doc@`) — the mismatched delimiter is shown in **bright red** (bold), and a
message describing the mismatch appears in the minibuffer, e.g.
> `Klammertext: closing foo@ does not match opening @doc`
An unbalanced delimiter (an opening with no close, or vice versa) is flagged the
same way. This turns the naming convention into a live check: name a long
klammer's closing delimiter and a typo'd or unbalanced name lights up
immediately. The red comes from `klammertext-mismatch-face`, which is remapped
over `show-paren-mismatch` **only in Klammertext buffers** (your global
`show-paren-mismatch` face is left untouched); customize it to taste.
This is wired in automatically (`show-paren-data-function`); you only need
`show-paren-mode` enabled. It relies on nothing in the syntax table — Klammertext
delimiters can't be expressed there — so it does not interfere with other
`@`/`#` characters.
### Jumping between matches
`klammertext-jump-to-match`, bound to **`C-c C-j`**, moves point to the matching
delimiter: from an opening `@name` to its close, and from a close back to its
opening `@name`. It uses the same matcher as the highlighting. The starting
position is pushed to the mark ring, so `C-u C-SPC` jumps back. (Also available
as `M-x klammertext-jump-to-match`.)
## Indentation (experimental)
With `klammertext-indent.el` loaded (the optional require above), **TAB**
indents the current line — and `indent-region` a selection — to reflect the
klammer nesting, two spaces per level:
```
@ol
Item one
| Item two
@ol
Embedded item one
| Embedded item two
@
| Item three
@
```
The rule: a line indents to 2 × depth; a line *beginning* with a bar run
(`|`, `||`, …) or a closing delimiter sits one level less — at its owner's
opening column. So the bars and the close line up under the `@` of the list
they belong to, and `| ` (bar + space) puts item text exactly at the content
column. The bar rule is dimension-independent: `||` table rows drop to the
opener's column the same way. All three `@`-tiers indent uniformly.
Exceptions, all deliberate:
- Klammers in `klammertext-transparent-klammers` (default: `document`)
contribute no level, so a document's ordinary paragraphs stay at the left
margin.
- Lines inside a literal klammer's verbatim content (`@code ... code@`), and
inside the argument span of a klammer in `klammertext-code-klammers`
(default: `eval` — inline Python is indentation-sensitive), are never
touched. Neither are removed regions (`#[ ... ]#`, after `##`).
Nothing reformats automatically — whitespace is content in Klammertext, so
indentation happens only when you ask for it (TAB, `indent-region`). The
offset is `klammertext-indent-offset` (default 2); all three variables are
customizable in the `klammertext-indent` group.
## Table alignment (experimental)
With `klammertext-align.el` loaded (the optional require above), **`C-c C-a`**
with point anywhere inside a `@table` span pads the cells of its rows so the
`|` separators line up:
```
@table
First item | Second | A third item that's longer ||
Row 2 | Text | Not as long ||
@
```
A row is one line ending with the row delimiter `||` (the customary trailing
delimiter — the parser strips one trailing delimiter, and it keeps every row
uniform, which also suits program-generated tables); the last row may omit
it. Alignment is for small data items, so a row is left untouched — and
contributes nothing to the column widths — when any of its cells is longer
than `klammertext-align-cell-max` (30) characters or the row spans lines.
If the aligned rows would exceed `klammertext-align-row-max` (100) columns,
nothing changes and the reason is reported.
The padding is semantically free: the SKS strips cell content, and no
whitespace is ever inserted inside a bar run (which would turn a `||` row
separator into an empty `| |` cell). Bars inside a nested klammer in a cell
(`@frac 1 | 2 @`) belong to that klammer, not the table, and are left alone.
Aligned rows adopt the leading whitespace of the first aligned row — run TAB
first if the rows disagree.
## Literal klammers
Inside a `literal` argument — for example the body of `@code ... code@``#`
and `@` are literal text, not Klammertext syntax. The mode highlights the
opening `@code` and closing `code@` but leaves the interior as normal text,
for any klammer registered in `klammertext-literal-klammers`. `@code` is
registered by default.
If you define your own klammer with a `literal` parameter (a relatively
advanced action — see the `literal` argument type in the project
documentation), register it in your init file:
```elisp
(klammertext-add-literal-klammer "myverbatim")
```
Because the list is consulted at fontification time, registering a klammer
while a buffer is already open takes effect after `M-x font-lock-update` (or
re-visiting the file).
## Known limitations (deliberate, for now)
- Unescaped `@` is always treated as a delimiter (as the Klammermachine does),
so an `@` in prose that is *not* meant as a klammer — e.g. an email address
written `foo@bar` instead of `foo^@bar` — will be highlighted. This reflects
what the machine actually sees.
- Very large multiline blocks or literal spans edited far from their opening
may occasionally need `M-x font-lock-update` to re-highlight correctly.