mirror of https://github.com/buggins/dlangui.git
Text editor line marks support, bookmarks support
This commit is contained in:
parent
732685c99d
commit
5baf435713
|
|
@ -433,6 +433,10 @@ interface EditableContentListener {
|
|||
void onContentChange(EditableContent content, EditOperation operation, ref TextRange rangeBefore, ref TextRange rangeAfter, Object source);
|
||||
}
|
||||
|
||||
interface EditableContentMarksChangeListener {
|
||||
void onMarksChange(EditableContent content, LineIcon[] movedMarks, LineIcon[] removedMarks);
|
||||
}
|
||||
|
||||
/// TokenCategory holder
|
||||
alias TokenProp = ubyte;
|
||||
/// TokenCategory string
|
||||
|
|
@ -583,6 +587,8 @@ class EditableContent {
|
|||
|
||||
/// listeners for edit operations
|
||||
Signal!EditableContentListener contentChanged;
|
||||
/// listeners for mark changes after edit operation
|
||||
Signal!EditableContentMarksChangeListener marksChanged;
|
||||
|
||||
protected bool _multiline;
|
||||
/// returns true if miltyline content is supported
|
||||
|
|
@ -959,6 +965,12 @@ class EditableContent {
|
|||
void handleContentChange(EditOperation op, ref TextRange rangeBefore, ref TextRange rangeAfter, Object source) {
|
||||
// update highlight if necessary
|
||||
updateTokenProps(rangeAfter.start.line, rangeAfter.end.line + 1);
|
||||
LineIcon[] moved;
|
||||
LineIcon[] removed;
|
||||
if (_lineIcons.updateLinePositions(rangeBefore, rangeAfter, moved, removed)) {
|
||||
if (marksChanged.assigned)
|
||||
marksChanged(this, moved, removed);
|
||||
}
|
||||
// call listeners
|
||||
if (contentChanged.assigned)
|
||||
contentChanged(this, op, rangeBefore, rangeAfter, source);
|
||||
|
|
@ -1438,10 +1450,20 @@ enum LineIconType : int {
|
|||
|
||||
/// text editor line icon
|
||||
class LineIcon {
|
||||
/// mark type
|
||||
LineIconType type;
|
||||
/// line number
|
||||
int line;
|
||||
LineIconType type;
|
||||
/// arbitrary parameter
|
||||
Object param;
|
||||
/// empty
|
||||
this() {
|
||||
}
|
||||
this(LineIconType type, int line, Object obj = null) {
|
||||
this.type = type;
|
||||
this.line = line;
|
||||
this.param = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// text editor line icon list
|
||||
|
|
@ -1516,12 +1538,16 @@ struct LineIcons {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
/// remove all icon marks of specified type
|
||||
void removeByType(LineIconType type) {
|
||||
/// remove all icon marks of specified type, return true if any of items removed
|
||||
bool removeByType(LineIconType type) {
|
||||
bool res = false;
|
||||
for (int i = _len - 1; i >= 0; i--) {
|
||||
if (_items[i].type == type)
|
||||
if (_items[i].type == type) {
|
||||
remove(i);
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
/// get array of icons of specified type
|
||||
LineIcon[] findByType(LineIconType type) {
|
||||
|
|
@ -1532,9 +1558,89 @@ struct LineIcons {
|
|||
}
|
||||
return res;
|
||||
}
|
||||
/// update mark position lines after text change
|
||||
void updateLinePositions(TextRange rangeBefore, TextRange rangeAfter) {
|
||||
// TODO
|
||||
/// get array of icons of specified type
|
||||
LineIcon findByLineAndType(int line, LineIconType type) {
|
||||
for (int i = 0; i < _len; i++) {
|
||||
if (_items[i].type == type && _items[i].line == line)
|
||||
return _items[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// update mark position lines after text change, returns true if any of marks were moved or removed
|
||||
bool updateLinePositions(TextRange rangeBefore, TextRange rangeAfter, ref LineIcon[] moved, ref LineIcon[] removed) {
|
||||
moved = null;
|
||||
removed = null;
|
||||
bool res = false;
|
||||
for (int i = _len - 1; i >= 0; i--) {
|
||||
LineIcon item = _items[i];
|
||||
if (rangeBefore.start.line > item.line && rangeAfter.start.line > item.line)
|
||||
continue; // line is before ranges
|
||||
else if (rangeBefore.start.line < item.line || rangeAfter.start.line < item.line) {
|
||||
// line is fully after change
|
||||
int deltaLines = rangeAfter.end.line - rangeBefore.end.line;
|
||||
if (!deltaLines)
|
||||
continue;
|
||||
if (deltaLines < 0 && rangeBefore.end.line >= item.line && rangeAfter.end.line < item.line) {
|
||||
// remove
|
||||
removed ~= item;
|
||||
_items.remove(i);
|
||||
res = true;
|
||||
} else {
|
||||
// move
|
||||
item.line += deltaLines;
|
||||
moved ~= item;
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
LineIcon findNext(LineIconType type, int line, int direction) {
|
||||
LineIcon firstBefore;
|
||||
LineIcon firstAfter;
|
||||
if (direction < 0) {
|
||||
// backward
|
||||
for (int i = _len - 1; i >= 0; i--) {
|
||||
LineIcon item = _items[i];
|
||||
if (item.type != type)
|
||||
continue;
|
||||
if (!firstBefore && item.line < line)
|
||||
firstBefore = item;
|
||||
else if (!firstAfter && item.line > line)
|
||||
firstAfter = item;
|
||||
}
|
||||
} else {
|
||||
// forward
|
||||
for (int i = 0; i < _len; i++) {
|
||||
LineIcon item = _items[i];
|
||||
if (item.type != type)
|
||||
continue;
|
||||
if (!firstBefore && item.line < line)
|
||||
firstBefore = item;
|
||||
else if (!firstAfter && item.line > line)
|
||||
firstAfter = item;
|
||||
}
|
||||
}
|
||||
if (firstAfter)
|
||||
return firstAfter;
|
||||
return firstBefore;
|
||||
}
|
||||
|
||||
@property bool hasBookmarks() {
|
||||
for (int i = 0; i < _len; i++) {
|
||||
if (_items[i].type == LineIconType.bookmark)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void toggleBookmark(int line) {
|
||||
LineIcon existing = findByLineAndType(line, LineIconType.bookmark);
|
||||
if (existing)
|
||||
remove(existing);
|
||||
else
|
||||
add(new LineIcon(LineIconType.bookmark, line));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,6 +177,13 @@ enum EditorActions : int {
|
|||
DeleteLine,
|
||||
/// Insert line
|
||||
InsertLine,
|
||||
|
||||
/// Toggle bookmark in current line
|
||||
ToggleBookmark,
|
||||
/// move cursor to next bookmark
|
||||
GoToNextBookmark,
|
||||
/// move cursor to previous bookmark
|
||||
GoToPreviousBookmark,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -193,6 +200,9 @@ const Action ACTION_EDITOR_TOGGLE_REPLACE_MODE = (new Action(EditorActions.Toggl
|
|||
const Action ACTION_EDITOR_SELECT_ALL = (new Action(EditorActions.SelectAll, KeyCode.KEY_A, KeyFlag.Control));
|
||||
const Action ACTION_EDITOR_TOGGLE_LINE_COMMENT = (new Action(EditorActions.ToggleLineComment, KeyCode.KEY_DIVIDE, KeyFlag.Control));
|
||||
const Action ACTION_EDITOR_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.ToggleBlockComment, KeyCode.KEY_DIVIDE, KeyFlag.Control | KeyFlag.Shift));
|
||||
const Action ACTION_EDITOR_TOGGLE_BOOKMARK = (new Action(EditorActions.ToggleBookmark, "ACTION_EDITOR_TOGGLE_BOOKMARK"c));
|
||||
const Action ACTION_EDITOR_GOTO_NEXT_BOOKMARK = (new Action(EditorActions.GoToNextBookmark, "ACTION_EDITOR_GOTO_NEXT_BOOKMARK"c));
|
||||
const Action ACTION_EDITOR_GOTO_PREVIOUS_BOOKMARK = (new Action(EditorActions.GoToPreviousBookmark, "ACTION_EDITOR_GOTO_PREVIOUS_BOOKMARK"c));
|
||||
|
||||
const Action[] STD_EDITOR_ACTIONS = [ACTION_EDITOR_INSERT_NEW_LINE, ACTION_EDITOR_PREPEND_NEW_LINE,
|
||||
ACTION_EDITOR_APPEND_NEW_LINE, ACTION_EDITOR_DELETE_LINE, ACTION_EDITOR_TOGGLE_REPLACE_MODE,
|
||||
|
|
@ -449,6 +459,12 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
return enabled && _content.hasUndo;
|
||||
case EditorActions.Redo:
|
||||
return enabled && _content.hasRedo;
|
||||
case EditorActions.ToggleBookmark:
|
||||
return _content.multiline;
|
||||
case EditorActions.GoToNextBookmark:
|
||||
return _content.multiline && _content.lineIcons.hasBookmarks;
|
||||
case EditorActions.GoToPreviousBookmark:
|
||||
return _content.multiline && _content.lineIcons.hasBookmarks;
|
||||
default:
|
||||
return super.isActionEnabled(action);
|
||||
}
|
||||
|
|
@ -1289,6 +1305,22 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
ensureCaretVisible();
|
||||
requestActionsUpdate();
|
||||
return true;
|
||||
case EditorActions.ToggleBookmark:
|
||||
if (_content.multiline) {
|
||||
_content.lineIcons.toggleBookmark(_selectionRange.end.line);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
case EditorActions.GoToNextBookmark:
|
||||
case EditorActions.GoToPreviousBookmark:
|
||||
if (_content.multiline) {
|
||||
LineIcon mark = _content.lineIcons.findNext(LineIconType.bookmark, _selectionRange.end.line, a.id == EditorActions.GoToNextBookmark ? 1 : -1);
|
||||
if (mark) {
|
||||
setCaretPos(mark.line, 0, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,3 +20,7 @@ CREATE_NEW_FOLDER=Create new folder
|
|||
INPUT_NAME_FOR_FOLDER=Input folder name
|
||||
CREATE_FOLDER_ERROR_TITLE=Cannot create folder
|
||||
CREATE_FOLDER_ERROR_MESSAGE=Folder creation is failed
|
||||
|
||||
ACTION_EDITOR_TOGGLE_BOOKMARK=Toggle bookmark
|
||||
ACTION_EDITOR_GOTO_NEXT_BOOKMARK=Go to next bookmark
|
||||
ACTION_EDITOR_GOTO_PREVIOUS_BOOKMARK=Go to previous bookmark
|
||||
|
|
|
|||
Loading…
Reference in New Issue