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.
|
||||
|
||||
### M5 — Command vocabulary + project model + switchers — IN PROGRESS
|
||||
- `:`-verb pack — DONE. `src/commands/`: `texttransforms.{h,cpp}` (pure,
|
||||
unit-tested: sort/rsort, case upper|lower|title|snake|camel|kebab, base64
|
||||
enc/dec, rot13, uuid) + `olliecommands.{h,cpp}` (a `KTextEditor::Command`
|
||||
registering `sort`, `rsort`, `case`, `b64enc`, `b64dec`, `rot13`, `uuid`,
|
||||
`pipe`). Verbs transform the selection in place (or the whole document when
|
||||
nothing is selected); `pipe <shell>` runs `sh -c <shell>` with the selection
|
||||
on stdin and replaces it with stdout. 15 transform tests. The command object
|
||||
is created once by `OlliePlugin` (auto-registers globally).
|
||||
- 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.
|
||||
- `:`-verb pack — DONE (palette path). `src/commands/`: `texttransforms.{h,cpp}`
|
||||
(pure, unit-tested: sort/rsort, case upper|lower|title|snake|camel|kebab,
|
||||
base64 enc/dec, rot13, uuid) + `olliecommands.{h,cpp}`. The verb logic lives in
|
||||
`OllieCommands::runVerb(view, cmd, msg)` and transforms the selection in place
|
||||
(or the whole document when nothing is selected); `pipe <shell>` runs
|
||||
`sh -c <shell>` with the selection on stdin.
|
||||
- Verbs are invoked from the **M-x palette** (entries prefixed `ollie:cmd:`,
|
||||
executed by calling `OllieCommands::runVerb` directly). `case` is expanded
|
||||
into one entry per style; `pipe` is palette-omitted (needs free text).
|
||||
- A live test (`test_olliecommands_live`, headless KTextEditor doc/view)
|
||||
proves the transforms mutate a real buffer.
|
||||
- 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.
|
||||
- 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)
|
||||
target_link_libraries(test_texttransforms PRIVATE Qt6::Core Qt6::Test)
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
const KTextEditor::Range &)
|
||||
{
|
||||
return runVerb(view, cmd, msg);
|
||||
}
|
||||
|
||||
bool OllieCommands::runVerb(KTextEditor::View *view, const QString &cmd, QString &msg)
|
||||
{
|
||||
if (!view) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,14 @@ public:
|
|||
const KTextEditor::Range &range = KTextEditor::Range::invalid()) 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:
|
||||
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)
|
||||
{
|
||||
// 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)) {
|
||||
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)) {
|
||||
if (KTextEditor::View *view = m_mainWindow->activeView()) {
|
||||
QString msg;
|
||||
c->exec(view, command, msg);
|
||||
}
|
||||
OllieCommands::runVerb(view, command, msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue