Terminal: hyper link mode: Try more aggressively to detect a path
Consider ':' a potential path delimiter and try all combinations of chopped off prefixes and suffixes. This makes detection in the output of a multi-file grep work even if the found line starts with a path character or is a path. A path in the typical colon delimited search paths (e.g. PATH) is detected as well.
This commit is contained in:
@@ -30,6 +30,8 @@
|
|||||||
#include <UTF8.h>
|
#include <UTF8.h>
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include <Array.h>
|
||||||
|
|
||||||
#include "ActiveProcessInfo.h"
|
#include "ActiveProcessInfo.h"
|
||||||
#include "Shell.h"
|
#include "Shell.h"
|
||||||
#include "TermConst.h"
|
#include "TermConst.h"
|
||||||
@@ -800,55 +802,108 @@ TermView::HyperLinkState::_GetHyperLinkAt(BPoint where, bool pathPrefixOnly,
|
|||||||
if (text.IsEmpty())
|
if (text.IsEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check, whether the file exists
|
// Collect a list of colons in the string and their respective positions in
|
||||||
BString actualPath;
|
// the text buffer. We do this up-front so we can unlock the text buffer
|
||||||
if (_EntryExists(text, actualPath)) {
|
// while we're doing all the entry existence tests.
|
||||||
_link = HyperLink(text, actualPath, HyperLink::TYPE_PATH);
|
typedef Array<CharPosition> ColonList;
|
||||||
return true;
|
ColonList colonPositions;
|
||||||
}
|
TermPos searchPos = _start;
|
||||||
|
for (int32 index = 0; (index = text.FindFirst(':', index)) >= 0;) {
|
||||||
// As such this isn't an existing path. Try a few common alternative cases:
|
TermPos foundStart;
|
||||||
// * "<path>:"
|
TermPos foundEnd;
|
||||||
// * "<path>:<line>"
|
if (!textBuffer->Find(":", searchPos, true, true, false, foundStart,
|
||||||
// * "<path>:<line>:"
|
foundEnd)) {
|
||||||
// * "<path>:<line>:<column>"
|
|
||||||
// * "<path>:<line>:<column>:"
|
|
||||||
|
|
||||||
if (text.Length() <= 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (text[text.Length() - 1] == ':') {
|
|
||||||
text.Truncate(text.Length() - 1);
|
|
||||||
if (!textBuffer->PreviousLinePos(_end))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_EntryExists(text, actualPath)) {
|
|
||||||
_link = HyperLink(text, actualPath, HyperLink::TYPE_PATH);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharPosition colonPosition;
|
||||||
|
colonPosition.index = index;
|
||||||
|
colonPosition.position = foundStart;
|
||||||
|
if (!colonPositions.Add(colonPosition))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
index++;
|
||||||
|
searchPos = foundEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
BString path = text;
|
textBufferLocker.Unlock();
|
||||||
|
|
||||||
for (int32 i = 0; i < 2; i++) {
|
// Since we also want to consider ':' a potential path delimiter, in two
|
||||||
int32 colonIndex = path.FindLast(':');
|
// nested loops we chop off components from the beginning respective the
|
||||||
if (colonIndex <= 0 || colonIndex == path.Length() - 1)
|
// end.
|
||||||
return false;
|
BString originalText = text;
|
||||||
|
TermPos originalStart = _start;
|
||||||
|
TermPos originalEnd = _end;
|
||||||
|
|
||||||
char* numberEnd;
|
int32 colonCount = colonPositions.Count();
|
||||||
strtol(path.String() + colonIndex + 1, &numberEnd, 0);
|
for (int32 startColonIndex = -1; startColonIndex < colonCount;
|
||||||
if (*numberEnd != '\0')
|
startColonIndex++) {
|
||||||
return false;
|
int32 startIndex;
|
||||||
|
if (startColonIndex < 0) {
|
||||||
|
startIndex = 0;
|
||||||
|
_start = originalStart;
|
||||||
|
} else {
|
||||||
|
startIndex = colonPositions[startColonIndex].index + 1;
|
||||||
|
_start = colonPositions[startColonIndex].position;
|
||||||
|
if (_start >= pos)
|
||||||
|
break;
|
||||||
|
_start.x++;
|
||||||
|
// Note: This is potentially a non-normalized position (i.e.
|
||||||
|
// the end of a soft-wrapped line). While not that nice, it
|
||||||
|
// works anyway.
|
||||||
|
}
|
||||||
|
|
||||||
path.Truncate(colonIndex);
|
for (int32 endColonIndex = colonCount; endColonIndex > startColonIndex;
|
||||||
if (_EntryExists(path, actualPath)) {
|
endColonIndex--) {
|
||||||
BString address = path == actualPath
|
int32 endIndex;
|
||||||
? text : BString(fCurrentDirectory) << '/' << text;
|
if (endColonIndex == colonCount) {
|
||||||
_link = HyperLink(text, address,
|
endIndex = originalText.Length();
|
||||||
i == 0
|
_end = originalEnd;
|
||||||
? HyperLink::TYPE_PATH_WITH_LINE
|
} else {
|
||||||
: HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN);
|
endIndex = colonPositions[endColonIndex].index;
|
||||||
return true;
|
_end = colonPositions[endColonIndex].position;
|
||||||
|
if (_end <= pos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
originalText.CopyInto(text, startIndex, endIndex - startIndex);
|
||||||
|
if (text.IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check, whether the file exists
|
||||||
|
BString actualPath;
|
||||||
|
if (_EntryExists(text, actualPath)) {
|
||||||
|
_link = HyperLink(text, actualPath, HyperLink::TYPE_PATH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As such this isn't an existing path. We also want to recognize:
|
||||||
|
// * "<path>:<line>"
|
||||||
|
// * "<path>:<line>:<column>"
|
||||||
|
|
||||||
|
BString path = text;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < 2; i++) {
|
||||||
|
int32 colonIndex = path.FindLast(':');
|
||||||
|
if (colonIndex <= 0 || colonIndex == path.Length() - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
char* numberEnd;
|
||||||
|
strtol(path.String() + colonIndex + 1, &numberEnd, 0);
|
||||||
|
if (*numberEnd != '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
path.Truncate(colonIndex);
|
||||||
|
if (_EntryExists(path, actualPath)) {
|
||||||
|
BString address = path == actualPath
|
||||||
|
? text : BString(fCurrentDirectory) << '/' << text;
|
||||||
|
_link = HyperLink(text, address,
|
||||||
|
i == 0
|
||||||
|
? HyperLink::TYPE_PATH_WITH_LINE
|
||||||
|
: HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ private:
|
|||||||
virtual rgb_color BackgroundColor();
|
virtual rgb_color BackgroundColor();
|
||||||
virtual uint32 AdjustTextAttributes(uint32 attributes);
|
virtual uint32 AdjustTextAttributes(uint32 attributes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CharPosition {
|
||||||
|
int32 index;
|
||||||
|
TermPos position;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _GetHyperLinkAt(BPoint where,
|
bool _GetHyperLinkAt(BPoint where,
|
||||||
bool pathPrefixOnly, HyperLink& _link,
|
bool pathPrefixOnly, HyperLink& _link,
|
||||||
|
|||||||
Reference in New Issue
Block a user