230 lines
7.0 KiB
C
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
|