commit d0b7725c29c752154eac0f92e68dab0a8d97ed6d
parent c7fb61a9e5c1d0bbc781946ebcf6416f85509aac
Author: rexim <reximkut@gmail.com>
Date: Thu, 29 Dec 2022 14:23:00 +0700
Port text representation from noed
Diffstat:
| M | src/editor.c | | | 254 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
| M | src/editor.h | | | 51 | ++++++++++++++++++++++++++++++++++++--------------- |
| M | src/main.c | | | 49 | +++++++++++++++++++++++++++---------------------- |
3 files changed, 168 insertions(+), 186 deletions(-)
diff --git a/src/editor.c b/src/editor.c
@@ -6,203 +6,159 @@
#include "./editor.h"
#include "./sv.h"
-#define LINE_INIT_CAPACITY 1024
-#define EDITOR_INIT_CAPACITY 128
-
-static void editor_create_first_new_line(Editor *editor);
-
-static void line_grow(Line *line, size_t n)
+void editor_backspace(Editor *e)
{
- size_t new_capacity = line->capacity;
-
- assert(new_capacity >= line->size);
- while (new_capacity - line->size < n) {
- if (new_capacity == 0) {
- new_capacity = LINE_INIT_CAPACITY;
- } else {
- new_capacity *= 2;
- }
- }
-
- if (new_capacity != line->capacity) {
- line->chars = realloc(line->chars, new_capacity);
- line->capacity = new_capacity;
+ if (e->cursor > e->data.count) {
+ e->cursor = e->data.count;
}
+ if (e->cursor == 0) return;
+
+ memmove(
+ &e->data.items[e->cursor - 1],
+ &e->data.items[e->cursor],
+ e->data.count - e->cursor
+ );
+ e->cursor -= 1;
+ e->data.count -= 1;
+ editor_recompute_lines(e);
}
-void line_append_text(Line *line, const char *text, size_t text_size)
+void editor_delete(Editor *e)
{
- size_t col = line->size;
- line_insert_text_before(line, text, text_size, &col);
+ if (e->cursor >= e->data.count) return;
+ memmove(
+ &e->data.items[e->cursor],
+ &e->data.items[e->cursor + 1],
+ e->data.count - e->cursor - 1
+ );
+ e->data.count -= 1;
+ editor_recompute_lines(e);
}
-void line_insert_text_before(Line *line, const char *text, size_t text_size, size_t *col)
+void editor_save_to_file(const Editor *editor, const char *file_path)
{
- if (*col > line->size) {
- *col = line->size;
+ FILE *f = fopen(file_path, "w");
+ if (f == NULL) {
+ fprintf(stdout, "ERROR: could not open file `%s`: %s\n",
+ file_path, strerror(errno));
+ exit(1);
}
- line_grow(line, text_size);
-
- memmove(line->chars + *col + text_size,
- line->chars + *col,
- line->size - *col);
- memcpy(line->chars + *col, text, text_size);
- line->size += text_size;
- *col += text_size;
+ fwrite(editor->data.items, 1, editor->data.count, f);
+ fclose(f);
}
-void line_backspace(Line *line, size_t *col)
+static size_t file_size(FILE *file)
{
- if (*col > line->size) {
- *col = line->size;
- }
-
- if (*col > 0 && line->size > 0) {
- memmove(line->chars + *col - 1,
- line->chars + *col,
- line->size - *col);
- line->size -= 1;
- *col -= 1;
- }
+ long saved = ftell(file);
+ assert(saved >= 0);
+ int err = fseek(file, 0, SEEK_END);
+ assert(err == 0);
+ long result = ftell(file);
+ assert(result >= 0);
+ err = fseek(file, saved, SEEK_SET);
+ assert(err == 0);
+ return result;
}
-void line_delete(Line *line, size_t *col)
+void editor_load_from_file(Editor *e, FILE *file)
{
- if (*col > line->size) {
- *col = line->size;
- }
+ e->data.count = 0;
- if (*col < line->size && line->size > 0) {
- memmove(line->chars + *col,
- line->chars + *col + 1,
- line->size - *col);
- line->size -= 1;
- }
-}
+ size_t data_size = file_size(file);
-static void editor_grow(Editor *editor, size_t n)
-{
- size_t new_capacity = editor->capacity;
-
- assert(new_capacity >= editor->size);
- while (new_capacity - editor->size < n) {
- if (new_capacity == 0) {
- new_capacity = EDITOR_INIT_CAPACITY;
- } else {
- new_capacity *= 2;
- }
+ if (e->data.capacity < data_size) {
+ e->data.capacity = data_size;
+ e->data.items = realloc(e->data.items, e->data.capacity*sizeof(*e->data.items));
+ assert(e->data.items != NULL && "Buy more RAM lol");
}
- if (new_capacity != editor->capacity) {
- editor->lines = realloc(editor->lines, new_capacity * sizeof(editor->lines[0]));
- editor->capacity = new_capacity;
- }
-}
-
-void editor_insert_new_line(Editor *editor)
-{
- if (editor->cursor_row > editor->size) {
- editor->cursor_row = editor->size;
- }
+ fread(e->data.items, data_size, 1, file);
+ assert(!ferror(file));
+ e->data.count = data_size;
- editor_grow(editor, 1);
-
- const size_t line_size = sizeof(editor->lines[0]);
- memmove(editor->lines + editor->cursor_row + 1,
- editor->lines + editor->cursor_row,
- (editor->size - editor->cursor_row) * line_size);
- memset(&editor->lines[editor->cursor_row + 1], 0, line_size);
- editor->cursor_row += 1;
- editor->cursor_col = 0;
- editor->size += 1;
+ editor_recompute_lines(e);
}
-static void editor_create_first_new_line(Editor *editor)
+size_t editor_cursor_row(const Editor *e)
{
- if (editor->cursor_row >= editor->size) {
- if (editor->size > 0) {
- editor->cursor_row = editor->size - 1;
- } else {
- editor_grow(editor, 1);
- memset(&editor->lines[editor->size], 0, sizeof(editor->lines[0]));
- editor->size += 1;
+ assert(e->lines.count > 0);
+ for (size_t row = 0; row < e->lines.count; ++row) {
+ Line_ line = e->lines.items[row];
+ if (line.begin <= e->cursor && e->cursor <= line.end) {
+ return row;
}
}
+ return e->lines.count - 1;
}
-void editor_insert_text_before_cursor(Editor *editor, const char *text)
+void editor_move_line_up(Editor *e)
{
- editor_create_first_new_line(editor);
- line_insert_text_before(&editor->lines[editor->cursor_row], text, strlen(text), &editor->cursor_col);
+ size_t cursor_row = editor_cursor_row(e);
+ size_t cursor_col = e->cursor - e->lines.items[cursor_row].begin;
+ if (cursor_row > 0) {
+ Line_ next_line = e->lines.items[cursor_row - 1];
+ size_t next_line_size = next_line.end - next_line.begin;
+ if (cursor_col > next_line_size) cursor_col = next_line_size;
+ e->cursor = next_line.begin + cursor_col;
+ }
}
-void editor_backspace(Editor *editor)
+void editor_move_line_down(Editor *e)
{
- editor_create_first_new_line(editor);
- line_backspace(&editor->lines[editor->cursor_row], &editor->cursor_col);
+ size_t cursor_row = editor_cursor_row(e);
+ size_t cursor_col = e->cursor - e->lines.items[cursor_row].begin;
+ if (cursor_row < e->lines.count - 1) {
+ Line_ next_line = e->lines.items[cursor_row + 1];
+ size_t next_line_size = next_line.end - next_line.begin;
+ if (cursor_col > next_line_size) cursor_col = next_line_size;
+ e->cursor = next_line.begin + cursor_col;
+ }
}
-void editor_delete(Editor *editor)
+void editor_move_char_left(Editor *e)
{
- editor_create_first_new_line(editor);
- line_delete(&editor->lines[editor->cursor_row], &editor->cursor_col);
+ if (e->cursor > 0) e->cursor -= 1;
}
-const char *editor_char_under_cursor(const Editor *editor)
+void editor_move_char_right(Editor *e)
{
- if (editor->cursor_row < editor->size) {
- if (editor->cursor_col < editor->lines[editor->cursor_row].size) {
- return &editor->lines[editor->cursor_row].chars[editor->cursor_col];
- }
- }
- return NULL;
+ if (e->cursor < e->data.count) e->cursor += 1;
}
-void editor_save_to_file(const Editor *editor, const char *file_path)
+void editor_insert_char(Editor *e, char x)
{
- FILE *f = fopen(file_path, "w");
- if (f == NULL) {
- fprintf(stdout, "ERROR: could not open file `%s`: %s\n",
- file_path, strerror(errno));
- exit(1);
+ if (e->cursor > e->data.count) {
+ e->cursor = e->data.count;
}
- for (size_t row = 0; row < editor->size; ++row) {
- fwrite(editor->lines[row].chars, 1, editor->lines[row].size, f);
- fputc('\n', f);
- }
+ da_append(&e->data, '\0');
+ memmove(
+ &e->data.items[e->cursor + 1],
+ &e->data.items[e->cursor],
+ e->data.count - e->cursor - 1
+ );
+ e->data.items[e->cursor] = x;
+ e->cursor += 1;
- fclose(f);
+ editor_recompute_lines(e);
}
-void editor_load_from_file(Editor *editor, FILE *file)
+void editor_recompute_lines(Editor *e)
{
- assert(editor->lines == NULL && "You can only load files into an empty editor");
- editor_create_first_new_line(editor);
-
- static char chunk[640 * 1024];
-
- while (!feof(file)) {
- size_t n = fread(chunk, 1, sizeof(chunk), file);
-
- String_View chunk_sv = {
- .data = chunk,
- .count = n
- };
-
- while (chunk_sv.count > 0) {
- String_View chunk_line = {0};
- Line *line = &editor->lines[editor->size - 1];
- if (sv_try_chop_by_delim(&chunk_sv, '\n', &chunk_line)) {
- line_append_text(line, chunk_line.data, chunk_line.count);
- editor_insert_new_line(editor);
- } else {
- line_append_text(line, chunk_sv.data, chunk_sv.count);
- chunk_sv = SV_NULL;
- }
+ e->lines.count = 0;
+
+ Line_ line;
+ line.begin = 0;
+
+ for (size_t i = 0; i < e->data.count; ++i) {
+ if (e->data.items[i] == '\n') {
+ line.end = i;
+ da_append(&e->lines, line);
+ line.begin = i + 1;
}
}
- editor->cursor_row = 0;
+ line.end = e->data.count;
+ da_append(&e->lines, line);
}
diff --git a/src/editor.h b/src/editor.h
@@ -4,31 +4,52 @@
#include <stdlib.h>
typedef struct {
- size_t capacity;
- size_t size;
- char *chars;
-} Line;
+ size_t begin;
+ size_t end;
+} Line_;
-void line_append_text(Line *line, const char *text, size_t text_size);
-void line_insert_text_before(Line *line, const char *text, size_t text_size, size_t *col);
-void line_backspace(Line *line, size_t *col);
-void line_delete(Line *line, size_t *col);
+typedef struct {
+ char *items;
+ size_t count;
+ size_t capacity;
+} Data;
typedef struct {
+ Line_ *items;
+ size_t count;
size_t capacity;
- size_t size;
- Line *lines;
- size_t cursor_row;
- size_t cursor_col;
+} Lines;
+
+#define DA_INIT_CAP 256
+
+#define da_append(da, item) \
+ do { \
+ if ((da)->count >= (da)->capacity) { \
+ (da)->capacity = (da)->capacity == 0 ? DA_INIT_CAP : (da)->capacity*2; \
+ (da)->items = realloc((da)->items, (da)->capacity*sizeof(*(da)->items)); \
+ assert((da)->items != NULL && "Buy more RAM lol"); \
+ } \
+ \
+ (da)->items[(da)->count++] = (item); \
+ } while (0)
+
+typedef struct {
+ Data data;
+ Lines lines;
+ size_t cursor;
} Editor;
void editor_save_to_file(const Editor *editor, const char *file_path);
void editor_load_from_file(Editor *editor, FILE *file);
-void editor_insert_text_before_cursor(Editor *editor, const char *text);
-void editor_insert_new_line(Editor *editor);
void editor_backspace(Editor *editor);
void editor_delete(Editor *editor);
-const char *editor_char_under_cursor(const Editor *editor);
+size_t editor_cursor_row(const Editor *e);
+void editor_move_line_up(Editor *e);
+void editor_move_line_down(Editor *e);
+void editor_move_char_left(Editor *e);
+void editor_move_char_right(Editor *e);
+void editor_insert_char(Editor *e, char x);
+void editor_recompute_lines(Editor *e);
#endif // EDITOR_H_
diff --git a/src/main.c b/src/main.c
@@ -32,7 +32,6 @@
#define FPS 60
#define DELTA_TIME (1.0f / FPS)
-
Editor editor = {0};
Vec2f camera_pos = {0};
float camera_scale = 3.0f;
@@ -95,13 +94,13 @@ void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Cursor_R
free_glyph_buffer_clear(fgb);
{
- for (size_t row = 0; row < editor->size; ++row) {
- const Line *line = editor->lines + row;
+ for (size_t row = 0; row < editor->lines.count; ++row) {
+ Line_ line = editor->lines.items[row];
const Vec2f begin = vec2f(0, -(float)row * FREE_GLYPH_FONT_SIZE);
Vec2f end = begin;
free_glyph_buffer_render_line_sized(
- fgb, line->chars, line->size,
+ fgb, editor->data.items + line.begin, line.end - line.begin,
&end,
vec4fs(1.0f), vec4fs(0.0f));
// TODO: the max_line_len should be calculated based on what's visible on the screen right now
@@ -118,12 +117,16 @@ void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Cursor_R
Vec2f cursor_pos = vec2fs(0.0f);
{
- cursor_pos.y = -(float) editor->cursor_row * FREE_GLYPH_FONT_SIZE;
-
- if (editor->cursor_row < editor->size) {
- Line *line = &editor->lines[editor->cursor_row];
- cursor_pos.x = free_glyph_buffer_cursor_pos(fgb, line->chars, line->size, vec2f(0.0, cursor_pos.y), editor->cursor_col);
- }
+ size_t cursor_row = editor_cursor_row(editor);
+ Line_ line = editor->lines.items[cursor_row];
+ size_t cursor_col = editor->cursor - line.begin;
+ cursor_pos.y = -(float) cursor_row * FREE_GLYPH_FONT_SIZE;
+ cursor_pos.x = free_glyph_buffer_cursor_pos(
+ fgb,
+ editor->data.items + line.begin, line.end - line.begin,
+ vec2f(0.0, cursor_pos.y),
+ cursor_col
+ );
}
cursor_renderer_use(cr);
@@ -160,6 +163,8 @@ void render_editor_into_fgb(SDL_Window *window, Free_Glyph_Buffer *fgb, Cursor_R
int main(int argc, char **argv)
{
+ editor_recompute_lines(&editor);
+
FT_Library library = {0};
FT_Error error = FT_Init_FreeType(&library);
@@ -287,7 +292,7 @@ int main(int argc, char **argv)
break;
case SDLK_RETURN: {
- editor_insert_new_line(&editor);
+ editor_insert_char(&editor, '\n');
cursor_renderer_use(&cr);
glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
}
@@ -301,32 +306,28 @@ int main(int argc, char **argv)
break;
case SDLK_UP: {
- if (editor.cursor_row > 0) {
- editor.cursor_row -= 1;
- }
+ editor_move_line_up(&editor);
cursor_renderer_use(&cr);
glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
}
break;
case SDLK_DOWN: {
- editor.cursor_row += 1;
+ editor_move_line_down(&editor);
cursor_renderer_use(&cr);
glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
}
break;
case SDLK_LEFT: {
- if (editor.cursor_col > 0) {
- editor.cursor_col -= 1;
- cursor_renderer_use(&cr);
- glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
- }
+ editor_move_char_left(&editor);
+ cursor_renderer_use(&cr);
+ glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
}
break;
case SDLK_RIGHT: {
- editor.cursor_col += 1;
+ editor_move_char_right(&editor);
cursor_renderer_use(&cr);
glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
@@ -337,7 +338,11 @@ int main(int argc, char **argv)
break;
case SDL_TEXTINPUT: {
- editor_insert_text_before_cursor(&editor, event.text.text);
+ const char *text = event.text.text;
+ size_t text_len = strlen(text);
+ for (size_t i = 0; i < text_len; ++i) {
+ editor_insert_char(&editor, text[i]);
+ }
cursor_renderer_use(&cr);
glUniform1f(cr.uniforms[UNIFORM_SLOT_LAST_STROKE], (float) SDL_GetTicks() / 1000.0f);
}