From 20c13a93fa124f46be32c23fa4d244300b840e2d Mon Sep 17 00:00:00 2001 From: Oscar Lesta Date: Tue, 5 Mar 2024 07:15:54 -0300 Subject: [PATCH] Implement `lpe file:line:col` and `/bin/open file:line:col`. The latter is what Terminal uses when "hyperlinking" to filenames. Fixes #68. --- Sources/PApp.cpp | 49 +++++++++++++++++++++++++++++++++++--------- lpe/lpe.cpp | 53 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 24 deletions(-) diff --git a/Sources/PApp.cpp b/Sources/PApp.cpp index dd2319f..9fcf63a 100644 --- a/Sources/PApp.cpp +++ b/Sources/PApp.cpp @@ -684,16 +684,29 @@ void PApp::RefsReceived(BMessage *inMessage) } else if (inMessage->HasInt32("be:line")) { - int32 line; + int32 line, column; FailOSErr(inMessage->FindInt32("be:line", &line)); - BMessage msg(msg_SelectLines); - FailOSErr(msg.AddInt32("from", line)); - FailOSErr(msg.AddInt32("to", line - 1)); - BMessenger msgr(d->TextView()); - FailOSErr(msgr.SendMessage(&msg)); + + if (inMessage->FindInt32("be:column", &column) == B_OK) + { + int32 offset = d->TextView()->Column2Offset(line - 1, column - 1); + BMessage msg(msg_Select); + FailOSErr(msg.AddInt32("anchor", offset)); + FailOSErr(msg.AddInt32("caret", offset)); + + FailOSErr(msgr.SendMessage(&msg)); + } + else + { + BMessage msg(msg_SelectLines); + FailOSErr(msg.AddInt32("from", line)); + FailOSErr(msg.AddInt32("to", line - 1)); + + FailOSErr(msgr.SendMessage(&msg)); + } } } } @@ -866,10 +879,26 @@ void PApp::MessageReceived(BMessage *msg) int32 lineNr; if (w && msg->FindInt32("line", &lineNr) == B_OK) { - BMessage m(msg_SelectLines); - FailOSErr(m.AddInt32("from", lineNr)); - FailOSErr(m.AddInt32("to", lineNr - 1)); - w->PostMessage(&m, w->PreferredHandler()); + int32 colNr; + if (msg->FindInt32("column", &colNr) == B_OK) + { + PDoc *d = dynamic_cast(OpenWindow(doc)); + if (d) + { + int32 offset = d->TextView()->Column2Offset(lineNr - 1, colNr - 1); + BMessage m(msg_Select); + FailOSErr(m.AddInt32("anchor", offset)); + FailOSErr(m.AddInt32("caret", offset)); + w->PostMessage(&m, w->PreferredHandler()); + } + } + else + { + BMessage m(msg_SelectLines); + FailOSErr(m.AddInt32("from", lineNr)); + FailOSErr(m.AddInt32("to", lineNr - 1)); + w->PostMessage(&m, w->PreferredHandler()); + } } if (w) diff --git a/lpe/lpe.cpp b/lpe/lpe.cpp index 91c102f..feba240 100644 --- a/lpe/lpe.cpp +++ b/lpe/lpe.cpp @@ -53,12 +53,11 @@ static BString sTempFilePath; void DoError(const char *e, ...); void Usage(bool error); -void OpenInPe(entry_ref& ref, int lineNr); +void OpenInPe(entry_ref& ref, int lineNr, int colNr=0); void Usage(bool error) { - puts("usage: lpe [--type ] [file:linenr | +linenr [file] | file] " - "..."); + puts("usage: lpe [--type ] [file:linenr[:colnr] | +linenr [file] | file] ..."); puts("If no file has been specified, copy stdin to a temporary file and"); puts("open that. In that case specifies the file extension to"); puts("be used to help Pe recognize the content type."); @@ -80,14 +79,17 @@ void DoError(const char *e, ...) exit(1); } /* error */ -void OpenInPe(entry_ref& doc, int lineNr) +void OpenInPe(entry_ref& doc, int lineNr, int colNr) { BMessage msg(msg_CommandLineOpen), reply; msg.AddRef("refs", &doc); - if (lineNr >= 0) + if (lineNr > 0) msg.AddInt32("line", lineNr); + if (colNr > 0) + msg.AddInt32("column", colNr); + entry_ref pe; if (be_roster->FindApp("application/x-vnd.beunited.pe", &pe)) DoError("Could not find Pe!"); @@ -152,12 +154,11 @@ int main(int argc, char *argv[]) { int i = 0; char *p; - char *dpPtr; int lineNr = -1; + int colNr = -1; status_t err; BEntry e; BString path; - int nr; bool pathSeen = false; const char* fileType = NULL; @@ -190,17 +191,40 @@ int main(int argc, char *argv[]) { pathSeen = true; path = argv[i]; - dpPtr = strrchr(argv[i], ':'); - if (dpPtr != NULL) + + err = e.SetTo(path.String()); + if (err == B_OK && !e.Exists() && path.FindLast(':')) { - nr = strtoul(dpPtr + 1, &p, 10); - if (strlen(p) == 0) + // remove final ':', if any. + if (path[path.Length() - 1] == ':') + path.Truncate(path.Length() - 1); + + err = e.SetTo(path.String()); + if (err == B_OK && !e.Exists()) { - path.SetTo(argv[i], dpPtr-argv[i]); - lineNr = nr; + // See if we find "file:line" or "file:line:col" + i = path.FindLast(':'); + if (i > 0) + { + // "file:line" + lineNr = atoi(path.String() + i + 1); + path.Truncate(i); + + err = e.SetTo(path.String()); + if (err == B_OK && !e.Exists()) + { + // "file:line:col" + colNr = lineNr; + i = path.FindLast(':'); + lineNr = atoi(path.String() + i + 1); + path.Truncate(i); + } + } } } +// printf("DEBUG: lineNr = %d, colNr = %d. path = '%s'\n", lineNr, colNr, path.String()); + err = e.SetTo(path.String(), true); if (err) DoError("Error trying to access file %s, (%s)", path.String(), strerror(err)); // if (! e.Exists()) DoError("File %s does not exist", path.String()); @@ -209,8 +233,9 @@ int main(int argc, char *argv[]) entry_ref ref; err = e.GetRef(&ref); if (err) DoError("Error trying to access file %s, (%s)", path.String(), strerror(err)); - OpenInPe(ref, lineNr); + OpenInPe(ref, lineNr, colNr); lineNr = -1; + colNr = -1; } } }