M5: run :-verbs directly via OllieCommands::runVerb, fix palette no-op
queryCommand/commandList do not see our auto-registered KTextEditor::Command on this build, so the palette now calls OllieCommands::runVerb directly. Rewrite the live test to exercise runVerb against a real doc/view (case, rot13, sort, uuid, base64 round-trip). Document the command-line limitation.
This commit is contained in:
parent
e1bf0c9432
commit
a69e471e08
27
docs/PLAN.md
27
docs/PLAN.md
|
|
@ -171,18 +171,21 @@ Therefore the palette is replaced, not extended, and the replacement is built on
|
||||||
consuming it — no registered shortcut, so no ambiguity, no per-view sweeping.
|
consuming it — no registered shortcut, so no ambiguity, no per-view sweeping.
|
||||||
|
|
||||||
### M5 — Command vocabulary + project model + switchers — IN PROGRESS
|
### M5 — Command vocabulary + project model + switchers — IN PROGRESS
|
||||||
- `:`-verb pack — DONE. `src/commands/`: `texttransforms.{h,cpp}` (pure,
|
- `:`-verb pack — DONE (palette path). `src/commands/`: `texttransforms.{h,cpp}`
|
||||||
unit-tested: sort/rsort, case upper|lower|title|snake|camel|kebab, base64
|
(pure, unit-tested: sort/rsort, case upper|lower|title|snake|camel|kebab,
|
||||||
enc/dec, rot13, uuid) + `olliecommands.{h,cpp}` (a `KTextEditor::Command`
|
base64 enc/dec, rot13, uuid) + `olliecommands.{h,cpp}`. The verb logic lives in
|
||||||
registering `sort`, `rsort`, `case`, `b64enc`, `b64dec`, `rot13`, `uuid`,
|
`OllieCommands::runVerb(view, cmd, msg)` and transforms the selection in place
|
||||||
`pipe`). Verbs transform the selection in place (or the whole document when
|
(or the whole document when nothing is selected); `pipe <shell>` runs
|
||||||
nothing is selected); `pipe <shell>` runs `sh -c <shell>` with the selection
|
`sh -c <shell>` with the selection on stdin.
|
||||||
on stdin and replaces it with stdout. 15 transform tests. The command object
|
- Verbs are invoked from the **M-x palette** (entries prefixed `ollie:cmd:`,
|
||||||
is created once by `OlliePlugin` (auto-registers globally).
|
executed by calling `OllieCommands::runVerb` directly). `case` is expanded
|
||||||
- Also surfaced in the M-x palette as directly-runnable entries (`case` is
|
into one entry per style; `pipe` is palette-omitted (needs free text).
|
||||||
expanded into one entry per style). The palette id is prefixed `ollie:cmd:`
|
- A live test (`test_olliecommands_live`, headless KTextEditor doc/view)
|
||||||
and executed via `Editor::queryCommand(verb)->exec(view, cmd, msg)`. The
|
proves the transforms mutate a real buffer.
|
||||||
free-text `pipe` verb stays on the command line only.
|
- KNOWN LIMITATION: `KTextEditor::Command` auto-registration via the base
|
||||||
|
constructor is NOT visible to `Editor::queryCommand()`/`commandList()` on
|
||||||
|
this build, so the verbs are not (yet) reachable from Kate's `:` command
|
||||||
|
line — only via the palette. Proper command-line registration is a follow-up.
|
||||||
- Project = directory ("open folder == open project"): TODO.
|
- Project = directory ("open folder == open project"): TODO.
|
||||||
- Fuzzy file / symbol switchers scoped to the folder: TODO.
|
- Fuzzy file / symbol switchers scoped to the folder: TODO.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,9 @@ if(Qt6Test_FOUND)
|
||||||
add_executable(test_texttransforms test_texttransforms.cpp texttransforms.cpp texttransforms.h)
|
add_executable(test_texttransforms test_texttransforms.cpp texttransforms.cpp texttransforms.h)
|
||||||
target_link_libraries(test_texttransforms PRIVATE Qt6::Core Qt6::Test)
|
target_link_libraries(test_texttransforms PRIVATE Qt6::Core Qt6::Test)
|
||||||
add_test(NAME texttransforms COMMAND test_texttransforms)
|
add_test(NAME texttransforms COMMAND test_texttransforms)
|
||||||
|
|
||||||
|
add_executable(test_olliecommands_live test_olliecommands_live.cpp)
|
||||||
|
target_link_libraries(test_olliecommands_live PRIVATE
|
||||||
|
olliecommands_lib Qt6::Test KF6::TextEditor)
|
||||||
|
add_test(NAME olliecommands_live COMMAND test_olliecommands_live)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,11 @@ void applyResult(KTextEditor::View *view, const Target &t, const QString &result
|
||||||
|
|
||||||
bool OllieCommands::exec(KTextEditor::View *view, const QString &cmd, QString &msg,
|
bool OllieCommands::exec(KTextEditor::View *view, const QString &cmd, QString &msg,
|
||||||
const KTextEditor::Range &)
|
const KTextEditor::Range &)
|
||||||
|
{
|
||||||
|
return runVerb(view, cmd, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OllieCommands::runVerb(KTextEditor::View *view, const QString &cmd, QString &msg)
|
||||||
{
|
{
|
||||||
if (!view) {
|
if (!view) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,14 @@ public:
|
||||||
const KTextEditor::Range &range = KTextEditor::Range::invalid()) override;
|
const KTextEditor::Range &range = KTextEditor::Range::invalid()) override;
|
||||||
bool help(KTextEditor::View *view, const QString &cmd, QString &msg) override;
|
bool help(KTextEditor::View *view, const QString &cmd, QString &msg) override;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Execute a verb command string (e.g. "case upper", "sort u") directly on
|
||||||
|
* \a view, without going through the editor's command registry. Used by the
|
||||||
|
* command palette, whose entries cannot rely on Command auto-registration
|
||||||
|
* being visible to Editor::queryCommand(). Returns true on success.
|
||||||
|
*/
|
||||||
|
static bool runVerb(KTextEditor::View *view, const QString &cmd, QString &msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static QStringList supportedCmds();
|
static QStringList supportedCmds();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.0-or-later
|
||||||
|
*
|
||||||
|
* Live test: run the ":"-verbs directly (OllieCommands::runVerb) on a real
|
||||||
|
* KTextEditor Document/View and confirm the buffer is mutated. This is the path
|
||||||
|
* the command palette uses, independent of the editor's command registry.
|
||||||
|
* Requires a (headless) QApplication; run with QT_QPA_PLATFORM=offscreen.
|
||||||
|
*/
|
||||||
|
#include "olliecommands.h"
|
||||||
|
|
||||||
|
#include <KTextEditor/Document>
|
||||||
|
#include <KTextEditor/Editor>
|
||||||
|
#include <KTextEditor/View>
|
||||||
|
|
||||||
|
#include <QTest>
|
||||||
|
|
||||||
|
using namespace katecustom;
|
||||||
|
|
||||||
|
class TestOllieCommandsLive : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
KTextEditor::Editor *m_editor = nullptr;
|
||||||
|
|
||||||
|
KTextEditor::View *makeView(const QString &text, KTextEditor::Document *&docOut)
|
||||||
|
{
|
||||||
|
docOut = m_editor->createDocument(this);
|
||||||
|
docOut->setText(text);
|
||||||
|
return docOut->createView(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void initTestCase()
|
||||||
|
{
|
||||||
|
m_editor = KTextEditor::Editor::instance();
|
||||||
|
QVERIFY(m_editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void caseUpperWholeDocument()
|
||||||
|
{
|
||||||
|
KTextEditor::Document *doc = nullptr;
|
||||||
|
KTextEditor::View *v = makeView(QStringLiteral("helloWorld"), doc);
|
||||||
|
QString msg;
|
||||||
|
QVERIFY2(OllieCommands::runVerb(v, QStringLiteral("case upper"), msg), qPrintable(msg));
|
||||||
|
QCOMPARE(doc->text(), QStringLiteral("HELLOWORLD"));
|
||||||
|
delete v;
|
||||||
|
delete doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rot13OnSelection()
|
||||||
|
{
|
||||||
|
KTextEditor::Document *doc = nullptr;
|
||||||
|
KTextEditor::View *v = makeView(QStringLiteral("abc XYZ"), doc);
|
||||||
|
v->setSelection(doc->documentRange());
|
||||||
|
QString msg;
|
||||||
|
QVERIFY(OllieCommands::runVerb(v, QStringLiteral("rot13"), msg));
|
||||||
|
QCOMPARE(doc->text(), QStringLiteral("nop KLM"));
|
||||||
|
delete v;
|
||||||
|
delete doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sortLinesWholeDocument()
|
||||||
|
{
|
||||||
|
KTextEditor::Document *doc = nullptr;
|
||||||
|
KTextEditor::View *v = makeView(QStringLiteral("banana\napple\ncherry"), doc);
|
||||||
|
QString msg;
|
||||||
|
QVERIFY(OllieCommands::runVerb(v, QStringLiteral("sort"), msg));
|
||||||
|
QCOMPARE(doc->text(), QStringLiteral("apple\nbanana\ncherry"));
|
||||||
|
delete v;
|
||||||
|
delete doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uuidInsertsAtCursor()
|
||||||
|
{
|
||||||
|
KTextEditor::Document *doc = nullptr;
|
||||||
|
KTextEditor::View *v = makeView(QString(), doc);
|
||||||
|
QString msg;
|
||||||
|
QVERIFY(OllieCommands::runVerb(v, QStringLiteral("uuid"), msg));
|
||||||
|
QCOMPARE(doc->text().size(), 36); // 8-4-4-4-12 + 4 hyphens
|
||||||
|
delete v;
|
||||||
|
delete doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void base64RoundTripOnSelection()
|
||||||
|
{
|
||||||
|
KTextEditor::Document *doc = nullptr;
|
||||||
|
KTextEditor::View *v = makeView(QStringLiteral("hello"), doc);
|
||||||
|
v->setSelection(doc->documentRange());
|
||||||
|
QString msg;
|
||||||
|
QVERIFY(OllieCommands::runVerb(v, QStringLiteral("b64enc"), msg));
|
||||||
|
QCOMPARE(doc->text(), QStringLiteral("aGVsbG8="));
|
||||||
|
v->setSelection(doc->documentRange());
|
||||||
|
QVERIFY(OllieCommands::runVerb(v, QStringLiteral("b64dec"), msg));
|
||||||
|
QCOMPARE(doc->text(), QStringLiteral("hello"));
|
||||||
|
delete v;
|
||||||
|
delete doc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(TestOllieCommandsLive)
|
||||||
|
#include "test_olliecommands_live.moc"
|
||||||
|
|
@ -375,17 +375,14 @@ void OllieView::showCommandPalette()
|
||||||
|
|
||||||
void OllieView::runAction(const QString &actionId)
|
void OllieView::runAction(const QString &actionId)
|
||||||
{
|
{
|
||||||
// A ":"-verb entry: execute the command on the active view.
|
// A ":"-verb entry: execute the command directly on the active view.
|
||||||
|
// We call OllieCommands::runVerb rather than Editor::queryCommand because
|
||||||
|
// our Command's auto-registration is not reliably visible to queryCommand.
|
||||||
if (actionId.startsWith(kCmdPrefix)) {
|
if (actionId.startsWith(kCmdPrefix)) {
|
||||||
const QString command = actionId.mid(QString(kCmdPrefix).size());
|
const QString command = actionId.mid(QString(kCmdPrefix).size());
|
||||||
KTextEditor::View *view = m_mainWindow->activeView();
|
if (KTextEditor::View *view = m_mainWindow->activeView()) {
|
||||||
KTextEditor::Editor *editor = KTextEditor::Editor::instance();
|
QString msg;
|
||||||
if (view && editor) {
|
OllieCommands::runVerb(view, command, msg);
|
||||||
const QString verb = command.section(QLatin1Char(' '), 0, 0);
|
|
||||||
if (KTextEditor::Command *c = editor->queryCommand(verb)) {
|
|
||||||
QString msg;
|
|
||||||
c->exec(view, command, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue