diff --git a/src/core/core.c b/src/core/core.c index a4ced41..87a96d5 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -62,6 +62,7 @@ #include "core_type_info.c" #include "core_hash.c" #include "core_hash_table.c" +#include "core_array.c" #ifndef DONT_INCLUDE_GENERATED_MATH #include "core_math.gen.c" #endif diff --git a/src/core/core.h b/src/core/core.h index 7fc65a1..ae564b7 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -15,3 +15,4 @@ #include "core_platform.h" #include "core_hash_table.h" #include "core_ctx.h" +#include "core_array.h" diff --git a/src/text_editor/core_array.c b/src/core/core_array.c similarity index 53% rename from src/text_editor/core_array.c rename to src/core/core_array.c index 046745c..510d233 100644 --- a/src/text_editor/core_array.c +++ b/src/core/core_array.c @@ -1,63 +1,3 @@ -typedef enum { - alokind_alloc, - alokind_dealloc, -} alokind_t; - -typedef struct alo_t alo_t; -struct alo_t { - void *object; - void *(*proc)(alo_t alo, alokind_t kind, void *ptr, size_t size); -}; - -fn void *arena_alo_proc(alo_t alo, alokind_t kind, void *ptr, size_t size) { - ma_arena_t *ma = alo.object; - if (kind == alokind_alloc) { - return ma_push_size(alo.object, size); - } else if (kind == alokind_dealloc) { - return NULL; - } else_is_invalid; - return NULL; -} - -fn alo_t ma_alo(ma_arena_t *arena) { - return (alo_t){arena, arena_alo_proc}; -} - -fn alo_t ma_temp_alo(ma_temp_t temp) { - return ma_alo(temp.arena); -} - -fn void dealloc(alo_t alo, void *ptr) { - alo.proc(alo, alokind_dealloc, ptr, 0); -} - -fn void *alloc_size(alo_t alo, size_t size) { - return alo.proc(alo, alokind_alloc, NULL, size); -} - -#define alloc_type(alo, type) (type *)alloc_size((aloc), sizeof(type)) -#define alloc_array(alo, type, count) (type *)alloc_size((alo), sizeof(type) * (count)) - -#define array(type) struct { alo_t alo; type *data; i64 len; i64 cap; } -typedef array(void) array_void_t; -typedef array(i64) array_i64_t; - -#define arrisz(x) sizeof((x)->data[0]) -#define arrcst(x) ((array_void_t *)(x)) -#define array_init(a, this, count) (array__init((a), arrcst(this), arrisz(this), (count))) -#define array_add(this, ...) (array__grow(arrcst(this), arrisz(this), 1), (this)->data[(this)->len++] = __VA_ARGS__) -#define array_pop(this) (assert_expr((this)->len > 0), (this)->data[--(this)->len]) -#define array_dealloc(this) (dealloc((this)->alo, (this)->data)) -#define array_addn(this, n) (array__grow(arrcst(this), arrisz(this), (n)), (this)->len += (n), &(this)->data[(this)->len - (n)]) -#define array_insert(this, i, item) (array__insert(arrcst(this), arrisz(this), (i)), (this)->data[(i)] = (item)) -#define array_swapdel(this, i) (assert_expr((i) < (this)->len), (this)->data[(i)] = (this)->data[--(this)->len]) -#define array_del(this, i) (array__del(arrcst(this), arrisz(this), (i), 1)) -#define array_deln(this, i, count) (array__del(arrcst(this), arrisz(this), (i), (count))) -#define array_copy(alo, dst, src) (array__copy((alo), arrcst(dst), (array_void_t *)(src), arrisz(dst))) -#define array_last(x) ((x)->data[(x)->len - 1]) - -#define array_for(type, it, array) for (type *it = (array)->data; it < (array)->data + (array)->len; it += 1) - fn void array__init(alo_t alo, array_void_t *this, size_t item_size, i64 count) { assert(this->data == NULL); this->data = alloc_size(alo, item_size * count); @@ -112,7 +52,7 @@ fn void array__insert(array_void_t *this, size_t item_size, i64 idx) { fn_test void test_array(void) { ma_temp_t scratch = ma_begin_scratch(); { - array_i64_t arr = (array_i64_t){.alo = ma_temp_alo(scratch)}; + array_i64_t arr = (array_i64_t){.alo = malot(scratch)}; for (int i = 0; i < 512; i += 1) { array_add(&arr, i); } @@ -130,7 +70,7 @@ fn_test void test_array(void) { } { - array_i64_t arr = (array_i64_t){.alo = ma_temp_alo(scratch)}; + array_i64_t arr = (array_i64_t){.alo = malot(scratch)}; i64 *i = array_addn(&arr, 10); assert(arr.len == 10 && arr.cap == 16); i64 *j = array_addn(&arr, 2); @@ -140,7 +80,7 @@ fn_test void test_array(void) { } { - array_i64_t arr = (array_i64_t){.alo = ma_temp_alo(scratch)}; + array_i64_t arr = (array_i64_t){.alo = malot(scratch)}; for (int i = 0; i < 512; i += 1) { array_add(&arr, i); } @@ -164,7 +104,7 @@ fn_test void test_array(void) { assert(arr.data[3] == 3); array_i64_t copy = {0}; - array_copy(ma_temp_alo(scratch), ©, &arr); + array_copy(malot(scratch), ©, &arr); for (i64 i = 0; i < arr.len; i += 1) { assert(arr.data[i] == copy.data[i]); } @@ -174,12 +114,3 @@ fn_test void test_array(void) { ma_end_scratch(scratch); } - -fn s16_t s16_alo_copy(alo_t ma, s16_t string) { - i64 byte_size = sizeof(u16) * string.len; - u16 *copy = (u16 *)alloc_size(ma, byte_size + sizeof(u16)); - memory_copy(copy, string.str, byte_size); - copy[string.len] = 0; - s16_t result = s16_make(copy, string.len); - return result; -} diff --git a/src/core/core_array.h b/src/core/core_array.h new file mode 100644 index 0000000..ed87e4d --- /dev/null +++ b/src/core/core_array.h @@ -0,0 +1,24 @@ +#define array(type) struct { alo_t alo; type *data; i64 len; i64 cap; } +typedef array(void) array_void_t; +typedef array(i64) array_i64_t; + +#define arrisz(x) sizeof((x)->data[0]) +#define arrcst(x) ((array_void_t *)(x)) +#define array_init(a, this, count) (array__init((a), arrcst(this), arrisz(this), (count))) +#define array_add(this, ...) (array__grow(arrcst(this), arrisz(this), 1), (this)->data[(this)->len++] = __VA_ARGS__) +#define array_pop(this) (assert_expr((this)->len > 0), (this)->data[--(this)->len]) +#define array_dealloc(this) (dealloc((this)->alo, (this)->data)) +#define array_addn(this, n) (array__grow(arrcst(this), arrisz(this), (n)), (this)->len += (n), &(this)->data[(this)->len - (n)]) +#define array_insert(this, i, item) (array__insert(arrcst(this), arrisz(this), (i)), (this)->data[(i)] = (item)) +#define array_swapdel(this, i) (assert_expr((i) < (this)->len), (this)->data[(i)] = (this)->data[--(this)->len]) +#define array_del(this, i) (array__del(arrcst(this), arrisz(this), (i), 1)) +#define array_deln(this, i, count) (array__del(arrcst(this), arrisz(this), (i), (count))) +#define array_copy(alo, dst, src) (array__copy((alo), arrcst(dst), (array_void_t *)(src), arrisz(dst))) +#define array_last(x) ((x)->data[(x)->len - 1]) +#define array_for(type, it, array) for (type *it = (array)->data; it < (array)->data + (array)->len; it += 1) + +fn void array__init(alo_t alo, array_void_t *this, size_t item_size, i64 count); +fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size); +fn void array__grow(array_void_t *this, size_t item_size, i64 item_count); +fn void array__del(array_void_t *this, size_t item_size, i64 idx, i64 count); +fn void array__insert(array_void_t *this, size_t item_size, i64 idx); \ No newline at end of file diff --git a/src/core/core_ctx.c b/src/core/core_ctx.c index 998cb25..16f0813 100644 --- a/src/core/core_ctx.c +++ b/src/core/core_ctx.c @@ -11,4 +11,30 @@ gb_thread thread_ctx_t global_thread_context = { fn void core_init(void) { tcx = &global_thread_context; os_core_init(); -} \ No newline at end of file +} + +fn void *ma_arena_alo_proc(alo_t alo, alokind_t kind, void *ptr, size_t size) { + ma_arena_t *ma = alo.object; + if (kind == alokind_alloc) { + return ma_push_size(alo.object, size); + } else if (kind == alokind_dealloc) { + return NULL; + } else_is_invalid; + return NULL; +} + +fn alo_t malo(ma_arena_t *arena) { + return (alo_t){arena, ma_arena_alo_proc}; +} + +fn alo_t malot(ma_temp_t temp) { + return malo(temp.arena); +} + +fn void dealloc(alo_t alo, void *ptr) { + alo.proc(alo, alokind_dealloc, ptr, 0); +} + +fn void *alloc_size(alo_t alo, size_t size) { + return alo.proc(alo, alokind_alloc, NULL, size); +} diff --git a/src/core/core_ctx.h b/src/core/core_ctx.h index 2d3906f..25ac551 100644 --- a/src/core/core_ctx.h +++ b/src/core/core_ctx.h @@ -19,4 +19,22 @@ enum { tcx_slot_app, }; +typedef enum { + alokind_alloc, + alokind_dealloc, +} alokind_t; + +typedef struct alo_t alo_t; +struct alo_t { + void *object; + void *(*proc)(alo_t alo, alokind_t kind, void *ptr, size_t size); +}; + +#define alloc_type(alo, type) (type *)alloc_size((aloc), sizeof(type)) +#define alloc_array(alo, type, count) (type *)alloc_size((alo), sizeof(type) * (count)) +fn alo_t malo(ma_arena_t *arena); +fn alo_t malot(ma_temp_t temp); +fn void dealloc(alo_t alo, void *ptr); +fn void *alloc_size(alo_t alo, size_t size); + gb_thread thread_ctx_t *tcx; diff --git a/src/core/core_string16.c b/src/core/core_string16.c index e718632..9edde9b 100644 --- a/src/core/core_string16.c +++ b/src/core/core_string16.c @@ -489,6 +489,15 @@ fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags) return result; } +fn s16_t s16_copy_ex(alo_t ma, s16_t string) { + i64 byte_size = sizeof(u16) * string.len; + u16 *copy = (u16 *)alloc_size(ma, byte_size + sizeof(u16)); + memory_copy(copy, string.str, byte_size); + copy[string.len] = 0; + s16_t result = s16_make(copy, string.len); + return result; +} + fn_test void test_string16(void) { ma_temp_t scratch = ma_begin_scratch(); diff --git a/src/testing/testing.gen.c b/src/testing/testing.gen.c index 1149d7c..d58ccd4 100644 --- a/src/testing/testing.gen.c +++ b/src/testing/testing.gen.c @@ -1,8 +1,10 @@ void test_string16(void); void test_hash_table(void); void test_intern_table(void); +void test_array(void); fn void run_tests(void) { test_string16(); test_hash_table(); test_intern_table(); + test_array(); } diff --git a/src/text_editor/text_editor_buffer.c b/src/text_editor/buffer16.c similarity index 89% rename from src/text_editor/text_editor_buffer.c rename to src/text_editor/buffer16.c index 94346f9..9adc33d 100644 --- a/src/text_editor/text_editor_buffer.c +++ b/src/text_editor/buffer16.c @@ -1,74 +1,57 @@ #define BUFFER_DEBUG 1 -typedef struct caret_t caret_t; -struct caret_t { - i64 ifront; - union { - r1i64_t range; - i64 pos[2]; - }; -}; - -typedef struct xy_t xy_t; -struct xy_t { - i64 col; - i64 line; -}; - -typedef struct edit16_t edit16_t; -struct edit16_t { - r1i64_t range; - s16_t string; -}; - -// @todo: redo tree -typedef array(edit16_t) array_edit16_t; -typedef array(caret_t) array_caret_t; -typedef struct history16_t history16_t; -struct history16_t { - array_edit16_t edits; - array_caret_t carets; -}; - -typedef array(history16_t) array_history16_t; -typedef struct buffer16_id_t buffer16_id_t; -struct buffer16_id_t { i64 e; }; - -typedef struct buffer16_t buffer16_t; -struct buffer16_t { - s8_t name; - buffer16_id_t id; - - i32 change_id; - i8 edit_phase; - - struct { - b8 dirty: 1; - b8 history: 1; - b8 line_starts: 1; - } flags; - - union { - s16_t string; - u16 *data; - struct { - u16 *str; - i64 len; - }; - }; - i64 cap; - array_i64_t line_starts; - - array_history16_t undo_stack; - array_history16_t redo_stack; - alo_t alo; -}; - gb i64 buffer_raw_ids; -const b32 dont_kill_selection = false; -const b32 kill_selection = true; -fn void buffer16_multi_cursor_apply_edits(buffer16_t *buffer, array_edit16_t edits); + +/////////////////////////////// +// caret helpers +/////////////////////////////// + +fn i64 caret_get_front(caret_t caret) { + i64 result = caret.pos[caret.ifront]; + return result; +} + +fn i64 caret_get_back(caret_t caret) { + i64 result = caret.pos[(caret.ifront + 1) % 2]; + return result; +} + +fn caret_t caret_make(i64 front, i64 back) { + caret_t result = {0}; + if (front >= back) { + result.range.min = back; + result.range.max = front; + result.ifront = 1; + } else { + result.range.min = front; + result.range.max = back; + result.ifront = 0; + } + return result; +} + +fn caret_t caret_set_front(caret_t caret, i64 pos) { + i64 back = caret_get_back(caret); + caret_t result = caret_make(pos, back); + return result; +} + +fn caret_t caret_set_back(caret_t caret, i64 pos) { + i64 front = caret_get_front(caret); + caret_t result = caret_make(front, pos); + return result; +} + +fn b32 carets_are_equal(caret_t a, caret_t b) { + b32 result = r1i64_are_equal(a.range, b.range) && a.ifront == b.ifront; + return result; +} + +fn b32 carets_overlap(caret_t a, caret_t b) { + b32 result = r1i64_overlap(a.range, b.range); + return result; +} /////////////////////////////// // buffer helpers @@ -181,47 +164,6 @@ fn r1i64_t buffer16_clamp_range(buffer16_t *buffer, r1i64_t range) { return result; } -fn i64 caret_get_front(caret_t caret) { - i64 result = caret.pos[caret.ifront]; - return result; -} - -fn i64 caret_get_back(caret_t caret) { - i64 result = caret.pos[(caret.ifront + 1) % 2]; - return result; -} - -fn caret_t caret_make(i64 front, i64 back) { - caret_t result = {0}; - if (front >= back) { - result.range.min = back; - result.range.max = front; - result.ifront = 1; - } else { - result.range.min = front; - result.range.max = back; - result.ifront = 0; - } - return result; -} - -fn caret_t caret_set_front(caret_t caret, i64 pos) { - i64 back = caret_get_back(caret); - caret_t result = caret_make(pos, back); - return result; -} - -fn caret_t caret_set_back(caret_t caret, i64 pos) { - i64 front = caret_get_front(caret); - caret_t result = caret_make(front, pos); - return result; -} - -fn b32 carets_are_equal(caret_t a, caret_t b) { - b32 result = r1i64_are_equal(a.range, b.range) && a.ifront == b.ifront; - return result; -} - fn i64 buffer16_get_word_start(buffer16_t *buffer, i64 pos) { pos = CLAMP(pos, (i64)0, buffer->len); for (i64 i = pos - 1; i >= 0; i -= 1) { @@ -257,7 +199,7 @@ fn i64 buffer16_get_next_word_end(buffer16_t *buffer, i64 pos) { // semantics - proper max is one past last index if (!(i < buffer->len)) break; - fn if (prev == L'\n' || (prev && prev != buffer->str[i]) || char16_is_word(buffer->str[i])) { + if (prev == L'\n' || (prev && prev != buffer->str[i]) || char16_is_word(buffer->str[i])) { break; } prev = buffer->str[i]; @@ -271,7 +213,7 @@ fn i64 buffer16_get_prev_word_start(buffer16_t *buffer, i64 pos) { u16 prev = 0; i64 i = pos - 1; for (; i >= 0; i -= 1) { - fn if (prev == L'\n' || (prev && prev != buffer->str[i]) || char16_is_word(buffer->str[i])) { + if (prev == L'\n' || (prev && prev != buffer->str[i]) || char16_is_word(buffer->str[i])) { break; } pos = i; @@ -332,20 +274,6 @@ fn i64 buffer16_offset_pos_by_line(buffer16_t *buffer, i64 pos, i64 line_offset) // raw buffer operations /////////////////////////////// -fn void buffer16_raw_init(alo_t alo, buffer16_t *buffer, s8_t name, i64 size) { - buffer->id = (buffer16_id_t){++buffer_raw_ids}; - buffer->name = name; - buffer->alo = alo; - buffer->cap = size; - buffer->data = alloc_array(alo, u16, size); - array_init(alo, &buffer->line_starts, 128); - array_init(alo, &buffer->undo_stack, 128); - array_init(alo, &buffer->redo_stack, 128); - buffer->flags.line_starts = true; - buffer->flags.history = true; - array_add(&buffer->line_starts, 0); -} - fn void buffer16_raw_grow(buffer16_t *buffer, i64 change_size) { i64 new_size = buffer->len + change_size; if (new_size > buffer->cap) { @@ -453,6 +381,32 @@ fn void buffer16_raw_replace_text(buffer16_t *buffer, r1i64_t range, s16_t strin #endif } +/////////////////////////////// +// buffer multicursor + history +/////////////////////////////// + +fn void buffer16_init(alo_t alo, buffer16_t *buffer, s8_t name, i64 size) { + buffer->id = (buffer16_id_t){++buffer_raw_ids}; + buffer->name = name; + buffer->alo = alo; + buffer->cap = size; + buffer->data = alloc_array(alo, u16, size); + array_init(alo, &buffer->line_starts, 128); + array_init(alo, &buffer->undo_stack, 128); + array_init(alo, &buffer->redo_stack, 128); + buffer->flags.line_starts = true; + buffer->flags.history = true; + array_add(&buffer->line_starts, 0); +} + +fn void buffer16_deinit(buffer16_t *buffer) { + // @todo: verify this works + array_dealloc(&buffer->line_starts); + dealloc(buffer->alo, buffer->data); + buffer16_dealloc_history_array(buffer, &buffer->undo_stack); + buffer16_dealloc_history_array(buffer, &buffer->redo_stack); +} + fn void buffer16_save_history_before_merge_cursor(buffer16_t *buffer, array_history16_t *stack, array_caret_t *carets) { if (!buffer->flags.history) { return; @@ -473,24 +427,25 @@ fn void buffer16_save_history_before_apply_edits(buffer16_t *buffer, array_histo // make reverse edits array_for(edit16_t, it, &entry->edits) { - it->range = (r1i64_t){it->range.min, it->range.min + it->string.len}; - it->string = s16_alo_copy(buffer->alo, buffer16_get_string(buffer, it->range)); + r1i64_t new_range = {it->range.min, it->range.min + it->string.len}; + s16_t string = buffer16_get_string(buffer, it->range); + it->string = s16_copy_ex(buffer->alo, string); + it->range = new_range; } ma_temp_t scratch = ma_begin_scratch1(buffer->alo.object); array_edit16_t temp_edit = {0}; - array_copy(ma_temp_alo(scratch), &temp_edit, &entry->edits); + array_copy(malot(scratch), &temp_edit, &entry->edits); // fix reverse edits - for (int i = 0; i < edits->len; i += 1) { - edit16_t *it = edits->data + i; - i64 remove_size = r1i64_size(it->range); - i64 insert_size = it->string.len; + array_for(edit16_t, edit, edits) { + i64 remove_size = r1i64_size(edit->range); + i64 insert_size = edit->string.len; i64 offset = insert_size - remove_size; - for (int j = 0; j < entry->edits.len; j += 1) { + for (i64 i = 0; i < entry->edits.len; i += 1) { edit16_t *new_edit = entry->edits.data + i; edit16_t *old_edit = temp_edit.data + i; - if (old_edit->range.min > it->range.min) { + if (old_edit->range.min > edit->range.min) { new_edit->range.min += offset; new_edit->range.max += offset; } @@ -520,11 +475,12 @@ fn void buffer16_redo_edit(buffer16_t *buffer, array_caret_t *carets) { } fn void buffer16_undo_edit(buffer16_t *buffer, array_caret_t *carets) { - if (!buffer->flags.history || buffer->redo_stack.len <= 0) { + if (!buffer->flags.history || buffer->undo_stack.len <= 0) { return; } history16_t entry = array_pop(&buffer->undo_stack); + buffer16_save_history_before_merge_cursor(buffer, &buffer->redo_stack, carets); buffer16_save_history_before_apply_edits(buffer, &buffer->redo_stack, &entry.edits); buffer16_multi_cursor_apply_edits(buffer, entry.edits); @@ -557,10 +513,6 @@ fn void buffer16_dealloc_history_entries(buffer16_t *buffer, array_history16_t * } -fn void buffer16_clear_redo_stack(buffer16_t *buffer) { - buffer16_dealloc_history_entries(buffer, &buffer->redo_stack); -} - fn void buffer16_dealloc_history_array(buffer16_t *buffer, array_history16_t *entries) { buffer16_dealloc_history_entries(buffer, entries); array_dealloc(entries); @@ -575,7 +527,7 @@ fn array_edit16_t buffer16_begin_edit(alo_t alo, buffer16_t *buffer, array_caret buffer->edit_phase += 1; assert(carets->len); buffer16_save_history_before_merge_cursor(buffer, &buffer->undo_stack, carets); - buffer16_clear_redo_stack(buffer); + buffer16_dealloc_history_entries(buffer, &buffer->redo_stack); } array_edit16_t edits = (array_edit16_t){.alo = alo}; return edits; @@ -596,7 +548,7 @@ fn void buffer16_adjust_carets(array_edit16_t *edits, array_caret_t *carets) { assert(edits->alo.object == carets->alo.object); array_caret_t new_carets = {0}; - array_copy(ma_temp_alo(scratch), &new_carets, carets); + array_copy(malot(scratch), &new_carets, carets); array_for(edit16_t, it, edits) { i64 remove_size = r1i64_size(it->range); i64 insert_size = it->string.len; @@ -643,7 +595,7 @@ fn void buffer16_end_edit(buffer16_t *buffer, array_edit16_t *edits, array_caret assert(buffer->alo.object == edits->alo.object); array_caret_t new_carets = {0}; - array_copy(ma_temp_alo(scratch), &new_carets, carets); + array_copy(malot(scratch), &new_carets, carets); array_for(edit16_t, it, edits) { i64 remove_size = r1i64_size(it->range); i64 insert_size = it->string.len; @@ -679,7 +631,7 @@ fn void buffer16_end_edit(buffer16_t *buffer, array_edit16_t *edits, array_caret ma_end_scratch(scratch); } -void caret_merge_sort(i64 Count, caret_t *First, caret_t *Temp) { +fn void caret_merge_sort(i64 Count, caret_t *First, caret_t *Temp) { // SortKey = range.min if (Count == 1) { // NOTE(casey): No work to do. @@ -733,7 +685,7 @@ void caret_merge_sort(i64 Count, caret_t *First, caret_t *Temp) { } } -void edit16_merge_sort(i64 Count, edit16_t *First, edit16_t *Temp) { +fn void edit16_merge_sort(i64 Count, edit16_t *First, edit16_t *Temp) { // SortKey = range.min if (Count == 1) { // NOTE(casey): No work to do. @@ -814,7 +766,7 @@ fn void buffer16_multi_cursor_apply_edits(buffer16_t *buffer, array_edit16_t edi { ma_temp_t scratch = ma_begin_scratch1(buffer->alo.object); array_edit16_t edits_copy = {0}; - array_copy(ma_temp_alo(scratch), &edits_copy, &edits); + array_copy(malot(scratch), &edits_copy, &edits); if (edits.len > 1) edit16_merge_sort(edits.len, edits_copy.data, edits.data); edits = edits_copy; ma_end_scratch(scratch); @@ -854,7 +806,7 @@ fn void buffer16_merge_carets(buffer16_t *buffer, array_caret_t *carets) { ma_temp_t scratch = ma_begin_scratch1(buffer->alo.object); array_caret_t c1 = {0}; - array_copy(ma_temp_alo(scratch), &c1, carets); + array_copy(malot(scratch), &c1, carets); if (carets->len > 1) { caret_merge_sort(carets->len, c1.data, carets->data); } @@ -887,7 +839,7 @@ fn_test void buffer16_test(void) { { s16_t string = s16("thing itself"); buffer16_t *buffer = ma_push_type(scratch.arena, buffer16_t); - buffer16_raw_init(ma_temp_alo(scratch), buffer, S8_FILE_AND_LINE, 16); + buffer16_init(malot(scratch), buffer, S8_FILE_AND_LINE, 16); buffer16_raw_replace_text(buffer, r1i64_null, string); assert(s16_are_equal(buffer->string, string)); assert(buffer->cap == 16); @@ -919,7 +871,7 @@ fn_test void buffer16_test(void) { { s16_t string = s16("thing itself_and meme"); buffer16_t *buffer = ma_push_type(scratch.arena, buffer16_t); - buffer16_raw_init(ma_temp_alo(scratch), buffer, S8_FILE_AND_LINE, 10); + buffer16_init(malot(scratch), buffer, S8_FILE_AND_LINE, 10); buffer16_raw_replace_text(buffer, r1i64_null, string); r1i64_t range = buffer16_enclose_word(buffer, 18); buffer16_raw_replace_text(buffer, range, s16("cat")); @@ -934,7 +886,7 @@ fn_test void buffer16_test(void) { { buffer16_t *buffer = ma_push_type(scratch.arena, buffer16_t); - buffer16_raw_init(ma_temp_alo(scratch), buffer, S8_FILE_AND_LINE, 16); + buffer16_init(malot(scratch), buffer, S8_FILE_AND_LINE, 16); for (int i = 0; i < 16; i += 1) { buffer16_raw_replace_text(buffer, r1i64_null, s16("line of memes\n")); } @@ -942,14 +894,15 @@ fn_test void buffer16_test(void) { } { - + s16_t string = s16("some thing or another and stuff like that"); + s16_t meme_string = s16("meme meme or another and stuff like that"); buffer16_t *buffer = ma_push_type(scratch.arena, buffer16_t); - buffer16_raw_init(ma_temp_alo(scratch), buffer, S8_FILE_AND_LINE, 128); - buffer16_raw_replace_text(buffer, r1i64_null, s16("some thing or another and stuff like that")); + buffer16_init(malot(scratch), buffer, S8_FILE_AND_LINE, 128); + buffer16_raw_replace_text(buffer, r1i64_null, string); { array_caret_t carets = {0}; - array_init(ma_temp_alo(scratch), &carets, 32); + array_init(malot(scratch), &carets, 32); array_add(&carets, caret_make(0, 4)); array_add(&carets, caret_make(3, 8)); array_add(&carets, caret_make(3, 8)); @@ -964,12 +917,12 @@ fn_test void buffer16_test(void) { { array_caret_t carets = {0}; - array_init(ma_temp_alo(scratch), &carets, 32); + array_init(malot(scratch), &carets, 32); array_add(&carets, caret_make(0, 4)); array_add(&carets, caret_make(0, 3)); array_add(&carets, caret_make(5, 10)); - array_edit16_t edits = buffer16_begin_edit(ma_temp_alo(scratch), buffer, &carets); + array_edit16_t edits = buffer16_begin_edit(malot(scratch), buffer, &carets); buffer16_merge_carets(buffer, &carets); assert(carets.len == 2); @@ -979,7 +932,14 @@ fn_test void buffer16_test(void) { } buffer16_end_edit(buffer, &edits, &carets, kill_selection); - assert(s16_are_equal(buffer->string, s16("meme meme or another and stuff like that"))); + assert(s16_are_equal(buffer->string, meme_string)); + + for (i32 i = 0; i < 32; i += 1) { + buffer16_undo_edit(buffer, &carets); + assert(s16_are_equal(buffer->string, string)); + buffer16_redo_edit(buffer, &carets); + assert(s16_are_equal(buffer->string, meme_string)); + } } } diff --git a/src/text_editor/buffer16.h b/src/text_editor/buffer16.h new file mode 100644 index 0000000..bb58012 --- /dev/null +++ b/src/text_editor/buffer16.h @@ -0,0 +1,129 @@ +typedef struct caret_t caret_t; +struct caret_t { + i64 ifront; + union { + r1i64_t range; + i64 pos[2]; + }; +}; + +typedef struct xy_t xy_t; +struct xy_t { + i64 col; + i64 line; +}; + +typedef struct edit16_t edit16_t; +struct edit16_t { + r1i64_t range; + s16_t string; +}; + +// @todo: redo tree +typedef array(edit16_t) array_edit16_t; +typedef array(caret_t) array_caret_t; +typedef struct history16_t history16_t; +struct history16_t { + array_edit16_t edits; + array_caret_t carets; +}; + +typedef array(history16_t) array_history16_t; +typedef struct buffer16_id_t buffer16_id_t; +struct buffer16_id_t { i64 e; }; + +typedef struct buffer16_t buffer16_t; +struct buffer16_t { + s8_t name; + buffer16_id_t id; + + i32 change_id; + i8 edit_phase; + + struct { + b8 dirty: 1; + b8 history: 1; + b8 line_starts: 1; + } flags; + + union { + s16_t string; + u16 *data; + struct { + u16 *str; + i64 len; + }; + }; + i64 cap; + array_i64_t line_starts; + + array_history16_t undo_stack; + array_history16_t redo_stack; + alo_t alo; +}; + +const b32 dont_kill_selection = false; +const b32 kill_selection = true; + + +/////////////////////////////// +// caret helpers +fn caret_t caret_make(i64 front, i64 back); +fn i64 caret_get_front(caret_t caret); +fn i64 caret_get_back(caret_t caret); +fn caret_t caret_set_front(caret_t caret, i64 pos); +fn caret_t caret_set_back(caret_t caret, i64 pos); +fn b32 carets_are_equal(caret_t a, caret_t b); +fn b32 carets_overlap(caret_t a, caret_t b); + +/////////////////////////////// +// buffer helpers +fn i64 buffer16_pos_to_line(buffer16_t *buffer, i64 pos); +fn r1i64_t buffer16_get_line_range(buffer16_t *buffer, i64 line); +fn r1i64_t buffer16_get_line_range_full(buffer16_t *buffer, i64 line, i64 *eof); +fn xy_t buffer16_pos_to_xy(buffer16_t *buffer, i64 pos); +fn i64 buffer16_xy_to_pos(buffer16_t *buffer, xy_t xy); +fn i64 buffer16_xy_to_pos_without_new_line(buffer16_t *buffer, xy_t xy); +fn s16_t buffer16_get_string(buffer16_t *buffer, r1i64_t range); +fn s16_t buffer16_get_line_string(buffer16_t *buffer, i64 line); +fn r1i64_t buffer16_get_range_end(buffer16_t *buffer); +fn r1i64_t buffer16_get_range(buffer16_t *buffer); +fn i64 buffer16_clamp_pos(buffer16_t *buffer, i64 pos); +fn r1i64_t buffer16_clamp_range(buffer16_t *buffer, r1i64_t range); +fn i64 buffer16_get_word_start(buffer16_t *buffer, i64 pos); +fn i64 buffer16_get_word_end(buffer16_t *buffer, i64 pos); +fn i64 buffer16_get_next_word_end(buffer16_t *buffer, i64 pos); +fn i64 buffer16_get_prev_word_start(buffer16_t *buffer, i64 pos); +fn i64 buffer16_get_line_start(buffer16_t *buffer, i64 pos, i64 *eof); +fn i64 buffer16_get_line_end(buffer16_t *buffer, i64 pos, i64 *eof); +fn i64 buffer16_get_line_start_full(buffer16_t *buffer, i64 pos); +fn i64 buffer16_get_line_end_full(buffer16_t *buffer, i64 pos); +fn r1i64_t buffer16_enclose_word(buffer16_t *buffer, i64 pos); +fn u16 buffer16_get_char(buffer16_t *buffer, i64 pos); +fn i64 buffer16_offset_pos_by_line(buffer16_t *buffer, i64 pos, i64 line_offset); + +/////////////////////////////// +// buffer raw textural operations. no history +fn void buffer16_raw_grow(buffer16_t *buffer, i64 change_size); +fn void buffer16_raw_replace_text(buffer16_t *buffer, r1i64_t range, s16_t string); + +/////////////////////////////// +// buffer multicursor + history +fn void buffer16_init(alo_t alo, buffer16_t *buffer, s8_t name, i64 size); +fn void buffer16_deinit(buffer16_t *buffer); +fn void buffer16_add_edit(array_edit16_t *edits, r1i64_t range, s16_t string); +fn array_edit16_t buffer16_begin_edit(alo_t alo, buffer16_t *buffer, array_caret_t *carets); +fn void buffer16_end_edit(buffer16_t *buffer, array_edit16_t *edits, array_caret_t *carets, b32 kill_selection); +fn void buffer16_merge_carets(buffer16_t *buffer, array_caret_t *carets); +fn void buffer16_adjust_carets(array_edit16_t *edits, array_caret_t *carets); + +fn void buffer16_redo_edit(buffer16_t *buffer, array_caret_t *carets); +fn void buffer16_undo_edit(buffer16_t *buffer, array_caret_t *carets); + +fn void buffer16_save_history_before_merge_cursor(buffer16_t *buffer, array_history16_t *stack, array_caret_t *carets); +fn void buffer16_save_history_before_apply_edits(buffer16_t *buffer, array_history16_t *stack, array_edit16_t *edits); +fn void buffer16_pre_begin_edit_save_caret_history(buffer16_t *buffer, array_caret_t *carets); + +fn void buffer16_dealloc_history_entries(buffer16_t *buffer, array_history16_t *entries); +fn void buffer16_dealloc_history_array(buffer16_t *buffer, array_history16_t *entries); +fn void buffer16_multi_cursor_apply_edits(buffer16_t *buffer, array_edit16_t edits); diff --git a/src/text_editor/text_editor_main.c b/src/text_editor/text_editor_main.c index 5e20589..6ade677 100644 --- a/src/text_editor/text_editor_main.c +++ b/src/text_editor/text_editor_main.c @@ -2,6 +2,7 @@ #include "os/os.h" #include "app/app.h" #include "profiler/profiler.h" +#include "buffer16.h" // #include "ui/ui.h" @@ -10,8 +11,7 @@ #include "app/app.c" #include "profiler/profiler.c" #include "render/render.c" -#include "core_array.c" -#include "text_editor_buffer.c" +#include "buffer16.c" // #include "ui/ui.c" #include "text_editor.gen.c" diff --git a/src/ui/ui.c b/src/ui/ui.c index 281c23f..2af5ff8 100644 --- a/src/ui/ui.c +++ b/src/ui/ui.c @@ -367,7 +367,7 @@ fn ui_signal_t ui_signal_from_box(ui_box_t *box) { } fn v2f32_t ui_aligned_text_pos(f32 offset, ui_text_align_t text_align, r2f32_t rect, s8_t string, v2f32_t string_size) { - v2f32_t rect_size = r2f32_get_size(rect); + v2f32_t rect_size = r2f32_size(rect); v2f32_t rect_string_diff = v2f32_sub(rect_size, string_size); v2f32_t center_pos = v2f32_divs(rect_string_diff, 2); v2f32_t pos_in_rect = v2f32(0, center_pos.y); @@ -390,7 +390,7 @@ struct ui_draw_compute_t { fn r2f32_t ui_get_appear_rect(ui_box_t *box) { r2f32_t result = box->rect; if (box->flags.animate_appear && !ui_id_is_null(box->id)) { - v2f32_t size = v2f32_muls(r2f32_get_size(result), 0.15f); + v2f32_t size = v2f32_muls(r2f32_size(result), 0.15f); r2f32_t smaller_rect = r2f32_shrink(result, size); f32 appear_t = f32_ease_out_n(f32_clamp01(box->appear_t * 2), 10); result = r2f32_lerp(smaller_rect, result, appear_t); @@ -634,7 +634,7 @@ fn void ui_tree_table_begin(ui_code_loc_t loc) { fn void ui_tree_table_end(void) { ui_box_t *box = ui_pop_top(); ui_set_children_sums(box); - ui_next_rect(ui_top_lop(), ui_top_rectp(), r2f32_get_size(box->rect)); + ui_next_rect(ui_top_lop(), ui_top_rectp(), r2f32_size(box->rect)); } #define ui_tree_table_expandable(...) defer_if (ui_tree_table_push_expandable(UILOC, __VA_ARGS__).clicked, ui_tree_table_pop_expandable()) @@ -998,7 +998,7 @@ struct ui_scroller_t { fn void ui_scroller_calc_vertical(ui_scroller_t s) { ui_set_top(s.verti.box) { - f32 scroller_rect_pixels = r2f32_get_size(s.verti.box->rect).y; + f32 scroller_rect_pixels = r2f32_size(s.verti.box->rect).y; f32 all_items_size = s.p.verti.max_size; f32 scroller_size = f32_clamp01(s.verti.item_box_pixels / (all_items_size + s.verti.item_box_pixels)); f32 scrollable_space = (1 - scroller_size); @@ -1023,7 +1023,7 @@ fn void ui_scroller_calc_vertical(ui_scroller_t s) { } if (upper_box_signal.dragging || down_box_signal.dragging) { s.p.verti.value[0] = (ev->mouse_pos.y - upper_box->rect.min.y) * coef; - s.p.verti.value[0] -= (r2f32_get_size(slider_box->rect).y / 2) * coef; + s.p.verti.value[0] -= (r2f32_size(slider_box->rect).y / 2) * coef; } if (ev->kind == app_event_kind_mouse_wheel) { s.p.verti.value[0] -= ev->mouse_wheel_delta.y; @@ -1038,7 +1038,7 @@ fn ui_scroller_t ui_begin_scroller(ui_code_loc_t loc, ui_scroller_params_t p) { if (p.verti.enabled) { s.verti.box = ui_box(.loc = loc, .rect = r2f32_cut_right(&p.parent->rect, ui_dm(0.5f)), .flags = {.draw_rect = true}); r2f32_cut_bottom(&s.verti.box->rect, ui_dm(0.5f)); - s.verti.item_box_pixels = r2f32_get_size(p.parent->rect).y; + s.verti.item_box_pixels = r2f32_size(p.parent->rect).y; if (p.verti.item_count) { s.p.verti.max_size = s.p.verti.item_pixels * s.p.verti.item_count; ui_scroller_calc_vertical(s); @@ -1077,7 +1077,7 @@ fn void ui_end_scroller(ui_scroller_t s) { if (s.p.hori.enabled) { ui_set_top(s.hori.box) { - f32 scroller_rect_pixels = r2f32_get_size(s.hori.box->rect).x; + f32 scroller_rect_pixels = r2f32_size(s.hori.box->rect).x; f32 scroller_button_size_norm = f32_clamp01(scroller_rect_pixels / s.p.hori.max_size); f32 scrollable_space = (1.f - scroller_button_size_norm); @@ -1101,7 +1101,7 @@ fn void ui_end_scroller(ui_scroller_t s) { } if (left_box_sig.dragging || right_box_sig.dragging) { s.p.hori.value[0] = (ev->mouse_pos.x - left_box->rect.min.x) * coef; - s.p.hori.value[0] -= (r2f32_get_size(slider_box->rect).x / 2) * coef; + s.p.hori.value[0] -= (r2f32_size(slider_box->rect).x / 2) * coef; } if (ev->kind == app_event_kind_mouse_wheel) { s.p.hori.value[0] -= ev->mouse_wheel_delta.x; @@ -1399,7 +1399,7 @@ fn void ui_demo_update(app_frame_t *frame, mt_tweak_t *tweak_table, i32 tweak_co ui_serial_type(UILOC, &ui_test_event, type(app_event_t)); r2f32_t scroll_rect = r2f32_fix(ui_top_rect()); - scroller.p.verti.max_size = r2f32_get_size(scroll_rect).y; + scroller.p.verti.max_size = r2f32_size(scroll_rect).y; } ui_end_scroller(scroller); diff --git a/src/wasm_app/wasm_app.gen.c b/src/wasm_app/wasm_app.gen.c index 4d1fab2..37bc685 100644 --- a/src/wasm_app/wasm_app.gen.c +++ b/src/wasm_app/wasm_app.gen.c @@ -10,5 +10,6 @@ void run_all_tests(void) { test_string16(); test_hash_table(); test_intern_table(); + test_array(); ui_test_text_replace(); }// run_all_tests()