From da0b9ab2c76661c8aa2002cbf195122cf06ae039 Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin <patrick@spacegirl.nl> Date: Fri, 22 Mar 2024 21:00:21 -0500 Subject: [PATCH] start actual editor stuff --- debug.plist | 8 +++ justfile | 2 +- src/buffer.h | 154 ++++++++++++++++++++++++++++++++++++++++++ src/compile_flags.txt | 1 + src/ed_array.h | 36 ++++++++-- src/gfx.h | 1 - src/ht.h | 5 +- src/main.c | 11 ++- src/string.h | 18 ++++- src/ui.h | 13 +++- 10 files changed, 236 insertions(+), 13 deletions(-) create mode 100644 debug.plist create mode 100644 src/buffer.h diff --git a/debug.plist b/debug.plist new file mode 100644 index 0000000..e09573c --- /dev/null +++ b/debug.plist @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> + <dict> + <key>com.apple.security.get-task-allow</key> + <true/> + </dict> +</plist> diff --git a/justfile b/justfile index f62278e..9c355fb 100644 --- a/justfile +++ b/justfile @@ -3,7 +3,7 @@ alias r := run build: transpile_shaders_metal mkdir -p bin - cc -Ivendor/ -g -Wall -Wextra -framework Cocoa -framework QuartzCore -framework CoreImage -framework Metal -framework MetalKit -ObjC src/*.c -o bin/an_editor + cc -Ivendor/ -O0 -g -Wall -Wextra -framework Cocoa -framework QuartzCore -framework CoreImage -framework Metal -framework MetalKit -ObjC src/*.c -o bin/an_editor # cc -Ivendor/ -g -Wall -Wextra src/*.c -o bin/an_editor -lEGL -lGLESv2 -lGL -lm -lX11 -lXi -lXcursor # cc bin/*.o -o bin/an_editor -lEGL -lGLESv2 -lGL -lm -lX11 -lXi -lXcursor diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..e93e38b --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,154 @@ +#ifndef ED_BUFFER_INCLUDED +#define ED_BUFFER_INCLUDED +#include "ed_array.h" +#include "string.h" +#include "ui.h" + +typedef struct { + size_t link_index; + size_t content_index; +} ed_buffer_offset; + +typedef struct { + uint64_t column; + uint64_t line; + ed_buffer_offset offset; +} ed_buffer_cursor; + +typedef enum { + ED_BUFFER_CONTENT_LINK_TYPE_ORIGINAL, + ED_BUFFER_CONTENT_LINK_TYPE_ADDED, +} ed_buffer_content_link_t; + +typedef struct { + ed_buffer_content_link_t type; + size_t start; + size_t end; + size_t len; +} ed_buffer_content_link; +arrayTemplate(ed_buffer_content_link); + +typedef struct { + array(uint8_t) original_content; + array(uint8_t) added_content; + + array(ed_buffer_content_link) linked_content; +} ed_buffer_data; + +typedef struct { + ed_buffer_data data; + ed_buffer_cursor cursor; +} ed_buffer; + +#ifdef ED_BUFFER_IMPLEMENTATION + +static ed_buffer_data _ed_buffer_init_buffer_data(slice(uint8_t) data) { + array(ed_buffer_content_link) linked_content = newArray(ed_buffer_content_link, 16); + pushArray(ed_buffer_content_link, &linked_content, ((ed_buffer_content_link) { + .type = ED_BUFFER_CONTENT_LINK_TYPE_ORIGINAL, + .start = 0, + .end = data.len, + .len = data.len, + })); + + return (ed_buffer_data) { + .original_content = newArrayFromSlice(uint8_t, data), + .added_content = newArray(uint8_t, 512), + .linked_content = linked_content, + }; +} + +uint8_t ed_buffer_get_char_at(ed_buffer *buffer, ed_buffer_cursor cursor) { + ed_buffer_content_link link = buffer->data.linked_content.data[cursor.offset.link_index]; + uint8_t character; + + if (link.type == ED_BUFFER_CONTENT_LINK_TYPE_ORIGINAL) { + character = buffer->data.original_content.data[link.start+cursor.offset.content_index]; + } else if (link.type == ED_BUFFER_CONTENT_LINK_TYPE_ADDED) { + character = buffer->data.added_content.data[link.start+cursor.offset.content_index]; + } else { + character = 0; + } + + return character; +} + +ed_buffer ed_buffer_from_file(string path) { + slice(uint8_t) data = { + .data = (uint8_t *)"Hello!\nThis is a test document!\nWith three lines.\nJust kidding, there actually four", + .len = 83, + }; + ed_buffer buffer = { + .data = _ed_buffer_init_buffer_data(data), + .cursor = { + .column = 0, + .line = 0, + .offset = { + .link_index = 0, + .content_index = 0, + }, + } + }; + + return buffer; +} + +bool ed_buffer_content_iter(ed_buffer *buffer, ed_buffer_cursor *cursor) { + if (cursor->offset.link_index >= buffer->data.linked_content.size + || cursor->offset.content_index >= (buffer->data.linked_content.data[cursor->offset.link_index].len)) + { + return false; + } + + uint8_t character = ed_buffer_get_char_at(buffer, *cursor); + + ed_buffer_content_link link = buffer->data.linked_content.data[cursor->offset.link_index]; + if (cursor->offset.content_index < link.len-1) { + cursor->offset.content_index += 1; + } else if (cursor->offset.link_index < buffer->data.linked_content.size-1) { + cursor->offset.content_index = 0; + cursor->offset.link_index += 1; + } else { + return false; + } + + if (character == '\n') { + cursor->column = 0; + cursor->line += 1; + } else { + cursor->column += 1; + } + + return true; +} + +void ed_buffer_render(ui_context *cx, ed_buffer *buffer) { + ui_element(cx, _String("Buffer"), UI_AXIS_VERTICAL, ui_make_size(ui_fill, ui_fill), UI_FLAG_DRAW_BACKGROUND); + ui_push_parent(cx); + { + ed_buffer_cursor cursor = buffer->cursor; + do { + uint8_t line_buffer[512]; + size_t line_buffer_index = 0; + + do { + uint8_t character = ed_buffer_get_char_at(buffer, cursor); + if (character == '\n' || line_buffer_index >= 512) { + break; + } + + line_buffer[line_buffer_index] = character; + line_buffer_index += 1; + } while(ed_buffer_content_iter(buffer, &cursor)); + + uint8_t *str = malloc(line_buffer_index * sizeof(uint8_t)); + memcpy(str, line_buffer, line_buffer_index * sizeof(uint8_t)); + + ui_element(cx, (string){ .data = str, .len = line_buffer_index, .owned = true }, UI_AXIS_HORIZONTAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_TEXT); + } while(ed_buffer_content_iter(buffer, &cursor)); + } + ui_pop_parent(cx); +} + +#endif +#endif diff --git a/src/compile_flags.txt b/src/compile_flags.txt index 665d6c2..1169529 100644 --- a/src/compile_flags.txt +++ b/src/compile_flags.txt @@ -2,5 +2,6 @@ -DED_HT_IMPLEMENTATION -DED_STRING_IMPLEMENTATION -DED_GFX_IMPLEMENTATION +-DED_BUFFER_IMPLEMENTATION -I../vendor/ -ObjC diff --git a/src/ed_array.h b/src/ed_array.h index dac74d2..150ff98 100644 --- a/src/ed_array.h +++ b/src/ed_array.h @@ -1,14 +1,16 @@ #ifndef ED_ARRAY_INCLUDED #define ED_ARRAY_INCLUDED +#include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <memory.h> -#define array(T) struct T ## Array +#define array(T) struct T ## _Array #define arrayTemplate(T) array(T) {\ size_t size, capacity;\ T *data;\ };\ -array(T) T ## ArrayConstruct(size_t size) {\ +array(T) T ## _ArrayConstruct(size_t size) {\ array(T) this;\ this.size = 0;\ this.capacity = size;\ @@ -18,7 +20,7 @@ array(T) T ## ArrayConstruct(size_t size) {\ }\ return this;\ };\ -void T ## PushArray(array(T) *arr, T value) {\ +void T ## _PushArray(array(T) *arr, T value) {\ if (arr->size+1 <= arr->capacity) {\ arr->data[arr->size] = value;\ arr->size += 1;\ @@ -27,7 +29,31 @@ void T ## PushArray(array(T) *arr, T value) {\ }\ }; -#define newArray(T, size) T ## ArrayConstruct(size) -#define pushArray(T, arr, value) T ## PushArray(arr, (value)) +#define slice(T) struct T ## _Slice +#define sliceTemplate(T) slice(T) {\ + size_t len;\ + T *data;\ +};\ +array(T) T ## _FromSlice(slice(T) s) {\ + array(T) arr = T ## _ArrayConstruct(s.len);\ + memcpy(arr.data, s.data, sizeof(T) * s.len);\ + arr.size = s.len;\ + return arr;\ +}\ +slice(T) T ## _SliceConstruct(void *data, size_t len) {\ + slice(T) this;\ + this.len = len;\ + this.data = data;\ + return this;\ +} + +#define newArray(T, size) T ## _ArrayConstruct(size) +#define newArrayFromSlice(T, s) T ## _FromSlice(s) +#define pushArray(T, arr, value) T ## _PushArray(arr, (value)) + +#define newSlice(T, data, len) T ## _SliceConstruct(data, len) + +arrayTemplate(uint8_t); +sliceTemplate(uint8_t); #endif diff --git a/src/gfx.h b/src/gfx.h index c65d501..d6594d0 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -260,7 +260,6 @@ void _metal_gfx_send_events(_metal_gfx_context *cx) { untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; [cx->application sendEvent:event]; - [cx->application updateWindows]; } void _metal_gfx_present(_metal_gfx_context *cx) { diff --git a/src/ht.h b/src/ht.h index 81519dd..70efa4a 100644 --- a/src/ht.h +++ b/src/ht.h @@ -61,7 +61,10 @@ bool ht_set(ed_ht *ht, string key, void *value) { for (size_t i=hash; i<ht->capacity; ++i) { if (ht->key_slots[i].key.data == NULL || string_eq(ht->key_slots[i].key, key)) { - ht->key_slots[i].key = key; + if (ht->key_slots[i].key.data != NULL) { + free(ht->key_slots[i].key.data); + } + ht->key_slots[i].key = string_copy(key); memcpy(ht->value_slots+i*ht->value_size, value, ht->value_size); return true; diff --git a/src/main.c b/src/main.c index d1ac154..9d2091b 100644 --- a/src/main.c +++ b/src/main.c @@ -11,11 +11,13 @@ #define ED_STRING_IMPLEMENTATION #define ED_HT_IMPLEMENTATION #define ED_UI_IMPLEMENTATION +#define ED_BUFFER_IMPLEMENTATION #include "string.h" #include "ht.h" #include "ui.h" #include "ed_array.h" #include "gfx.h" +#include "buffer.h" // static Arena default_arena = {0}; // static Arena temporary_arena = {0}; @@ -56,6 +58,8 @@ static struct { ui_context ui_cx; gfx_context_t *gfx_cx; + + ed_buffer test_buffer; } state; void queue_text(string text, float position[2]) { @@ -177,6 +181,7 @@ void ed_init(_gfx_frame_func frame_func) { gfx_push_texture_buffer(state.gfx_cx, font_bitmap_size, font_bitmap_size, font_bitmap, font_bitmap_size*font_bitmap_size * sizeof(uint8_t)); + state.test_buffer = ed_buffer_from_file(_String("")); } void render_ui_text(string text, float position[2]) { @@ -190,14 +195,16 @@ void ed_frame() { state.ui_cx.frame_elements.data[0].size.computed_size[0] = state.gfx_cx->frame_width; state.ui_cx.frame_elements.data[0].size.computed_size[1] = state.gfx_cx->frame_height; - ui_element(&state.ui_cx, _String("Number 1"), UI_AXIS_VERTICAL, ui_make_size(ui_fill, ui_fill), 0); + ui_element(&state.ui_cx, _String("Number 1"), UI_AXIS_VERTICAL, ui_make_size(ui_children_sum, ui_fill), 0); ui_push_parent(&state.ui_cx); { ui_element(&state.ui_cx, _String("ui element 2"), UI_AXIS_HORIZONTAL, ui_make_size(ui_fit_text, ui_fill), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); ui_element(&state.ui_cx, _String("ui element 2"), UI_AXIS_HORIZONTAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); } ui_pop_parent(&state.ui_cx); - ui_element(&state.ui_cx, _String("Look I don't have to hardcode any values"), UI_AXIS_VERTICAL, ui_make_size(ui_fit_text, ui_fit_text), UI_FLAG_DRAW_BACKGROUND|UI_FLAG_DRAW_TEXT); + + // Test buffer + ed_buffer_render(&state.ui_cx, &state.test_buffer); ui_compute_layout(&state.ui_cx, 0); diff --git a/src/string.h b/src/string.h index f9186d3..26b6d64 100644 --- a/src/string.h +++ b/src/string.h @@ -1,13 +1,17 @@ #ifndef ED_STRING_INCLUDED #define ED_STRING_INCLUDED +#include <stdlib.h> #include <stddef.h> #include <stdint.h> +#include <stdbool.h> -#define _String(text) ((string) { .data = (uint8_t*) text, .len = sizeof(text) }) +#define _String(text) ((string) { .data = (uint8_t*) text, .len = sizeof(text), .owned = false }) typedef struct { uint8_t *data; size_t len; + + bool owned; } string; @@ -22,5 +26,17 @@ bool string_eq(string a, string b) { return true; } +string string_copy(string a) { + string new_string; + + new_string.data = malloc(a.len * sizeof(uint8_t)); + new_string.len = a.len; + new_string.owned = true; + + memcpy(new_string.data, a.data, new_string.len * sizeof(uint8_t)); + + return new_string; +} + #endif #endif diff --git a/src/ui.h b/src/ui.h index 6e9fcd7..b00a527 100644 --- a/src/ui.h +++ b/src/ui.h @@ -190,11 +190,12 @@ size_t ui_element(ui_context *cx, string label, ui_axis axis, ui_semantic_size s frame_data.size.computed_size[0] = cache_data->size.computed_size[0]; frame_data.size.computed_size[1] = cache_data->size.computed_size[1]; } else { - assert("couldn't insert into ui element cache" && ht_set(&cx->cached_elements, label, &(ui_element_cache_data) { + bool did_insert = ht_set(&cx->cached_elements, label, &(ui_element_cache_data) { .label = label, .size = { 0 }, .last_instantiated_index = cx->frame_index, - })); + }); + assert("couldn't insert into ui element cache" && did_insert); } pushArray(ui_element_frame_data, &cx->frame_elements, frame_data); @@ -452,6 +453,14 @@ void ui_prune(ui_context *cx) { } } + size_t child_index = _elm(0)->first; + do { + __auto_type elm = _elm(child_index); + if (elm->label.owned) { + free(elm->label.data); + } + } while ((child_index = _next(child_index)) < SIZE_MAX); + cx->frame_index += 1; cx->frame_elements.size = 1; cx->frame_elements.data[0].first = SIZE_MAX;