radial: add a conditional Ollie submenu to the right-button radial
When the sibling Ollie Kate plugin (ollie-kate) is loaded in the window, the
right-button radial grows an 'Ollie' branch: Ask, Explain, Fix, Refactor, Tests,
Doc, Verbatim, Start.
Ollie's context actions are not window/collection actions (they live on a
transient context menu, which the radial suppresses anyway), so findActionByName
cannot resolve them. Instead each slice carries an 'ollie:<verb>' id; triggerOllieVerb()
resolves the plugin view via pluginView("ollie-kate") and invokes its
Q_INVOKABLE action method by name (submitSelectionPrompt for fix/refactor/test/doc,
the zero-arg methods for the rest). The branch is built at show time and omitted
when the plugin is not loaded, mirroring the LSP branch. 18/18 ctest green.
This commit is contained in:
parent
36e9890ec7
commit
67e8d53827
|
|
@ -218,6 +218,10 @@ through a list.
|
|||
Format, Code Action, Symbol Info, Hover. It is decided at open time (resolving
|
||||
the actions live), so it appears only when a language server is backing the
|
||||
buffer and is hidden entirely otherwise.
|
||||
- **Ollie branch (conditional).** When the **Ollie** Kate plugin (the sibling
|
||||
AI-agent plugin) is enabled, the right-button radial grows an **Ollie**
|
||||
submenu — Ask, Explain, Fix, Refactor, Tests, Doc, Verbatim, Start — invoking
|
||||
Ollie's context actions. Shown only while that plugin is loaded.
|
||||
- **Pointer follows focus.** When a slice changes the active pane (split, close,
|
||||
or focus-move), the pointer is warped to the centre of the new pane so the
|
||||
mouse stays where your attention is — the same cursor-follows-focus feel as
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ void RadialView::showRadialAt(int defIndex, const QPoint &globalPos)
|
|||
if (RadialNode lsp = lspBranchIfActive(); !lsp.children.isEmpty()) {
|
||||
root.children.push_back(lsp);
|
||||
}
|
||||
if (RadialNode ollie = ollieBranchIfActive(); !ollie.children.isEmpty()) {
|
||||
root.children.push_back(ollie);
|
||||
}
|
||||
}
|
||||
|
||||
m_radial->popup(root, globalPos);
|
||||
|
|
@ -199,8 +202,87 @@ RadialNode RadialView::lspBranchIfActive() const
|
|||
return branch;
|
||||
}
|
||||
|
||||
RadialNode RadialView::ollieBranchIfActive() const
|
||||
{
|
||||
// Only show the Ollie branch when the Ollie Kate plugin is loaded in this
|
||||
// window. Its context actions are not window/collection actions (they live
|
||||
// on a transient context menu), so we cannot resolve them via
|
||||
// findActionByName; instead we invoke the plugin view's Q_INVOKABLE action
|
||||
// methods by name in onRadialActivated. Each slice carries an "ollie:" id.
|
||||
RadialNode branch;
|
||||
if (!m_mainWindow->pluginView(QStringLiteral("ollie-kate"))) {
|
||||
return branch; // not enabled -> empty, caller omits it
|
||||
}
|
||||
|
||||
auto leaf = [](const QString &label, const QString &id) {
|
||||
RadialNode n;
|
||||
n.label = label;
|
||||
n.actionId = id;
|
||||
return n;
|
||||
};
|
||||
|
||||
branch.label = QStringLiteral("Ollie");
|
||||
branch.children = {
|
||||
leaf(QStringLiteral("Ask"), QStringLiteral("ollie:ask")),
|
||||
leaf(QStringLiteral("Explain"), QStringLiteral("ollie:explain")),
|
||||
leaf(QStringLiteral("Fix"), QStringLiteral("ollie:fix")),
|
||||
leaf(QStringLiteral("Refactor"), QStringLiteral("ollie:refactor")),
|
||||
leaf(QStringLiteral("Tests"), QStringLiteral("ollie:test")),
|
||||
leaf(QStringLiteral("Doc"), QStringLiteral("ollie:doc")),
|
||||
leaf(QStringLiteral("Verbatim"), QStringLiteral("ollie:verbatim")),
|
||||
leaf(QStringLiteral("Start"), QStringLiteral("ollie:start")),
|
||||
};
|
||||
return branch;
|
||||
}
|
||||
|
||||
// Dispatch an "ollie:" radial slice to the Ollie Kate plugin's view by invoking
|
||||
// its Q_INVOKABLE action method. Returns true if the id was an Ollie verb (even
|
||||
// if the plugin is momentarily unavailable), so the caller does not also try to
|
||||
// resolve it as a Kate action.
|
||||
bool RadialView::triggerOllieVerb(const QString &actionId) const
|
||||
{
|
||||
if (!actionId.startsWith(QLatin1String("ollie:"))) {
|
||||
return false;
|
||||
}
|
||||
QObject *view = m_mainWindow->pluginView(QStringLiteral("ollie-kate"));
|
||||
if (!view) {
|
||||
return true; // recognised as ours, but nothing to invoke
|
||||
}
|
||||
const QString verb = actionId.mid(QStringLiteral("ollie:").size());
|
||||
|
||||
// The selection-prompt verbs share one method with an argument; the rest are
|
||||
// zero-argument methods matching the Q_INVOKABLE names on the Ollie view.
|
||||
if (verb == QLatin1String("fix")) {
|
||||
QMetaObject::invokeMethod(view, "submitSelectionPrompt",
|
||||
Q_ARG(QString, QStringLiteral("Fix")));
|
||||
} else if (verb == QLatin1String("refactor")) {
|
||||
QMetaObject::invokeMethod(view, "submitSelectionPrompt",
|
||||
Q_ARG(QString, QStringLiteral("Refactor")));
|
||||
} else if (verb == QLatin1String("test")) {
|
||||
QMetaObject::invokeMethod(view, "submitSelectionPrompt",
|
||||
Q_ARG(QString, QStringLiteral("Write unit tests for")));
|
||||
} else if (verb == QLatin1String("doc")) {
|
||||
QMetaObject::invokeMethod(view, "submitSelectionPrompt",
|
||||
Q_ARG(QString, QStringLiteral("Add documentation comments to")));
|
||||
} else if (verb == QLatin1String("ask")) {
|
||||
QMetaObject::invokeMethod(view, "askAboutFile");
|
||||
} else if (verb == QLatin1String("explain")) {
|
||||
QMetaObject::invokeMethod(view, "explainSelection");
|
||||
} else if (verb == QLatin1String("verbatim")) {
|
||||
QMetaObject::invokeMethod(view, "sendVerbatim");
|
||||
} else if (verb == QLatin1String("start")) {
|
||||
QMetaObject::invokeMethod(view, "startSession");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RadialView::onRadialActivated(const QString &actionId)
|
||||
{
|
||||
// Ollie verbs are not Kate actions; dispatch them to the Ollie plugin view.
|
||||
if (triggerOllieVerb(actionId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Launcher doors (palette / switchers) are reachable from inside a radial as
|
||||
// special slices. Sibling deft plugins register these actions on the window;
|
||||
// trigger them by objectName so no cross-plugin link is needed.
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ private:
|
|||
// the right-button editing radial at show time.
|
||||
RadialNode lspBranchIfActive() const;
|
||||
|
||||
// Build an "Ollie" submenu of the Ollie Kate plugin's context actions when
|
||||
// that plugin is loaded in this window; empty otherwise so the caller omits
|
||||
// it. Spliced into the right-button editing radial at show time.
|
||||
RadialNode ollieBranchIfActive() const;
|
||||
|
||||
// Dispatch an "ollie:"-prefixed slice id to the Ollie plugin view's
|
||||
// Q_INVOKABLE action method. Returns true if the id was an Ollie verb, so
|
||||
// onRadialActivated does not also treat it as a Kate action.
|
||||
bool triggerOllieVerb(const QString &actionId) const;
|
||||
|
||||
// Find a Kate action by its raw objectName (then visible text) across all
|
||||
// GUI clients. Resolves radial-slice ids, including the launcher actions
|
||||
// that sibling deft plugins register on the window.
|
||||
|
|
|
|||
Loading…
Reference in New Issue