an_editor/src/buffer.h

230 lines
7.0 KiB
C

#ifndef ED_BUFFER_INCLUDED
#define ED_BUFFER_INCLUDED
#include "ed_array.h"
#include "string.h"
#include "ui.h"
#include <stdbool.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) {
char text[] =
"bool ht_set(ed_ht *ht, string key, void *value) {\n"
" ht_hash_t hash = ht_hash(key, ht->capacity);\n"
"\n"
" for (size_t i=hash; i<ht->capacity; ++i) {\n"
" if (ht->key_slots[i].key.data == NULL || string_eq(ht->key_slots[i].key, key)) {\n"
" if (ht->key_slots[i].key.data != NULL) {\n"
" free(ht->key_slots[i].key.data);\n"
" }\n"
" ht->key_slots[i].key = string_copy(key);\n"
"\n"
" memcpy(ht->value_slots+i*ht->value_size, value, ht->value_size);\n"
" return true;\n"
" }\n"
" }\n"
" return false;\n"
"}\n";
slice(uint8_t) data = {
.data = text,
.len = sizeof(text),
};
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_insert_text(ed_buffer *buffer, string text, ed_buffer_cursor cursor) {
if (text.len == 0) {
return;
}
size_t content_start = buffer->data.added_content.size;
pushArrayMulti(uint8_t, &buffer->data.added_content, text.data, text.len);
if (cursor.offset.content_index == 0) {
insertArrayAt(ed_buffer_content_link,
&buffer->data.linked_content,
cursor.offset.link_index,
((ed_buffer_content_link) {
.type = ED_BUFFER_CONTENT_LINK_TYPE_ADDED,
.start = content_start,
.end = content_start+text.len,
.len = text.len,
})
);
} else {
ed_buffer_content_link end_link = buffer->data.linked_content.data[cursor.offset.link_index];
end_link.start += cursor.offset.content_index;
end_link.len -= cursor.offset.content_index;
buffer->data.linked_content.data[cursor.offset.link_index].end = end_link.start;
buffer->data.linked_content.data[cursor.offset.link_index].len = buffer->data.linked_content.data[cursor.offset.link_index].end - buffer->data.linked_content.data[cursor.offset.link_index].start;
// insert new content
insertArrayAt(ed_buffer_content_link,
&buffer->data.linked_content,
cursor.offset.link_index+1,
((ed_buffer_content_link) {
.type = ED_BUFFER_CONTENT_LINK_TYPE_ADDED,
.start = content_start,
.end = content_start+text.len,
.len = text.len,
})
);
// insert cut slice
insertArrayAt(ed_buffer_content_link,
&buffer->data.linked_content,
cursor.offset.link_index+2,
end_link
);
}
}
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|UI_FLAG_DRAW_BACKGROUND
);
} while(ed_buffer_content_iter(buffer, &cursor));
}
ui_pop_parent(cx);
}
#endif
#endif