Native C++ 9P2000 client over QLocalSocket (no libplumb/lib9pclient
link) talking to a running plan9port plumber:
- ninep: Tversion/Tattach/Twalk/Topen/Tread/Twrite/Tclunk, LE wire,
msize negotiated from 8192; cancellable split read (beginRead +
recvReadReply) so the edit-port reader thread honours a stop flag
without a second outstanding Tread or any cross-thread socket touch.
- plumbmsg: PlumbMsg pack/unpack with libplumb attribute quoting;
unit-tested against golden bytes captured from a live plumber.
- plumbresolve: plan9 addr (N / N:C / N.C, 1-based) -> 0-based cursor.
- plumber: send() via the send port; PlumbReader QThread on the edit
port emits edit(file,addr,wdir) via a queued signal. Namespace socket
is $NAMESPACE/plumb or /tmp/ns.$USER.$DISPLAY/plumb (plan9 getns).
Plugin: F2 (ollie_plumb) plumbs selection/wordAt(cursor) through the
send port, falling back to internal URL/file resolution; incoming edit
messages open via openUrl + activateView + setCursorPosition.
Tests: test_plumbmsg + test_plumbresolve headless; test_plumb_live does
a real send->rules->edit round-trip against a running plumber and
skips+passes when none is reachable. 16/16 ctest green; live 4/4.
|
||
|---|---|---|
| docs | ||
| src | ||
| .gitignore | ||
| CMakeLists.txt | ||
| README.md | ||
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+Xopens 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