highlight selected word occurences in text editor - close #420

This commit is contained in:
Vadim Lopatin 2017-09-08 13:04:23 +03:00
parent 2a78f1d9d1
commit d61d3ee1a4
1 changed files with 50 additions and 28 deletions

View File

@ -1167,6 +1167,20 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
requestActionsUpdate(); requestActionsUpdate();
} }
protected dstring _textToHighlight;
protected uint _textToHighlightOptions;
/// text pattern to highlight - e.g. for search
@property dstring textToHighlight() {
return _textToHighlight;
}
/// set text to highlight -- e.g. for search
void setTextToHighlight(dstring pattern, uint textToHighlightOptions) {
_textToHighlight = pattern;
_textToHighlightOptions = textToHighlightOptions;
invalidate();
}
protected void selectWordByMouse(int x, int y) { protected void selectWordByMouse(int x, int y) {
TextPosition oldCaretPos = _caretPos; TextPosition oldCaretPos = _caretPos;
TextPosition newPos = clientToTextPos(Point(x,y)); TextPosition newPos = clientToTextPos(Point(x,y));
@ -2742,57 +2756,65 @@ class EditBox : EditWidgetBase {
super.measure(parentWidth, parentHeight); super.measure(parentWidth, parentHeight);
} }
protected dstring _textToHighlight;
protected uint _textToHighlightOptions;
/// text pattern to highlight - e.g. for search
@property dstring textToHighlight() {
return _textToHighlight;
}
/// set text to highlight -- e.g. for search
void setTextToHighlight(dstring pattern, uint textToHighlightOptions) {
_textToHighlight = pattern;
_textToHighlightOptions = textToHighlightOptions;
invalidate();
}
protected void highlightTextPattern(DrawBuf buf, int lineIndex, Rect lineRect, Rect visibleRect) { protected void highlightTextPattern(DrawBuf buf, int lineIndex, Rect lineRect, Rect visibleRect) {
if (!_textToHighlight.length) dstring pattern = _textToHighlight;
uint options = _textToHighlightOptions;
if (!pattern.length) {
// support highlighting selection text - if whole word is selected
if (_selectionRange.empty || !_selectionRange.singleLine)
return;
if (_selectionRange.start.line >= _content.length)
return;
dstring selLine = _content.line(_selectionRange.start.line);
int start = _selectionRange.start.pos;
int end = _selectionRange.end.pos;
if (start >= selLine.length)
return;
pattern = selLine[start .. end];
if (!isWordChar(pattern[0]) || !isWordChar(pattern[$-1]))
return;
if (!isWholeWord(selLine, start, end))
return;
// whole word is selected - enable highlight for it
options = TextSearchFlag.CaseSensitive | TextSearchFlag.WholeWords;
}
if (!pattern.length)
return; return;
dstring lineText = _content.line(lineIndex); dstring lineText = _content.line(lineIndex);
if (lineText.length < _textToHighlight.length) if (lineText.length < pattern.length)
return; return;
ptrdiff_t start = 0; ptrdiff_t start = 0;
import std.string : indexOf, CaseSensitive, Yes, No; import std.string : indexOf, CaseSensitive, Yes, No;
bool caseSensitive = (_textToHighlightOptions & TextSearchFlag.CaseSensitive) != 0; bool caseSensitive = (options & TextSearchFlag.CaseSensitive) != 0;
bool wholeWords = (_textToHighlightOptions & TextSearchFlag.WholeWords) != 0; bool wholeWords = (options & TextSearchFlag.WholeWords) != 0;
bool selectionOnly = (_textToHighlightOptions & TextSearchFlag.SelectionOnly) != 0; bool selectionOnly = (options & TextSearchFlag.SelectionOnly) != 0;
for (;;) { for (;;) {
ptrdiff_t pos = lineText[start .. $].indexOf(_textToHighlight, caseSensitive ? Yes.caseSensitive : No.caseSensitive); ptrdiff_t pos = lineText[start .. $].indexOf(pattern, caseSensitive ? Yes.caseSensitive : No.caseSensitive);
if (pos < 0) if (pos < 0)
break; break;
// found text to highlight // found text to highlight
start += pos; start += pos;
if (!wholeWords || isWholeWord(lineText, start, start + _textToHighlight.length)) { if (!wholeWords || isWholeWord(lineText, start, start + pattern.length)) {
TextRange r = TextRange(TextPosition(lineIndex, cast(int)start), TextPosition(lineIndex, cast(int)(start + _textToHighlight.length))); TextRange r = TextRange(TextPosition(lineIndex, cast(int)start), TextPosition(lineIndex, cast(int)(start + pattern.length)));
uint color = r.isInsideOrNext(caretPos) ? _searchHighlightColorCurrent : _searchHighlightColorOther; uint color = r.isInsideOrNext(caretPos) ? _searchHighlightColorCurrent : _searchHighlightColorOther;
highlightLineRange(buf, lineRect, color, r); highlightLineRange(buf, lineRect, color, r);
} }
start += _textToHighlight.length; start += pattern.length;
} }
} }
static bool isWordChar(dchar ch) { static bool isWordChar(dchar ch) {
if (ch >= 'a' && ch <= 'z') if (ch >= 'a' && ch <= 'z')
return false; return true;
if (ch >= 'A' && ch <= 'Z') if (ch >= 'A' && ch <= 'Z')
return false; return true;
if (ch == '_') if (ch == '_')
return false; return true;
return true; return false;
} }
static bool isValidWordBound(dchar innerChar, dchar outerChar) { static bool isValidWordBound(dchar innerChar, dchar outerChar) {
return isWordChar(innerChar) || isWordChar(outerChar); return !isWordChar(innerChar) || !isWordChar(outerChar);
} }
/// returns true if selected range of string is whole word /// returns true if selected range of string is whole word
static bool isWholeWord(dstring lineText, size_t start, size_t end) { static bool isWholeWord(dstring lineText, size_t start, size_t end) {
@ -3509,7 +3531,7 @@ class FindPanel : HorizontalLayout {
} }
void close() { void close() {
_editor.setTextToHighlight(null, false); _editor.setTextToHighlight(null, 0);
_editor.closeFindPanel(); _editor.closeFindPanel();
} }