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?)
|
- 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 make non-editable, informative, with different font size, title bar. Which might also contain tabs
|
||||||
- How to design clickable tree view in this way?
|
- How to design clickable tree view in this way?
|
||||||
@@ -26,30 +35,14 @@ Commands TODO:
|
|||||||
|
|
||||||
|
|
||||||
backlog
|
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
|
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 Search whole words, case sensitive etc.
|
||||||
FEATURE Select all searched occurences
|
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 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!)
|
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
|
FEATURE Some decl/function indexing in fuzzy format
|
||||||
ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky
|
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
|
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
|
- Search and replace
|
||||||
- word complete
|
- 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?)
|
- 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!
|
- code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey!
|
||||||
- combine glyph and selection rendering
|
- 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
|
- 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?)
|
- 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
|
- 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
|
- 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
|
- font cache and on demand unicode loads
|
||||||
- color parens, braces
|
- color parens, braces
|
||||||
- redo tree
|
|
||||||
- gap buffer
|
- gap buffer
|
||||||
- optimize rendering - command buffer, and vertice buffer instead of vertice buffer with scissor
|
- 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;
|
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) {
|
void TrimTrailingWhitespace(Buffer *buffer, bool trim_lines_with_caret = false) {
|
||||||
Scratch scratch;
|
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) {
|
void GotoNextInList(Window *window, Int line_offset = 1) {
|
||||||
Assert(line_offset == 1 || line_offset == -1);
|
Assert(line_offset == 1 || line_offset == -1);
|
||||||
View *active_view = GetView(window->active_view);
|
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;
|
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 = "") {
|
void New(Window *window, String name = "") {
|
||||||
View *view = GetView(window->active_view);
|
View *view = GetView(window->active_view);
|
||||||
Buffer *buffer = GetBuffer(view->active_buffer);
|
Buffer *buffer = GetBuffer(view->active_buffer);
|
||||||
@@ -1114,14 +617,6 @@ void SetProjectFile(Buffer *buffer) {
|
|||||||
LuaProjectBuffer->user_change_id = -1;
|
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() {
|
void Command_Save() {
|
||||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||||
SaveBuffer(active.buffer);
|
SaveBuffer(active.buffer);
|
||||||
@@ -1163,43 +658,6 @@ void Command_ToggleFullscreen() {
|
|||||||
IsInFullscreen = !IsInFullscreen;
|
IsInFullscreen = !IsInFullscreen;
|
||||||
} RegisterCommand(Command_ToggleFullscreen, "f11");
|
} 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() {
|
void Command_SetProjectFile() {
|
||||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
SetProjectFile(main.buffer);
|
SetProjectFile(main.buffer);
|
||||||
@@ -1220,11 +678,6 @@ void Command_SetProject() {
|
|||||||
Command_SetProjectFile();
|
Command_SetProjectFile();
|
||||||
} RegisterCommand(Command_SetProject, "");
|
} RegisterCommand(Command_SetProject, "");
|
||||||
|
|
||||||
void Command_ToggleDebug() {
|
|
||||||
Window *window = GetWindow(DebugWindowID);
|
|
||||||
window->visible = !window->visible;
|
|
||||||
} RegisterCommand(Command_ToggleDebug, "ctrl-0");
|
|
||||||
|
|
||||||
void Command_KillProcess() {
|
void Command_KillProcess() {
|
||||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
KillProcess(main.view);
|
KillProcess(main.view);
|
||||||
@@ -1235,32 +688,6 @@ void Command_KillWindow() {
|
|||||||
main.window->kill = true;
|
main.window->kill = true;
|
||||||
} RegisterCommand(Command_KillWindow, "ctrl-w");
|
} 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() {
|
void Command_GotoBackward() {
|
||||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
GotoBackward(main.window);
|
GotoBackward(main.window);
|
||||||
@@ -1313,56 +740,13 @@ void Command_MakeFontSmaller() {
|
|||||||
}
|
}
|
||||||
} RegisterCommand(Command_MakeFontSmaller, "ctrl-minus");
|
} 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() {
|
void Command_Open() {
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
BSet active = GetBSet(ActiveWindowID);
|
||||||
if (active.view->fuzzy_search) {
|
if (active.window->id == CommandBarWindowID) {
|
||||||
FuzzySearchOpen(active);
|
CommandWindowOpen(active);
|
||||||
} else {
|
} else {
|
||||||
BSet active = GetBSet(LastActiveLayoutWindowID);
|
BSet active = GetBSet(LastActiveLayoutWindowID);
|
||||||
Open(FetchLoadWord(active));
|
Open(FetchLoadWord(active.view));
|
||||||
}
|
}
|
||||||
} RegisterCommand(Command_Open, "ctrl-q");
|
} RegisterCommand(Command_Open, "ctrl-q");
|
||||||
|
|
||||||
@@ -1582,17 +966,13 @@ void Command_InsertNewLineDown() {
|
|||||||
IdentedNewLine(active.view);
|
IdentedNewLine(active.view);
|
||||||
} RegisterCommand(Command_InsertNewLineDown, "ctrl-enter");
|
} 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() {
|
void Command_NewLine() {
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
BSet active = GetBSet(ActiveWindowID);
|
||||||
IdentedNewLine(active.view);
|
if (active.window->id == CommandBarWindowID) {
|
||||||
|
CommandWindowOpen(active);
|
||||||
|
} else {
|
||||||
|
IdentedNewLine(active.view);
|
||||||
|
}
|
||||||
} RegisterCommand(Command_NewLine, "enter");
|
} RegisterCommand(Command_NewLine, "enter");
|
||||||
|
|
||||||
void Command_CreateCaretOnNextFind() {
|
void Command_CreateCaretOnNextFind() {
|
||||||
|
|||||||
@@ -77,12 +77,15 @@ String Intern(InternTable *table, String string) {
|
|||||||
// optimize worst offenders (like event text)
|
// optimize worst offenders (like event text)
|
||||||
InternTable GlobalInternTable;
|
InternTable GlobalInternTable;
|
||||||
|
|
||||||
bool SkipRemainingCommands;
|
|
||||||
Array<CommandData> CommandFunctions;
|
Array<CommandData> CommandFunctions;
|
||||||
Array<LuaFunctionData> LuaFunctions;
|
Array<LuaFunctionData> LuaFunctions;
|
||||||
Array<FunctionData> TestFunctions;
|
Array<FunctionData> TestFunctions;
|
||||||
Array<Variable> Variables;
|
Array<Variable> Variables;
|
||||||
|
|
||||||
|
Array<Process> ActiveProcesses = {};
|
||||||
|
Array<String> ProcessEnviroment = {};
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
// CONFIG
|
// CONFIG
|
||||||
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
|
Color GruvboxDark0Hard = {0x1d, 0x20, 0x21, 0xff};
|
||||||
|
|||||||
@@ -232,11 +232,6 @@ int Lua_Cmd(lua_State *L) {
|
|||||||
BeginJump(&set);
|
BeginJump(&set);
|
||||||
Exec(set.view->id, true, cmd, working_dir);
|
Exec(set.view->id, true, cmd, working_dir);
|
||||||
EndJump(set);
|
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 {
|
} else {
|
||||||
JumpGarbageBuffer(&main);
|
JumpGarbageBuffer(&main);
|
||||||
main.window->active_goto_list = main.view->id;
|
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?
|
// 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
|
// 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
|
// 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) {
|
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);
|
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.view_id = view.id;
|
||||||
process.scroll_to_end = scroll_to_end;
|
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);
|
ReportDebugf("ExecAndWait cmd = %S working_dir = %S stdin_string = %S", cmd, working_dir, stdin_string);
|
||||||
|
|
||||||
Buffer *temp_buffer = CreateTempBuffer(allocator, 4096 * 4);
|
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);
|
Scratch scratch(allocator);
|
||||||
String poll = PollStdout(scratch, &process, true);
|
String poll = PollStdout(scratch, &process, true);
|
||||||
if (poll.len) RawAppend(temp_buffer, poll);
|
if (poll.len) RawAppend(temp_buffer, poll);
|
||||||
|
|||||||
@@ -30,14 +30,19 @@
|
|||||||
#include "buffer.cpp"
|
#include "buffer.cpp"
|
||||||
#include "view.cpp"
|
#include "view.cpp"
|
||||||
#include "window.cpp"
|
#include "window.cpp"
|
||||||
|
#include "window_command.cpp"
|
||||||
|
#include "window_debug.cpp"
|
||||||
|
#include "window_status.cpp"
|
||||||
|
#include "window_search.cpp"
|
||||||
|
|
||||||
#include "process.cpp"
|
#include "process.cpp"
|
||||||
#include "event.cpp"
|
#include "event.cpp"
|
||||||
#include "parser.cpp"
|
#include "parser.cpp"
|
||||||
|
|
||||||
|
|
||||||
#include "commands.cpp"
|
#include "commands.cpp"
|
||||||
#include "lua_api.cpp"
|
#include "lua_api.cpp"
|
||||||
#include "commands_clipboard.cpp"
|
#include "commands_clipboard.cpp"
|
||||||
#include "title_bar.cpp"
|
|
||||||
|
|
||||||
#include "generated_config.cpp"
|
#include "generated_config.cpp"
|
||||||
|
|
||||||
@@ -390,18 +395,11 @@ void OnCommand(Event event) {
|
|||||||
|
|
||||||
BSet main = GetBSet(LastActiveLayoutWindowID);
|
BSet main = GetBSet(LastActiveLayoutWindowID);
|
||||||
BSet active = GetBSet(ActiveWindowID);
|
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) {
|
For (CommandFunctions) {
|
||||||
if (it.trigger && MatchEvent(it.trigger, &event)) {
|
if (it.trigger && MatchEvent(it.trigger, &event)) {
|
||||||
it.function();
|
it.function();
|
||||||
if (SkipRemainingCommands) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,42 +412,15 @@ void OnCommand(Event event) {
|
|||||||
String16 string16 = ToString16(scratch, event.text);
|
String16 string16 = ToString16(scratch, event.text);
|
||||||
Replace(active.view, string16);
|
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() {
|
void GarbageCollect() {
|
||||||
Allocator sys_allocator = GetSystemAllocator();
|
Allocator sys_allocator = GetSystemAllocator();
|
||||||
|
|
||||||
|
For (Views) {
|
||||||
|
IF_DEBUG(AssertRanges(it->carets));
|
||||||
|
}
|
||||||
|
|
||||||
For (Windows) {
|
For (Windows) {
|
||||||
if (it->sync_visibility_with_focus) {
|
if (it->sync_visibility_with_focus) {
|
||||||
if (it->id == ActiveWindowID) {
|
if (it->id == ActiveWindowID) {
|
||||||
@@ -535,11 +506,12 @@ void Update(Event event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnCommand(event);
|
OnCommand(event);
|
||||||
|
StatusWindowUpdate();
|
||||||
|
DebugWindowUpdate();
|
||||||
|
CommandWindowUpdate();
|
||||||
UpdateProcesses();
|
UpdateProcesses();
|
||||||
CoUpdate(&event);
|
CoUpdate(&event);
|
||||||
ReloadLuaConfigs();
|
ReloadLuaConfigs();
|
||||||
StatusBarUpdate();
|
|
||||||
UpdateDebugBuffer();
|
|
||||||
CallLuaOnUpdate(&event);
|
CallLuaOnUpdate(&event);
|
||||||
GarbageCollect();
|
GarbageCollect();
|
||||||
|
|
||||||
@@ -576,7 +548,7 @@ void Windows_SetupVCVarsall(mco_coro *co) {
|
|||||||
String s = Trim(it);
|
String s = Trim(it);
|
||||||
Array<String> values = Split(scratch, s, "=");
|
Array<String> values = Split(scratch, s, "=");
|
||||||
if (values.len == 1) continue;
|
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
|
#if !OS_WINDOWS
|
||||||
for (int i = 0; environ[i]; i += 1) {
|
for (int i = 0; environ[i]; i += 1) {
|
||||||
Add(&Enviroment, Copy(Perm, environ[i]));
|
Add(&ProcessEnviroment, Copy(Perm, environ[i]));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ struct BSet {
|
|||||||
View *view;
|
View *view;
|
||||||
Buffer *buffer;
|
Buffer *buffer;
|
||||||
};
|
};
|
||||||
|
BSet GetBSet(struct Window *window);
|
||||||
|
BSet GetBSet(WindowID window_id);
|
||||||
|
|
||||||
|
|
||||||
// @WARNING: be careful about using this, should only be used for debugging
|
// @WARNING: be careful about using this, should only be used for debugging
|
||||||
// the problem with this is that we want events to be reproducible.
|
// 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);
|
View *CreateView(BufferID active_buffer);
|
||||||
void ReopenBuffer(Buffer *buffer);
|
void ReopenBuffer(Buffer *buffer);
|
||||||
inline Buffer *FindBuffer(String name);
|
inline Buffer *FindBuffer(String name);
|
||||||
|
bool ProcessIsActive(ViewID view);
|
||||||
|
|
||||||
inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
|
inline bool operator==(BufferID a, BufferID b) { return a.id == b.id; }
|
||||||
inline bool operator==(ViewID a, ViewID 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;
|
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;
|
Caret main_caret_on_begin_frame;
|
||||||
bool update_scroll;
|
bool update_scroll;
|
||||||
|
|
||||||
bool fuzzy_search;
|
|
||||||
String16 prev_search_line;
|
String16 prev_search_line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -109,80 +109,10 @@ void InitWindows() {
|
|||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
|
|
||||||
CreateWind();
|
CreateWind();
|
||||||
CreateWind();
|
CommandWindowInit();
|
||||||
|
SearchWindowInit();
|
||||||
// COMMAND BAR
|
StatusWindowInit();
|
||||||
{
|
DebugWindowInit();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalcNiceties(Window *n) {
|
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) {
|
void LayoutWindows(int16_t wx, int16_t wy) {
|
||||||
Rect2I screen_rect = RectI0Size(wx, wy);
|
Rect2I screen_rect = RectI0Size(wx, wy);
|
||||||
|
|
||||||
// Command bar
|
CommandWindowLayout(&screen_rect, wx, wy);
|
||||||
{
|
SearchWindowLayout(&screen_rect, wx, wy);
|
||||||
Window *n = GetWindow(CommandBarWindowID);
|
StatusWindowLayout(&screen_rect, wx, wy);
|
||||||
Rect2I *rect = &screen_rect;
|
DebugWindowLayout(&screen_rect, wx, wy);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Column layout
|
// Column layout
|
||||||
Int c = 0;
|
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; }
|
||||||
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);
|
Buffer *buffer = GetBuffer(DebugBufferID);
|
||||||
|
|
||||||
Window *window = GetActiveWind();
|
Window *window = GetActiveWind();
|
||||||
@@ -41,74 +72,7 @@ void UpdateDebugBuffer() {
|
|||||||
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage);
|
RawAppendf(buffer, "int garbage = %d\n", main.buffer->garbage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusBarUpdate() {
|
void Command_ToggleDebug() {
|
||||||
Window *status_bar_window = GetWindow(StatusBarWindowID, NULL);
|
Window *window = GetWindow(DebugWindowID);
|
||||||
if (status_bar_window == NULL) {
|
window->visible = !window->visible;
|
||||||
return;
|
} RegisterCommand(Command_ToggleDebug, "ctrl-0");
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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