diff --git a/src/text_editor/buffer_history.cpp b/src/text_editor/buffer_history.cpp index 3e29c25..15d17a0 100644 --- a/src/text_editor/buffer_history.cpp +++ b/src/text_editor/buffer_history.cpp @@ -104,7 +104,7 @@ void AfterEdit(Buffer *buffer, Array *edits, Array *carets) { buffer->debug_edit_phase -= 2; HistoryEntry *entry = GetLast(buffer->undo_stack); -#if 1 +#if BUFFER_DEBUG Assert(entry->carets.len); Assert(entry->edits.len); for (Int i = 0; i < edits->len - 1; i += 1) { @@ -133,8 +133,4 @@ void AfterEdit(Buffer *buffer, Array *edits, Array *carets) { } } for (Int i = 0; i < carets->len; i += 1) carets->data[i] = new_carets[i]; - - // Make sure all carets are in range - // @todo: remove? - For(*carets) it.range = Clamp(*buffer, it.range); } diff --git a/src/text_editor/string16.cpp b/src/text_editor/string16.cpp index e025131..964d90c 100644 --- a/src/text_editor/string16.cpp +++ b/src/text_editor/string16.cpp @@ -49,3 +49,28 @@ bool AreEqual(String16 a, String16 b, unsigned ignore_case = false) { } inline bool operator==(String16 a, String16 b) { return AreEqual(a, b); } inline bool operator!=(String16 a, String16 b) { return !AreEqual(a, b); } + +String16 Merge(Allocator allocator, Array list, String16 separator = " ") { + int64_t char_count = 0; + For(list) char_count += it.len; + if (char_count == 0) return {}; + int64_t node_count = list.len; + + int64_t base_size = (char_count + 1); + int64_t sep_size = (node_count - 1) * separator.len; + int64_t size = base_size + sep_size; + wchar_t *buff = (wchar_t *)AllocSize(allocator, sizeof(wchar_t) * (size + 1)); + String16 string = {buff, 0}; + For(list) { + Assert(string.len + it.len <= size); + memcpy(string.data + string.len, it.data, it.len * sizeof(wchar_t)); + string.len += it.len; + if (!IsLast(list, it)) { + memcpy(string.data + string.len, separator.data, separator.len * sizeof(wchar_t)); + string.len += separator.len; + } + } + Assert(string.len == size - 1); + string.data[size] = 0; + return string; +} diff --git a/src/text_editor/text_editor.cpp b/src/text_editor/text_editor.cpp index 22d8e40..0b19eb2 100644 --- a/src/text_editor/text_editor.cpp +++ b/src/text_editor/text_editor.cpp @@ -22,13 +22,12 @@ #include "colors.cpp" #include "view.h" +#include "view_commands_clipboard.cpp" #include "view_commands.cpp" #include "view_draw.cpp" /* -- Ctrl + Z, Ctrl + C - Undo redo history - Ctrl + D - create new cursor at next occurence of word -- Ctrl + X, Ctrl + C, Ctrl + V - Copy paste - Scrollbars - Line numbers - file info bar at bottom (line, column, line endings) diff --git a/src/text_editor/view_commands.cpp b/src/text_editor/view_commands.cpp index b2cf5e9..7fa3c7d 100644 --- a/src/text_editor/view_commands.cpp +++ b/src/text_editor/view_commands.cpp @@ -222,6 +222,15 @@ void HandleKeybindings(View *_view) { UndoEdit(&buf, &view.carets); } + if (CtrlPress(KEY_C)) { + Command_Copy(&view); + } else if (CtrlPress(KEY_V)) { + Command_Paste(&view); + } else if (CtrlPress(KEY_X)) { + Command_Copy(&view); + Command_Replace(&view, L""); + } + if (ShiftPress(KEY_PAGE_UP)) { Command_MoveCursorsByPageSize(&view, DIR_UP, SHIFT_PRESSED); } else if (Press(KEY_PAGE_UP)) { diff --git a/src/text_editor/view_commands_clipboard.cpp b/src/text_editor/view_commands_clipboard.cpp new file mode 100644 index 0000000..f907e01 --- /dev/null +++ b/src/text_editor/view_commands_clipboard.cpp @@ -0,0 +1,67 @@ +String16 SavedClipboardString; +Array SavedClipboardCursors; + +void Command_Copy(View *view) { + Allocator sys_allocator = GetSystemAllocator(); + + SavedClipboardCursors.allocator = sys_allocator; + if (SavedClipboardCursors.data) { + For(SavedClipboardCursors) Dealloc(sys_allocator, &it.data); + SavedClipboardCursors.len = 0; + } + + if (SavedClipboardString.data) { + Dealloc(sys_allocator, &SavedClipboardString.data); + SavedClipboardString = {}; + } + + // First, if there is no selection - select the entire line + For(view->carets) { + if (GetSize(it.range) == 0) { + Int line = PosToLine(*view->buffer, it.range.min); + Range line_range = GetLineRange(*view->buffer, line); + it.range = line_range; + } + } + + For(view->carets) { + String16 string = GetString(*view->buffer, it.range); + String16 copy = Copy(sys_allocator, string); + Add(&SavedClipboardCursors, copy); + } + + // @todo: maybe only add new line if there is no new line at the end, experiment with it + SavedClipboardString = Merge(sys_allocator, SavedClipboardCursors, L"\n"); + Scratch scratch; + SetClipboardText(ToString(scratch, SavedClipboardString).data); +} + +void Command_Paste(View *view) { + Scratch scratch; + const char *text = GetClipboardText(); + String string_ = text; + String16 string = ToString16(scratch, string_); + + // Regular paste + if (string != SavedClipboardString || SavedClipboardCursors.len != view->carets.len) { + BeforeEdit(view->buffer, view->carets); + MergeCarets(&view->carets); + Array edits = {scratch}; + For(view->carets) AddEdit(&edits, it.range, string); + ApplyEdits(view->buffer, edits); + AfterEdit(view->buffer, &edits, &view->carets); + return; + } + + // Multicursor paste + BeforeEdit(view->buffer, view->carets); + MergeCarets(&view->carets); + Array edits = {scratch}; + for (int64_t i = 0; i < view->carets.len; i += 1) { + String16 string = SavedClipboardCursors[i]; + Caret &it = view->carets[i]; + AddEdit(&edits, it.range, string); + } + ApplyEdits(view->buffer, edits); + AfterEdit(view->buffer, &edits, &view->carets); +} \ No newline at end of file