From dca2514023bab2f011591022bc7ab07abecdc978 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 7 Oct 2026 17:06:56 +0200 Subject: [PATCH] Radial: add top-level 'Cursors to Line Ends' multi-cursor action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Multi-cursor on every selected line is a quintessential in-place action (select lines, gesture, keep typing) — a natural fit for a top-level radial slice. Wired to Kate's createMultiCursorsFromSelection via its visible text 'Add Cursors to Line Ends'. findActionByName now falls back to a case-insensitive visible-text match when the objectName lookup misses, so slices resolve across Kate versions even when action ids differ. Dropped 'Select All' from the radial (reachable via Ctrl+A and the palette). All 5 ctest suites green. --- src/plugin/ollieplugin.cpp | 29 +++++++++++++++++++++++++---- src/radial/radialconfig.cpp | 6 +++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/plugin/ollieplugin.cpp b/src/plugin/ollieplugin.cpp index 203d04b..fa92fd0 100644 --- a/src/plugin/ollieplugin.cpp +++ b/src/plugin/ollieplugin.cpp @@ -238,20 +238,41 @@ void OllieView::runAction(const QString &actionId) } } -QAction *OllieView::findActionByName(const QString &objectName) const +QAction *OllieView::findActionByName(const QString &nameOrText) const { KXMLGUIFactory *factory = m_mainWindow->guiFactory(); - if (!factory || objectName.isEmpty()) { + if (!factory || nameOrText.isEmpty()) { return nullptr; } const QList clients = factory->clients(); + + // First pass: exact objectName match (fast, unambiguous). + for (KXMLGUIClient *client : clients) { + if (KActionCollection *coll = client->actionCollection()) { + if (QAction *a = coll->action(nameOrText)) { + return a; + } + } + } + + // Fallback: match by visible text, case-insensitively. Keeps radial slices + // working when a Kate action's objectName differs from our config id across + // versions (we can reference it by its menu label instead). + const QString wanted = nameOrText.trimmed(); for (KXMLGUIClient *client : clients) { KActionCollection *coll = client->actionCollection(); if (!coll) { continue; } - if (QAction *a = coll->action(objectName)) { - return a; + const QList actions = coll->actions(); + for (QAction *a : actions) { + if (!a) { + continue; + } + const QString text = a->text().remove(QLatin1Char('&')).trimmed(); + if (text.compare(wanted, Qt::CaseInsensitive) == 0) { + return a; + } } } return nullptr; diff --git a/src/radial/radialconfig.cpp b/src/radial/radialconfig.cpp index 0651735..ca0710f 100644 --- a/src/radial/radialconfig.cpp +++ b/src/radial/radialconfig.cpp @@ -119,7 +119,11 @@ QList RadialConfig::builtinDefault() leaf(QStringLiteral("Paste"), QStringLiteral("edit_paste")), leaf(QStringLiteral("Undo"), QStringLiteral("edit_undo")), leaf(QStringLiteral("Redo"), QStringLiteral("edit_redo")), - leaf(QStringLiteral("Select All"), QStringLiteral("edit_select_all")), + // Multi-cursor on every selected line: a quintessential in-place action + // (select lines → gesture → keep typing). Referenced by visible text so + // it resolves regardless of the Kate action's objectName. + leaf(QStringLiteral("Cursors to Line Ends"), + QStringLiteral("Add Cursors to Line Ends")), more, };