Scope X/Y to the set of documents Kate currently has open
(Application::documents()) — acme's open-window set — instead of the project
index on disk. The regex matches each buffer's local file path (or display
name for an unsaved scratch buffer). Nothing is opened or read from disk; the
live Documents are edited in place, each its own undo step.
Smaller blast radius than a project-wide sweep and closer to acme's X/Y, which
iterate open windows. Drops the ProjectIndexer dependency from the X/Y path.
Docs (SAM.md, PLAN.md) updated. 18/18 ctest green.
Replace QRegularExpression with SamRegex (src/sam/samregex.{h,cpp}), a
faithful port of plan9port src/cmd/sam/regexp.c: a Thompson/Pike NFA.
- Leftmost-LONGEST (POSIX): matches real sam exactly, including overlapping
alternation (a|ab on 'ab' -> 'ab'), eliminating the one remaining
greedy-vs-longest divergence from PCRE.
- Linear time, no backtracking: immune to catastrophic blowup ((a*)*b over
10k 'a' returns instantly).
- sam dialect only: . * + ? | ( ) [ ] ^ $ and \ escaping (\n = newline);
^/$ per-line and ./negated-classes exclude newline, all intrinsic. No
PCRE extras (\d \w \b, lookaround, non-greedy) — sam never had them.
Port notes: shunting-yard compiler + Pike VM with per-thread capture sets and
leftmost-longest newmatch(). Fixed two porting bugs vs the C original: the
l-union aliasing of OR's left/continuation with .next, and reading the popped
subid during popator for correct capture-group ids.
SamEngine now compiles/matches via SamRegex (search, s, x/y/g/v, replacement
captures). Tests: new test_samregex (18) + updated test_samengine (31, incl.
leftmostLongestSubstitution, sam-dialect capture groups). 18/18 ctest suites.
Docs: rewrite docs/SAM.md (no more PCRE deviation; dialect + semantics are
sam's), update PLAN.md and the panel hint.
Verified against plan9port: regexp(7) defines ^ as 'beginning of a line'
and $ as 'end of a line', and sam's regexp.c BOL (p==0 || prev=='\\n') /
EOL (next char '\\n') confirm per-line anchoring. The engine was matching
with buffer-wide anchors, so ,s/^/> /g only touched the first line and the
sam idiom ,x/.+/ s/^/> / failed to prefix each line.
Fix: compile every pattern with QRegularExpression::MultilineOption. '.'
still does not cross newlines (sam-faithful; PCRE default). Add 3 regression
tests (caretIsPerLine, dollarIsPerLine, samAnchorIdiom); 30/30 engine tests.
Docs: correct docs/SAM.md — ^/$ per-line is faithful, not a deviation;
reframe PCRE extras as an escape hatch (prefer structural composition), not
'free upgrades'. Fix the panel hint and PLAN.md accordingly.
Add docs/SAM.md — a user-facing reference for the regex deviation, with
examples verified against the engine:
- leftmost-greedy (PCRE) vs leftmost-longest (sam): diverges only on
overlapping alternation (a|ab); order alternatives longest-first.
- ^/$ anchor buffer-wide, not per-line, by default. Workarounds:
structural ,x/.+/ … (preferred) or the (?m) inline flag.
- identical behaviour table (. and newlines, empty-match advance, &/\N).
- PCRE bonuses sam lacks: \d \w \b, lookahead, non-greedy, (?i)(?m)(?s).
Cross-link from PLAN.md and surface the two biggest gotchas (buffer-wide
anchors, alternation order) directly in the Sam panel hint label.