Windows refactor and moving things around

This commit is contained in:
Krzosa Karol
2025-12-20 18:17:28 +01:00
parent f637352669
commit 266378154a
16 changed files with 865 additions and 898 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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};

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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; }

View File

@@ -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);
}
}

View File

@@ -11,7 +11,6 @@ struct View {
Caret main_caret_on_begin_frame;
bool update_scroll;
bool fuzzy_search;
String16 prev_search_line;
};

View File

@@ -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 = &copy_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 = &copy_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 = &copy_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;

View File

@@ -48,3 +48,16 @@ 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);
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);

View 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 = &copy_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);
}
}

View File

@@ -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");

View 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 = &copy_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");

View 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 = &copy_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);
}