Go to file
Levi Neely 4cdd762bb6 sam: ^/$ are per-line (MultilineOption), matching plan9 regexp(7)
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.
2026-10-08 14:29:19 +02:00
docs sam: ^/$ are per-line (MultilineOption), matching plan9 regexp(7) 2026-10-08 14:29:19 +02:00
src sam: ^/$ are per-line (MultilineOption), matching plan9 regexp(7) 2026-10-08 14:29:19 +02:00
.gitignore Initial commit: FuzzyRanker keystone + project plan 2026-10-07 15:45:58 +02:00
CMakeLists.txt Radial: Wayland pointer warp via zwp_pointer_constraints_v1 2026-10-08 12:18:01 +02:00
README.md M5: :-verb command pack (sort/case/base64/rot13/uuid/pipe) 2026-10-07 17:54:20 +02:00

README.md

kate-custom

A suite of Kate plugins for people who despise menus. The aim is a text editor that is driven by the mouse at the cursor and by plain-letter keyboard input — never by hunting through nested menubars or memorizing complex chords.

Design constraints

These are hard constraints that shape every decision:

  • Mouse-heavy. The fastest input is the mouse, used locally at the caret (radial / floating surfaces), not a trek to the menubar.
  • One-handed typing. Keyboard input must work comfortably with one hand.
  • No complex chords. Single modifier at most (Ctrl+letter). No leader-key chord trees, no multi-cursor keybinds.
  • Compact keyboard. F-keys and nav clusters live on a layer toggle, so they carry extra cognitive cost and are avoided as primary triggers.
  • Emacs/Sublime fluency. M-x (Alt+x) is comfortable and welcome as a primary keyboard entry point, as is a Sublime-style type-to-filter palette.

Unifying principle

One action registry. Three doors onto it: M-x (keyboard), a radial caret menu (mouse), and the : command line (optional). No action requires an F-key or a chord.

Why not just use Kate's command bar?

Kate's KCommandBar is a sealed widget: it accepts a list of actions via setActions() and exposes no hook to customize its matcher. Its matcher, KFuzzyMatcher, is single-needle, strictly in-order subsequence, with no typo tolerance — by KDE's own documentation, "gti" will not match "git". There is no "orderless" (space-separated tokens in any order) and no company-style live completion.

So the project replaces the palette rather than extending it, built on a custom matcher (FuzzyRanker).

Environment

  • Kate 25.12.3, KDE Frameworks 6, Qt 6
  • C++20, CMake, extra-cmake-modules
  • C++ is the only first-class plugin path on this install (no Python/Pâté binding present)

Build

cmake -B build -S .
cmake --build build
QT_QPA_PLATFORM=offscreen ./build/bin/test_fuzzyranker   # run the matcher tests
ctest --test-dir build                                   # or via ctest

Install the plugin into Kate

The plugin builds to build/bin/kf6/ktexteditor/olliepalette.so. Drop it where Kate scans for KTextEditor plugins (a user path on QT_PLUGIN_PATH):

install -D build/bin/kf6/ktexteditor/olliepalette.so \
  ~/.local/lib/x86_64-linux-gnu/qt6/plugins/kf6/ktexteditor/olliepalette.so

Then in Kate: Settings → Configure Kate → Plugins → enable Ollie Command Palette. Press Alt+X (M-x) to open the command palette; type to filter, Enter or click to run. Open the editing radial menu either by pressing Alt+R (opens at the caret) or by pressing the right mouse button in the editor (opens at the pointer; the normal context menu is suppressed while this is enabled). Move toward a slice and release — or click; a branch slice (marked ▸) opens a submenu, the centre hub goes back/cancels.

Status

See docs/PLAN.md for the full roadmap.

  • Milestone 1 — FuzzyRanker (keystone): DONE. Orderless, layered scoring (exact / substring / word-initials / subsequence / bounded typo), merged highlight ranges. 14 unit tests, all green.
  • Milestone 2 — custom palette widget: DONE. PaletteModel + PaletteWidget (frameless popup, live filtering, highlighted matches, keyboard + mouse activation). 10 model unit tests, all green.
  • Milestone 3 — KTextEditor plugin + M-x: DONE. Loadable olliepalette.so; Alt+X opens the palette over every action in the window's GUI clients.
  • Milestone 4 — radial caret menu: DONE (first increment). Multi-level radial menu at the caret (Alt+R) or at the pointer via a right-mouse gesture, mouse-driven selection, config tree with per-radial key + mouse triggers. Free-form stroke gestures next.
  • Milestone 5 — command vocabulary + project-as-directory + switchers: next.

Layout

CMakeLists.txt            top-level KF6/Qt6/ECM project
src/
  fuzzy/
    fuzzyranker.{h,cpp}   orderless + layered fuzzy matcher
    test_fuzzyranker.cpp  QTest suite
  palette/
    palettemodel.{h,cpp}  ranked, filterable list model (headless)
    palettewidget.{h,cpp} frameless command-palette popup
    test_palettemodel.cpp QTest suite
  radial/
    radialmodel.{h,cpp}   radial tree + hit-test geometry (headless)
    radialmenu.{h,cpp}    frameless multi-level radial widget
    radialconfig.{h,cpp}  JSON → radial tree + built-in default
    test_radialmodel.cpp  QTest suite
    test_radialconfig.cpp QTest suite
  commands/
    texttransforms.{h,cpp}  pure text transforms (headless)
    olliecommands.{h,cpp}   ":"-verb KTextEditor::Command pack
    test_texttransforms.cpp QTest suite
  plugin/
    ollieplugin.{h,cpp}   KTextEditor::Plugin + M-x + radial wiring
    ollieplugin.json      plugin metadata
docs/
  PLAN.md                 goal, constraints, roadmap