plugin: plumb file token with acme isfilec expansion
Replace Document::wordAt() in plumbAtCursor() with fileTokenAt(), an acme-style button-3 file expansion: grow over isFileChar() (alnum, '_', and '. - + / : @', matching plan9port acme's isfilec), with ':' ending the file name and only a digit-led ':line[:col]' suffix kept attached. This grabs whole paths like /a/b/dpg_identity.php:584 under the caret. Also reverts the earlier ^W change so acmeEraseWord again matches acme's C isalnum (which excludes '_').
This commit is contained in:
parent
08a75c06af
commit
019fed6db4
|
|
@ -348,7 +348,10 @@ Kate flow through the real plumber rules.
|
|||
- **Plugin wiring** (`src/plugin/ollieplugin.cpp`): an `ollie_plumb` QAction on
|
||||
**F2** (testing trigger; a function key, so no collision with the Alt+letter
|
||||
door policy — final gesture will be RMB). `plumbAtCursor()` plumbs the
|
||||
selection, else `Document::wordAt(cursorPosition)`, with the active doc's dir
|
||||
selection, else the acme-style file-path token under the caret
|
||||
(`fileTokenAt` + `isFileChar`, matching plan9port acme's `isfilec`: alnum,
|
||||
`_`, and `. - + / : @`; `:` ends the file name and only a digit-led
|
||||
`:line[:col]` suffix is kept), with the active doc's dir
|
||||
as `wdir`; on send failure it falls back to an internal resolver (URL →
|
||||
`QDesktopServices`, path[:line] → open here). Incoming `edit` messages are
|
||||
opened via `MainWindow::openUrl` + `activateView` + `setCursorPosition`; a
|
||||
|
|
|
|||
|
|
@ -99,6 +99,29 @@ bool isQuote(QChar c)
|
|||
return u == '\'' || u == '"' || u == '`';
|
||||
}
|
||||
|
||||
// Characters that may appear in a plumbable file path, mirroring plan9port
|
||||
// acme's isfilec() (look.c). Acme treats a rune as a file char when its
|
||||
// isalnum() is true OR it is one of ". - + / : @". Acme's isalnum() counts '_'
|
||||
// as alphanumeric (it is not in acme's punctuation set), so '_' is a file char;
|
||||
// QChar::isLetterOrNumber() excludes it, hence the explicit test.
|
||||
bool isFileChar(QChar c)
|
||||
{
|
||||
if (c.isLetterOrNumber() || c == QLatin1Char('_')) {
|
||||
return true;
|
||||
}
|
||||
switch (c.unicode()) {
|
||||
case '.':
|
||||
case '-':
|
||||
case '+':
|
||||
case '/':
|
||||
case ':':
|
||||
case '@':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance a cursor by one character, wrapping across line ends. Returns false
|
||||
// at end of document.
|
||||
bool stepForward(KTextEditor::Document *doc, KTextEditor::Cursor &c)
|
||||
|
|
@ -213,6 +236,51 @@ KTextEditor::Cursor findQuoteBackward(KTextEditor::Document *doc, int line, int
|
|||
return KTextEditor::Cursor::invalid();
|
||||
}
|
||||
|
||||
// Expand the caret position into the surrounding file-path token, mirroring
|
||||
// plan9port acme's button-3 file expansion (look.c). Grow left and right over
|
||||
// isFileChar() runs, but treat ':' as acme does: it ends the file name and may
|
||||
// introduce a numeric ":line[:col]" address, which is kept attached to the
|
||||
// token (the plumber / onPlumbEdit splits it downstream). Expansion is
|
||||
// line-local; acme stops at white space and a newline is never a file char.
|
||||
QString fileTokenAt(KTextEditor::Document *doc, const KTextEditor::Cursor &at)
|
||||
{
|
||||
const int line = at.line();
|
||||
const int len = doc->lineLength(line);
|
||||
auto ch = [&](int c) { return doc->characterAt(KTextEditor::Cursor(line, c)); };
|
||||
auto isFileNoColon = [&](QChar c) { return isFileChar(c) && c != QLatin1Char(':'); };
|
||||
|
||||
// File name: grow left and right over file chars, stopping before any ':'
|
||||
// (acme ends the name at the colon and parses an address after it).
|
||||
int lo = at.column();
|
||||
int hi = at.column();
|
||||
while (hi < len && isFileNoColon(ch(hi))) {
|
||||
++hi;
|
||||
}
|
||||
while (lo > 0 && isFileNoColon(ch(lo - 1))) {
|
||||
--lo;
|
||||
}
|
||||
if (hi <= lo) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
// Optional ":line[:col]" address: only when the colon is immediately
|
||||
// followed by a digit, matching acme's isaddrc gate and the numeric suffix
|
||||
// onPlumbEdit expects. Consume up to two colon-separated digit runs.
|
||||
int end = hi;
|
||||
for (int part = 0; part < 2 && end < len && ch(end) == QLatin1Char(':'); ++part) {
|
||||
int scan = end + 1;
|
||||
if (scan >= len || !ch(scan).isDigit()) {
|
||||
break; // ':' not introducing a number — leave it out of the token
|
||||
}
|
||||
while (scan < len && ch(scan).isDigit()) {
|
||||
++scan;
|
||||
}
|
||||
end = scan;
|
||||
}
|
||||
|
||||
return doc->text(KTextEditor::Range(line, lo, line, end));
|
||||
}
|
||||
|
||||
// Prefix marking a palette id that is a ":" command string to execute rather
|
||||
// than a QAction to trigger.
|
||||
const QLatin1String kCmdPrefix("ollie:cmd:");
|
||||
|
|
@ -873,14 +941,15 @@ void OllieView::plumbAtCursor()
|
|||
}
|
||||
|
||||
// What to plumb: an explicit selection wins (lets the user plumb a path
|
||||
// with a line suffix like "foo.cpp:42"), otherwise the word under the
|
||||
// caret.
|
||||
// with a line suffix like "foo.cpp:42"), otherwise the file-path token
|
||||
// under the caret, expanded acme-style (isFileChar: alnum, '_', and
|
||||
// ". - + / : @") so paths and their ":line" address are grabbed whole.
|
||||
QString data;
|
||||
if (view->selection()) {
|
||||
data = view->selectionText().trimmed();
|
||||
}
|
||||
if (data.isEmpty()) {
|
||||
data = doc->wordAt(view->cursorPosition());
|
||||
data = fileTokenAt(doc, view->cursorPosition());
|
||||
}
|
||||
if (data.isEmpty()) {
|
||||
return;
|
||||
|
|
@ -1702,9 +1771,7 @@ void OllieView::acmeEraseWord()
|
|||
break;
|
||||
}
|
||||
const QChar r = doc->characterAt(prev);
|
||||
// Acme's isalnum() treats '_' as a word character (it is not in acme's
|
||||
// punctuation set), so ^W does not stop on underscores.
|
||||
const bool alnum = r.isLetterOrNumber() || r == QLatin1Char('_');
|
||||
const bool alnum = r.isLetterOrNumber();
|
||||
if (alnum && skipping) {
|
||||
skipping = false;
|
||||
} else if (!alnum && !skipping) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue