Windows refactor and moving things around
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
- What precise workflow do I need for me to be viable to use this?
|
||||
- From a user (novice) point of view, how does it look like?
|
||||
|
||||
- Move things to window_ .cpp files (command, build, search, debug, status .. )
|
||||
- Remove LUA and replace with keybindings, config, commands
|
||||
- "DO YOU REALLY WANT TO QUIT?" popup
|
||||
- open all in the folder and ctrl + p like in VSCode (without special buffers)
|
||||
- Guide on the first page for new users with links to configs, tutorials
|
||||
|
||||
- Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?)
|
||||
- How to make non-editable, informative, with different font size, title bar. Which might also contain tabs
|
||||
- How to design clickable tree view in this way?
|
||||
@@ -26,30 +35,14 @@ Commands TODO:
|
||||
|
||||
|
||||
backlog
|
||||
DESIGN try to make console less special, make stuff reusable etc.
|
||||
DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version?
|
||||
ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu
|
||||
DESIGN Moving vertically between splits, which keys???
|
||||
DESIGN Console, when writing commands and evaling in console it should properly insert a new line after our thing when writing on last line
|
||||
DESIGN The cursor hopping history needs a bit of fixing, probably needs to be more complicated with collapsing commands
|
||||
FEATURE KillConsole, or maybe some window targetting but how??
|
||||
ISSUE I hit a case where GC tried deleting a buffer which was not attached to the buffer list, it had zeroed next, prev. It happened after iterating through directories using the ctrl + period
|
||||
FEATURE Search whole words, case sensitive etc.
|
||||
FEATURE Select all searched occurences
|
||||
PLATFORM Fix windows build
|
||||
ISSUE What to do / how should Reopen work after we delete the file on disk in some other program?
|
||||
DESIGN Changing window properties by changing the window name?
|
||||
FEATURE commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
|
||||
FEATURE Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
|
||||
DESIGN Check. Convert more commands to taking buffer instead of view
|
||||
DESIGN Check. Rewrite more commands to use already implemented commands?
|
||||
FEATURE Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
|
||||
FEATURE Some decl/function indexing in fuzzy format
|
||||
ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky
|
||||
FEATURE dump text editor state to file, restore state
|
||||
DESIGN ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar
|
||||
FEATURE Find matches using grep, change things in that buffer then apply those changes to all items
|
||||
FEATURE group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character
|
||||
- Search and replace
|
||||
- word complete
|
||||
- Search all buffers in 10X style, incrementally searched results popping up on every key press (maybe we need coroutine library in C so this is easier?)
|
||||
@@ -58,7 +51,6 @@ FEATURE group history entries so the you can rollback through multiple ones at o
|
||||
- code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey!
|
||||
- combine glyph and selection rendering
|
||||
|
||||
- expose a coroutine based scripting enviorment where user can execute shell commands wait for them and perform actions in very linear manner
|
||||
- Test stdin writing code
|
||||
- Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?)
|
||||
- drop text into window
|
||||
@@ -68,9 +60,6 @@ FEATURE group history entries so the you can rollback through multiple ones at o
|
||||
- I want a way to assign flags to buffers/views/windows from user perspective so that console window concept can be created from user space
|
||||
- font cache and on demand unicode loads
|
||||
- color parens, braces
|
||||
- redo tree
|
||||
- gap buffer
|
||||
- optimize rendering - command buffer, and vertice buffer instead of vertice buffer with scissor
|
||||
|
||||
|
||||
!!As little lua code as possible, but lua code should be powerful just in case of quick edits
|
||||
@@ -1572,3 +1572,17 @@ bool BufferIsReferenced(BufferID buffer_id) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReopenBuffer(Buffer *buffer) {
|
||||
Scratch scratch;
|
||||
String string = ReadFile(scratch, buffer->name);
|
||||
if (string.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String16 string16 = ToUnixString16(scratch, string);
|
||||
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), string16);
|
||||
buffer->file_mod_time = GetFileModTime(buffer->name);
|
||||
buffer->changed_on_disk = false;
|
||||
buffer->dirty = false;
|
||||
}
|
||||
|
||||
@@ -310,309 +310,6 @@ void MoveCursorByPageSize(Window *window, int direction, bool shift = false) {
|
||||
}
|
||||
}
|
||||
|
||||
void MoveCursorToSide(View *view, int direction, bool shift = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
For(view->carets) {
|
||||
Int pos = GetFront(it);
|
||||
if (direction == DIR_RIGHT) {
|
||||
pos = GetLineEnd(buffer, pos);
|
||||
} else {
|
||||
Int indent = GetIndentAtPos(buffer, pos);
|
||||
Int new_pos = GetLineStart(buffer, pos);
|
||||
if (new_pos + indent != pos) {
|
||||
pos = new_pos + indent;
|
||||
} else {
|
||||
pos = new_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (shift) {
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
it.range.max = it.range.min = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool shift = false) {
|
||||
Int front = GetFront(it);
|
||||
Int range_size = GetSize(it.range);
|
||||
switch (direction) {
|
||||
case DIR_UP: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
if (PosToLine(buffer, front) == 0) {
|
||||
it = SetFront(it, 0);
|
||||
} else {
|
||||
Int pos = OffsetByLine(buffer, front, -1);
|
||||
it = SetFront(it, pos);
|
||||
}
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = OffsetByLine(buffer, it.range.min, -1);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.min);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_DOWN: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
if (LastLine(buffer) == PosToLine(buffer, front)) {
|
||||
it = SetFront(it, buffer->len);
|
||||
} else {
|
||||
Int pos = OffsetByLine(buffer, front, 1);
|
||||
it = SetFront(it, pos);
|
||||
}
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = OffsetByLine(buffer, it.range.max, 1);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.max);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_LEFT: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevWordStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != it.range.min) {
|
||||
it = MakeCaret(it.range.min);
|
||||
} else {
|
||||
Int pos = GetPrevWordStart(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
} else if (shift) {
|
||||
Int pos = GetPrevChar(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = GetPrevChar(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.min);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_RIGHT: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextWordEnd(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != it.range.max) {
|
||||
it = MakeCaret(it.range.max);
|
||||
} else {
|
||||
Int pos = GetNextWordEnd(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
} else if (shift) {
|
||||
Int pos = GetNextChar(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = GetNextChar(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.max);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
void MoveCarets(View *view, int direction, bool ctrl = false, bool shift = false) {
|
||||
Assert(direction < DIR_COUNT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
For(view->carets) {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, shift);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveCaretsLine(View *view, int direction) {
|
||||
Assert(direction == DIR_DOWN || direction == DIR_UP);
|
||||
Scratch scratch;
|
||||
|
||||
// @todo: this doesn't work well at the end of buffer
|
||||
struct XYPair {
|
||||
XY front;
|
||||
XY back;
|
||||
};
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
Array<XYPair> saved_xy = {scratch};
|
||||
For(view->carets) {
|
||||
Int eof_current = 0;
|
||||
Range lines_to_move_range = {GetFullLineStart(buffer, it.range.min), GetFullLineEnd(buffer, it.range.max, &eof_current)};
|
||||
if (lines_to_move_range.min == 0 && direction == DIR_UP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Int eof = 0;
|
||||
Int next_line_start = lines_to_move_range.max;
|
||||
Int next_line_end = GetFullLineEnd(buffer, next_line_start, &eof);
|
||||
Int prev_line_end = lines_to_move_range.min - 1;
|
||||
Int prev_line_start = GetFullLineStart(buffer, prev_line_end);
|
||||
|
||||
if (direction == DIR_DOWN && eof) {
|
||||
continue;
|
||||
} else if (direction == DIR_UP && eof_current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String16 string = Copy16(scratch, GetString(buffer, lines_to_move_range));
|
||||
|
||||
AddEdit(&edits, lines_to_move_range, {});
|
||||
if (direction == DIR_DOWN) {
|
||||
AddEdit(&edits, MakeRange(next_line_end), string);
|
||||
} else {
|
||||
AddEdit(&edits, MakeRange(prev_line_start), string);
|
||||
}
|
||||
|
||||
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))});
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
|
||||
Int line_offset = direction == DIR_UP ? -1 : +1;
|
||||
for (Int i = 0; i < saved_xy.len; i += 1) {
|
||||
Caret &caret = view->carets[i];
|
||||
XYPair &xypair = saved_xy[i];
|
||||
xypair.front.line += line_offset;
|
||||
xypair.back.line += line_offset;
|
||||
Int front = XYToPos(buffer, xypair.front);
|
||||
Int back = XYToPos(buffer, xypair.back);
|
||||
|
||||
caret = MakeCaret(front, back);
|
||||
}
|
||||
}
|
||||
|
||||
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) AddEdit(&edits, it.range, string);
|
||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
||||
return edits;
|
||||
}
|
||||
|
||||
void Replace(View *view, String16 string) {
|
||||
Scratch scratch;
|
||||
ReplaceEx(scratch, view, string);
|
||||
}
|
||||
|
||||
void DuplicateLine(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Scratch scratch;
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
|
||||
Array<Edit> edits = {scratch};
|
||||
For(view->carets) {
|
||||
Int eof = 0;
|
||||
Range range = {};
|
||||
range.max = GetFullLineEnd(buffer, it.range.max, &eof);
|
||||
range.min = GetFullLineStart(buffer, it.range.min);
|
||||
range.min -= Clamp(eof, (Int)0, buffer->len);
|
||||
String16 string = Copy16(scratch, GetString(buffer, range));
|
||||
|
||||
Int pos = direction == DIR_UP ? range.min : range.max;
|
||||
AddEdit(&edits, MakeRange(pos), string);
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
|
||||
Int coef = direction == DIR_UP ? -1 : 1;
|
||||
for (Int i = 0; i < edits.len; i += 1) {
|
||||
Caret *caret = view->carets.data + i;
|
||||
|
||||
XY xymin = PosToXY(buffer, caret->range.min);
|
||||
XY xymax = PosToXY(buffer, caret->range.max);
|
||||
Int line_count = xymax.line - xymin.line + 1;
|
||||
|
||||
xymin.line += coef * line_count;
|
||||
xymax.line += coef * line_count;
|
||||
|
||||
caret->range.min = XYToPos(buffer, xymin);
|
||||
caret->range.max = XYToPos(buffer, xymax);
|
||||
}
|
||||
}
|
||||
|
||||
Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
|
||||
Scratch scratch(allocator);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Caret> caret_copy = TightCopy(scratch, view->carets);
|
||||
Array<Caret> temp = TightCopy(scratch, view->carets);
|
||||
if (view->carets.len > 1) MergeSort(view->carets.len, caret_copy.data, temp.data);
|
||||
|
||||
Array<Range> result = {allocator};
|
||||
For(caret_copy) {
|
||||
Int min_line = PosToLine(buffer, it.range.min);
|
||||
Int max_line = PosToLine(buffer, it.range.max);
|
||||
Range line_range = {min_line, max_line + 1};
|
||||
|
||||
if (result.len == 0) {
|
||||
Add(&result, line_range);
|
||||
continue;
|
||||
}
|
||||
|
||||
Range *last = GetLast(result);
|
||||
if (AreOverlapping(*last, line_range)) {
|
||||
last->max = Max(last->max, line_range.max);
|
||||
} else {
|
||||
Add(&result, line_range);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void IndentSelectedLines(View *view, bool shift = false) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
|
||||
Array<Range> line_ranges_to_indent = GetSelectedLinesSorted(scratch, view);
|
||||
For(line_ranges_to_indent) {
|
||||
for (Int i = it.min; i < it.max; i += 1) {
|
||||
Range pos_range_of_line = GetLineRange(buffer, i);
|
||||
|
||||
if (!shift) {
|
||||
String16 whitespace_string = {u" ", StyleIndentSize};
|
||||
AddEdit(&edits, {pos_range_of_line.min, pos_range_of_line.min}, whitespace_string);
|
||||
} else {
|
||||
String16 string = GetString(buffer, pos_range_of_line);
|
||||
Int whitespace_len = 0;
|
||||
for (Int i = 0; i < StyleIndentSize && i < string.len && string.data[i] == ' '; i += 1) {
|
||||
whitespace_len += 1;
|
||||
}
|
||||
|
||||
AddEdit(&edits, {pos_range_of_line.min, pos_range_of_line.min + whitespace_len}, u"");
|
||||
}
|
||||
}
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
void TrimTrailingWhitespace(Buffer *buffer, bool trim_lines_with_caret = false) {
|
||||
Scratch scratch;
|
||||
|
||||
@@ -737,167 +434,6 @@ void EncloseScope(View *view) {
|
||||
}
|
||||
}
|
||||
|
||||
void EncloseSpace(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
For (view->carets) {
|
||||
it.range.min = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||
it.range.max = GetNextEmptyLineStart(buffer, it.range.max);
|
||||
}
|
||||
}
|
||||
|
||||
void Delete(View *view, int direction, bool ctrl = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Scratch scratch;
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
|
||||
// Select things to delete
|
||||
For(view->carets) {
|
||||
if (GetSize(it.range)) continue;
|
||||
if (direction == DIR_LEFT) {
|
||||
|
||||
// Delete indent in multiple of IndentSize
|
||||
Range indent_range = GetIndentRangeAtPos(buffer, it.range.min);
|
||||
if (ctrl == false && it.range.min > indent_range.min && it.range.max <= indent_range.max) {
|
||||
Int offset = it.range.min - indent_range.min;
|
||||
Int to_delete = (offset % (StyleIndentSize));
|
||||
if (to_delete == 0) to_delete = StyleIndentSize;
|
||||
to_delete = Clamp(to_delete, (Int)1, StyleIndentSize);
|
||||
for (Int i = 0; i < to_delete; i += 1) {
|
||||
it = MoveCaret(buffer, it, direction, false, SHIFT_PRESS);
|
||||
}
|
||||
|
||||
} else {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, SHIFT_PRESS);
|
||||
}
|
||||
} else {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, SHIFT_PRESS);
|
||||
}
|
||||
}
|
||||
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) AddEdit(&edits, it.range, {});
|
||||
EndEdit(buffer, &edits, &view->carets, true);
|
||||
}
|
||||
|
||||
void SelectAll(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
String16 string_buffer = GetString(buffer);
|
||||
|
||||
for (Int pos = 0;;) {
|
||||
Int index = 0;
|
||||
String16 medium = Skip(string_buffer, pos);
|
||||
if (!Seek(medium, needle, &index)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Add(&view->carets, MakeCaret(pos + index + needle.len, pos + index));
|
||||
pos += needle.len;
|
||||
}
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
void CreateCursorVertical(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Int line_offset = direction == DIR_UP ? -1 : 1;
|
||||
|
||||
Scratch scratch;
|
||||
Array<Caret> arr = {scratch};
|
||||
For(view->carets) {
|
||||
if (PosToLine(buffer, it.range.min) == PosToLine(buffer, it.range.max)) {
|
||||
Int f = OffsetByLine(buffer, GetFront(it), line_offset);
|
||||
Int b = OffsetByLine(buffer, GetBack(it), line_offset);
|
||||
Add(&arr, MakeCaret(f, b));
|
||||
} else {
|
||||
Int pos = direction == DIR_UP ? it.range.min : it.range.max;
|
||||
Caret caret = MakeCaret(pos);
|
||||
caret = MoveCaret(buffer, caret, direction);
|
||||
Add(&arr, caret);
|
||||
}
|
||||
}
|
||||
For(arr) Add(&view->carets, it);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
void SelectRange(View *view, Caret caret) {
|
||||
view->carets.len = 1;
|
||||
view->carets[0] = caret;
|
||||
}
|
||||
|
||||
void SelectRange(View *view, Range range) {
|
||||
SelectRange(view, MakeCaret(range.min, range.max));
|
||||
}
|
||||
|
||||
void SelectEntireBuffer(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
SelectRange(view, GetRange(buffer));
|
||||
}
|
||||
|
||||
Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
|
||||
Int pos = GetFront(caret);
|
||||
String16 medium = GetString(buffer, {0, pos});
|
||||
|
||||
Caret result = caret;
|
||||
Int index = 0;
|
||||
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
|
||||
result = MakeCaret(index, index + needle.len);
|
||||
} else {
|
||||
medium = GetString(buffer);
|
||||
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
|
||||
result = MakeCaret(index, index + needle.len);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
|
||||
Int pos = GetMax(caret);
|
||||
String16 medium = GetString(buffer, {pos, INT64_MAX});
|
||||
|
||||
Caret result = caret;
|
||||
Int index = 0;
|
||||
if (Seek(medium, needle, &index)) {
|
||||
result = MakeCaret(pos + index + needle.len, pos + index);
|
||||
} else {
|
||||
medium = GetString(buffer);
|
||||
if (Seek(medium, needle, &index)) {
|
||||
result = MakeCaret(index + needle.len, index);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IdentedNewLine(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Scratch scratch;
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) {
|
||||
Int front = GetFront(it);
|
||||
Int line = PosToLine(buffer, front);
|
||||
Int indent = GetLineIndent(buffer, line);
|
||||
String string = Format(scratch, "\n%.*s", (int)indent, " ");
|
||||
String16 string16 = ToString16(scratch, string);
|
||||
AddEdit(&edits, it.range, string16);
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
||||
}
|
||||
|
||||
void Find(View *seek_view, String16 needle, bool forward = true) {
|
||||
Buffer *seek_buffer = GetBuffer(seek_view->active_buffer);
|
||||
Caret caret = seek_view->carets[0];
|
||||
if (forward) caret = FindNext(seek_buffer, needle, caret);
|
||||
if (!forward) caret = FindPrev(seek_buffer, needle, caret);
|
||||
SelectRange(seek_view, caret);
|
||||
|
||||
IF_DEBUG(AssertRanges(seek_view->carets));
|
||||
}
|
||||
|
||||
void GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
Assert(line_offset == 1 || line_offset == -1);
|
||||
View *active_view = GetView(window->active_view);
|
||||
@@ -935,39 +471,6 @@ void GotoNextInList(Window *window, Int line_offset = 1) {
|
||||
if (!opened) window->active_view = active_view->id;
|
||||
}
|
||||
|
||||
void FuzzySortView(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Scratch scratch;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, buffer, 0, buffer->line_starts.len, needle);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, buffer->cap);
|
||||
For(ratings) {
|
||||
String16 s = GetLineStringWithoutNL(buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
|
||||
SelectEntireBuffer(view);
|
||||
Replace(view, GetString(temp_buffer));
|
||||
SelectRange(view, MakeRange(0));
|
||||
}
|
||||
|
||||
void ReopenBuffer(Buffer *buffer) {
|
||||
Scratch scratch;
|
||||
String string = ReadFile(scratch, buffer->name);
|
||||
if (string.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String16 string16 = ToUnixString16(scratch, string);
|
||||
ReplaceWithoutMovingCarets(buffer, GetRange(buffer), string16);
|
||||
buffer->file_mod_time = GetFileModTime(buffer->name);
|
||||
buffer->changed_on_disk = false;
|
||||
buffer->dirty = false;
|
||||
}
|
||||
|
||||
void New(Window *window, String name = "") {
|
||||
View *view = GetView(window->active_view);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
@@ -1114,14 +617,6 @@ void SetProjectFile(Buffer *buffer) {
|
||||
LuaProjectBuffer->user_change_id = -1;
|
||||
}
|
||||
|
||||
String16 FetchLoadWord(BSet set) {
|
||||
Caret caret = set.view->carets[0];
|
||||
Range range = caret.range;
|
||||
if (GetSize(caret.range) == 0) range = EncloseLoadWord(set.buffer, GetFront(caret));
|
||||
String16 string = GetString(set.buffer, range);
|
||||
return string;
|
||||
}
|
||||
|
||||
void Command_Save() {
|
||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||
SaveBuffer(active.buffer);
|
||||
@@ -1163,43 +658,6 @@ void Command_ToggleFullscreen() {
|
||||
IsInFullscreen = !IsInFullscreen;
|
||||
} RegisterCommand(Command_ToggleFullscreen, "f11");
|
||||
|
||||
void Command_ListCode() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
JumpGarbageBuffer(&main);
|
||||
ListFilesRecursive(main.buffer, WorkDir);
|
||||
main.view->fuzzy_search = true;
|
||||
main.view->update_scroll = true;
|
||||
SelectRange(main.view, GetBufferEndAsRange(main.buffer));
|
||||
} RegisterCommand(Command_ListCode, "");
|
||||
|
||||
void Command_ShowBufferList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Buffers) {
|
||||
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowBufferList, "ctrl-p");
|
||||
|
||||
void Command_ListViews() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Views) {
|
||||
Buffer *buffer = GetBuffer(it->active_buffer);
|
||||
Appendf(command_bar.view, "%d %S\n", (int)it->id.id, buffer->name);
|
||||
}
|
||||
command_bar.view->fuzzy_search = true;
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ListViews, "");
|
||||
|
||||
void Command_SetProjectFile() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
SetProjectFile(main.buffer);
|
||||
@@ -1220,11 +678,6 @@ void Command_SetProject() {
|
||||
Command_SetProjectFile();
|
||||
} RegisterCommand(Command_SetProject, "");
|
||||
|
||||
void Command_ToggleDebug() {
|
||||
Window *window = GetWindow(DebugWindowID);
|
||||
window->visible = !window->visible;
|
||||
} RegisterCommand(Command_ToggleDebug, "ctrl-0");
|
||||
|
||||
void Command_KillProcess() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
KillProcess(main.view);
|
||||
@@ -1235,32 +688,6 @@ void Command_KillWindow() {
|
||||
main.window->kill = true;
|
||||
} RegisterCommand(Command_KillWindow, "ctrl-w");
|
||||
|
||||
void Command_ShowCommands() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = true;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(CommandFunctions) {
|
||||
Appendf(command_bar.view, "%S\n", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowCommands, "ctrl-shift-p");
|
||||
|
||||
void Command_ShowLuaFunctions() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(LuaFunctions) {
|
||||
Appendf(command_bar.view, "%S()\n ", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowLuaFunctions, "");
|
||||
|
||||
void Command_GotoBackward() {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
GotoBackward(main.window);
|
||||
@@ -1313,56 +740,13 @@ void Command_MakeFontSmaller() {
|
||||
}
|
||||
} RegisterCommand(Command_MakeFontSmaller, "ctrl-minus");
|
||||
|
||||
void Command_Search() {
|
||||
Window *window = GetWindow(SearchBarWindowID);
|
||||
window->visible = !window->visible;
|
||||
} RegisterCommand(Command_Search, "ctrl-f");
|
||||
|
||||
void EvalCommand(String command) {
|
||||
For (CommandFunctions) {
|
||||
if (it.name == command) {
|
||||
it.function();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EvalCommand(String16 command) {
|
||||
Scratch scratch;
|
||||
EvalCommand(ToString(scratch, command));
|
||||
}
|
||||
|
||||
void FuzzySearchOpen(BSet active) {
|
||||
Range range = active.view->carets[0].range;
|
||||
String16 string = FetchLoadWord(active);
|
||||
if (GetSize(range) == 0) {
|
||||
Int line = PosToLine(active.buffer, range.min);
|
||||
if ((active.buffer->line_starts.len - 1) == line) {
|
||||
line = ClampBottom(0ll, line - 1ll);
|
||||
}
|
||||
|
||||
string = GetLineStringWithoutNL(active.buffer, line);
|
||||
Int idx = 0;
|
||||
if (Seek(string, u"||", &idx)) {
|
||||
string = Skip(string, idx + 3);
|
||||
}
|
||||
}
|
||||
if (active.window->eval_command) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ActiveWindowID = main.window->id;
|
||||
EvalCommand(string);
|
||||
} else {
|
||||
Open(string);
|
||||
}
|
||||
}
|
||||
|
||||
void Command_Open() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.view->fuzzy_search) {
|
||||
FuzzySearchOpen(active);
|
||||
if (active.window->id == CommandBarWindowID) {
|
||||
CommandWindowOpen(active);
|
||||
} else {
|
||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||
Open(FetchLoadWord(active));
|
||||
Open(FetchLoadWord(active.view));
|
||||
}
|
||||
} RegisterCommand(Command_Open, "ctrl-q");
|
||||
|
||||
@@ -1582,17 +966,13 @@ void Command_InsertNewLineDown() {
|
||||
IdentedNewLine(active.view);
|
||||
} RegisterCommand(Command_InsertNewLineDown, "ctrl-enter");
|
||||
|
||||
void Command_SelectFuzzySearchEntry() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.view->fuzzy_search) {
|
||||
FuzzySearchOpen(active);
|
||||
SkipRemainingCommands = true;
|
||||
}
|
||||
} RegisterCommand(Command_SelectFuzzySearchEntry, "enter");
|
||||
|
||||
void Command_NewLine() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
IdentedNewLine(active.view);
|
||||
if (active.window->id == CommandBarWindowID) {
|
||||
CommandWindowOpen(active);
|
||||
} else {
|
||||
IdentedNewLine(active.view);
|
||||
}
|
||||
} RegisterCommand(Command_NewLine, "enter");
|
||||
|
||||
void Command_CreateCaretOnNextFind() {
|
||||
|
||||
@@ -77,12 +77,15 @@ String Intern(InternTable *table, String string) {
|
||||
// optimize worst offenders (like event text)
|
||||
InternTable GlobalInternTable;
|
||||
|
||||
bool SkipRemainingCommands;
|
||||
Array<CommandData> CommandFunctions;
|
||||
Array<LuaFunctionData> LuaFunctions;
|
||||
Array<FunctionData> TestFunctions;
|
||||
Array<Variable> Variables;
|
||||
|
||||
Array<Process> ActiveProcesses = {};
|
||||
Array<String> ProcessEnviroment = {};
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
// CONFIG
|
||||
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
|
||||
|
||||
@@ -232,11 +232,6 @@ int Lua_Cmd(lua_State *L) {
|
||||
BeginJump(&set);
|
||||
Exec(set.view->id, true, cmd, working_dir);
|
||||
EndJump(set);
|
||||
} else if (kind == "fuzzy") {
|
||||
JumpGarbageBuffer(&main);
|
||||
Exec(main.view->id, true, cmd, working_dir);
|
||||
main.view->fuzzy_search = true;
|
||||
ActiveWindowID = main.window->id;
|
||||
} else {
|
||||
JumpGarbageBuffer(&main);
|
||||
main.window->active_goto_list = main.view->id;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
Array<Process> ActiveProcesses = {};
|
||||
Array<String> Enviroment = {};
|
||||
|
||||
// WARNING: seems that this maybe can't work reliably?
|
||||
// in case of 'git grep a' it's possible that child process spawns it's own
|
||||
// child process and then it won't print anything because it won't have
|
||||
@@ -25,7 +22,7 @@ void UpdateProcesses() {
|
||||
}
|
||||
|
||||
void Exec(ViewID view, bool scroll_to_end, String cmd, String working_dir) {
|
||||
Process process = SpawnProcess(cmd, working_dir, {}, Enviroment);
|
||||
Process process = SpawnProcess(cmd, working_dir, {}, ProcessEnviroment);
|
||||
ReportDebugf("process %lld start. is_valid = %d cmd = %S working_dir = %S", process.id, process.is_valid, cmd, working_dir);
|
||||
process.view_id = view.id;
|
||||
process.scroll_to_end = scroll_to_end;
|
||||
@@ -42,7 +39,7 @@ Buffer *ExecAndWait(Allocator allocator, String cmd, String working_dir, String
|
||||
ReportDebugf("ExecAndWait cmd = %S working_dir = %S stdin_string = %S", cmd, working_dir, stdin_string);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(allocator, 4096 * 4);
|
||||
for (Process process = SpawnProcess(cmd, working_dir, stdin_string, Enviroment); IsValid(&process);) {
|
||||
for (Process process = SpawnProcess(cmd, working_dir, stdin_string, ProcessEnviroment); IsValid(&process);) {
|
||||
Scratch scratch(allocator);
|
||||
String poll = PollStdout(scratch, &process, true);
|
||||
if (poll.len) RawAppend(temp_buffer, poll);
|
||||
|
||||
@@ -30,14 +30,19 @@
|
||||
#include "buffer.cpp"
|
||||
#include "view.cpp"
|
||||
#include "window.cpp"
|
||||
#include "window_command.cpp"
|
||||
#include "window_debug.cpp"
|
||||
#include "window_status.cpp"
|
||||
#include "window_search.cpp"
|
||||
|
||||
#include "process.cpp"
|
||||
#include "event.cpp"
|
||||
#include "parser.cpp"
|
||||
|
||||
|
||||
#include "commands.cpp"
|
||||
#include "lua_api.cpp"
|
||||
#include "commands_clipboard.cpp"
|
||||
#include "title_bar.cpp"
|
||||
|
||||
#include "generated_config.cpp"
|
||||
|
||||
@@ -390,18 +395,11 @@ void OnCommand(Event event) {
|
||||
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
Int buffer_change_id = active.buffer->change_id;
|
||||
|
||||
// @todo: somehow detect in post command that buffer changed but random buffer can get changed??? Not sure
|
||||
// maybe we use a timestamo instead !
|
||||
Int buffer_change_id = active.buffer->change_id;
|
||||
|
||||
SkipRemainingCommands = false;
|
||||
For (CommandFunctions) {
|
||||
if (it.trigger && MatchEvent(it.trigger, &event)) {
|
||||
it.function();
|
||||
if (SkipRemainingCommands) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,42 +412,15 @@ void OnCommand(Event event) {
|
||||
String16 string16 = ToString16(scratch, event.text);
|
||||
Replace(active.view, string16);
|
||||
}
|
||||
|
||||
if (active.view->fuzzy_search) {
|
||||
if (!ProcessIsActive(active.view->id)) {
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
if (active.view->prev_search_line != last_line_string) {
|
||||
active.view->prev_search_line = last_line_string;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
|
||||
For(IterateInReverse(&ratings)) {
|
||||
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
|
||||
|
||||
Caret caret = active.view->carets[0];
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
SelectEntireBuffer(active.view);
|
||||
Replace(active.view, GetString(temp_buffer));
|
||||
active.view->carets[0] = caret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MergeCarets(active.buffer, &active.view->carets);
|
||||
IF_DEBUG(AssertRanges(active.view->carets));
|
||||
MergeCarets(main.buffer, &main.view->carets);
|
||||
IF_DEBUG(AssertRanges(main.view->carets));
|
||||
}
|
||||
|
||||
void GarbageCollect() {
|
||||
Allocator sys_allocator = GetSystemAllocator();
|
||||
|
||||
For (Views) {
|
||||
IF_DEBUG(AssertRanges(it->carets));
|
||||
}
|
||||
|
||||
For (Windows) {
|
||||
if (it->sync_visibility_with_focus) {
|
||||
if (it->id == ActiveWindowID) {
|
||||
@@ -535,11 +506,12 @@ void Update(Event event) {
|
||||
}
|
||||
|
||||
OnCommand(event);
|
||||
StatusWindowUpdate();
|
||||
DebugWindowUpdate();
|
||||
CommandWindowUpdate();
|
||||
UpdateProcesses();
|
||||
CoUpdate(&event);
|
||||
ReloadLuaConfigs();
|
||||
StatusBarUpdate();
|
||||
UpdateDebugBuffer();
|
||||
CallLuaOnUpdate(&event);
|
||||
GarbageCollect();
|
||||
|
||||
@@ -576,7 +548,7 @@ void Windows_SetupVCVarsall(mco_coro *co) {
|
||||
String s = Trim(it);
|
||||
Array<String> values = Split(scratch, s, "=");
|
||||
if (values.len == 1) continue;
|
||||
Add(&Enviroment, Copy(GetSystemAllocator(), s));
|
||||
Add(&ProcessEnviroment, Copy(GetSystemAllocator(), s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +633,7 @@ int main(int argc, char **argv)
|
||||
|
||||
#if !OS_WINDOWS
|
||||
for (int i = 0; environ[i]; i += 1) {
|
||||
Add(&Enviroment, Copy(Perm, environ[i]));
|
||||
Add(&ProcessEnviroment, Copy(Perm, environ[i]));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ struct BSet {
|
||||
View *view;
|
||||
Buffer *buffer;
|
||||
};
|
||||
BSet GetBSet(struct Window *window);
|
||||
BSet GetBSet(WindowID window_id);
|
||||
|
||||
|
||||
// @WARNING: be careful about using this, should only be used for debugging
|
||||
// the problem with this is that we want events to be reproducible.
|
||||
@@ -100,6 +103,7 @@ Buffer *CreateBuffer(Allocator allocator, String name, Int size = 4096);
|
||||
View *CreateView(BufferID active_buffer);
|
||||
void ReopenBuffer(Buffer *buffer);
|
||||
inline Buffer *FindBuffer(String name);
|
||||
bool ProcessIsActive(ViewID view);
|
||||
|
||||
inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
|
||||
inline bool operator==(ViewID a, ViewID b) { return a.id == b.id; }
|
||||
|
||||
@@ -75,3 +75,494 @@ API bool ViewIsReferenced(ViewID view) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String16 FetchLoadWord(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Caret caret = view->carets[0];
|
||||
Range range = caret.range;
|
||||
if (GetSize(caret.range) == 0) range = EncloseLoadWord(buffer, GetFront(caret));
|
||||
String16 string = GetString(buffer, range);
|
||||
return string;
|
||||
}
|
||||
|
||||
void IdentedNewLine(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Scratch scratch;
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) {
|
||||
Int front = GetFront(it);
|
||||
Int line = PosToLine(buffer, front);
|
||||
Int indent = GetLineIndent(buffer, line);
|
||||
String string = Format(scratch, "\n%.*s", (int)indent, " ");
|
||||
String16 string16 = ToString16(scratch, string);
|
||||
AddEdit(&edits, it.range, string16);
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
||||
}
|
||||
|
||||
Caret FindPrev(Buffer *buffer, String16 needle, Caret caret) {
|
||||
Int pos = GetFront(caret);
|
||||
String16 medium = GetString(buffer, {0, pos});
|
||||
|
||||
Caret result = caret;
|
||||
Int index = 0;
|
||||
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
|
||||
result = MakeCaret(index, index + needle.len);
|
||||
} else {
|
||||
medium = GetString(buffer);
|
||||
if (Seek(medium, needle, &index, SeekFlag_MatchFindLast)) {
|
||||
result = MakeCaret(index, index + needle.len);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Caret FindNext(Buffer *buffer, String16 needle, Caret caret) {
|
||||
Int pos = GetMax(caret);
|
||||
String16 medium = GetString(buffer, {pos, INT64_MAX});
|
||||
|
||||
Caret result = caret;
|
||||
Int index = 0;
|
||||
if (Seek(medium, needle, &index)) {
|
||||
result = MakeCaret(pos + index + needle.len, pos + index);
|
||||
} else {
|
||||
medium = GetString(buffer);
|
||||
if (Seek(medium, needle, &index)) {
|
||||
result = MakeCaret(index + needle.len, index);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SelectRange(View *view, Caret caret) {
|
||||
view->carets.len = 1;
|
||||
view->carets[0] = caret;
|
||||
}
|
||||
|
||||
void SelectRange(View *view, Range range) {
|
||||
SelectRange(view, MakeCaret(range.min, range.max));
|
||||
}
|
||||
|
||||
void SelectEntireBuffer(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
SelectRange(view, GetRange(buffer));
|
||||
}
|
||||
|
||||
void Find(View *seek_view, String16 needle, bool forward = true) {
|
||||
Buffer *seek_buffer = GetBuffer(seek_view->active_buffer);
|
||||
Caret caret = seek_view->carets[0];
|
||||
if (forward) caret = FindNext(seek_buffer, needle, caret);
|
||||
if (!forward) caret = FindPrev(seek_buffer, needle, caret);
|
||||
SelectRange(seek_view, caret);
|
||||
IF_DEBUG(AssertRanges(seek_view->carets));
|
||||
}
|
||||
|
||||
void FuzzySortView(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Scratch scratch;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, buffer, 0, buffer->line_starts.len, needle);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, buffer->cap);
|
||||
For(ratings) {
|
||||
String16 s = GetLineStringWithoutNL(buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
|
||||
SelectEntireBuffer(view);
|
||||
Replace(view, GetString(temp_buffer));
|
||||
SelectRange(view, MakeRange(0));
|
||||
}
|
||||
|
||||
void SelectAll(View *view, String16 needle) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
String16 string_buffer = GetString(buffer);
|
||||
|
||||
for (Int pos = 0;;) {
|
||||
Int index = 0;
|
||||
String16 medium = Skip(string_buffer, pos);
|
||||
if (!Seek(medium, needle, &index)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Add(&view->carets, MakeCaret(pos + index + needle.len, pos + index));
|
||||
pos += needle.len;
|
||||
}
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
Caret MoveCaret(Buffer *buffer, Caret it, int direction, bool ctrl = false, bool shift = false) {
|
||||
Int front = GetFront(it);
|
||||
Int range_size = GetSize(it.range);
|
||||
switch (direction) {
|
||||
case DIR_UP: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
if (PosToLine(buffer, front) == 0) {
|
||||
it = SetFront(it, 0);
|
||||
} else {
|
||||
Int pos = OffsetByLine(buffer, front, -1);
|
||||
it = SetFront(it, pos);
|
||||
}
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = OffsetByLine(buffer, it.range.min, -1);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.min);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_DOWN: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
Int pos = GetNextEmptyLineStart(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
} else if (shift) {
|
||||
if (LastLine(buffer) == PosToLine(buffer, front)) {
|
||||
it = SetFront(it, buffer->len);
|
||||
} else {
|
||||
Int pos = OffsetByLine(buffer, front, 1);
|
||||
it = SetFront(it, pos);
|
||||
}
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = OffsetByLine(buffer, it.range.max, 1);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.max);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_LEFT: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetPrevWordStart(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != it.range.min) {
|
||||
it = MakeCaret(it.range.min);
|
||||
} else {
|
||||
Int pos = GetPrevWordStart(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
} else if (shift) {
|
||||
Int pos = GetPrevChar(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = GetPrevChar(buffer, it.range.min);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.min);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DIR_RIGHT: {
|
||||
if (ctrl && shift) {
|
||||
Int pos = GetNextWordEnd(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else if (ctrl) {
|
||||
if (range_size != 0 && front != it.range.max) {
|
||||
it = MakeCaret(it.range.max);
|
||||
} else {
|
||||
Int pos = GetNextWordEnd(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
}
|
||||
} else if (shift) {
|
||||
Int pos = GetNextChar(buffer, front);
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
if (range_size == 0) {
|
||||
Int pos = GetNextChar(buffer, it.range.max);
|
||||
it = MakeCaret(pos);
|
||||
} else {
|
||||
it = MakeCaret(it.range.max);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
void MoveCarets(View *view, int direction, bool ctrl = false, bool shift = false) {
|
||||
Assert(direction < DIR_COUNT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
For(view->carets) {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, shift);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveCaretsLine(View *view, int direction) {
|
||||
Assert(direction == DIR_DOWN || direction == DIR_UP);
|
||||
Scratch scratch;
|
||||
|
||||
// @todo: this doesn't work well at the end of buffer
|
||||
struct XYPair {
|
||||
XY front;
|
||||
XY back;
|
||||
};
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
Array<XYPair> saved_xy = {scratch};
|
||||
For(view->carets) {
|
||||
Int eof_current = 0;
|
||||
Range lines_to_move_range = {GetFullLineStart(buffer, it.range.min), GetFullLineEnd(buffer, it.range.max, &eof_current)};
|
||||
if (lines_to_move_range.min == 0 && direction == DIR_UP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Int eof = 0;
|
||||
Int next_line_start = lines_to_move_range.max;
|
||||
Int next_line_end = GetFullLineEnd(buffer, next_line_start, &eof);
|
||||
Int prev_line_end = lines_to_move_range.min - 1;
|
||||
Int prev_line_start = GetFullLineStart(buffer, prev_line_end);
|
||||
|
||||
if (direction == DIR_DOWN && eof) {
|
||||
continue;
|
||||
} else if (direction == DIR_UP && eof_current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String16 string = Copy16(scratch, GetString(buffer, lines_to_move_range));
|
||||
|
||||
AddEdit(&edits, lines_to_move_range, {});
|
||||
if (direction == DIR_DOWN) {
|
||||
AddEdit(&edits, MakeRange(next_line_end), string);
|
||||
} else {
|
||||
AddEdit(&edits, MakeRange(prev_line_start), string);
|
||||
}
|
||||
|
||||
Add(&saved_xy, {PosToXY(buffer, GetFront(it)), PosToXY(buffer, GetBack(it))});
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
|
||||
Int line_offset = direction == DIR_UP ? -1 : +1;
|
||||
for (Int i = 0; i < saved_xy.len; i += 1) {
|
||||
Caret &caret = view->carets[i];
|
||||
XYPair &xypair = saved_xy[i];
|
||||
xypair.front.line += line_offset;
|
||||
xypair.back.line += line_offset;
|
||||
Int front = XYToPos(buffer, xypair.front);
|
||||
Int back = XYToPos(buffer, xypair.back);
|
||||
|
||||
caret = MakeCaret(front, back);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateCursorVertical(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Int line_offset = direction == DIR_UP ? -1 : 1;
|
||||
|
||||
Scratch scratch;
|
||||
Array<Caret> arr = {scratch};
|
||||
For(view->carets) {
|
||||
if (PosToLine(buffer, it.range.min) == PosToLine(buffer, it.range.max)) {
|
||||
Int f = OffsetByLine(buffer, GetFront(it), line_offset);
|
||||
Int b = OffsetByLine(buffer, GetBack(it), line_offset);
|
||||
Add(&arr, MakeCaret(f, b));
|
||||
} else {
|
||||
Int pos = direction == DIR_UP ? it.range.min : it.range.max;
|
||||
Caret caret = MakeCaret(pos);
|
||||
caret = MoveCaret(buffer, caret, direction);
|
||||
Add(&arr, caret);
|
||||
}
|
||||
}
|
||||
For(arr) Add(&view->carets, it);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
}
|
||||
|
||||
void Delete(View *view, int direction, bool ctrl = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Scratch scratch;
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
|
||||
// Select things to delete
|
||||
For(view->carets) {
|
||||
if (GetSize(it.range)) continue;
|
||||
if (direction == DIR_LEFT) {
|
||||
|
||||
// Delete indent in multiple of IndentSize
|
||||
Range indent_range = GetIndentRangeAtPos(buffer, it.range.min);
|
||||
if (ctrl == false && it.range.min > indent_range.min && it.range.max <= indent_range.max) {
|
||||
Int offset = it.range.min - indent_range.min;
|
||||
Int to_delete = (offset % (StyleIndentSize));
|
||||
if (to_delete == 0) to_delete = StyleIndentSize;
|
||||
to_delete = Clamp(to_delete, (Int)1, StyleIndentSize);
|
||||
for (Int i = 0; i < to_delete; i += 1) {
|
||||
it = MoveCaret(buffer, it, direction, false, SHIFT_PRESS);
|
||||
}
|
||||
|
||||
} else {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, SHIFT_PRESS);
|
||||
}
|
||||
} else {
|
||||
it = MoveCaret(buffer, it, direction, ctrl, SHIFT_PRESS);
|
||||
}
|
||||
}
|
||||
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) AddEdit(&edits, it.range, {});
|
||||
EndEdit(buffer, &edits, &view->carets, true);
|
||||
}
|
||||
|
||||
void EncloseSpace(View *view) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
For (view->carets) {
|
||||
it.range.min = GetPrevEmptyLineStart(buffer, it.range.min);
|
||||
it.range.max = GetNextEmptyLineStart(buffer, it.range.max);
|
||||
}
|
||||
}
|
||||
|
||||
Array<Range> GetSelectedLinesSorted(Allocator allocator, View *view) {
|
||||
Scratch scratch(allocator);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Caret> caret_copy = TightCopy(scratch, view->carets);
|
||||
Array<Caret> temp = TightCopy(scratch, view->carets);
|
||||
if (view->carets.len > 1) MergeSort(view->carets.len, caret_copy.data, temp.data);
|
||||
|
||||
Array<Range> result = {allocator};
|
||||
For(caret_copy) {
|
||||
Int min_line = PosToLine(buffer, it.range.min);
|
||||
Int max_line = PosToLine(buffer, it.range.max);
|
||||
Range line_range = {min_line, max_line + 1};
|
||||
|
||||
if (result.len == 0) {
|
||||
Add(&result, line_range);
|
||||
continue;
|
||||
}
|
||||
|
||||
Range *last = GetLast(result);
|
||||
if (AreOverlapping(*last, line_range)) {
|
||||
last->max = Max(last->max, line_range.max);
|
||||
} else {
|
||||
Add(&result, line_range);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void IndentSelectedLines(View *view, bool shift = false) {
|
||||
Scratch scratch;
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
|
||||
Array<Range> line_ranges_to_indent = GetSelectedLinesSorted(scratch, view);
|
||||
For(line_ranges_to_indent) {
|
||||
for (Int i = it.min; i < it.max; i += 1) {
|
||||
Range pos_range_of_line = GetLineRange(buffer, i);
|
||||
|
||||
if (!shift) {
|
||||
String16 whitespace_string = {u" ", StyleIndentSize};
|
||||
AddEdit(&edits, {pos_range_of_line.min, pos_range_of_line.min}, whitespace_string);
|
||||
} else {
|
||||
String16 string = GetString(buffer, pos_range_of_line);
|
||||
Int whitespace_len = 0;
|
||||
for (Int i = 0; i < StyleIndentSize && i < string.len && string.data[i] == ' '; i += 1) {
|
||||
whitespace_len += 1;
|
||||
}
|
||||
|
||||
AddEdit(&edits, {pos_range_of_line.min, pos_range_of_line.min + whitespace_len}, u"");
|
||||
}
|
||||
}
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
view->update_scroll = false;
|
||||
}
|
||||
|
||||
void MoveCursorToSide(View *view, int direction, bool shift = false) {
|
||||
Assert(direction == DIR_LEFT || direction == DIR_RIGHT);
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
|
||||
For(view->carets) {
|
||||
Int pos = GetFront(it);
|
||||
if (direction == DIR_RIGHT) {
|
||||
pos = GetLineEnd(buffer, pos);
|
||||
} else {
|
||||
Int indent = GetIndentAtPos(buffer, pos);
|
||||
Int new_pos = GetLineStart(buffer, pos);
|
||||
if (new_pos + indent != pos) {
|
||||
pos = new_pos + indent;
|
||||
} else {
|
||||
pos = new_pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (shift) {
|
||||
it = SetFront(it, pos);
|
||||
} else {
|
||||
it.range.max = it.range.min = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<Edit> ReplaceEx(Allocator scratch, View *view, String16 string) {
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
Array<Edit> edits = BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
For(view->carets) AddEdit(&edits, it.range, string);
|
||||
EndEdit(buffer, &edits, &view->carets, KILL_SELECTION);
|
||||
return edits;
|
||||
}
|
||||
|
||||
void Replace(View *view, String16 string) {
|
||||
Scratch scratch;
|
||||
ReplaceEx(scratch, view, string);
|
||||
}
|
||||
|
||||
void DuplicateLine(View *view, int direction) {
|
||||
Assert(direction == DIR_UP || direction == DIR_DOWN);
|
||||
Scratch scratch;
|
||||
|
||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||
BeginEdit(scratch, buffer, view->carets);
|
||||
MergeCarets(buffer, &view->carets);
|
||||
|
||||
Array<Edit> edits = {scratch};
|
||||
For(view->carets) {
|
||||
Int eof = 0;
|
||||
Range range = {};
|
||||
range.max = GetFullLineEnd(buffer, it.range.max, &eof);
|
||||
range.min = GetFullLineStart(buffer, it.range.min);
|
||||
range.min -= Clamp(eof, (Int)0, buffer->len);
|
||||
String16 string = Copy16(scratch, GetString(buffer, range));
|
||||
|
||||
Int pos = direction == DIR_UP ? range.min : range.max;
|
||||
AddEdit(&edits, MakeRange(pos), string);
|
||||
}
|
||||
EndEdit(buffer, &edits, &view->carets, !KILL_SELECTION);
|
||||
|
||||
Int coef = direction == DIR_UP ? -1 : 1;
|
||||
for (Int i = 0; i < edits.len; i += 1) {
|
||||
Caret *caret = view->carets.data + i;
|
||||
|
||||
XY xymin = PosToXY(buffer, caret->range.min);
|
||||
XY xymax = PosToXY(buffer, caret->range.max);
|
||||
Int line_count = xymax.line - xymin.line + 1;
|
||||
|
||||
xymin.line += coef * line_count;
|
||||
xymax.line += coef * line_count;
|
||||
|
||||
caret->range.min = XYToPos(buffer, xymin);
|
||||
caret->range.max = XYToPos(buffer, xymax);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ struct View {
|
||||
Caret main_caret_on_begin_frame;
|
||||
bool update_scroll;
|
||||
|
||||
bool fuzzy_search;
|
||||
String16 prev_search_line;
|
||||
};
|
||||
|
||||
|
||||
@@ -109,80 +109,10 @@ void InitWindows() {
|
||||
Scratch scratch;
|
||||
|
||||
CreateWind();
|
||||
CreateWind();
|
||||
|
||||
// COMMAND BAR
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
CommandBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "command_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->sync_visibility_with_focus = true;
|
||||
window->lose_focus_on_escape = true;
|
||||
window->jump_history = false;
|
||||
view->fuzzy_search = true;
|
||||
}
|
||||
|
||||
// SEARCH BAR
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
SearchBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "search_bar");
|
||||
SearchBufferID = buffer->id;
|
||||
View *view = CreateView(buffer->id);
|
||||
SearchViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->lose_focus_on_escape = true;
|
||||
}
|
||||
|
||||
// STATUS BAR at the bottom
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
StatusBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "status_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
window->font = &SecondaryFont;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_line_highlight = false;
|
||||
window->draw_darker = true;
|
||||
window->layout = false;
|
||||
}
|
||||
|
||||
// DEBUG WINDOW
|
||||
{
|
||||
Window *window = CreateWind();
|
||||
DebugWindowID = window->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->visible = false;
|
||||
window->z = 2;
|
||||
window->layout = false;
|
||||
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
|
||||
DebugBufferID = buffer->id;
|
||||
buffer->no_history = true;
|
||||
|
||||
View *view = CreateView(buffer->id);
|
||||
DebugViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
|
||||
window->visible = false;
|
||||
}
|
||||
CommandWindowInit();
|
||||
SearchWindowInit();
|
||||
StatusWindowInit();
|
||||
DebugWindowInit();
|
||||
}
|
||||
|
||||
void CalcNiceties(Window *n) {
|
||||
@@ -208,53 +138,10 @@ double WindowCalcEvenResizerValue(Int screen_size_x, Int *out_count = NULL) {
|
||||
void LayoutWindows(int16_t wx, int16_t wy) {
|
||||
Rect2I screen_rect = RectI0Size(wx, wy);
|
||||
|
||||
// Command bar
|
||||
{
|
||||
Window *n = GetWindow(CommandBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// bar at the bottom
|
||||
{
|
||||
Window *n = GetWindow(StatusBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// search bar
|
||||
{
|
||||
Window *n = GetWindow(SearchBarWindowID);
|
||||
Rect2I *rect = &screen_rect;
|
||||
Rect2I copy_rect = screen_rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
// floating debug window
|
||||
{
|
||||
Window *n = GetWindow(DebugWindowID);
|
||||
Rect2 screen_rect = Rect0Size(wx, wy);
|
||||
Vec2 size = GetSize(screen_rect);
|
||||
|
||||
Rect2 a = CutRight(&screen_rect, 0.3f * size.x);
|
||||
Rect2 b = CutTop(&a, 0.4f * size.y);
|
||||
Rect2 c = Shrink(b, 20);
|
||||
n->document_rect = n->total_rect = ToRect2I(c);
|
||||
}
|
||||
CommandWindowLayout(&screen_rect, wx, wy);
|
||||
SearchWindowLayout(&screen_rect, wx, wy);
|
||||
StatusWindowLayout(&screen_rect, wx, wy);
|
||||
DebugWindowLayout(&screen_rect, wx, wy);
|
||||
|
||||
// Column layout
|
||||
Int c = 0;
|
||||
|
||||
@@ -47,4 +47,17 @@ struct Scroller {
|
||||
|
||||
inline bool operator==(WindowID a, WindowID b) { return a.id == b.id; }
|
||||
inline bool operator!=(WindowID a, WindowID b) { return a.id != b.id; }
|
||||
Rect2I GetVisibleCells(Window *window);
|
||||
Rect2I GetVisibleCells(Window *window);
|
||||
Window *CreateWind();
|
||||
|
||||
void CommandWindowLayout(Rect2I *rect, Int wx, Int wy);
|
||||
void CommandWindowInit();
|
||||
|
||||
void SearchWindowLayout(Rect2I *rect, Int wx, Int wy);
|
||||
void SearchWindowInit();
|
||||
|
||||
void StatusWindowInit();
|
||||
void StatusWindowLayout(Rect2I *rect, Int wx, Int wy);
|
||||
|
||||
void DebugWindowInit();
|
||||
void DebugWindowLayout(Rect2I *rect, Int wx, Int wy);
|
||||
133
src/text_editor/window_command.cpp
Normal file
133
src/text_editor/window_command.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
void CommandWindowInit() {
|
||||
Window *window = CreateWind();
|
||||
CommandBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "command_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->sync_visibility_with_focus = true;
|
||||
window->lose_focus_on_escape = true;
|
||||
window->jump_history = false;
|
||||
}
|
||||
|
||||
void CommandWindowLayout(Rect2I *rect, Int wx, Int wy) {
|
||||
Window *n = GetWindow(CommandBarWindowID);
|
||||
Rect2I copy_rect = *rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = Clamp((Int)n->font->line_spacing*10, (Int)0, (Int)wx - 100);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
void CommandWindowUpdate() {
|
||||
BSet active = GetBSet(ActiveWindowID);
|
||||
if (active.window->id == CommandBarWindowID) {
|
||||
if (!ProcessIsActive(active.view->id)) {
|
||||
Scratch scratch;
|
||||
String16 last_line_string = GetLineStringWithoutNL(active.buffer, active.buffer->line_starts.len - 1);
|
||||
if (active.view->prev_search_line != last_line_string) {
|
||||
active.view->prev_search_line = last_line_string;
|
||||
Array<FuzzyPair> ratings = FuzzySearchLines(scratch, active.buffer, 0, active.buffer->line_starts.len - 1, last_line_string);
|
||||
|
||||
Buffer *temp_buffer = CreateTempBuffer(scratch, active.buffer->cap);
|
||||
For(IterateInReverse(&ratings)) {
|
||||
String16 s = GetLineStringWithoutNL(active.buffer, it.index);
|
||||
if (s.len == 0) continue;
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), s);
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), u"\n");
|
||||
}
|
||||
RawReplaceText(temp_buffer, GetBufferEndAsRange(temp_buffer), last_line_string);
|
||||
|
||||
Caret caret = active.view->carets[0];
|
||||
SaveCaretHistoryBeforeBeginEdit(active.buffer, active.view->carets);
|
||||
SelectEntireBuffer(active.view);
|
||||
Replace(active.view, GetString(temp_buffer));
|
||||
active.view->carets[0] = caret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Command_ShowCommands() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = true;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(CommandFunctions) {
|
||||
Appendf(command_bar.view, "%S\n", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowCommands, "ctrl-shift-p");
|
||||
|
||||
void Command_ShowLuaFunctions() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(LuaFunctions) {
|
||||
Appendf(command_bar.view, "%S()\n ", it.name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowLuaFunctions, "");
|
||||
|
||||
|
||||
void Command_ShowBufferList() {
|
||||
BSet command_bar = GetBSet(CommandBarWindowID);
|
||||
command_bar.window->visible = true;
|
||||
command_bar.window->eval_command = false;
|
||||
ActiveWindowID = command_bar.window->id;
|
||||
ResetBuffer(command_bar.buffer);
|
||||
For(Buffers) {
|
||||
RawAppendf(command_bar.buffer, "%-80S || %S\n", SkipToLastSlash(it->name), it->name);
|
||||
}
|
||||
command_bar.view->update_scroll = true;
|
||||
SelectRange(command_bar.view, GetBufferEndAsRange(command_bar.buffer));
|
||||
} RegisterCommand(Command_ShowBufferList, "ctrl-p");
|
||||
|
||||
void EvalCommand(String command) {
|
||||
For (CommandFunctions) {
|
||||
if (it.name == command) {
|
||||
it.function();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EvalCommand(String16 command) {
|
||||
Scratch scratch;
|
||||
EvalCommand(ToString(scratch, command));
|
||||
}
|
||||
|
||||
void CommandWindowOpen(BSet active) {
|
||||
Range range = active.view->carets[0].range;
|
||||
String16 string = FetchLoadWord(active.view);
|
||||
if (GetSize(range) == 0) {
|
||||
Int line = PosToLine(active.buffer, range.min);
|
||||
if ((active.buffer->line_starts.len - 1) == line) {
|
||||
line = ClampBottom(0ll, line - 1ll);
|
||||
}
|
||||
|
||||
string = GetLineStringWithoutNL(active.buffer, line);
|
||||
Int idx = 0;
|
||||
if (Seek(string, u"||", &idx)) {
|
||||
string = Skip(string, idx + 3);
|
||||
}
|
||||
}
|
||||
if (active.window->eval_command) {
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
ActiveWindowID = main.window->id;
|
||||
EvalCommand(string);
|
||||
} else {
|
||||
Open(string);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,35 @@
|
||||
void UpdateDebugBuffer() {
|
||||
void DebugWindowInit() {
|
||||
Window *window = CreateWind();
|
||||
DebugWindowID = window->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->visible = false;
|
||||
window->z = 2;
|
||||
window->layout = false;
|
||||
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, GetUniqueBufferName(WorkDir, "debug"));
|
||||
DebugBufferID = buffer->id;
|
||||
buffer->no_history = true;
|
||||
|
||||
View *view = CreateView(buffer->id);
|
||||
DebugViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
|
||||
window->visible = false;
|
||||
}
|
||||
|
||||
void DebugWindowLayout(Rect2I *rect, Int wx, Int wy) {
|
||||
Window *n = GetWindow(DebugWindowID);
|
||||
Rect2 screen_rect = Rect0Size((float)wx, (float)wy);
|
||||
Vec2 size = GetSize(screen_rect);
|
||||
|
||||
Rect2 a = CutRight(&screen_rect, 0.3f * size.x);
|
||||
Rect2 b = CutTop(&a, 0.4f * size.y);
|
||||
Rect2 c = Shrink(b, 20);
|
||||
n->document_rect = n->total_rect = ToRect2I(c);
|
||||
}
|
||||
|
||||
void DebugWindowUpdate() {
|
||||
Buffer *buffer = GetBuffer(DebugBufferID);
|
||||
|
||||
Window *window = GetActiveWind();
|
||||
@@ -41,74 +72,7 @@ void UpdateDebugBuffer() {
|
||||
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage);
|
||||
}
|
||||
|
||||
void StatusBarUpdate() {
|
||||
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
|
||||
if (status_bar_window == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet title = GetBSet(status_bar_window);
|
||||
title.view->scroll.y = 0;
|
||||
|
||||
String16 buffer_string = GetString(title.buffer);
|
||||
Range replace_range = {0, title.buffer->len};
|
||||
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
||||
|
||||
// Parse the title and line
|
||||
if (title.window->id == ActiveWindowID) {
|
||||
if (title.buffer->change_id == title.window->status_bar_last_buffer_change_id) {
|
||||
return;
|
||||
}
|
||||
String16 buffer_name = GetString(title.buffer, replace_range);
|
||||
buffer_name = Skip(buffer_name, 1);
|
||||
buffer_name = Trim(buffer_name);
|
||||
|
||||
Int column = ChopNumber(&buffer_name);
|
||||
if (column == -1) return;
|
||||
|
||||
Int line = ChopNumber(&buffer_name);
|
||||
if (line == -1) {
|
||||
line = column;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
Int buffer_pos = XYToPos(main.buffer, {column, line});
|
||||
Caret &caret = main.view->carets[0];
|
||||
if (GetFront(caret) != buffer_pos) {
|
||||
caret = MakeCaret(buffer_pos);
|
||||
}
|
||||
title.window->status_bar_last_buffer_change_id = title.buffer->change_id;
|
||||
return;
|
||||
}
|
||||
|
||||
Caret caret = main.view->carets[0];
|
||||
XY xy = PosToXY(main.buffer, GetFront(caret));
|
||||
|
||||
// add separator at the end of buffer
|
||||
if (!found_separator) {
|
||||
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
|
||||
}
|
||||
|
||||
|
||||
// replace data up to separator with filename and stuff
|
||||
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
|
||||
String s = Format(scratch, "# %S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
|
||||
For (ActiveProcesses) {
|
||||
if (it.view_id == main.view->id.id) {
|
||||
s = Format(scratch, "%S %lld Kill()", s, (long long)it.id);
|
||||
}
|
||||
}
|
||||
|
||||
String16 string = ToString16(scratch, s);
|
||||
String16 string_to_replace = GetString(title.buffer, replace_range);
|
||||
if (string_to_replace != string) {
|
||||
SelectRange(title.view, replace_range);
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, string);
|
||||
}
|
||||
|
||||
SelectRange(title.view, MakeRange(0));
|
||||
ResetHistory(title.buffer);
|
||||
}
|
||||
void Command_ToggleDebug() {
|
||||
Window *window = GetWindow(DebugWindowID);
|
||||
window->visible = !window->visible;
|
||||
} RegisterCommand(Command_ToggleDebug, "ctrl-0");
|
||||
31
src/text_editor/window_search.cpp
Normal file
31
src/text_editor/window_search.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
void SearchWindowInit() {
|
||||
Window *window = CreateWind();
|
||||
SearchBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "search_bar");
|
||||
SearchBufferID = buffer->id;
|
||||
View *view = CreateView(buffer->id);
|
||||
SearchViewID = view->id;
|
||||
window->active_view = view->id;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_darker = true;
|
||||
window->draw_line_highlight = false;
|
||||
window->layout = false;
|
||||
window->visible = false;
|
||||
window->lose_focus_on_escape = true;
|
||||
}
|
||||
|
||||
void SearchWindowLayout(Rect2I *rect, Int wx, Int wy) {
|
||||
Window *n = GetWindow(SearchBarWindowID);
|
||||
Rect2I copy_rect = *rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
void Command_Search() {
|
||||
Window *window = GetWindow(SearchBarWindowID);
|
||||
window->visible = !window->visible;
|
||||
} RegisterCommand(Command_Search, "ctrl-f");
|
||||
95
src/text_editor/window_status.cpp
Normal file
95
src/text_editor/window_status.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
void StatusWindowInit() {
|
||||
Window *window = CreateWind();
|
||||
StatusBarWindowID = window->id;
|
||||
Buffer *buffer = CreateBuffer(SysAllocator, "status_bar");
|
||||
View *view = CreateView(buffer->id);
|
||||
window->active_view = view->id;
|
||||
window->font = &SecondaryFont;
|
||||
window->draw_line_numbers = false;
|
||||
window->draw_scrollbar = false;
|
||||
window->draw_line_highlight = false;
|
||||
window->draw_darker = true;
|
||||
window->layout = false;
|
||||
}
|
||||
|
||||
void StatusWindowLayout(Rect2I *rect, Int wx, Int wy) {
|
||||
Window *n = GetWindow(StatusBarWindowID);
|
||||
Rect2I copy_rect = *rect;
|
||||
if (!n->visible) {
|
||||
rect = ©_rect;
|
||||
}
|
||||
Int barsize = GetExpandingBarSize(n);
|
||||
n->document_rect = n->total_rect = CutBottom(rect, barsize);
|
||||
}
|
||||
|
||||
void StatusWindowUpdate() {
|
||||
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
|
||||
if (status_bar_window == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scratch scratch;
|
||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||
BSet title = GetBSet(status_bar_window);
|
||||
title.view->scroll.y = 0;
|
||||
|
||||
String16 buffer_string = GetString(title.buffer);
|
||||
Range replace_range = {0, title.buffer->len};
|
||||
bool found_separator = Seek(buffer_string, u" |", &replace_range.max);
|
||||
|
||||
// Parse the title and line
|
||||
if (title.window->id == ActiveWindowID) {
|
||||
if (title.buffer->change_id == title.window->status_bar_last_buffer_change_id) {
|
||||
return;
|
||||
}
|
||||
String16 buffer_name = GetString(title.buffer, replace_range);
|
||||
buffer_name = Skip(buffer_name, 1);
|
||||
buffer_name = Trim(buffer_name);
|
||||
|
||||
Int column = ChopNumber(&buffer_name);
|
||||
if (column == -1) return;
|
||||
|
||||
Int line = ChopNumber(&buffer_name);
|
||||
if (line == -1) {
|
||||
line = column;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
Int buffer_pos = XYToPos(main.buffer, {column, line});
|
||||
Caret &caret = main.view->carets[0];
|
||||
if (GetFront(caret) != buffer_pos) {
|
||||
caret = MakeCaret(buffer_pos);
|
||||
}
|
||||
title.window->status_bar_last_buffer_change_id = title.buffer->change_id;
|
||||
return;
|
||||
}
|
||||
|
||||
Caret caret = main.view->carets[0];
|
||||
XY xy = PosToXY(main.buffer, GetFront(caret));
|
||||
|
||||
// add separator at the end of buffer
|
||||
if (!found_separator) {
|
||||
SelectRange(title.view, GetBufferEndAsRange(title.buffer));
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, u" |");
|
||||
}
|
||||
|
||||
|
||||
// replace data up to separator with filename and stuff
|
||||
const char *reopen = main.buffer->changed_on_disk ? " Reopen()" : "";
|
||||
String s = Format(scratch, "# %S:%lld:%lld%s", main.buffer->name, (long long)xy.line + 1ll, (long long)xy.col + 1ll, reopen);
|
||||
For (ActiveProcesses) {
|
||||
if (it.view_id == main.view->id.id) {
|
||||
s = Format(scratch, "%S %lld Kill()", s, (long long)it.id);
|
||||
}
|
||||
}
|
||||
|
||||
String16 string = ToString16(scratch, s);
|
||||
String16 string_to_replace = GetString(title.buffer, replace_range);
|
||||
if (string_to_replace != string) {
|
||||
SelectRange(title.view, replace_range);
|
||||
Array<Edit> edits = ReplaceEx(scratch, title.view, string);
|
||||
}
|
||||
|
||||
SelectRange(title.view, MakeRange(0));
|
||||
ResetHistory(title.buffer);
|
||||
}
|
||||
Reference in New Issue
Block a user