kate-deft/docs/SAM.md

112 lines
4.5 KiB
Markdown

# katesam — sam structural-regexp editing in Kate
The **Sam** tool view (left sidebar) runs the plan9
[sam](https://doc.cat-v.org/plan_9/4th_edition/papers/sam/) command language
against the active document, or project-wide via `X`/`Y`. Type a program, press
**Ctrl+Return** or click **Run**. Each Run is one undo step (Ctrl+Z reverts the
whole Run; multi-file `X`/`Y` undoes per file).
## The regex engine
katesam uses a **faithful port of sam's own regular-expression engine**
(`src/sam/samregex.{h,cpp}`, from plan9port `src/cmd/sam/regexp.c`), not PCRE.
This is a Thompson/Pike NFA, which gives the two properties sam relies on:
- **Leftmost-longest** (POSIX) matching, so results match real sam exactly,
including overlapping alternation.
- **Linear time**, with no backtracking — immune to catastrophic blowup. A
pattern like `(a*)*b` against thousands of `a` returns instantly.
There is **no PCRE deviation anymore**: the dialect, the match semantics, and
the anchors are sam's.
### Dialect
The sam dialect is deliberately small (sam `regexp(7)`):
```
. any character except newline
* + ? zero-or-more / one-or-more / zero-or-one
| alternation
( ) grouping and capture (\1..\9 in replacements)
[ ] [^ ] character class / negated class (ranges a-z)
^ $ beginning / end of a LINE
\c literal c (escapes a metacharacter); \n is newline
```
There is intentionally **no** `\d \w \s \b`, no lookaround, no non-greedy, and
no inline flags. sam never had them. Use character classes (`[0-9]`,
`[a-zA-Z_]`) and structural composition (`x y g v`) instead — that is the sam
way, and patterns stay portable to real sam.
### Semantics (all verified against the port)
| behaviour | katesam | note |
|---|---|---|
| overlapping alternation `a\|ab` on `ab` | matches `ab` | leftmost-**longest**; order of branches does not matter |
| `.` crosses newline | **no** | matches sam |
| `^` / `$` | per-line | `^` = start of a line, `$` = end of a line |
| `[^z]+` crosses newline | no | negated classes also exclude `\n`, as in sam |
| empty-match global `s/x*/-/g` on `axbx` | `-a-b-` | one advance per null match |
| `&` whole match, `\1..\9` groups in replacement | yes | up to 9 capture groups |
| pathological `(a*)*b` | linear time | NFA, no backtracking |
### Anchors are per-line
`^` matches the beginning of any line and `$` the end of any line — built into
the engine (sam `regexp.c`: `BOL` fires at offset 0 or after `\n`; `EOL` before
`\n`). So:
| program | input | result |
|---|---|---|
| `,s/^/> /g` | `a⏎b⏎c` | `> a⏎> b⏎> c` |
| `,s/$/;/g` | `a⏎b⏎c` | `a;⏎b;⏎c;` |
The structural idiom is equivalent and composes with guards/loops:
```
,x/.+/ s/^/> / prefix every (non-empty) line → > a⏎> b⏎> c
,x/.+/ a/;/ append ";" to every line → a;⏎b;⏎c;
```
## Composing edits — the sam way
sam's power is structural composition, not clever single regexes. Descend into
matches with `x`/`y`, guard with `g`/`v`, group with `{}`:
```
,x/[a-zA-Z_]+/ g/^[A-Z]/ c/CONST/ every identifier starting uppercase → CONST
,x/"[^"]*"/ s/foo/bar/g foo→bar only inside double-quoted strings
0/start/,/end/ x/[a-z]+/ s/.*/[&]/ bracket every lowercase word in a region
```
Multi-file `X`/`Y` applies an inner program across the **open buffers**:
```
X/\.cpp$/ ,s/old_api/new_api/g rewrite every open .cpp buffer
Y/_test\./ ,x/TODO/ d drop TODO lines in non-test buffers
```
(`X`/`Y` iterate the set of documents Kate currently has open — acme's
open-window set — not the project on disk. The regex matches each buffer's file
path, or its display name for an unsaved scratch buffer. Nothing is opened or
read from disk; edits land in the live buffers, each its own undo step. Review
and save deliberately.)
## Practical guidance
- Use character classes, not PCRE shorthands: `[0-9]` not `\d`, `[a-zA-Z_]` not
`\w`.
- Prefer structural composition (`x g v {}`) over one dense pattern.
- `^`/`$` are per-line; anchor directly (`,s/^…`) or loop (`,x/.+/ …`).
- Empty-match globals (`s/x*/…/g`) advance one position per null match — safe,
but as always with `*`, check the result.
## Scope
Supported: the full address language (`#n n 0 $ . '` `/re/ ?re?` compound
`+ - , ;`) and commands `a c i d s p = m t k x y g v {}` plus shell filters
`< > | !`. Out of scope (Kate manages files / its own undo): the multi-file menu
(`b B n D`), external file I/O (`e r w f`), `"re"` file-addressing, and sam's own
`u` (use Kate's Ctrl+Z).