Go to file
Levi Neely 1b56cca1a2 Acme keys: resolve shortcut ambiguity by stripping conflicting bindings
Adding our Ctrl+A/E/H/U/W actions alongside Kate's own (Select All, Close,
lowercase, …) left both claiming the same sequence, so Qt reported ambiguous
shortcuts. clearConflictingShortcuts() now walks every GUI-client action
collection and removes our sequences from any foreign action, also clearing
their KActionCollection default shortcuts so they are not restored. The sweep
runs at setup, once more deferred to the event loop (after the GUI factory
merges all clients), and on every viewCreated so new documents don't
re-introduce the conflict.

Also implements the five Acme motions against the View/Document API with
semantics ported from plan9port acme text.c. All 5 ctest suites green.
2026-10-07 17:43:39 +02:00
docs Acme keys: resolve shortcut ambiguity by stripping conflicting bindings 2026-10-07 17:43:39 +02:00
src Acme keys: resolve shortcut ambiguity by stripping conflicting bindings 2026-10-07 17:43:39 +02:00
.gitignore Initial commit: FuzzyRanker keystone + project plan 2026-10-07 15:45:58 +02:00
CMakeLists.txt M3: loadable KTextEditor plugin with M-x command palette 2026-10-07 15:59:05 +02:00
README.md Radial: add right-mouse-button gesture trigger 2026-10-07 16:43:52 +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
  plugin/
    ollieplugin.{h,cpp}   KTextEditor::Plugin + M-x + radial wiring
    ollieplugin.json      plugin metadata
docs/
  PLAN.md                 goal, constraints, roadmap