From 03b6b8056813d86f8785ca8562f810774ce95cef Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Fri, 2 Aug 2024 21:16:46 +0200 Subject: [PATCH] Indent selected lines --- src/text_editor/buffer_history.cpp | 17 ++- src/text_editor/commands_window.cpp | 192 +++++++--------------------- src/text_editor/text_editor.cpp | 1 + src/text_editor/title_bar.cpp | 144 +++++++++++++++++++++ src/text_editor/todo.txt | 1 + 5 files changed, 205 insertions(+), 150 deletions(-) create mode 100644 src/text_editor/title_bar.cpp diff --git a/src/text_editor/buffer_history.cpp b/src/text_editor/buffer_history.cpp index 4b73f74..4898f20 100644 --- a/src/text_editor/buffer_history.cpp +++ b/src/text_editor/buffer_history.cpp @@ -102,7 +102,8 @@ void BeforeEdit(Buffer *buffer, Array &carets) { ClearRedoStack(buffer); } -void AfterEdit(Buffer *buffer, Array *edits, Array *carets) { +bool KILL_SELECTION = true; +void AfterEdit(Buffer *buffer, Array *edits, Array *carets, bool kill_selection = true) { ProfileFunction(); Assert(buffer->debug_edit_phase == 2); buffer->debug_edit_phase -= 2; @@ -132,11 +133,19 @@ void AfterEdit(Buffer *buffer, Array *edits, Array *carets) { Caret &old_cursor = carets->data[i]; Caret &new_cursor = new_carets.data[i]; if (old_cursor.range.min == edit.range.min) { - new_cursor.range.min = new_cursor.range.max = new_cursor.range.min + insert_size; + new_cursor.range.min += insert_size; + new_cursor.range.max += insert_size; } else if (old_cursor.range.min > edit.range.min) { - new_cursor.range.min = new_cursor.range.max = new_cursor.range.min + offset; + new_cursor.range.min += offset; + new_cursor.range.max += offset; } } } - for (Int i = 0; i < carets->len; i += 1) carets->data[i] = new_carets[i]; + + for (Int i = 0; i < carets->len; i += 1) { + carets->data[i] = new_carets[i]; + if (kill_selection) { + carets->data[i].range.max = carets->data[i].range.min; + } + } } diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 4617bad..1fa0b3c 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -31,6 +31,49 @@ void Command_DuplicateLine(View *view, int direction) { For(view->carets) it = MakeCaret(MovePos(*buffer, it.range.min, direction, false)); } +void Command_IndentSelectedLines(View *view) { + Scratch scratch; + Buffer *buffer = GetBuffer(view->active_buffer); + + BeforeEdit(buffer, view->carets); + MergeCarets(view); + + Array caret_copy = TightCopy(scratch, view->carets); + Array temp = TightCopy(scratch, view->carets); + MergeSort(view->carets.len, caret_copy.data, temp.data); + + Array line_ranges_to_indent = {scratch}; + 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}; + + if (line_ranges_to_indent.len == 0) { + Add(&line_ranges_to_indent, line_range); + continue; + } + + Range *last = GetLast(line_ranges_to_indent); + if (AreOverlapping(*last, line_range)) { + last->max = Max(last->max, line_range.max); + } else { + Add(&line_ranges_to_indent, line_range); + } + } + + Array edits = {scratch}; + For(line_ranges_to_indent) { + for (Int i = it.min; i <= it.max; i += 1) { + Range pos_range_of_line = GetLineRange(*buffer, i); + AddEdit(&edits, {pos_range_of_line.min, pos_range_of_line.min}, L" "); + } + } + + ApplyEdits(buffer, edits); + AfterEdit(buffer, &edits, &view->carets, !KILL_SELECTION); + view->update_scroll = false; +} + bool SHIFT_PRESSED = true; void Command_MoveCursorsByPageSize(Window *window, int direction, bool shift = false) { Assert(direction == DIR_UP || direction == DIR_DOWN); @@ -179,6 +222,7 @@ void Command_EvalLua(View *view, String16 string) { // make sure overlapping edits won't happen. // // mouse_selection_anchor is special case for mouse handling ! + void MergeCarets(View *view, Range *mouse_selection_anchor) { ProfileFunction(); @@ -210,151 +254,6 @@ void MergeCarets(View *view, Range *mouse_selection_anchor) { Swap(&view->carets[first_caret_index], &view->carets[0]); } -String DebugViewList(Allocator allocator) { - Scratch scratch((Arena *)allocator.object); - Array strings = {scratch}; - For(Views) { - Buffer *buffer = GetBuffer(it.active_buffer); - String string = Format(scratch, "view = %lld buffer = %lld name = %.*s", (long long)it.id.id, (long long)buffer->id.id, FmtString(buffer->name)); - Add(&strings, string); - } - String result = Merge(allocator, strings, "\n"); - return result; -} - -String DebugWindowList(Allocator allocator) { - Scratch scratch((Arena *)allocator.object); - Array strings = {scratch}; - For(Windows) { - View *view = GetActiveView(&it); - Buffer *buffer = GetBuffer(view->active_buffer); - String string = Format(scratch, "window = %lld active_view = %lld buffer_name = %.*s", (long long)it.id.id, (long long)it.active_view.id, FmtString(buffer->name)); - Add(&strings, string); - } - String result = Merge(allocator, strings, "\n"); - return result; -} - -void ReplaceDebugData() { - Buffer *buffer = GetBuffer("*debug*"); - - Window *window = GetActiveWindow(); - View *view = GetActiveView(window); - if (view->active_buffer.id == buffer->id.id) return; - - Window *last_window = GetWindow(GetLastActiveWindow()); - View *last_view = GetActiveView(last_window); - Buffer *last_buffer = GetBuffer(last_view->active_buffer); - - Scratch scratch; - String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)last_window->id.id, (int)last_view->id.id, (int)last_buffer->id.id, (long long)FrameID); - String16 string = ToString16(scratch, s); - ReplaceText(buffer, GetRange(*buffer), string); - - String view_list = DebugViewList(scratch); - Append(buffer, ToString16(scratch, view_list)); - Append(buffer, L"\n"); - - String window_list = DebugWindowList(scratch); - Append(buffer, ToString16(scratch, window_list)); -} - -void ApplyTitleBarChangesToWindow(Window *window, View *view, Buffer *buffer) { - String16 buffer_string = GetString(*buffer); - Range replace_range = {0, buffer->len}; - if (Seek(buffer_string, L" |", &replace_range.max)) { - } - buffer_string = GetString(*buffer, replace_range); - buffer_string = Trim(buffer_string); - - String16 col = {}; - for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { - if (IsDigit(buffer_string.data[i])) { - col.data = buffer_string.data + i; - col.len += 1; - } else if (buffer_string.data[i] == L':') { - break; - } else { - return; - } - } - buffer_string = Chop(buffer_string, col.len + 1); - - String16 line = {}; - for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { - if (IsDigit(buffer_string.data[i])) { - line.data = buffer_string.data + i; - line.len += 1; - } else if (buffer_string.data[i] == L':') { - break; - } else { - return; - } - } - buffer_string = Chop(buffer_string, line.len + 1); - - Window *last_window = GetWindow(window->title_bar_window); - View *last_view = GetActiveView(last_window); - Buffer *last_buffer = GetBuffer(last_view->active_buffer); - Scratch scratch; - - String filepath = ToString(scratch, buffer_string); - if (filepath != last_buffer->name && !BufferNameExists(filepath)) { - // @todo: maybe intern the filenames? - // @leak - last_buffer->name = Copy(Perm, filepath); - } - - String line_string = ToString(scratch, line); - String col_string = ToString(scratch, col); - Int linei = strtoll(line_string.data, NULL, 10) - 1; - Int coli = strtoll(col_string.data, NULL, 10) - 1; - Int buffer_pos = XYToPos(*last_buffer, {coli, linei}); - - Caret &caret = last_view->carets[0]; - if (GetFront(caret) != buffer_pos) { - caret = MakeCaret(buffer_pos); - } - - window->title_bar_last_buffer_change_id = buffer->change_id; -} - -void ReplaceTitleBarData(Window *window) { - View *view = GetView(window->active_view); - view->scroll.y = 0; - Buffer *buffer = GetBuffer(view->active_buffer); - if (IsActive(window)) { - if (buffer->change_id != window->title_bar_last_buffer_change_id) { - ApplyTitleBarChangesToWindow(window, view, buffer); - } - return; - } - - Window *last_window = GetWindow(window->title_bar_window); - View *last_view = GetActiveView(last_window); - Buffer *last_buffer = GetBuffer(last_view->active_buffer); - Scratch scratch; - Caret caret = last_view->carets[0]; - XY xy = PosToXY(*last_buffer, GetFront(caret)); - String name = last_buffer->name; - - String16 buffer_string = GetString(*buffer); - Range replace_range = {0, buffer->len}; - if (!Seek(buffer_string, L" |", &replace_range.max)) { - Command_SelectRangeOneCursor(view, GetEndAsRange(*buffer)); - Command_Replace(view, L" |"); - } - - String s = Format(scratch, "%.*s:%lld:%lld", FmtString(last_buffer->name), (long long)xy.line + 1ll, (long long)xy.col + 1ll); - String16 string = ToString16(scratch, s); - String16 string_to_replace = GetString(*buffer, replace_range); - if (string_to_replace != string) { - Command_SelectRangeOneCursor(view, replace_range); - Command_Replace(view, string); - Command_SelectRangeOneCursor(view, {}); - } -} - void WindowCommand(Event event, Window *window, View *view) { ProfileFunction(); Buffer *buffer = GetBuffer(view->active_buffer); @@ -503,7 +402,8 @@ void WindowCommand(Event event, Window *window, View *view) { bool search = false; if (Press(SDLK_TAB)) { - Command_Replace(view, L" "); + // Command_Replace(view, L" "); + Command_IndentSelectedLines(view); search = true; } diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index fab6653..4048c88 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -35,6 +35,7 @@ int FullScreenPositionX, FullScreenPositionY; #include "commands.cpp" #include "commands_clipboard.cpp" #include "commands_window.cpp" +#include "title_bar.cpp" #include "lua.hpp" #include "lua_api.cpp" diff --git a/src/text_editor/title_bar.cpp b/src/text_editor/title_bar.cpp new file mode 100644 index 0000000..efa856d --- /dev/null +++ b/src/text_editor/title_bar.cpp @@ -0,0 +1,144 @@ +String DebugViewList(Allocator allocator) { + Scratch scratch((Arena *)allocator.object); + Array strings = {scratch}; + For(Views) { + Buffer *buffer = GetBuffer(it.active_buffer); + String string = Format(scratch, "view = %lld buffer = %lld name = %.*s", (long long)it.id.id, (long long)buffer->id.id, FmtString(buffer->name)); + Add(&strings, string); + } + String result = Merge(allocator, strings, "\n"); + return result; +} + +String DebugWindowList(Allocator allocator) { + Scratch scratch((Arena *)allocator.object); + Array strings = {scratch}; + For(Windows) { + View *view = GetActiveView(&it); + Buffer *buffer = GetBuffer(view->active_buffer); + String string = Format(scratch, "window = %lld active_view = %lld buffer_name = %.*s", (long long)it.id.id, (long long)it.active_view.id, FmtString(buffer->name)); + Add(&strings, string); + } + String result = Merge(allocator, strings, "\n"); + return result; +} + +void ReplaceDebugData() { + Buffer *buffer = GetBuffer("*debug*"); + + Window *window = GetActiveWindow(); + View *view = GetActiveView(window); + if (view->active_buffer.id == buffer->id.id) return; + + Window *last_window = GetWindow(GetLastActiveWindow()); + View *last_view = GetActiveView(last_window); + Buffer *last_buffer = GetBuffer(last_view->active_buffer); + + Scratch scratch; + String s = Format(scratch, "wid: %d\nvid: %d\nbid: %d\nframe: %lld\n", (int)last_window->id.id, (int)last_view->id.id, (int)last_buffer->id.id, (long long)FrameID); + String16 string = ToString16(scratch, s); + ReplaceText(buffer, GetRange(*buffer), string); + + String view_list = DebugViewList(scratch); + Append(buffer, ToString16(scratch, view_list)); + Append(buffer, L"\n"); + + String window_list = DebugWindowList(scratch); + Append(buffer, ToString16(scratch, window_list)); +} + +void ApplyTitleBarChangesToWindow(Window *window, View *view, Buffer *buffer) { + String16 buffer_string = GetString(*buffer); + Range replace_range = {0, buffer->len}; + if (Seek(buffer_string, L" |", &replace_range.max)) { + } + buffer_string = GetString(*buffer, replace_range); + buffer_string = Trim(buffer_string); + + String16 col = {}; + for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { + if (IsDigit(buffer_string.data[i])) { + col.data = buffer_string.data + i; + col.len += 1; + } else if (buffer_string.data[i] == L':') { + break; + } else { + return; + } + } + buffer_string = Chop(buffer_string, col.len + 1); + + String16 line = {}; + for (int64_t i = buffer_string.len - 1; i >= 0; i -= 1) { + if (IsDigit(buffer_string.data[i])) { + line.data = buffer_string.data + i; + line.len += 1; + } else if (buffer_string.data[i] == L':') { + break; + } else { + return; + } + } + buffer_string = Chop(buffer_string, line.len + 1); + + Window *last_window = GetWindow(window->title_bar_window); + View *last_view = GetActiveView(last_window); + Buffer *last_buffer = GetBuffer(last_view->active_buffer); + Scratch scratch; + + String filepath = ToString(scratch, buffer_string); + if (filepath != last_buffer->name && !BufferNameExists(filepath)) { + // @todo: maybe intern the filenames? + // @leak + last_buffer->name = Copy(Perm, filepath); + } + + String line_string = ToString(scratch, line); + String col_string = ToString(scratch, col); + Int linei = strtoll(line_string.data, NULL, 10) - 1; + Int coli = strtoll(col_string.data, NULL, 10) - 1; + Int buffer_pos = XYToPos(*last_buffer, {coli, linei}); + + Caret &caret = last_view->carets[0]; + if (GetFront(caret) != buffer_pos) { + caret = MakeCaret(buffer_pos); + } + + window->title_bar_last_buffer_change_id = buffer->change_id; +} + +void ReplaceTitleBarData(Window *window) { + View *view = GetView(window->active_view); + view->scroll.y = 0; + Buffer *buffer = GetBuffer(view->active_buffer); + if (IsActive(window)) { + if (buffer->change_id != window->title_bar_last_buffer_change_id) { + ApplyTitleBarChangesToWindow(window, view, buffer); + } + return; + } + + Window *last_window = GetWindow(window->title_bar_window); + View *last_view = GetActiveView(last_window); + Buffer *last_buffer = GetBuffer(last_view->active_buffer); + Scratch scratch; + Caret caret = last_view->carets[0]; + XY xy = PosToXY(*last_buffer, GetFront(caret)); + String name = last_buffer->name; + + String16 buffer_string = GetString(*buffer); + Range replace_range = {0, buffer->len}; + if (!Seek(buffer_string, L" |", &replace_range.max)) { + Command_SelectRangeOneCursor(view, GetEndAsRange(*buffer)); + Command_Replace(view, L" |"); + } + + String s = Format(scratch, "%.*s:%lld:%lld", FmtString(last_buffer->name), (long long)xy.line + 1ll, (long long)xy.col + 1ll); + String16 string = ToString16(scratch, s); + String16 string_to_replace = GetString(*buffer, replace_range); + if (string_to_replace != string) { + Command_SelectRangeOneCursor(view, replace_range); + Command_Replace(view, string); + Command_SelectRangeOneCursor(view, {}); + } +} \ No newline at end of file diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index cf205ec..0c7f30b 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -19,6 +19,7 @@ - be careful about globals - Windows + - layout using a tree!! - search as part of title window? - layouting, resize windows - maybe we can use first line number to use the window?