Terminal: Add a hyperlink mode
When holding down Command, text under the mouse is checked whether it
looks like a URL or a local path. If so, it is highlighted and can be
clicked, which will open the URL/file. Right-clicking opens a context
menu with items for opening the link/file or copying it to the
clipboard. When additionally holding down Shift, path prefixes up to
the component under the mouse will be considered (no effect for URLs).
Changes:
* Add HyperLink class. Encapsulates a type, the address, and an
optional base address. Features an Open() method to open the address.
* Move/add some string constants to TermConst.
* Move TermView::CharClassifier to top level and rename to
DefaultCharClassifier.
* Introduce TermViewHighlight and TermViewHighlighter. The former
refers to a range of text in a TermView's text buffer. It also
contains a pointer to a TermViewHighlighter object, which specifies
how the text range shall be rendered (colors and attributes).
* TermView:
- Add respective _{Add,Remove}Highlight() methods and adjust the code
to support highlights.
- Make the selection a TermViewHighlight. At least its visual aspect
is now handled like other highlights.
- Introduce an inner TextBufferSyncLocker. It is used instead of
BAutolock when locking the text buffer to synchronize the visual
buffer with it. After it unlocks it calls
_VisibleTextBufferChanged(), if the visual text buffer has changed,
which in turn calls a new callback on the active state.
- Add WindowActivated() and ModifiersChanged() callbacks to the state
interface.
- Add new states HyperLinkState and HyperLinkMenuState which
implement the new feature.
Fix modifier issues
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "HyperLink.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "TermConst.h"
|
||||||
|
|
||||||
|
|
||||||
|
HyperLink::HyperLink()
|
||||||
|
:
|
||||||
|
fAddress(),
|
||||||
|
fType(TYPE_URL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HyperLink::HyperLink(const BString& address, Type type,
|
||||||
|
const BString& baseAddress)
|
||||||
|
:
|
||||||
|
fAddress(address),
|
||||||
|
fBaseAddress(baseAddress.IsEmpty() ? address : baseAddress),
|
||||||
|
fType(type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
HyperLink::Open()
|
||||||
|
{
|
||||||
|
if (!IsValid())
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// open with the "open" program
|
||||||
|
BString address(fAddress);
|
||||||
|
address.CharacterEscape(kShellEscapeCharacters, '\\');
|
||||||
|
BString commandLine;
|
||||||
|
commandLine.SetToFormat("/bin/open %s", address.String());
|
||||||
|
return system(commandLine) == 0 ? B_OK : errno;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef HYPER_LINK_H
|
||||||
|
#define HYPER_LINK_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class HyperLink {
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
TYPE_URL,
|
||||||
|
TYPE_PATH,
|
||||||
|
TYPE_PATH_WITH_LINE,
|
||||||
|
TYPE_PATH_WITH_LINE_AND_COLUMN
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
HyperLink();
|
||||||
|
HyperLink(const BString& address, Type type,
|
||||||
|
const BString& baseAddress = BString());
|
||||||
|
|
||||||
|
bool IsValid() const { return !fAddress.IsEmpty(); }
|
||||||
|
|
||||||
|
const BString& Address() const { return fAddress; }
|
||||||
|
const BString& BaseAddress() const { return fBaseAddress; }
|
||||||
|
Type GetType() const { return fType; }
|
||||||
|
|
||||||
|
status_t Open();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fAddress;
|
||||||
|
BString fBaseAddress;
|
||||||
|
Type fType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // HYPER_LINK_H
|
||||||
@@ -16,6 +16,7 @@ Application Terminal :
|
|||||||
FindWindow.cpp
|
FindWindow.cpp
|
||||||
Globals.cpp
|
Globals.cpp
|
||||||
HistoryBuffer.cpp
|
HistoryBuffer.cpp
|
||||||
|
HyperLink.cpp
|
||||||
InlineInput.cpp
|
InlineInput.cpp
|
||||||
PatternEvaluator.cpp
|
PatternEvaluator.cpp
|
||||||
PrefHandler.cpp
|
PrefHandler.cpp
|
||||||
@@ -33,6 +34,7 @@ Application Terminal :
|
|||||||
TermParse.cpp
|
TermParse.cpp
|
||||||
TermScrollView.cpp
|
TermScrollView.cpp
|
||||||
TermView.cpp
|
TermView.cpp
|
||||||
|
TermViewHighlight.cpp
|
||||||
TermViewStates.cpp
|
TermViewStates.cpp
|
||||||
TermWindow.cpp
|
TermWindow.cpp
|
||||||
TitlePlaceholderMapper.cpp
|
TitlePlaceholderMapper.cpp
|
||||||
|
|||||||
@@ -31,3 +31,7 @@ const char* const kTooTipSetWindowTitlePlaceholders = B_TRANSLATE(
|
|||||||
"\t%p\t-\tThe name of the active process in the current tab.\n"
|
"\t%p\t-\tThe name of the active process in the current tab.\n"
|
||||||
"\t%t\t-\tThe title of the current tab.\n"
|
"\t%t\t-\tThe title of the current tab.\n"
|
||||||
"\t%%\t-\tThe character '%'.");
|
"\t%%\t-\tThe character '%'.");
|
||||||
|
|
||||||
|
const char* const kShellEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!";
|
||||||
|
const char* const kDefaultAdditionalWordCharacters = ":@-./_~";
|
||||||
|
const char* const kURLAdditionalWordCharacters = ":/-._~[]?#@!$&'()*+,;=";
|
||||||
|
|||||||
@@ -145,6 +145,10 @@ static const char* const PREF_WINDOW_TITLE = "Window title";
|
|||||||
extern const char* const kTooTipSetTabTitlePlaceholders;
|
extern const char* const kTooTipSetTabTitlePlaceholders;
|
||||||
extern const char* const kTooTipSetWindowTitlePlaceholders;
|
extern const char* const kTooTipSetWindowTitlePlaceholders;
|
||||||
|
|
||||||
|
extern const char* const kShellEscapeCharacters;
|
||||||
|
extern const char* const kDefaultAdditionalWordCharacters;
|
||||||
|
extern const char* const kURLAdditionalWordCharacters;
|
||||||
|
|
||||||
|
|
||||||
// Cursor style
|
// Cursor style
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
+228
-117
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
#include "TermView.h"
|
#include "TermView.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -102,9 +101,6 @@ static const bigtime_t kCursorBlinkInterval = 500000;
|
|||||||
static const rgb_color kBlackColor = { 0, 0, 0, 255 };
|
static const rgb_color kBlackColor = { 0, 0, 0, 255 };
|
||||||
static const rgb_color kWhiteColor = { 255, 255, 255, 255 };
|
static const rgb_color kWhiteColor = { 255, 255, 255, 255 };
|
||||||
|
|
||||||
static const char* kDefaultSpecialWordChars = ":@-./_~";
|
|
||||||
static const char* kEscapeCharacters = " ~`#$&*()\\|[]{};'\"<>?!";
|
|
||||||
|
|
||||||
// secondary mouse button drop
|
// secondary mouse button drop
|
||||||
const int32 kSecondaryMouseDropAction = 'SMDA';
|
const int32 kSecondaryMouseDropAction = 'SMDA';
|
||||||
|
|
||||||
@@ -125,40 +121,28 @@ restrict_value(const Type& value, const Type& min, const Type& max)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - CharClassifier
|
// #pragma mark - TextBufferSyncLocker
|
||||||
|
|
||||||
|
|
||||||
class TermView::CharClassifier : public TerminalCharClassifier {
|
class TermView::TextBufferSyncLocker {
|
||||||
public:
|
public:
|
||||||
CharClassifier(const char* specialWordChars)
|
TextBufferSyncLocker(TermView* view)
|
||||||
|
:
|
||||||
|
fView(view)
|
||||||
{
|
{
|
||||||
const char* p = specialWordChars;
|
fView->fTextBuffer->Lock();
|
||||||
while (p != NULL && *p) {
|
|
||||||
int count = UTF8Char::ByteCount(*p);
|
|
||||||
if (count <= 0 || count > 4)
|
|
||||||
break;
|
|
||||||
fSpecialWordChars.push_back(UTF8Char(p, count));
|
|
||||||
p += count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int Classify(const UTF8Char& character)
|
~TextBufferSyncLocker()
|
||||||
{
|
{
|
||||||
if (character.IsSpace())
|
fView->fTextBuffer->Unlock();
|
||||||
return CHAR_TYPE_SPACE;
|
|
||||||
|
|
||||||
if (character.IsAlNum())
|
if (fView->fVisibleTextBufferChanged)
|
||||||
return CHAR_TYPE_WORD_CHAR;
|
fView->_VisibleTextBufferChanged();
|
||||||
|
|
||||||
if (std::find(fSpecialWordChars.begin(), fSpecialWordChars.end(),
|
|
||||||
character) != fSpecialWordChars.end())
|
|
||||||
return CHAR_TYPE_WORD_CHAR;
|
|
||||||
|
|
||||||
return CHAR_TYPE_WORD_DELIMITER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<UTF8Char> fSpecialWordChars;
|
TermView* fView;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -299,6 +283,7 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
fCursor = TermPos(0, 0);
|
fCursor = TermPos(0, 0);
|
||||||
fTextBuffer = NULL;
|
fTextBuffer = NULL;
|
||||||
fVisibleTextBuffer = NULL;
|
fVisibleTextBuffer = NULL;
|
||||||
|
fVisibleTextBufferChanged = false;
|
||||||
fScrollBar = NULL;
|
fScrollBar = NULL;
|
||||||
fInline = NULL;
|
fInline = NULL;
|
||||||
fSelectForeColor = kWhiteColor;
|
fSelectForeColor = kWhiteColor;
|
||||||
@@ -308,8 +293,8 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
fScrolledSinceLastSync = 0;
|
fScrolledSinceLastSync = 0;
|
||||||
fSyncRunner = NULL;
|
fSyncRunner = NULL;
|
||||||
fConsiderClockedSync = false;
|
fConsiderClockedSync = false;
|
||||||
fSelStart = TermPos(-1, -1);
|
fSelection.SetHighlighter(this);
|
||||||
fSelEnd = TermPos(-1, -1);
|
fSelection.SetRange(TermPos(0, 0), TermPos(0, 0));
|
||||||
fPrevPos = TermPos(-1, - 1);
|
fPrevPos = TermPos(-1, - 1);
|
||||||
fReportX10MouseEvent = false;
|
fReportX10MouseEvent = false;
|
||||||
fReportNormalMouseEvent = false;
|
fReportNormalMouseEvent = false;
|
||||||
@@ -318,6 +303,8 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
fMouseClipboard = be_clipboard;
|
fMouseClipboard = be_clipboard;
|
||||||
fDefaultState = new(std::nothrow) DefaultState(this);
|
fDefaultState = new(std::nothrow) DefaultState(this);
|
||||||
fSelectState = new(std::nothrow) SelectState(this);
|
fSelectState = new(std::nothrow) SelectState(this);
|
||||||
|
fHyperLinkState = new(std::nothrow) HyperLinkState(this);
|
||||||
|
fHyperLinkMenuState = new(std::nothrow) HyperLinkMenuState(this);
|
||||||
fActiveState = NULL;
|
fActiveState = NULL;
|
||||||
|
|
||||||
fTextBuffer = new(std::nothrow) TerminalBuffer;
|
fTextBuffer = new(std::nothrow) TerminalBuffer;
|
||||||
@@ -329,8 +316,8 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
// TODO: Make the special word chars user-settable!
|
// TODO: Make the special word chars user-settable!
|
||||||
fCharClassifier = new(std::nothrow) CharClassifier(
|
fCharClassifier = new(std::nothrow) DefaultCharClassifier(
|
||||||
kDefaultSpecialWordChars);
|
kDefaultAdditionalWordCharacters);
|
||||||
if (fCharClassifier == NULL)
|
if (fCharClassifier == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -362,8 +349,12 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
if (error < B_OK)
|
if (error < B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (fDefaultState == NULL || fSelectState == NULL)
|
fHighlights.AddItem(&fSelection);
|
||||||
|
|
||||||
|
if (fDefaultState == NULL || fSelectState == NULL || fHyperLinkState == NULL
|
||||||
|
|| fHyperLinkMenuState == NULL) {
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
SetLowColor(fTextBackColor);
|
SetLowColor(fTextBackColor);
|
||||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||||
@@ -383,6 +374,8 @@ TermView::~TermView()
|
|||||||
|
|
||||||
delete fDefaultState;
|
delete fDefaultState;
|
||||||
delete fSelectState;
|
delete fSelectState;
|
||||||
|
delete fHyperLinkState;
|
||||||
|
delete fHyperLinkMenuState;
|
||||||
delete fSyncRunner;
|
delete fSyncRunner;
|
||||||
delete fAutoScrollRunner;
|
delete fAutoScrollRunner;
|
||||||
delete fCharClassifier;
|
delete fCharClassifier;
|
||||||
@@ -457,6 +450,20 @@ TermView::Archive(BMessage* data, bool deep) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rgb_color
|
||||||
|
TermView::ForegroundColor()
|
||||||
|
{
|
||||||
|
return fSelectForeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rgb_color
|
||||||
|
TermView::BackgroundColor()
|
||||||
|
{
|
||||||
|
return fSelectBackColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline int32
|
inline int32
|
||||||
TermView::_LineAt(float y)
|
TermView::_LineAt(float y)
|
||||||
{
|
{
|
||||||
@@ -582,12 +589,13 @@ TermView::SetTermSize(int rows, int columns, bool notifyShell)
|
|||||||
|
|
||||||
// synchronize the visible text buffer
|
// synchronize the visible text buffer
|
||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
|
|
||||||
_SynchronizeWithTextBuffer(0, -1);
|
_SynchronizeWithTextBuffer(0, -1);
|
||||||
int32 offset = _LineAt(0);
|
int32 offset = _LineAt(0);
|
||||||
fVisibleTextBuffer->SynchronizeWith(fTextBuffer, offset, offset,
|
fVisibleTextBuffer->SynchronizeWith(fTextBuffer, offset, offset,
|
||||||
offset + rows + 2);
|
offset + rows + 2);
|
||||||
|
fVisibleTextBufferChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notifyShell)
|
if (notifyShell)
|
||||||
@@ -784,7 +792,8 @@ TermView::Copy(BClipboard *clipboard)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
BString copyStr;
|
BString copyStr;
|
||||||
fTextBuffer->GetStringFromRegion(copyStr, fSelStart, fSelEnd);
|
fTextBuffer->GetStringFromRegion(copyStr, fSelection.Start(),
|
||||||
|
fSelection.End());
|
||||||
|
|
||||||
if (clipboard->Lock()) {
|
if (clipboard->Lock()) {
|
||||||
BMessage *clipMsg = NULL;
|
BMessage *clipMsg = NULL;
|
||||||
@@ -934,8 +943,11 @@ TermView::_Deactivate()
|
|||||||
//! Draw part of a line in the given view.
|
//! Draw part of a line in the given view.
|
||||||
void
|
void
|
||||||
TermView::_DrawLinePart(int32 x1, int32 y1, uint32 attr, char *buf,
|
TermView::_DrawLinePart(int32 x1, int32 y1, uint32 attr, char *buf,
|
||||||
int32 width, bool mouse, bool cursor, BView *inView)
|
int32 width, Highlight* highlight, bool cursor, BView *inView)
|
||||||
{
|
{
|
||||||
|
if (highlight != NULL)
|
||||||
|
attr = highlight->Highlighter()->AdjustTextAttributes(attr);
|
||||||
|
|
||||||
inView->SetFont(IS_BOLD(attr) && !fEmulateBold ? &fBoldFont : &fHalfFont);
|
inView->SetFont(IS_BOLD(attr) && !fEmulateBold ? &fBoldFont : &fHalfFont);
|
||||||
|
|
||||||
// Set pen point
|
// Set pen point
|
||||||
@@ -958,9 +970,9 @@ TermView::_DrawLinePart(int32 x1, int32 y1, uint32 attr, char *buf,
|
|||||||
if (cursor) {
|
if (cursor) {
|
||||||
rgb_fore = fCursorForeColor;
|
rgb_fore = fCursorForeColor;
|
||||||
rgb_back = fCursorBackColor;
|
rgb_back = fCursorBackColor;
|
||||||
} else if (mouse) {
|
} else if (highlight != NULL) {
|
||||||
rgb_fore = fSelectForeColor;
|
rgb_fore = highlight->Highlighter()->ForegroundColor();
|
||||||
rgb_back = fSelectBackColor;
|
rgb_back = highlight->Highlighter()->BackgroundColor();
|
||||||
} else {
|
} else {
|
||||||
// Reverse attribute(If selected area, don't reverse color).
|
// Reverse attribute(If selected area, don't reverse color).
|
||||||
if (IS_INVERSE(attr)) {
|
if (IS_INVERSE(attr)) {
|
||||||
@@ -1025,7 +1037,7 @@ TermView::_DrawCursor()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool selected = _CheckSelectedRegion(TermPos(fCursor.x, fCursor.y));
|
Highlight* highlight = _CheckHighlightRegion(TermPos(fCursor.x, fCursor.y));
|
||||||
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
if (fVisibleTextBuffer->GetChar(fCursor.y - firstVisible, fCursor.x,
|
||||||
character, attr) == A_CHAR
|
character, attr) == A_CHAR
|
||||||
&& (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) {
|
&& (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) {
|
||||||
@@ -1037,11 +1049,11 @@ TermView::_DrawCursor()
|
|||||||
buffer[bytes] = '\0';
|
buffer[bytes] = '\0';
|
||||||
|
|
||||||
_DrawLinePart(fCursor.x * fFontWidth, (int32)rect.top, attr, buffer,
|
_DrawLinePart(fCursor.x * fFontWidth, (int32)rect.top, attr, buffer,
|
||||||
width, selected, cursorVisible, this);
|
width, highlight, cursorVisible, this);
|
||||||
} else {
|
} else {
|
||||||
if (selected)
|
if (highlight != NULL)
|
||||||
SetHighColor(fSelectBackColor);
|
SetHighColor(highlight->Highlighter()->BackgroundColor());
|
||||||
else if (cursorVisible )
|
else if (cursorVisible)
|
||||||
SetHighColor(fCursorBackColor );
|
SetHighColor(fCursorBackColor );
|
||||||
else {
|
else {
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
@@ -1144,6 +1156,7 @@ void
|
|||||||
TermView::AttachedToWindow()
|
TermView::AttachedToWindow()
|
||||||
{
|
{
|
||||||
fMouseButtons = 0;
|
fMouseButtons = 0;
|
||||||
|
fModifiers = modifiers();
|
||||||
|
|
||||||
// update the terminal size because it may have changed while the TermView
|
// update the terminal size because it may have changed while the TermView
|
||||||
// was detached from the window. On such conditions FrameResized was not
|
// was detached from the window. On such conditions FrameResized was not
|
||||||
@@ -1162,7 +1175,7 @@ TermView::AttachedToWindow()
|
|||||||
&message, 500000);
|
&message, 500000);
|
||||||
|
|
||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
fTextBuffer->SetListener(thisMessenger);
|
fTextBuffer->SetListener(thisMessenger);
|
||||||
_SynchronizeWithTextBuffer(0, -1);
|
_SynchronizeWithTextBuffer(0, -1);
|
||||||
}
|
}
|
||||||
@@ -1240,15 +1253,15 @@ TermView::Draw(BRect updateRect)
|
|||||||
|
|
||||||
for (int32 i = k; i <= x2;) {
|
for (int32 i = k; i <= x2;) {
|
||||||
int32 lastColumn = x2;
|
int32 lastColumn = x2;
|
||||||
bool insideSelection = _CheckSelectedRegion(j, i, lastColumn);
|
Highlight* highlight = _CheckHighlightRegion(j, i, lastColumn);
|
||||||
// This will clip lastColumn to the selection start or end
|
// This will clip lastColumn to the selection start or end
|
||||||
// to ensure the selection is not drawn at the same time as
|
// to ensure the selection is not drawn at the same time as
|
||||||
// something else
|
// something else
|
||||||
int32 count = fVisibleTextBuffer->GetString(j - firstVisible, i,
|
int32 count = fVisibleTextBuffer->GetString(j - firstVisible, i,
|
||||||
lastColumn, buf, attr);
|
lastColumn, buf, attr);
|
||||||
|
|
||||||
// debug_printf(" fVisibleTextBuffer->GetString(%ld, %ld, %ld) -> (%ld, \"%.*s\"), selected: %d\n",
|
// debug_printf(" fVisibleTextBuffer->GetString(%ld, %ld, %ld) -> (%ld, \"%.*s\"), highlight: %p\n",
|
||||||
// j - firstVisible, i, lastColumn, count, (int)count, buf, insideSelection);
|
// j - firstVisible, i, lastColumn, count, (int)count, buf, highlight);
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
// No chars to draw : we just fill the rectangle with the
|
// No chars to draw : we just fill the rectangle with the
|
||||||
@@ -1258,8 +1271,9 @@ TermView::Draw(BRect updateRect)
|
|||||||
fFontWidth * nextColumn - 1, 0);
|
fFontWidth * nextColumn - 1, 0);
|
||||||
rect.bottom = rect.top + fFontHeight - 1;
|
rect.bottom = rect.top + fFontHeight - 1;
|
||||||
|
|
||||||
rgb_color rgb_back = insideSelection
|
rgb_color rgb_back = highlight != NULL
|
||||||
? fSelectBackColor : fTextBackColor;
|
? highlight->Highlighter()->BackgroundColor()
|
||||||
|
: fTextBackColor;
|
||||||
|
|
||||||
if (fTextBuffer->IsAlternateScreenActive()) {
|
if (fTextBuffer->IsAlternateScreenActive()) {
|
||||||
// alternate screen uses cell attributes
|
// alternate screen uses cell attributes
|
||||||
@@ -1294,7 +1308,7 @@ TermView::Draw(BRect updateRect)
|
|||||||
count = FULL_WIDTH;
|
count = FULL_WIDTH;
|
||||||
|
|
||||||
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),
|
||||||
attr, buf, count, insideSelection, false, this);
|
attr, buf, count, highlight, false, this);
|
||||||
i += count;
|
i += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1365,6 +1379,15 @@ TermView::WindowActivated(bool active)
|
|||||||
if (fActive)
|
if (fActive)
|
||||||
_Deactivate();
|
_Deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fActiveState->WindowActivated(active);
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
int32 oldModifiers = fModifiers;
|
||||||
|
fModifiers = modifiers();
|
||||||
|
if (fModifiers != oldModifiers)
|
||||||
|
fActiveState->ModifiersChanged(oldModifiers, fModifiers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1576,6 +1599,15 @@ TermView::MessageReceived(BMessage *msg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case B_MODIFIERS_CHANGED:
|
||||||
|
{
|
||||||
|
int32 oldModifiers = fModifiers;
|
||||||
|
fModifiers = msg->GetInt32("modifiers", 0);
|
||||||
|
if (fModifiers != oldModifiers)
|
||||||
|
fActiveState->ModifiersChanged(oldModifiers, fModifiers);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case B_INPUT_METHOD_EVENT:
|
case B_INPUT_METHOD_EVENT:
|
||||||
{
|
{
|
||||||
int32 opcode;
|
int32 opcode;
|
||||||
@@ -1677,7 +1709,7 @@ TermView::MessageReceived(BMessage *msg)
|
|||||||
break;
|
break;
|
||||||
case MSG_TERMINAL_BUFFER_CHANGED:
|
case MSG_TERMINAL_BUFFER_CHANGED:
|
||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
_SynchronizeWithTextBuffer(0, -1);
|
_SynchronizeWithTextBuffer(0, -1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1842,7 +1874,7 @@ TermView::ScrollTo(BPoint where)
|
|||||||
//debug_printf("fVisibleTextBuffer->ScrollBy(%ld)\n", newFirstLine - oldFirstLine);
|
//debug_printf("fVisibleTextBuffer->ScrollBy(%ld)\n", newFirstLine - oldFirstLine);
|
||||||
fVisibleTextBuffer->ScrollBy(newFirstLine - oldFirstLine);
|
fVisibleTextBuffer->ScrollBy(newFirstLine - oldFirstLine);
|
||||||
}
|
}
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
_SynchronizeWithTextBuffer(newFirstLine, oldFirstLine - 1);
|
_SynchronizeWithTextBuffer(newFirstLine, oldFirstLine - 1);
|
||||||
else
|
else
|
||||||
@@ -2004,11 +2036,11 @@ TermView::_DoSecondaryMouseDropAction(BMessage* msg)
|
|||||||
int32 slash = string.FindLast("/");
|
int32 slash = string.FindLast("/");
|
||||||
string.Truncate(slash);
|
string.Truncate(slash);
|
||||||
}
|
}
|
||||||
string.CharacterEscape(kEscapeCharacters, '\\');
|
string.CharacterEscape(kShellEscapeCharacters, '\\');
|
||||||
itemString += string;
|
itemString += string;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
string.CharacterEscape(kEscapeCharacters, '\\');
|
string.CharacterEscape(kShellEscapeCharacters, '\\');
|
||||||
itemString += string;
|
itemString += string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2035,7 +2067,7 @@ TermView::_DoFileDrop(entry_ref& ref)
|
|||||||
BPath path(&ent);
|
BPath path(&ent);
|
||||||
BString string(path.Path());
|
BString string(path.Path());
|
||||||
|
|
||||||
string.CharacterEscape(kEscapeCharacters, '\\');
|
string.CharacterEscape(kShellEscapeCharacters, '\\');
|
||||||
_WritePTY(string.String(), string.Length());
|
_WritePTY(string.String(), string.Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2099,7 +2131,9 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
// sync time not passed yet -- keep counting
|
// sync time not passed yet -- keep counting
|
||||||
fScrolledSinceLastSync += linesScrolled;
|
fScrolledSinceLastSync += linesScrolled;
|
||||||
return;
|
return;
|
||||||
} else if (fScrolledSinceLastSync + linesScrolled <= fRows) {
|
}
|
||||||
|
|
||||||
|
if (fScrolledSinceLastSync + linesScrolled <= fRows) {
|
||||||
// time's up, but not enough happened
|
// time's up, but not enough happened
|
||||||
delete fSyncRunner;
|
delete fSyncRunner;
|
||||||
fSyncRunner = NULL;
|
fSyncRunner = NULL;
|
||||||
@@ -2111,6 +2145,8 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
fScrolledSinceLastSync = 0;
|
fScrolledSinceLastSync = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fVisibleTextBufferChanged = true;
|
||||||
|
|
||||||
// Simple case first -- complete invalidation.
|
// Simple case first -- complete invalidation.
|
||||||
if (info.invalidateAll) {
|
if (info.invalidateAll) {
|
||||||
Invalidate();
|
Invalidate();
|
||||||
@@ -2194,15 +2230,23 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
fVisibleTextBuffer->ScrollBy(linesScrolled);
|
fVisibleTextBuffer->ScrollBy(linesScrolled);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move selection
|
// move highlights
|
||||||
if (fSelStart != fSelEnd) {
|
for (int32 i = 0; Highlight* highlight = fHighlights.ItemAt(i); i++) {
|
||||||
fSelStart.y -= linesScrolled;
|
if (highlight->IsEmpty())
|
||||||
fSelEnd.y -= linesScrolled;
|
continue;
|
||||||
|
|
||||||
|
highlight->ScrollRange(linesScrolled);
|
||||||
|
if (highlight == &fSelection) {
|
||||||
fInitialSelectionStart.y -= linesScrolled;
|
fInitialSelectionStart.y -= linesScrolled;
|
||||||
fInitialSelectionEnd.y -= linesScrolled;
|
fInitialSelectionEnd.y -= linesScrolled;
|
||||||
|
}
|
||||||
|
|
||||||
if (fSelStart.y < -historySize)
|
if (highlight->Start().y < -historySize) {
|
||||||
|
if (highlight == &fSelection)
|
||||||
_Deselect();
|
_Deselect();
|
||||||
|
else
|
||||||
|
_ClearHighlight(highlight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2212,12 +2256,13 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
info.dirtyBottom);
|
info.dirtyBottom);
|
||||||
|
|
||||||
// clear the selection, if affected
|
// clear the selection, if affected
|
||||||
if (fSelStart != fSelEnd) {
|
if (!fSelection.IsEmpty()) {
|
||||||
// TODO: We're clearing the selection more often than necessary --
|
// TODO: We're clearing the selection more often than necessary --
|
||||||
// to avoid that, we'd also need to track the x coordinates of the
|
// to avoid that, we'd also need to track the x coordinates of the
|
||||||
// dirty range.
|
// dirty range.
|
||||||
int32 selectionBottom = fSelEnd.x > 0 ? fSelEnd.y : fSelEnd.y - 1;
|
int32 selectionBottom = fSelection.End().x > 0
|
||||||
if (fSelStart.y <= info.dirtyBottom
|
? fSelection.End().y : fSelection.End().y - 1;
|
||||||
|
if (fSelection.Start().y <= info.dirtyBottom
|
||||||
&& info.dirtyTop <= selectionBottom) {
|
&& info.dirtyTop <= selectionBottom) {
|
||||||
_Deselect();
|
_Deselect();
|
||||||
}
|
}
|
||||||
@@ -2247,6 +2292,17 @@ TermView::_SynchronizeWithTextBuffer(int32 visibleDirtyTop,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::_VisibleTextBufferChanged()
|
||||||
|
{
|
||||||
|
if (!fVisibleTextBufferChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fVisibleTextBufferChanged = false;
|
||||||
|
fActiveState->VisibleTextBufferChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Write strings to PTY device. If encoding system isn't UTF8, change
|
/*! Write strings to PTY device. If encoding system isn't UTF8, change
|
||||||
encoding to UTF8 before writing PTY.
|
encoding to UTF8 before writing PTY.
|
||||||
*/
|
*/
|
||||||
@@ -2322,9 +2378,8 @@ TermView::MouseDown(BPoint where)
|
|||||||
|
|
||||||
BMessage* currentMessage = Window()->CurrentMessage();
|
BMessage* currentMessage = Window()->CurrentMessage();
|
||||||
int32 buttons = currentMessage->GetInt32("buttons", 0);
|
int32 buttons = currentMessage->GetInt32("buttons", 0);
|
||||||
int32 modifiers = currentMessage->GetInt32("modifiers", 0);
|
|
||||||
|
|
||||||
fActiveState->MouseDown(where, buttons, modifiers);
|
fActiveState->MouseDown(where, buttons, fModifiers);
|
||||||
|
|
||||||
fMouseButtons = buttons;
|
fMouseButtons = buttons;
|
||||||
fLastClickPoint = where;
|
fLastClickPoint = where;
|
||||||
@@ -2334,7 +2389,7 @@ TermView::MouseDown(BPoint where)
|
|||||||
void
|
void
|
||||||
TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message)
|
TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message)
|
||||||
{
|
{
|
||||||
fActiveState->MouseMoved(where, transit, message);
|
fActiveState->MouseMoved(where, transit, message, fModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2354,7 +2409,7 @@ void
|
|||||||
TermView::_Select(TermPos start, TermPos end, bool inclusive,
|
TermView::_Select(TermPos start, TermPos end, bool inclusive,
|
||||||
bool setInitialSelection)
|
bool setInitialSelection)
|
||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
|
|
||||||
_SynchronizeWithTextBuffer(0, -1);
|
_SynchronizeWithTextBuffer(0, -1);
|
||||||
|
|
||||||
@@ -2396,18 +2451,17 @@ TermView::_Select(TermPos start, TermPos end, bool inclusive,
|
|||||||
end.x = fColumns;
|
end.x = fColumns;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fSelStart != fSelEnd)
|
if (!fSelection.IsEmpty())
|
||||||
_InvalidateTextRange(fSelStart, fSelEnd);
|
_InvalidateTextRange(fSelection.Start(), fSelection.End());
|
||||||
|
|
||||||
fSelStart = start;
|
fSelection.SetRange(start, end);
|
||||||
fSelEnd = end;
|
|
||||||
|
|
||||||
if (setInitialSelection) {
|
if (setInitialSelection) {
|
||||||
fInitialSelectionStart = fSelStart;
|
fInitialSelectionStart = fSelection.Start();
|
||||||
fInitialSelectionEnd = fSelEnd;
|
fInitialSelectionEnd = fSelection.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
_InvalidateTextRange(fSelStart, fSelEnd);
|
_InvalidateTextRange(fSelection.Start(), fSelection.End());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2419,8 +2473,8 @@ TermView::_ExtendSelection(TermPos pos, bool inclusive,
|
|||||||
if (!useInitialSelection && !_HasSelection())
|
if (!useInitialSelection && !_HasSelection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TermPos start = fSelStart;
|
TermPos start = fSelection.Start();
|
||||||
TermPos end = fSelEnd;
|
TermPos end = fSelection.End();
|
||||||
|
|
||||||
if (useInitialSelection) {
|
if (useInitialSelection) {
|
||||||
start = fInitialSelectionStart;
|
start = fInitialSelectionStart;
|
||||||
@@ -2446,22 +2500,17 @@ void
|
|||||||
TermView::_Deselect()
|
TermView::_Deselect()
|
||||||
{
|
{
|
||||||
//debug_printf("TermView::_Deselect(): has selection: %d\n", _HasSelection());
|
//debug_printf("TermView::_Deselect(): has selection: %d\n", _HasSelection());
|
||||||
if (!_HasSelection())
|
if (_ClearHighlight(&fSelection)) {
|
||||||
return;
|
|
||||||
|
|
||||||
_InvalidateTextRange(fSelStart, fSelEnd);
|
|
||||||
|
|
||||||
fSelStart.SetTo(0, 0);
|
|
||||||
fSelEnd.SetTo(0, 0);
|
|
||||||
fInitialSelectionStart.SetTo(0, 0);
|
fInitialSelectionStart.SetTo(0, 0);
|
||||||
fInitialSelectionEnd.SetTo(0, 0);
|
fInitialSelectionEnd.SetTo(0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TermView::_HasSelection() const
|
TermView::_HasSelection() const
|
||||||
{
|
{
|
||||||
return fSelStart != fSelEnd;
|
return !fSelection.IsEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2476,11 +2525,15 @@ TermView::_SelectWord(BPoint where, bool extend, bool useInitialSelection)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (extend) {
|
if (extend) {
|
||||||
if (start < (useInitialSelection ? fInitialSelectionStart : fSelStart))
|
if (start
|
||||||
|
< (useInitialSelection
|
||||||
|
? fInitialSelectionStart : fSelection.Start())) {
|
||||||
_ExtendSelection(start, false, useInitialSelection);
|
_ExtendSelection(start, false, useInitialSelection);
|
||||||
else if (end > (useInitialSelection ? fInitialSelectionEnd : fSelEnd))
|
} else if (end
|
||||||
|
> (useInitialSelection
|
||||||
|
? fInitialSelectionEnd : fSelection.End())) {
|
||||||
_ExtendSelection(end, false, useInitialSelection);
|
_ExtendSelection(end, false, useInitialSelection);
|
||||||
else if (useInitialSelection)
|
} else if (useInitialSelection)
|
||||||
_Select(start, end, false, false);
|
_Select(start, end, false, false);
|
||||||
} else
|
} else
|
||||||
_Select(start, end, false, !useInitialSelection);
|
_Select(start, end, false, !useInitialSelection);
|
||||||
@@ -2494,47 +2547,101 @@ TermView::_SelectLine(BPoint where, bool extend, bool useInitialSelection)
|
|||||||
TermPos end = TermPos(0, start.y + 1);
|
TermPos end = TermPos(0, start.y + 1);
|
||||||
|
|
||||||
if (extend) {
|
if (extend) {
|
||||||
if (start < (useInitialSelection ? fInitialSelectionStart : fSelStart))
|
if (start
|
||||||
|
< (useInitialSelection
|
||||||
|
? fInitialSelectionStart : fSelection.Start())) {
|
||||||
_ExtendSelection(start, false, useInitialSelection);
|
_ExtendSelection(start, false, useInitialSelection);
|
||||||
else if (end > (useInitialSelection ? fInitialSelectionEnd : fSelEnd))
|
} else if (end
|
||||||
|
> (useInitialSelection
|
||||||
|
? fInitialSelectionEnd : fSelection.End())) {
|
||||||
_ExtendSelection(end, false, useInitialSelection);
|
_ExtendSelection(end, false, useInitialSelection);
|
||||||
else if (useInitialSelection)
|
} else if (useInitialSelection)
|
||||||
_Select(start, end, false, false);
|
_Select(start, end, false, false);
|
||||||
} else
|
} else
|
||||||
_Select(start, end, false, !useInitialSelection);
|
_Select(start, end, false, !useInitialSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
void
|
||||||
TermView::_CheckSelectedRegion(const TermPos &pos) const
|
TermView::_AddHighlight(Highlight* highlight)
|
||||||
{
|
{
|
||||||
return pos >= fSelStart && pos < fSelEnd;
|
fHighlights.AddItem(highlight);
|
||||||
|
|
||||||
|
if (!highlight->IsEmpty())
|
||||||
|
_InvalidateTextRange(highlight->Start(), highlight->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::_RemoveHighlight(Highlight* highlight)
|
||||||
|
{
|
||||||
|
fHighlights.RemoveItem(highlight);
|
||||||
|
|
||||||
|
if (!highlight->IsEmpty())
|
||||||
|
_InvalidateTextRange(highlight->Start(), highlight->End());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TermView::_CheckSelectedRegion(int32 row, int32 firstColumn,
|
TermView::_ClearHighlight(Highlight* highlight)
|
||||||
int32& lastColumn) const
|
|
||||||
{
|
{
|
||||||
if (fSelStart == fSelEnd)
|
if (highlight->IsEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (row == fSelStart.y && firstColumn < fSelStart.x
|
_InvalidateTextRange(highlight->Start(), highlight->End());
|
||||||
&& lastColumn >= fSelStart.x) {
|
|
||||||
// region starts before the selection, but intersects with it
|
highlight->SetRange(TermPos(0, 0), TermPos(0, 0));
|
||||||
lastColumn = fSelStart.x - 1;
|
return true;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TermView::Highlight*
|
||||||
|
TermView::_CheckHighlightRegion(const TermPos &pos) const
|
||||||
|
{
|
||||||
|
for (int32 i = 0; Highlight* highlight = fHighlights.ItemAt(i); i++) {
|
||||||
|
if (highlight->RangeContains(pos))
|
||||||
|
return highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row == fSelEnd.y && firstColumn < fSelEnd.x
|
return NULL;
|
||||||
&& lastColumn >= fSelEnd.x) {
|
}
|
||||||
// region starts in the selection, but exceeds the end
|
|
||||||
lastColumn = fSelEnd.x - 1;
|
|
||||||
return true;
|
TermView::Highlight*
|
||||||
|
TermView::_CheckHighlightRegion(int32 row, int32 firstColumn,
|
||||||
|
int32& lastColumn) const
|
||||||
|
{
|
||||||
|
Highlight* nextHighlight = NULL;
|
||||||
|
|
||||||
|
for (int32 i = 0; Highlight* highlight = fHighlights.ItemAt(i); i++) {
|
||||||
|
if (highlight->IsEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (row == highlight->Start().y && firstColumn < highlight->Start().x
|
||||||
|
&& lastColumn >= highlight->Start().x) {
|
||||||
|
// region starts before the highlight, but intersects with it
|
||||||
|
if (nextHighlight == NULL
|
||||||
|
|| highlight->Start().x < nextHighlight->Start().x) {
|
||||||
|
nextHighlight = highlight;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row == highlight->End().y && firstColumn < highlight->End().x
|
||||||
|
&& lastColumn >= highlight->End().x) {
|
||||||
|
// region starts in the highlight, but exceeds the end
|
||||||
|
lastColumn = highlight->End().x - 1;
|
||||||
|
return highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
TermPos pos(firstColumn, row);
|
TermPos pos(firstColumn, row);
|
||||||
return pos >= fSelStart && pos < fSelEnd;
|
if (highlight->RangeContains(pos))
|
||||||
|
return highlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextHighlight != NULL)
|
||||||
|
lastColumn = nextHighlight->Start().x - 1;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2560,15 +2667,15 @@ bool
|
|||||||
TermView::Find(const BString &str, bool forwardSearch, bool matchCase,
|
TermView::Find(const BString &str, bool forwardSearch, bool matchCase,
|
||||||
bool matchWord)
|
bool matchWord)
|
||||||
{
|
{
|
||||||
BAutolock _(fTextBuffer);
|
TextBufferSyncLocker _(this);
|
||||||
_SynchronizeWithTextBuffer(0, -1);
|
_SynchronizeWithTextBuffer(0, -1);
|
||||||
|
|
||||||
TermPos start;
|
TermPos start;
|
||||||
if (_HasSelection()) {
|
if (_HasSelection()) {
|
||||||
if (forwardSearch)
|
if (forwardSearch)
|
||||||
start = fSelEnd;
|
start = fSelection.End();
|
||||||
else
|
else
|
||||||
start = fSelStart;
|
start = fSelection.Start();
|
||||||
} else {
|
} else {
|
||||||
// search from the very beginning/end
|
// search from the very beginning/end
|
||||||
if (forwardSearch)
|
if (forwardSearch)
|
||||||
@@ -2584,7 +2691,7 @@ TermView::Find(const BString &str, bool forwardSearch, bool matchCase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_Select(matchStart, matchEnd, false, true);
|
_Select(matchStart, matchEnd, false, true);
|
||||||
_ScrollToRange(fSelStart, fSelEnd);
|
_ScrollToRange(fSelection.Start(), fSelection.End());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2596,7 +2703,7 @@ TermView::GetSelection(BString &str)
|
|||||||
{
|
{
|
||||||
str.SetTo("");
|
str.SetTo("");
|
||||||
BAutolock _(fTextBuffer);
|
BAutolock _(fTextBuffer);
|
||||||
fTextBuffer->GetStringFromRegion(str, fSelStart, fSelEnd);
|
fTextBuffer->GetStringFromRegion(str, fSelection.Start(), fSelection.End());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2619,17 +2726,18 @@ TermView::InitiateDrag()
|
|||||||
BAutolock _(fTextBuffer);
|
BAutolock _(fTextBuffer);
|
||||||
|
|
||||||
BString copyStr("");
|
BString copyStr("");
|
||||||
fTextBuffer->GetStringFromRegion(copyStr, fSelStart, fSelEnd);
|
fTextBuffer->GetStringFromRegion(copyStr, fSelection.Start(),
|
||||||
|
fSelection.End());
|
||||||
|
|
||||||
BMessage message(B_MIME_DATA);
|
BMessage message(B_MIME_DATA);
|
||||||
message.AddData("text/plain", B_MIME_TYPE, copyStr.String(),
|
message.AddData("text/plain", B_MIME_TYPE, copyStr.String(),
|
||||||
copyStr.Length());
|
copyStr.Length());
|
||||||
|
|
||||||
BPoint start = _ConvertFromTerminal(fSelStart);
|
BPoint start = _ConvertFromTerminal(fSelection.Start());
|
||||||
BPoint end = _ConvertFromTerminal(fSelEnd);
|
BPoint end = _ConvertFromTerminal(fSelection.End());
|
||||||
|
|
||||||
BRect rect;
|
BRect rect;
|
||||||
if (fSelStart.y == fSelEnd.y)
|
if (fSelection.Start().y == fSelection.End().y)
|
||||||
rect.Set(start.x, start.y, end.x + fFontWidth, end.y + fFontHeight);
|
rect.Set(start.x, start.y, end.x + fFontWidth, end.y + fFontHeight);
|
||||||
else
|
else
|
||||||
rect.Set(0, start.y, fColumns * fFontWidth, end.y + fFontHeight);
|
rect.Set(0, start.y, fColumns * fFontWidth, end.y + fFontHeight);
|
||||||
@@ -2911,6 +3019,9 @@ TermView::Listener::NextTermView(TermView* view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_DEBUG_SNAPSHOTS
|
#ifdef USE_DEBUG_SNAPSHOTS
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
#include "TermPos.h"
|
#include "TermPos.h"
|
||||||
|
#include "TermViewHighlight.h"
|
||||||
|
|
||||||
|
|
||||||
class ActiveProcessInfo;
|
class ActiveProcessInfo;
|
||||||
@@ -30,6 +32,7 @@ class BScrollView;
|
|||||||
class BString;
|
class BString;
|
||||||
class BStringView;
|
class BStringView;
|
||||||
class BasicTerminalBuffer;
|
class BasicTerminalBuffer;
|
||||||
|
class DefaultCharClassifier;
|
||||||
class InlineInput;
|
class InlineInput;
|
||||||
class ResizeWindow;
|
class ResizeWindow;
|
||||||
class ShellInfo;
|
class ShellInfo;
|
||||||
@@ -38,10 +41,14 @@ class TermBuffer;
|
|||||||
class TerminalBuffer;
|
class TerminalBuffer;
|
||||||
class Shell;
|
class Shell;
|
||||||
|
|
||||||
class TermView : public BView {
|
|
||||||
|
class TermView : public BView, private TermViewHighlighter {
|
||||||
public:
|
public:
|
||||||
class Listener;
|
class Listener;
|
||||||
|
|
||||||
|
typedef TermViewHighlighter Highlighter;
|
||||||
|
typedef TermViewHighlight Highlight;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TermView(BRect frame,
|
TermView(BRect frame,
|
||||||
const ShellParameters& shellParameters,
|
const ShellParameters& shellParameters,
|
||||||
@@ -141,17 +148,29 @@ protected:
|
|||||||
const char* property);
|
const char* property);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CharClassifier;
|
class TextBufferSyncLocker;
|
||||||
|
friend class TextBufferSyncLocker;
|
||||||
|
|
||||||
class State;
|
class State;
|
||||||
class StandardBaseState;
|
class StandardBaseState;
|
||||||
class DefaultState;
|
class DefaultState;
|
||||||
class SelectState;
|
class SelectState;
|
||||||
|
class HyperLinkState;
|
||||||
|
class HyperLinkMenuState;
|
||||||
|
|
||||||
friend class State;
|
friend class State;
|
||||||
friend class StandardBaseState;
|
friend class StandardBaseState;
|
||||||
friend class DefaultState;
|
friend class DefaultState;
|
||||||
friend class SelectState;
|
friend class SelectState;
|
||||||
|
friend class HyperLinkState;
|
||||||
|
friend class HyperLinkMenuState;
|
||||||
|
|
||||||
|
typedef BObjectList<Highlight> HighlightList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TermViewHighlighter
|
||||||
|
virtual rgb_color ForegroundColor();
|
||||||
|
virtual rgb_color BackgroundColor();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// point and text offset conversion
|
// point and text offset conversion
|
||||||
@@ -174,8 +193,9 @@ private:
|
|||||||
void _SwitchCursorBlinking(bool blinkingOn);
|
void _SwitchCursorBlinking(bool blinkingOn);
|
||||||
|
|
||||||
void _DrawLinePart(int32 x1, int32 y1, uint32 attr,
|
void _DrawLinePart(int32 x1, int32 y1, uint32 attr,
|
||||||
char* buffer, int32 width, bool mouse,
|
char* buffer, int32 width,
|
||||||
bool cursor, BView* inView);
|
Highlight* highlight, bool cursor,
|
||||||
|
BView* inView);
|
||||||
void _DrawCursor();
|
void _DrawCursor();
|
||||||
void _InvalidateTextRange(TermPos start,
|
void _InvalidateTextRange(TermPos start,
|
||||||
TermPos end);
|
TermPos end);
|
||||||
@@ -193,6 +213,7 @@ private:
|
|||||||
void _SynchronizeWithTextBuffer(
|
void _SynchronizeWithTextBuffer(
|
||||||
int32 visibleDirtyTop,
|
int32 visibleDirtyTop,
|
||||||
int32 visibleDirtyBottom);
|
int32 visibleDirtyBottom);
|
||||||
|
void _VisibleTextBufferChanged();
|
||||||
|
|
||||||
void _WritePTY(const char* text, int32 numBytes);
|
void _WritePTY(const char* text, int32 numBytes);
|
||||||
|
|
||||||
@@ -209,8 +230,12 @@ private:
|
|||||||
void _SelectLine(BPoint where, bool extend,
|
void _SelectLine(BPoint where, bool extend,
|
||||||
bool useInitialSelection);
|
bool useInitialSelection);
|
||||||
|
|
||||||
bool _CheckSelectedRegion(const TermPos& pos) const;
|
void _AddHighlight(Highlight* highlight);
|
||||||
bool _CheckSelectedRegion(int32 row,
|
void _RemoveHighlight(Highlight* highlight);
|
||||||
|
bool _ClearHighlight(Highlight* highlight);
|
||||||
|
|
||||||
|
Highlight* _CheckHighlightRegion(const TermPos& pos) const;
|
||||||
|
Highlight* _CheckHighlightRegion(int32 row,
|
||||||
int32 firstColumn, int32& lastColumn) const;
|
int32 firstColumn, int32& lastColumn) const;
|
||||||
|
|
||||||
void _UpdateSIGWINCH();
|
void _UpdateSIGWINCH();
|
||||||
@@ -237,7 +262,7 @@ private:
|
|||||||
BMessageRunner* fAutoScrollRunner;
|
BMessageRunner* fAutoScrollRunner;
|
||||||
BMessageRunner* fResizeRunner;
|
BMessageRunner* fResizeRunner;
|
||||||
BStringView* fResizeView;
|
BStringView* fResizeView;
|
||||||
CharClassifier* fCharClassifier;
|
DefaultCharClassifier* fCharClassifier;
|
||||||
|
|
||||||
// Font and Width
|
// Font and Width
|
||||||
BFont fHalfFont;
|
BFont fHalfFont;
|
||||||
@@ -272,6 +297,7 @@ private:
|
|||||||
// Object pointer.
|
// Object pointer.
|
||||||
TerminalBuffer* fTextBuffer;
|
TerminalBuffer* fTextBuffer;
|
||||||
BasicTerminalBuffer* fVisibleTextBuffer;
|
BasicTerminalBuffer* fVisibleTextBuffer;
|
||||||
|
bool fVisibleTextBufferChanged;
|
||||||
BScrollBar* fScrollBar;
|
BScrollBar* fScrollBar;
|
||||||
InlineInput* fInline;
|
InlineInput* fInline;
|
||||||
|
|
||||||
@@ -297,14 +323,16 @@ private:
|
|||||||
bool fConsiderClockedSync;
|
bool fConsiderClockedSync;
|
||||||
|
|
||||||
// selection
|
// selection
|
||||||
TermPos fSelStart;
|
Highlight fSelection;
|
||||||
TermPos fSelEnd;
|
|
||||||
TermPos fInitialSelectionStart;
|
TermPos fInitialSelectionStart;
|
||||||
TermPos fInitialSelectionEnd;
|
TermPos fInitialSelectionEnd;
|
||||||
BPoint fLastClickPoint;
|
BPoint fLastClickPoint;
|
||||||
|
|
||||||
|
HighlightList fHighlights;
|
||||||
|
|
||||||
// mouse
|
// mouse
|
||||||
int32 fMouseButtons;
|
int32 fMouseButtons;
|
||||||
|
int32 fModifiers;
|
||||||
TermPos fPrevPos;
|
TermPos fPrevPos;
|
||||||
bool fReportX10MouseEvent;
|
bool fReportX10MouseEvent;
|
||||||
bool fReportNormalMouseEvent;
|
bool fReportNormalMouseEvent;
|
||||||
@@ -315,6 +343,8 @@ private:
|
|||||||
// states
|
// states
|
||||||
DefaultState* fDefaultState;
|
DefaultState* fDefaultState;
|
||||||
SelectState* fSelectState;
|
SelectState* fSelectState;
|
||||||
|
HyperLinkState* fHyperLinkState;
|
||||||
|
HyperLinkMenuState* fHyperLinkMenuState;
|
||||||
State* fActiveState;
|
State* fActiveState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "TermViewHighlight.h"
|
||||||
|
|
||||||
|
|
||||||
|
TermViewHighlighter::~TermViewHighlighter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
TermViewHighlighter::AdjustTextAttributes(uint32 attributes)
|
||||||
|
{
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef TERMVIEW_HIGHLIGHT_H
|
||||||
|
#define TERMVIEW_HIGHLIGHT_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <GraphicsDefs.h>
|
||||||
|
|
||||||
|
#include "TermPos.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TermViewHighlighter {
|
||||||
|
public:
|
||||||
|
virtual ~TermViewHighlighter();
|
||||||
|
|
||||||
|
virtual rgb_color ForegroundColor() = 0;
|
||||||
|
virtual rgb_color BackgroundColor() = 0;
|
||||||
|
virtual uint32 AdjustTextAttributes(uint32 attributes);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermViewHighlight {
|
||||||
|
public:
|
||||||
|
TermViewHighlight()
|
||||||
|
:
|
||||||
|
fHighlighter(NULL),
|
||||||
|
fStart(-1, -1),
|
||||||
|
fEnd(-1, -1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TermViewHighlighter* Highlighter() const
|
||||||
|
{
|
||||||
|
return fHighlighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHighlighter(TermViewHighlighter* highligher)
|
||||||
|
{
|
||||||
|
fHighlighter = highligher;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TermPos& Start() const
|
||||||
|
{
|
||||||
|
return fStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TermPos& End() const
|
||||||
|
{
|
||||||
|
return fEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const
|
||||||
|
{
|
||||||
|
return fStart == fEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RangeContains(const TermPos& pos) const
|
||||||
|
{
|
||||||
|
return pos >= fStart && pos < fEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRange(const TermPos& start, const TermPos& end)
|
||||||
|
{
|
||||||
|
fStart = start;
|
||||||
|
fEnd = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollRange(int32 byLines)
|
||||||
|
{
|
||||||
|
fStart.y -= byLines;
|
||||||
|
fEnd.y -= byLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TermViewHighlighter* fHighlighter;
|
||||||
|
TermPos fStart;
|
||||||
|
TermPos fEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TERMVIEW_HIGHLIGHT_H
|
||||||
@@ -16,17 +16,30 @@
|
|||||||
|
|
||||||
#include "TermViewStates.h"
|
#include "TermViewStates.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <Catalog.h>
|
||||||
|
#include <Clipboard.h>
|
||||||
|
#include <Cursor.h>
|
||||||
|
#include <LayoutBuilder.h>
|
||||||
#include <MessageRunner.h>
|
#include <MessageRunner.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
#include <ScrollBar.h>
|
#include <ScrollBar.h>
|
||||||
#include <UTF8.h>
|
#include <UTF8.h>
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
#include "Shell.h"
|
#include "Shell.h"
|
||||||
#include "TermConst.h"
|
#include "TermConst.h"
|
||||||
|
#include "TerminalBuffer.h"
|
||||||
#include "VTkeymap.h"
|
#include "VTkeymap.h"
|
||||||
#include "VTKeyTbl.h"
|
#include "VTKeyTbl.h"
|
||||||
|
|
||||||
|
|
||||||
|
#undef B_TRANSLATION_CONTEXT
|
||||||
|
#define B_TRANSLATION_CONTEXT "Terminal TermView"
|
||||||
|
|
||||||
|
|
||||||
// selection granularity
|
// selection granularity
|
||||||
enum {
|
enum {
|
||||||
SELECT_CHARS,
|
SELECT_CHARS,
|
||||||
@@ -36,6 +49,13 @@ enum {
|
|||||||
|
|
||||||
static const uint32 kAutoScroll = 'AScr';
|
static const uint32 kAutoScroll = 'AScr';
|
||||||
|
|
||||||
|
static const uint32 kMessageOpenLink = 'OLnk';
|
||||||
|
static const uint32 kMessageCopyLink = 'CLnk';
|
||||||
|
static const uint32 kMessageMenuClosed = 'MClo';
|
||||||
|
|
||||||
|
|
||||||
|
static const char* const kKnownURLProtocols = "http:https:ftp:mailto";
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - State
|
// #pragma mark - State
|
||||||
|
|
||||||
@@ -71,6 +91,12 @@ TermView::State::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::ModifiersChanged(int32 oldModifiers, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TermView::State::KeyDown(const char* bytes, int32 numBytes)
|
TermView::State::KeyDown(const char* bytes, int32 numBytes)
|
||||||
{
|
{
|
||||||
@@ -85,7 +111,7 @@ TermView::State::MouseDown(BPoint where, int32 buttons, int32 modifiers)
|
|||||||
|
|
||||||
void
|
void
|
||||||
TermView::State::MouseMoved(BPoint where, uint32 transit,
|
TermView::State::MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message)
|
const BMessage* message, int32 modifiers)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +122,18 @@ TermView::State::MouseUp(BPoint where, int32 buttons)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::WindowActivated(bool active)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::VisibleTextBufferChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - StandardBaseState
|
// #pragma mark - StandardBaseState
|
||||||
|
|
||||||
|
|
||||||
@@ -107,25 +145,22 @@ TermView::StandardBaseState::StandardBaseState(TermView* view)
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TermView::StandardBaseState::_StandardMouseMoved(BPoint where)
|
TermView::StandardBaseState::_StandardMouseMoved(BPoint where, int32 modifiers)
|
||||||
{
|
{
|
||||||
if (!fView->fReportAnyMouseEvent && !fView->fReportButtonMouseEvent)
|
if (!fView->fReportAnyMouseEvent && !fView->fReportButtonMouseEvent)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int32 modifier;
|
|
||||||
fView->Window()->CurrentMessage()->FindInt32("modifiers", &modifier);
|
|
||||||
|
|
||||||
TermPos clickPos = fView->_ConvertToTerminal(where);
|
TermPos clickPos = fView->_ConvertToTerminal(where);
|
||||||
|
|
||||||
if (fView->fReportButtonMouseEvent) {
|
if (fView->fReportButtonMouseEvent) {
|
||||||
if (fView->fPrevPos.x != clickPos.x
|
if (fView->fPrevPos.x != clickPos.x
|
||||||
|| fView->fPrevPos.y != clickPos.y) {
|
|| fView->fPrevPos.y != clickPos.y) {
|
||||||
fView->_SendMouseEvent(fView->fMouseButtons, modifier,
|
fView->_SendMouseEvent(fView->fMouseButtons, modifiers,
|
||||||
clickPos.x, clickPos.y, true);
|
clickPos.x, clickPos.y, true);
|
||||||
}
|
}
|
||||||
fView->fPrevPos = clickPos;
|
fView->fPrevPos = clickPos;
|
||||||
} else {
|
} else {
|
||||||
fView->_SendMouseEvent(fView->fMouseButtons, modifier, clickPos.x,
|
fView->_SendMouseEvent(fView->fMouseButtons, modifiers, clickPos.x,
|
||||||
clickPos.y, true);
|
clickPos.y, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +178,13 @@ TermView::DefaultState::DefaultState(TermView* view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::DefaultState::ModifiersChanged(int32 oldModifiers, int32 modifiers)
|
||||||
|
{
|
||||||
|
_CheckEnterHyperLinkState(modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes)
|
TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes)
|
||||||
{
|
{
|
||||||
@@ -341,9 +383,32 @@ TermView::DefaultState::MouseDown(BPoint where, int32 buttons, int32 modifiers)
|
|||||||
|
|
||||||
void
|
void
|
||||||
TermView::DefaultState::MouseMoved(BPoint where, uint32 transit,
|
TermView::DefaultState::MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message)
|
const BMessage* message, int32 modifiers)
|
||||||
{
|
{
|
||||||
_StandardMouseMoved(where);
|
if (_CheckEnterHyperLinkState(modifiers))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_StandardMouseMoved(where, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::DefaultState::WindowActivated(bool active)
|
||||||
|
{
|
||||||
|
if (active)
|
||||||
|
_CheckEnterHyperLinkState(fView->fModifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::DefaultState::_CheckEnterHyperLinkState(int32 modifiers)
|
||||||
|
{
|
||||||
|
if ((modifiers & B_COMMAND_KEY) != 0 && fView->Window()->IsActive()) {
|
||||||
|
fView->_NextState(fView->fHyperLinkState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -368,7 +433,7 @@ TermView::SelectState::Prepare(BPoint where, int32 modifiers)
|
|||||||
|
|
||||||
if (fView->_HasSelection()) {
|
if (fView->_HasSelection()) {
|
||||||
TermPos inPos = fView->_ConvertToTerminal(where);
|
TermPos inPos = fView->_ConvertToTerminal(where);
|
||||||
if (fView->_CheckSelectedRegion(inPos)) {
|
if (fView->fSelection.RangeContains(inPos)) {
|
||||||
if (modifiers & B_CONTROL_KEY) {
|
if (modifiers & B_CONTROL_KEY) {
|
||||||
BPoint p;
|
BPoint p;
|
||||||
uint32 bt;
|
uint32 bt;
|
||||||
@@ -448,9 +513,9 @@ TermView::SelectState::MessageReceived(BMessage* message)
|
|||||||
|
|
||||||
void
|
void
|
||||||
TermView::SelectState::MouseMoved(BPoint where, uint32 transit,
|
TermView::SelectState::MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message)
|
const BMessage* message, int32 modifiers)
|
||||||
{
|
{
|
||||||
if (_StandardMouseMoved(where))
|
if (_StandardMouseMoved(where, modifiers))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fCheckMouseTracking) {
|
if (fCheckMouseTracking) {
|
||||||
@@ -561,3 +626,376 @@ TermView::SelectState::_AutoScrollUpdate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - HyperLinkState
|
||||||
|
|
||||||
|
|
||||||
|
TermView::HyperLinkState::HyperLinkState(TermView* view)
|
||||||
|
:
|
||||||
|
State(view),
|
||||||
|
fURLCharClassifier(kURLAdditionalWordCharacters),
|
||||||
|
fPathComponentCharClassifier(
|
||||||
|
BString(kDefaultAdditionalWordCharacters).RemoveFirst("/")),
|
||||||
|
fHighlight(),
|
||||||
|
fHighlightActive(false)
|
||||||
|
{
|
||||||
|
fHighlight.SetHighlighter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::Entered()
|
||||||
|
{
|
||||||
|
_UpdateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::Exited()
|
||||||
|
{
|
||||||
|
_DeactivateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::ModifiersChanged(int32 oldModifiers, int32 modifiers)
|
||||||
|
{
|
||||||
|
if ((modifiers & B_COMMAND_KEY) == 0)
|
||||||
|
fView->_NextState(fView->fDefaultState);
|
||||||
|
else
|
||||||
|
_UpdateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::MouseDown(BPoint where, int32 buttons,
|
||||||
|
int32 modifiers)
|
||||||
|
{
|
||||||
|
TermPos start;
|
||||||
|
TermPos end;
|
||||||
|
HyperLink link;
|
||||||
|
bool pathPrefixOnly = (modifiers & B_SHIFT_KEY) != 0;
|
||||||
|
if (!_GetHyperLinkAt(where, pathPrefixOnly, link, start, end))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0) {
|
||||||
|
link.Open();
|
||||||
|
} else if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
|
||||||
|
fView->fHyperLinkMenuState->Prepare(where, link);
|
||||||
|
fView->_NextState(fView->fHyperLinkMenuState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message, int32 modifiers)
|
||||||
|
{
|
||||||
|
_UpdateHighlight(where, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::WindowActivated(bool active)
|
||||||
|
{
|
||||||
|
if (!active)
|
||||||
|
fView->_NextState(fView->fDefaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::VisibleTextBufferChanged()
|
||||||
|
{
|
||||||
|
_UpdateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rgb_color
|
||||||
|
TermView::HyperLinkState::ForegroundColor()
|
||||||
|
{
|
||||||
|
return make_color(0, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rgb_color
|
||||||
|
TermView::HyperLinkState::BackgroundColor()
|
||||||
|
{
|
||||||
|
return fView->fTextBackColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
TermView::HyperLinkState::AdjustTextAttributes(uint32 attributes)
|
||||||
|
{
|
||||||
|
return attributes | UNDERLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::HyperLinkState::_GetHyperLinkAt(BPoint where, bool pathPrefixOnly,
|
||||||
|
HyperLink& _link, TermPos& _start, TermPos& _end)
|
||||||
|
{
|
||||||
|
TerminalBuffer* textBuffer = fView->fTextBuffer;
|
||||||
|
BAutolock textBufferLocker(textBuffer);
|
||||||
|
|
||||||
|
TermPos pos = fView->_ConvertToTerminal(where);
|
||||||
|
|
||||||
|
// try to get a URL first
|
||||||
|
BString text;
|
||||||
|
if (!textBuffer->FindWord(pos, &fURLCharClassifier, false, _start, _end))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
text.Truncate(0);
|
||||||
|
textBuffer->GetStringFromRegion(text, _start, _end);
|
||||||
|
text.Trim();
|
||||||
|
|
||||||
|
// We're only happy, if it has a protocol part which we know.
|
||||||
|
int32 colonIndex = text.FindFirst(':');
|
||||||
|
if (colonIndex >= 0) {
|
||||||
|
BString protocol(text, colonIndex);
|
||||||
|
if (strstr(kKnownURLProtocols, protocol) != NULL) {
|
||||||
|
_link = HyperLink(text, HyperLink::TYPE_URL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no obvious URL -- try file name
|
||||||
|
if (!textBuffer->FindWord(pos, fView->fCharClassifier, false, _start, _end))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// In path-prefix-only mode we determine the end position anew by omitting
|
||||||
|
// the '/' in the allowed word chars.
|
||||||
|
if (pathPrefixOnly) {
|
||||||
|
TermPos componentStart;
|
||||||
|
TermPos componentEnd;
|
||||||
|
if (textBuffer->FindWord(pos, &fPathComponentCharClassifier, false,
|
||||||
|
componentStart, componentEnd)) {
|
||||||
|
_end = componentEnd;
|
||||||
|
} else {
|
||||||
|
// That means pos points to a '/'. We simply use the previous
|
||||||
|
// position.
|
||||||
|
_end = pos;
|
||||||
|
if (_start == _end) {
|
||||||
|
// Well, must be just "/". Advance to the next position.
|
||||||
|
if (!textBuffer->NextLinePos(_end, false))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text.Truncate(0);
|
||||||
|
textBuffer->GetStringFromRegion(text, _start, _end);
|
||||||
|
text.Trim();
|
||||||
|
if (text.IsEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check, whether the file exists
|
||||||
|
struct stat st;
|
||||||
|
if (lstat(text, &st) == 0) {
|
||||||
|
_link = HyperLink(text, HyperLink::TYPE_PATH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As such this isn't an existing path. Try a few common alternative cases:
|
||||||
|
// * "<path>:"
|
||||||
|
// * "<path>:<line>"
|
||||||
|
// * "<path>:<line>:"
|
||||||
|
// * "<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;
|
||||||
|
|
||||||
|
if (lstat(text, &st) == 0) {
|
||||||
|
_link = HyperLink(text, HyperLink::TYPE_PATH);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BString path = text;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < 2; i++) {
|
||||||
|
int32 colonIndex = path.FindLast(':');
|
||||||
|
if (colonIndex <= 0 || colonIndex == path.Length() - 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char* numberEnd;
|
||||||
|
strtol(path.String() + colonIndex + 1, &numberEnd, 0);
|
||||||
|
if (*numberEnd != '\0')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
path.Truncate(colonIndex);
|
||||||
|
if (lstat(path, &st) == 0) {
|
||||||
|
_link = HyperLink(text,
|
||||||
|
i == 0
|
||||||
|
? HyperLink::TYPE_PATH_WITH_LINE
|
||||||
|
: HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN,
|
||||||
|
path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::_UpdateHighlight()
|
||||||
|
{
|
||||||
|
BPoint where;
|
||||||
|
uint32 buttons;
|
||||||
|
fView->GetMouse(&where, &buttons, false);
|
||||||
|
_UpdateHighlight(where, fView->fModifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::_UpdateHighlight(BPoint where, int32 modifiers)
|
||||||
|
{
|
||||||
|
TermPos start;
|
||||||
|
TermPos end;
|
||||||
|
HyperLink link;
|
||||||
|
bool pathPrefixOnly = (modifiers & B_SHIFT_KEY) != 0;
|
||||||
|
if (_GetHyperLinkAt(where, pathPrefixOnly, link, start, end))
|
||||||
|
_ActivateHighlight(start, end);
|
||||||
|
else
|
||||||
|
_DeactivateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::_ActivateHighlight(const TermPos& start,
|
||||||
|
const TermPos& end)
|
||||||
|
{
|
||||||
|
if (fHighlightActive) {
|
||||||
|
if (fHighlight.Start() == start && fHighlight.End() == end)
|
||||||
|
return;
|
||||||
|
_DeactivateHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
fHighlight.SetRange(start, end);
|
||||||
|
fView->_AddHighlight(&fHighlight);
|
||||||
|
BCursor cursor(B_CURSOR_ID_FOLLOW_LINK);
|
||||||
|
fView->SetViewCursor(&cursor);
|
||||||
|
fHighlightActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkState::_DeactivateHighlight()
|
||||||
|
{
|
||||||
|
if (fHighlightActive) {
|
||||||
|
fView->_RemoveHighlight(&fHighlight);
|
||||||
|
BCursor cursor(B_CURSOR_ID_SYSTEM_DEFAULT);
|
||||||
|
fView->SetViewCursor(&cursor);
|
||||||
|
fHighlightActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - HyperLinkMenuState
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::HyperLinkMenuState::PopUpMenu : public BPopUpMenu {
|
||||||
|
public:
|
||||||
|
PopUpMenu(const BMessenger& messageTarget)
|
||||||
|
:
|
||||||
|
BPopUpMenu("open hyperlink"),
|
||||||
|
fMessageTarget(messageTarget)
|
||||||
|
{
|
||||||
|
SetAsyncAutoDestruct(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PopUpMenu()
|
||||||
|
{
|
||||||
|
fMessageTarget.SendMessage(kMessageMenuClosed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BMessenger fMessageTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TermView::HyperLinkMenuState::HyperLinkMenuState(TermView* view)
|
||||||
|
:
|
||||||
|
State(view),
|
||||||
|
fLink()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkMenuState::Prepare(BPoint point, const HyperLink& link)
|
||||||
|
{
|
||||||
|
fLink = link;
|
||||||
|
|
||||||
|
// open context menu
|
||||||
|
PopUpMenu* menu = new PopUpMenu(fView);
|
||||||
|
BLayoutBuilder::Menu<> menuBuilder(menu);
|
||||||
|
switch (link.GetType()) {
|
||||||
|
case HyperLink::TYPE_URL:
|
||||||
|
menuBuilder
|
||||||
|
.AddItem(B_TRANSLATE("Open link"), kMessageOpenLink)
|
||||||
|
.AddItem(B_TRANSLATE("Copy link location"), kMessageCopyLink);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HyperLink::TYPE_PATH:
|
||||||
|
case HyperLink::TYPE_PATH_WITH_LINE:
|
||||||
|
case HyperLink::TYPE_PATH_WITH_LINE_AND_COLUMN:
|
||||||
|
menuBuilder
|
||||||
|
.AddItem(B_TRANSLATE("Open path"), kMessageOpenLink)
|
||||||
|
.AddItem(B_TRANSLATE("Copy path"), kMessageCopyLink);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
menu->SetTargetForItems(fView);
|
||||||
|
menu->Go(fView->ConvertToScreen(point), true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::HyperLinkMenuState::Exited()
|
||||||
|
{
|
||||||
|
fLink = HyperLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::HyperLinkMenuState::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kMessageOpenLink:
|
||||||
|
if (fLink.IsValid())
|
||||||
|
fLink.Open();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case kMessageCopyLink:
|
||||||
|
if (fLink.IsValid()) {
|
||||||
|
if (!be_clipboard->Lock())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
be_clipboard->Clear();
|
||||||
|
|
||||||
|
if (BMessage *data = be_clipboard->Data()) {
|
||||||
|
data->AddData("text/plain", B_MIME_TYPE,
|
||||||
|
fLink.Address().String(),
|
||||||
|
fLink.Address().Length());
|
||||||
|
be_clipboard->Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
be_clipboard->Unlock();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case kMessageMenuClosed:
|
||||||
|
fView->_NextState(fView->fDefaultState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#define TERMVIEW_STATES_H
|
#define TERMVIEW_STATES_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "HyperLink.h"
|
||||||
|
#include "TerminalCharClassifier.h"
|
||||||
#include "TermView.h"
|
#include "TermView.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -28,14 +30,20 @@ public:
|
|||||||
virtual bool MessageReceived(BMessage* message);
|
virtual bool MessageReceived(BMessage* message);
|
||||||
// returns true, if handled
|
// returns true, if handled
|
||||||
|
|
||||||
|
virtual void ModifiersChanged(int32 oldModifiers,
|
||||||
|
int32 modifiers);
|
||||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
|
||||||
virtual void MouseDown(BPoint where, int32 buttons,
|
virtual void MouseDown(BPoint where, int32 buttons,
|
||||||
int32 modifiers);
|
int32 modifiers);
|
||||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message);
|
const BMessage* message, int32 modifiers);
|
||||||
virtual void MouseUp(BPoint where, int32 buttons);
|
virtual void MouseUp(BPoint where, int32 buttons);
|
||||||
|
|
||||||
|
virtual void WindowActivated(bool active);
|
||||||
|
|
||||||
|
virtual void VisibleTextBufferChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TermView* fView;
|
TermView* fView;
|
||||||
};
|
};
|
||||||
@@ -46,7 +54,8 @@ public:
|
|||||||
StandardBaseState(TermView* view);
|
StandardBaseState(TermView* view);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _StandardMouseMoved(BPoint where);
|
bool _StandardMouseMoved(BPoint where,
|
||||||
|
int32 modifiers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -54,12 +63,20 @@ class TermView::DefaultState : public TermView::StandardBaseState {
|
|||||||
public:
|
public:
|
||||||
DefaultState(TermView* view);
|
DefaultState(TermView* view);
|
||||||
|
|
||||||
|
virtual void ModifiersChanged(int32 oldModifiers,
|
||||||
|
int32 modifiers);
|
||||||
|
|
||||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
|
||||||
virtual void MouseDown(BPoint where, int32 buttons,
|
virtual void MouseDown(BPoint where, int32 buttons,
|
||||||
int32 modifiers);
|
int32 modifiers);
|
||||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message);
|
const BMessage* message, int32 modifiers);
|
||||||
|
|
||||||
|
virtual void WindowActivated(bool active);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _CheckEnterHyperLinkState(int32 modifiers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +89,7 @@ public:
|
|||||||
virtual bool MessageReceived(BMessage* message);
|
virtual bool MessageReceived(BMessage* message);
|
||||||
|
|
||||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
const BMessage* message);
|
const BMessage* message, int32 modifiers);
|
||||||
virtual void MouseUp(BPoint where, int32 buttons);
|
virtual void MouseUp(BPoint where, int32 buttons);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -85,4 +102,67 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::HyperLinkState : public TermView::State,
|
||||||
|
private TermViewHighlighter {
|
||||||
|
public:
|
||||||
|
HyperLinkState(TermView* view);
|
||||||
|
|
||||||
|
virtual void Entered();
|
||||||
|
virtual void Exited();
|
||||||
|
|
||||||
|
virtual void ModifiersChanged(int32 oldModifiers,
|
||||||
|
int32 modifiers);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, int32 buttons,
|
||||||
|
int32 modifiers);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message, int32 modifiers);
|
||||||
|
|
||||||
|
virtual void WindowActivated(bool active);
|
||||||
|
|
||||||
|
virtual void VisibleTextBufferChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TermViewHighlighter
|
||||||
|
virtual rgb_color ForegroundColor();
|
||||||
|
virtual rgb_color BackgroundColor();
|
||||||
|
virtual uint32 AdjustTextAttributes(uint32 attributes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _GetHyperLinkAt(BPoint where,
|
||||||
|
bool pathPrefixOnly, HyperLink& _link,
|
||||||
|
TermPos& _start, TermPos& _end);
|
||||||
|
|
||||||
|
void _UpdateHighlight();
|
||||||
|
void _UpdateHighlight(BPoint where, int32 modifiers);
|
||||||
|
void _ActivateHighlight(const TermPos& start,
|
||||||
|
const TermPos& end);
|
||||||
|
void _DeactivateHighlight();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DefaultCharClassifier fURLCharClassifier;
|
||||||
|
DefaultCharClassifier fPathComponentCharClassifier;
|
||||||
|
TermViewHighlight fHighlight;
|
||||||
|
bool fHighlightActive;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::HyperLinkMenuState : public TermView::State {
|
||||||
|
public:
|
||||||
|
HyperLinkMenuState(TermView* view);
|
||||||
|
|
||||||
|
void Prepare(BPoint point, const HyperLink& link);
|
||||||
|
|
||||||
|
virtual void Exited();
|
||||||
|
|
||||||
|
virtual bool MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PopUpMenu;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HyperLink fLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // TERMVIEW_STATES_H
|
#endif // TERMVIEW_STATES_H
|
||||||
|
|||||||
@@ -1,11 +1,52 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "TerminalCharClassifier.h"
|
#include "TerminalCharClassifier.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TerminalCharClassifier
|
||||||
|
|
||||||
|
|
||||||
TerminalCharClassifier::~TerminalCharClassifier()
|
TerminalCharClassifier::~TerminalCharClassifier()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DefaultCharClassifier
|
||||||
|
|
||||||
|
|
||||||
|
DefaultCharClassifier::DefaultCharClassifier(const char* additionalWordChars)
|
||||||
|
{
|
||||||
|
const char* p = additionalWordChars;
|
||||||
|
while (p != NULL && *p != '\0') {
|
||||||
|
int count = UTF8Char::ByteCount(*p);
|
||||||
|
if (count <= 0 || count > 4)
|
||||||
|
break;
|
||||||
|
fAdditionalWordChars.push_back(UTF8Char(p, count));
|
||||||
|
p += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
DefaultCharClassifier::Classify(const UTF8Char& character)
|
||||||
|
{
|
||||||
|
if (character.IsSpace())
|
||||||
|
return CHAR_TYPE_SPACE;
|
||||||
|
|
||||||
|
if (character.IsAlNum())
|
||||||
|
return CHAR_TYPE_WORD_CHAR;
|
||||||
|
|
||||||
|
if (std::find(fAdditionalWordChars.begin(), fAdditionalWordChars.end(),
|
||||||
|
character) != fAdditionalWordChars.end()) {
|
||||||
|
return CHAR_TYPE_WORD_CHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CHAR_TYPE_WORD_DELIMITER;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef TERMINAL_CHAR_CLASSIFIER_H
|
#ifndef TERMINAL_CHAR_CLASSIFIER_H
|
||||||
#define TERMINAL_CHAR_CLASSIFIER_H
|
#define TERMINAL_CHAR_CLASSIFIER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "UTF8Char.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CHAR_TYPE_SPACE,
|
CHAR_TYPE_SPACE,
|
||||||
CHAR_TYPE_WORD_CHAR,
|
CHAR_TYPE_WORD_CHAR,
|
||||||
@@ -23,4 +28,16 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultCharClassifier: public TerminalCharClassifier {
|
||||||
|
public:
|
||||||
|
DefaultCharClassifier(
|
||||||
|
const char* additionalWordChars);
|
||||||
|
|
||||||
|
virtual int Classify(const UTF8Char& character);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<UTF8Char> fAdditionalWordChars;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // TERMINAL_CHAR_CLASSIFIER_H
|
#endif // TERMINAL_CHAR_CLASSIFIER_H
|
||||||
|
|||||||
Reference in New Issue
Block a user