Przeglądaj źródła

Port text representation from noed

rexim 2 lat temu
rodzic
commit
d0b7725c29
3 zmienionych plików z 168 dodań i 186 usunięć
  1. 105 149
      src/editor.c
  2. 36 15
      src/editor.h
  3. 27 22
      src/main.c

+ 105 - 149
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);
 }

+ 36 - 15
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_

+ 27 - 22
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);
             }