From ce13f83d46c449bd13c4223c86ce7cf736b9a7ee Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Mon, 1 Jul 2024 15:13:23 +0200 Subject: [PATCH] Multicursor clipboard --- src/text_editor/clipboard.cpp | 62 +++++++++++++++++++++++++++++++++++ src/text_editor/layout.cpp | 14 +++++--- src/text_editor/main.cpp | 43 +++++------------------- 3 files changed, 80 insertions(+), 39 deletions(-) create mode 100644 src/text_editor/clipboard.cpp diff --git a/src/text_editor/clipboard.cpp b/src/text_editor/clipboard.cpp new file mode 100644 index 0000000..0e4547c --- /dev/null +++ b/src/text_editor/clipboard.cpp @@ -0,0 +1,62 @@ +String SavedClipboardString; +Array SavedClipboardCursors; + +void CopyToClipboard(Window *window) { + Allocator sys_allocator = GetSystemAllocator(); + + SavedClipboardCursors.allocator = sys_allocator; + if (SavedClipboardCursors.data) { + For(SavedClipboardCursors) Dealloc(sys_allocator, &it.data); + SavedClipboardCursors.clear(); + } + + if (SavedClipboardString.data) { + Dealloc(sys_allocator, &SavedClipboardString.data); + SavedClipboardString = {}; + } + + // First, if there is no selection - select the entire line + For(window->cursors) { + if (GetRangeSize(it.range) == 0) { + Line line = FindLine(window->buffer, it.range.min); + it.range = line.range; + } + } + + For(window->cursors) { + String string = GetString(window->buffer, it.range); + String copy = Copy(sys_allocator, string); + SavedClipboardCursors.add(copy); + } + + // @todo: maybe only add new line if there is no new line at the end, experiment with it + SavedClipboardString = Merge(sys_allocator, SavedClipboardCursors, "\n"); + SetClipboardText(SavedClipboardString.data); +} + +void PasteFromClipboard(Window *window) { + Scratch scratch; + const char *text = GetClipboardText(); + String string = text; + + // Regular paste + if (string != SavedClipboardString || SavedClipboardCursors.len != window->cursors.len) { + BeforeEdit(window); + Array edits = {scratch}; + For(window->cursors) AddEdit(&edits, it.range, string); + ApplyEdits(window, edits); + AfterEdit(window, edits); + return; + } + + // Multicursor paste + BeforeEdit(window); + Array edits = {scratch}; + for (int64_t i = 0; i < window->cursors.len; i += 1) { + String string = SavedClipboardCursors[i]; + Cursor &it = window->cursors[i]; + AddEdit(&edits, it.range, string); + } + ApplyEdits(window, edits); + AfterEdit(window, edits); +} \ No newline at end of file diff --git a/src/text_editor/layout.cpp b/src/text_editor/layout.cpp index 52faed9..f7c6b14 100644 --- a/src/text_editor/layout.cpp +++ b/src/text_editor/layout.cpp @@ -379,12 +379,16 @@ void BeforeEdit(Window *window) { window->history.debug_edit_phase += 1; Assert(window->cursors.len); SaveHistoryBeforeMergeCursor(window, &window->history.undo_stack); - For(window->history.redo_stack) { - it.cursors.dealloc(); - ForItem(edit, it.edits) Dealloc(it.edits.allocator, &edit.string.data); - it.edits.dealloc(); + + // Clear redo stack + { + For(window->history.redo_stack) { + it.cursors.dealloc(); + ForItem(edit, it.edits) Dealloc(it.edits.allocator, &edit.string.data); + it.edits.dealloc(); + } + window->history.redo_stack.dealloc(); } - window->history.redo_stack.dealloc(); MergeCursors(window); } diff --git a/src/text_editor/main.cpp b/src/text_editor/main.cpp index f3ef322..237d380 100644 --- a/src/text_editor/main.cpp +++ b/src/text_editor/main.cpp @@ -3,12 +3,14 @@ #include "raylib.h" #include "raymath.h" -// @todo: add history (undo, redo) // @todo: add clipboard history? // @todo: mouse double click +// @todo: context menu +// @todo: toy around with acme ideas #include "rect2.cpp" #include "buffer.cpp" #include "layout.cpp" +#include "clipboard.cpp" #include "utils.cpp" #include "event_recording.cpp" @@ -85,6 +87,7 @@ int main() { int64_t frame = -1; InitEventRecording(); while (!WindowShouldClose()) { + Clear(&FrameArena); For(windows) { Assert(it.cursors.len); it.main_cursor_begin_frame = it.cursors[0]; @@ -272,46 +275,18 @@ int main() { } } - // @todo: improve behaviour of all copy pasting if (IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)) { - Array strings = {FrameArena}; - For(focused_window->cursors) { - String string = GetString(focused_window->buffer, it.range); - strings.add(string); - } - String to_save = Merge(FrameArena, strings, "\n"); - SetClipboardText(to_save.data); + CopyToClipboard(focused_window); } if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_V) || IsKeyPressedRepeat(KEY_V))) { - BeforeEdit(focused_window); - Array edits = {FrameArena}; - const char *text = GetClipboardText(); - String string = text; - For(focused_window->cursors) { - AddEdit(&edits, it.range, string); - } - ApplyEdits(focused_window, edits); - AfterEdit(focused_window, edits); + PasteFromClipboard(focused_window); } if (IsKeyDown(KEY_LEFT_CONTROL) && (IsKeyPressed(KEY_X) || IsKeyPressedRepeat(KEY_X))) { - // First, if there is no selection - select the entire line - For(focused_window->cursors) { - if (GetRangeSize(it.range) == 0) { - Line line = FindLine(focused_window->buffer, it.range.min); - it.range = line.range; - } - } + CopyToClipboard(focused_window); BeforeEdit(focused_window); - Array edits = {FrameArena}; - Array strings = {FrameArena}; - For(focused_window->cursors) { - AddEdit(&edits, it.range, ""); - String string = GetString(focused_window->buffer, it.range); - strings.add(string); - } - String to_save = Merge(FrameArena, strings, "\n"); - SetClipboardText(to_save.data); + Array edits = {FrameArena}; + For(focused_window->cursors) AddEdit(&edits, it.range, ""); ApplyEdits(focused_window, edits); AfterEdit(focused_window, edits); }