From e1bf0c9432806c46d7a081a3e924ee5ec3ec0255 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 7 Oct 2026 18:21:55 +0200 Subject: [PATCH] Palette: surface :-verbs as runnable M-x entries The command palette now lists the :-verb pack alongside QActions: Sort Lines, Sort Lines (unique), Reverse Lines, Case: UPPER/lower/Title/snake/camel/kebab, Base64 Encode/Decode, ROT13, Insert UUID. Entries carry an ollie:cmd: id; on activation runAction executes the command via Editor::queryCommand(verb)->exec(view, cmd, msg). The free-text pipe verb stays on the command line. All 6 ctest suites green. --- docs/PLAN.md | 6 ++-- src/plugin/ollieplugin.cpp | 58 +++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/docs/PLAN.md b/docs/PLAN.md index 880ea03..9b8d4e2 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -179,8 +179,10 @@ Therefore the palette is replaced, not extended, and the replacement is built on nothing is selected); `pipe ` runs `sh -c ` with the selection on stdin and replaces it with stdout. 15 transform tests. The command object is created once by `OlliePlugin` (auto-registers globally). - - Reachable from Kate's command line today; surfacing the verbs in the M-x - palette (they are `Command`s, not `QAction`s) is a follow-up. + - Also surfaced in the M-x palette as directly-runnable entries (`case` is + expanded into one entry per style). The palette id is prefixed `ollie:cmd:` + and executed via `Editor::queryCommand(verb)->exec(view, cmd, msg)`. The + free-text `pipe` verb stays on the command line only. - Project = directory ("open folder == open project"): TODO. - Fuzzy file / symbol switchers scoped to the folder: TODO. diff --git a/src/plugin/ollieplugin.cpp b/src/plugin/ollieplugin.cpp index 92b309d..0a88bb0 100644 --- a/src/plugin/ollieplugin.cpp +++ b/src/plugin/ollieplugin.cpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -121,6 +123,36 @@ KTextEditor::Cursor findOpener(KTextEditor::Document *doc, KTextEditor::Cursor p } return KTextEditor::Cursor::invalid(); } + +// Prefix marking a palette id that is a ":" command string to execute rather +// than a QAction to trigger. +const QLatin1String kCmdPrefix("ollie:cmd:"); + +// The complete (argument-free) command verbs offered in the palette. Verbs that +// need free-text arguments (pipe) stay on the command line; `case` is expanded +// into one entry per style so each is directly runnable. +struct VerbItem { + QString command; // the full command string to execute + QString label; // palette label +}; +QList paletteVerbs() +{ + return { + {QStringLiteral("sort"), QStringLiteral("Sort Lines")}, + {QStringLiteral("sort u"), QStringLiteral("Sort Lines (unique)")}, + {QStringLiteral("rsort"), QStringLiteral("Reverse Lines")}, + {QStringLiteral("case upper"), QStringLiteral("Case: UPPER")}, + {QStringLiteral("case lower"), QStringLiteral("Case: lower")}, + {QStringLiteral("case title"), QStringLiteral("Case: Title")}, + {QStringLiteral("case snake"), QStringLiteral("Case: snake_case")}, + {QStringLiteral("case camel"), QStringLiteral("Case: camelCase")}, + {QStringLiteral("case kebab"), QStringLiteral("Case: kebab-case")}, + {QStringLiteral("b64enc"), QStringLiteral("Base64 Encode")}, + {QStringLiteral("b64dec"), QStringLiteral("Base64 Decode")}, + {QStringLiteral("rot13"), QStringLiteral("ROT13")}, + {QStringLiteral("uuid"), QStringLiteral("Insert UUID")}, + }; +} } // namespace // --------------------------------------------------------------------------- @@ -308,7 +340,7 @@ void OllieView::showCommandPalette() m_actionsById.clear(); QList items; - items.reserve(entries.size()); + items.reserve(entries.size() + 16); for (const ActionEntry &e : entries) { m_actionsById.insert(e.id, e.action); @@ -319,6 +351,15 @@ void OllieView::showCommandPalette() items.push_back(item); } + // Also offer the ":"-verb pack as directly-runnable palette entries. + for (const VerbItem &v : paletteVerbs()) { + PaletteItem item; + item.id = kCmdPrefix + v.command; + item.label = v.label; + item.group = QStringLiteral(":") + v.command; + items.push_back(item); + } + m_palette->setItems(items); // Center the palette near the top of the active window. @@ -334,6 +375,21 @@ void OllieView::showCommandPalette() void OllieView::runAction(const QString &actionId) { + // A ":"-verb entry: execute the command on the active view. + if (actionId.startsWith(kCmdPrefix)) { + const QString command = actionId.mid(QString(kCmdPrefix).size()); + KTextEditor::View *view = m_mainWindow->activeView(); + KTextEditor::Editor *editor = KTextEditor::Editor::instance(); + if (view && editor) { + const QString verb = command.section(QLatin1Char(' '), 0, 0); + if (KTextEditor::Command *c = editor->queryCommand(verb)) { + QString msg; + c->exec(view, command, msg); + } + } + return; + } + QPointer action = m_actionsById.value(actionId); if (action) { action->trigger();