From 7f85f8348eb0bddb73b13e19acf904b475b19202 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 3 Aug 2024 10:30:35 +0200 Subject: [PATCH] Trim whitespace on save and skip lines with cursor --- build_file.cpp | 1 + src/text_editor/commands_window.cpp | 95 ++++++++++++++++++------- src/text_editor/generated.cpp | 2 + src/text_editor/generated_variables.cpp | 3 +- src/text_editor/todo.txt | 4 +- 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/build_file.cpp b/build_file.cpp index 0ce3c63..a6536fe 100644 --- a/build_file.cpp +++ b/build_file.cpp @@ -398,6 +398,7 @@ void GenerateConfig() { style.add({"DrawLineNumbers", "1"}); style.add({"DrawScrollbar", "1"}); style.add({"IndentSize", "2"}); + style.add({"TrimWhitespaceOnSave", "1"}); { MA_Scratch scratch; diff --git a/src/text_editor/commands_window.cpp b/src/text_editor/commands_window.cpp index 2bb1500..6237b43 100644 --- a/src/text_editor/commands_window.cpp +++ b/src/text_editor/commands_window.cpp @@ -31,6 +31,34 @@ void Command_DuplicateLine(View *view, int direction) { For(view->carets) it = MakeCaret(MovePos(*buffer, it.range.min, direction, false)); } +Array GetSortedSelectedLines(Allocator allocator, View *view) { + Scratch scratch(allocator); + Buffer *buffer = GetBuffer(view->active_buffer); + Array caret_copy = TightCopy(scratch, view->carets); + Array temp = TightCopy(scratch, view->carets); + MergeSort(view->carets.len, caret_copy.data, temp.data); + + Array 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 Command_IndentSelectedLines(View *view, bool shift = false) { Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); @@ -38,32 +66,10 @@ void Command_IndentSelectedLines(View *view, bool shift = false) { 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}; + Array line_ranges_to_indent = GetSortedSelectedLines(scratch, view); + Array edits = {scratch}; For(line_ranges_to_indent) { - for (Int i = it.min; i <= it.max; i += 1) { + for (Int i = it.min; i < it.max; i += 1) { Range pos_range_of_line = GetLineRange(*buffer, i); if (!shift) { @@ -86,15 +92,45 @@ void Command_IndentSelectedLines(View *view, bool shift = false) { view->update_scroll = false; } -void Command_TrimTrailingWhitespace(View *view) { +Int FindRangeByPos(Array &ranges, Int pos) { + // binary search + Int low = 0; + Int high = ranges.len - 1; + Int result = -1; + + while (low <= high) { + Int mid = low + (high - low) / 2; + Range range = ranges[mid]; + if (pos >= range.min && pos < range.max) { + result = mid; + break; + } + + if (range.min < pos) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return result; +} + +void Command_TrimTrailingWhitespace(View *view, bool dont_trim_lines_with_cursor) { Scratch scratch; Buffer *buffer = GetBuffer(view->active_buffer); BeforeEdit(buffer, view->carets); MergeCarets(view); + Array lines_to_skip_triming = {}; + if (dont_trim_lines_with_cursor) lines_to_skip_triming = GetSortedSelectedLines(scratch, view); + Array edits = {scratch}; for (Int i = 0; i < buffer->line_starts.len; i += 1) { + Int range_index = FindRangeByPos(lines_to_skip_triming, i); + if (range_index != -1) continue; + Range range = GetLineRangeWithoutNL(*buffer, i); Int whitespace_end = range.max; for (; whitespace_end > range.min; whitespace_end -= 1) { @@ -448,7 +484,7 @@ void WindowCommand(Event event, Window *window, View *view) { } if (Ctrl(SDLK_W)) { - Command_TrimTrailingWhitespace(view); + Command_TrimTrailingWhitespace(view, false); } if (Ctrl(SDLK_BACKSPACE)) { @@ -570,6 +606,11 @@ void WindowCommand(Event event, Window *window, View *view) { } if (Ctrl(SDLK_S)) { + if (StyleTrimWhitespaceOnSave) { + bool dont_trim_lines_with_cursor = true; + Command_TrimTrailingWhitespace(view, dont_trim_lines_with_cursor); + } + String16 string16 = GetString(*buffer); Scratch scratch; String string = ToString(scratch, string16); diff --git a/src/text_editor/generated.cpp b/src/text_editor/generated.cpp index 91bbdeb..ae454d5 100644 --- a/src/text_editor/generated.cpp +++ b/src/text_editor/generated.cpp @@ -58,6 +58,7 @@ Style = {} Style.DrawLineNumbers = 1 Style.DrawScrollbar = 1 Style.IndentSize = 2 +Style.TrimWhitespaceOnSave = 1 -- @todo: should we rewrite linux paths to windows on windows and vice-versa? @@ -217,4 +218,5 @@ void ReloadStyle() { StyleDrawLineNumbers = GetStyle("DrawLineNumbers", StyleDrawLineNumbers); StyleDrawScrollbar = GetStyle("DrawScrollbar", StyleDrawScrollbar); StyleIndentSize = GetStyle("IndentSize", StyleIndentSize); + StyleTrimWhitespaceOnSave = GetStyle("TrimWhitespaceOnSave", StyleTrimWhitespaceOnSave); } \ No newline at end of file diff --git a/src/text_editor/generated_variables.cpp b/src/text_editor/generated_variables.cpp index 3af8c8d..0677daf 100644 --- a/src/text_editor/generated_variables.cpp +++ b/src/text_editor/generated_variables.cpp @@ -54,4 +54,5 @@ Color ColorTitleBarBackground = GruvboxLight1; Color ColorTitleBarSelection = GruvboxLight3; Int StyleDrawLineNumbers = 1; Int StyleDrawScrollbar = 1; -Int StyleIndentSize = 2; \ No newline at end of file +Int StyleIndentSize = 2; +Int StyleTrimWhitespaceOnSave = 1; \ No newline at end of file diff --git a/src/text_editor/todo.txt b/src/text_editor/todo.txt index 1a93ef7..e1a5688 100644 --- a/src/text_editor/todo.txt +++ b/src/text_editor/todo.txt @@ -4,10 +4,10 @@ - don't trim lines with cursor or selection on it - fix history of ctrl + enter -- option trim trailing whitespace before save and dont' trim on cursor - improve cursor movement, it's too clunky, too much stopping -- kill selected lines - better enclosures +- kill selected lines +- should be able click on title bar of windows which disappear on losing focus - search backwards - load selected string or auto enclosed word when midclick?, ctrl + click, ctrl + e? - experiment with using multiple cursors to select command and it's input