plumb: open a plumbed directory as a folder in Kate

When a plumbed path resolves to an existing directory, onPlumbEdit now opens
it as a folder in Kate (acme-style directory open) instead of trying to open
it as a document. Kate accepts a directory on its command line and is
single-instance, so relaunching the hosting kate binary (QCoreApplication::
applicationFilePath, QStandardPaths fallback) on the dir opens it in the
running window. No in-process public API exists to open a folder as a project
(our project bridge is read-only), so this uses the documented command-line
path rather than a guessed slot. 18/18 ctest.
This commit is contained in:
Levi Neely 2026-10-08 15:45:49 +02:00
parent 82f91755a5
commit 50d037690f
2 changed files with 24 additions and 1 deletions

View File

@ -346,7 +346,11 @@ Kate flow through the real plumber rules.
selection, else `Document::wordAt(cursorPosition)`, with the active doc's dir selection, else `Document::wordAt(cursorPosition)`, with the active doc's dir
as `wdir`; on send failure it falls back to an internal resolver (URL → as `wdir`; on send failure it falls back to an internal resolver (URL →
`QDesktopServices`, path[:line] → open here). Incoming `edit` messages are `QDesktopServices`, path[:line] → open here). Incoming `edit` messages are
opened via `MainWindow::openUrl` + `activateView` + `setCursorPosition`. opened via `MainWindow::openUrl` + `activateView` + `setCursorPosition`; a
plumbed path that resolves to a **directory** opens as a folder in Kate
instead (relaunches the hosting kate binary on the dir — Kate is
single-instance, so it opens in the running window; no in-process folder-open
API exists, so this is the documented command-line path).
- **Verification**: `test_plumbmsg` + `test_plumbresolve` run headless; - **Verification**: `test_plumbmsg` + `test_plumbresolve` run headless;
`test_plumb_live` does a **real round-trip** against a running plumber (send `test_plumb_live` does a **real round-trip** against a running plumber (send
`<file>:2` → rules → edit port → `edit()` signal) and **skips+passes** when no `<file>:2` → rules → edit port → `edit()` signal) and **skips+passes** when no

View File

@ -29,6 +29,7 @@
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QCoreApplication>
#include <QCursor> #include <QCursor>
#include <QDateTime> #include <QDateTime>
#include <QDesktopServices> #include <QDesktopServices>
@ -40,6 +41,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QKeySequence> #include <QKeySequence>
#include <QMouseEvent> #include <QMouseEvent>
#include <QProcess>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSet> #include <QSet>
#include <QStandardPaths> #include <QStandardPaths>
@ -895,6 +897,23 @@ void OllieView::onPlumbEdit(const QString &file, const QString &addr, const QStr
fi = QFileInfo(QDir(wdir).absoluteFilePath(path)); fi = QFileInfo(QDir(wdir).absoluteFilePath(path));
} }
// A plumbed directory opens as a folder in Kate (like acme opening a
// directory listing). Kate accepts a directory URL on its command line and,
// being single-instance, opens it in the running window. We relaunch the
// very binary hosting us so it is unambiguously "this Kate". There is no
// in-process public API to open a folder as a project, so this is the
// documented path, not a guessed one.
if (fi.exists() && fi.isDir()) {
QString kate = QCoreApplication::applicationFilePath();
if (kate.isEmpty() || !QFileInfo(kate).fileName().contains(QLatin1String("kate"))) {
kate = QStandardPaths::findExecutable(QStringLiteral("kate"));
}
if (!kate.isEmpty()) {
QProcess::startDetached(kate, {fi.absoluteFilePath()});
}
return;
}
const QUrl url = QUrl::fromLocalFile(fi.absoluteFilePath()); const QUrl url = QUrl::fromLocalFile(fi.absoluteFilePath());
KTextEditor::View *view = m_mainWindow->openUrl(url); KTextEditor::View *view = m_mainWindow->openUrl(url);
if (!view) { if (!view) {