Browse Source

Implement multiple lines

rexim 4 years ago
parent
commit
7ab113c2bf
6 changed files with 240 additions and 93 deletions
  1. 1 1
      Makefile
  2. 0 56
      buffer.c
  3. 0 16
      buffer.h
  4. 165 0
      editor.c
  5. 30 0
      editor.h
  6. 44 20
      main.c

+ 1 - 1
Makefile

@@ -2,4 +2,4 @@ CFLAGS=-Wall -Wextra -std=c11 -pedantic -ggdb `pkg-config --cflags sdl2`
 LIBS=`pkg-config --libs sdl2` -lm
 
 te: main.c
-	$(CC) $(CFLAGS) -o te main.c la.c buffer.c $(LIBS)
+	$(CC) $(CFLAGS) -o te main.c la.c editor.c $(LIBS)

+ 0 - 56
buffer.c

@@ -1,56 +0,0 @@
-#include <assert.h>
-#include <string.h>
-#include "./buffer.h"
-
-#define LINE_INIT_CAPACITY 1024
-
-static void line_grow(Line *line, size_t n)
-{
-    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;
-    }
-}
-
-void line_insert_text_before(Line *line, const char *text, size_t col)
-{
-    const size_t text_size = strlen(text);
-    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;
-}
-
-void line_backspace(Line *line, size_t col)
-{
-    if (col > 0 && line->size > 0) {
-        memmove(line->chars + col - 1,
-                line->chars + col,
-                line->size - col);
-        line->size -= 1;
-    }
-}
-
-void line_delete(Line *line, size_t col)
-{
-    if (col < line->size && line->size > 0) {
-        memmove(line->chars + col,
-                line->chars + col + 1,
-                line->size - col);
-        line->size -= 1;
-    }
-}

+ 0 - 16
buffer.h

@@ -1,16 +0,0 @@
-#ifndef BUFFER_H_
-#define BUFFER_H_
-
-#include <stdlib.h>
-
-typedef struct {
-    size_t capacity;
-    size_t size;
-    char *chars;
-} Line;
-
-void line_insert_text_before(Line *line, const char *text, size_t col);
-void line_backspace(Line *line, size_t col);
-void line_delete(Line *line, size_t col);
-
-#endif // BUFFER_H_

+ 165 - 0
editor.c

@@ -0,0 +1,165 @@
+#include <assert.h>
+#include <string.h>
+#include <stdbool.h>
+#include "./editor.h"
+
+#define LINE_INIT_CAPACITY 1024
+#define EDITOR_INIT_CAPACITY 128
+
+static void line_grow(Line *line, size_t n)
+{
+    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;
+    }
+}
+
+void line_insert_text_before(Line *line, const char *text, size_t *col)
+{
+    if (*col > line->size) {
+        *col = line->size;
+    }
+
+    const size_t text_size = strlen(text);
+    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;
+}
+
+void line_backspace(Line *line, size_t *col)
+{
+    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;
+    }
+}
+
+void line_delete(Line *line, size_t *col)
+{
+    if (*col > line->size) {
+        *col = line->size;
+    }
+
+    if (*col < line->size && line->size > 0) {
+        memmove(line->chars + *col,
+                line->chars + *col + 1,
+                line->size - *col);
+        line->size -= 1;
+    }
+}
+
+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 (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;
+    }
+
+    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;
+}
+
+void editor_push_new_line(Editor *editor)
+{
+    editor_grow(editor, 1);
+    memset(&editor->lines[editor->size], 0, sizeof(editor->lines[0]));
+    editor->size += 1;
+}
+
+void editor_insert_text_before_cursor(Editor *editor, const char *text)
+{
+    if (editor->cursor_row >= editor->size) {
+        if (editor->size > 0) {
+            editor->cursor_row = editor->size - 1;
+        } else {
+            editor_push_new_line(editor);
+        }
+    }
+
+    line_insert_text_before(&editor->lines[editor->cursor_row], text, &editor->cursor_col);
+}
+
+void editor_backspace(Editor *editor)
+{
+    if (editor->cursor_row >= editor->size) {
+        if (editor->size > 0) {
+            editor->cursor_row = editor->size - 1;
+        } else {
+            editor_push_new_line(editor);
+        }
+    }
+
+    line_backspace(&editor->lines[editor->cursor_row], &editor->cursor_col);
+}
+
+void editor_delete(Editor *editor)
+{
+    if (editor->cursor_row >= editor->size) {
+        if (editor->size > 0) {
+            editor->cursor_row = editor->size - 1;
+        } else {
+            editor_push_new_line(editor);
+        }
+    }
+
+    line_delete(&editor->lines[editor->cursor_row], &editor->cursor_col);
+}
+
+const char *editor_char_under_cursor(const Editor *editor)
+{
+    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;
+}

+ 30 - 0
editor.h

@@ -0,0 +1,30 @@
+#ifndef EDITOR_H_
+#define EDITOR_H_
+
+#include <stdlib.h>
+
+typedef struct {
+    size_t capacity;
+    size_t size;
+    char *chars;
+} Line;
+
+void line_insert_text_before(Line *line, const char *text, size_t *col);
+void line_backspace(Line *line, size_t *col);
+void line_delete(Line *line, size_t *col);
+
+typedef struct {
+    size_t capacity;
+    size_t size;
+    Line *lines;
+    size_t cursor_row;
+    size_t cursor_col;
+} Editor;
+
+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);
+
+#endif // EDITOR_H_

+ 44 - 20
main.c

@@ -9,7 +9,7 @@
 #define STB_IMAGE_IMPLEMENTATION
 #include "./stb_image.h"
 
-#include "./buffer.h"
+#include "./editor.h"
 
 #define FONT_WIDTH 128
 #define FONT_HEIGHT 64
@@ -138,8 +138,7 @@ void render_text_sized(SDL_Renderer *renderer, Font *font, const char *text, siz
     }
 }
 
-Line line = {0};
-size_t cursor = 0;
+Editor editor = {0};
 
 #define UNHEX(color) \
     ((color) >> (8 * 0)) & 0xFF, \
@@ -149,7 +148,9 @@ size_t cursor = 0;
 
 void render_cursor(SDL_Renderer *renderer, const Font *font)
 {
-    const Vec2f pos = vec2f((float) cursor * FONT_CHAR_WIDTH * FONT_SCALE, 0.0f);
+    const Vec2f pos =
+        vec2f((float) editor.cursor_col * FONT_CHAR_WIDTH * FONT_SCALE,
+              (float) editor.cursor_row * FONT_CHAR_HEIGHT * FONT_SCALE);
 
     const SDL_Rect rect = {
         .x = (int) floorf(pos.x),
@@ -161,9 +162,10 @@ void render_cursor(SDL_Renderer *renderer, const Font *font)
     scc(SDL_SetRenderDrawColor(renderer, UNHEX(0xFFFFFFFF)));
     scc(SDL_RenderFillRect(renderer, &rect));
 
-    set_texture_color(font->spritesheet, 0xFF000000);
-    if (cursor < line.size) {
-        render_char(renderer, font, line.chars[cursor], pos, FONT_SCALE);
+    const char *c = editor_char_under_cursor(&editor);
+    if (c) {
+        set_texture_color(font->spritesheet, 0xFF000000);
+        render_char(renderer, font, *c, pos, FONT_SCALE);
     }
 }
 
@@ -178,6 +180,16 @@ int main(int argc, char **argv)
     (void) argc;
     (void) argv;
 
+    editor_insert_text_before_cursor(&editor, "dhjfhskjdfhkjshdf");
+    editor_insert_new_line(&editor);
+    editor_insert_text_before_cursor(&editor, "3j4k23l4j");
+    editor_insert_new_line(&editor);
+    editor_insert_text_before_cursor(&editor, "456kj356klj35l6j");
+    editor_insert_new_line(&editor);
+    editor_insert_text_before_cursor(&editor, "46jkl45jkljclslkj");
+    editor_insert_new_line(&editor);
+    editor_insert_text_before_cursor(&editor, "tjk5kfkdjgk");
+
     scc(SDL_Init(SDL_INIT_VIDEO));
 
     SDL_Window *window =
@@ -203,28 +215,38 @@ int main(int argc, char **argv)
             case SDL_KEYDOWN: {
                 switch (event.key.keysym.sym) {
                 case SDLK_BACKSPACE: {
-                    line_backspace(&line, cursor);
-                    if (cursor > 0) {
-                        cursor -= 1;
-                    }
+                    editor_backspace(&editor);
                 }
                 break;
 
+                case SDLK_RETURN: {
+                    editor_insert_new_line(&editor);
+                } break;
+
                 case SDLK_DELETE: {
-                    line_delete(&line, cursor);
+                    editor_delete(&editor);
+                }
+                break;
+
+                case SDLK_UP: {
+                    if (editor.cursor_row > 0) {
+                        editor.cursor_row -= 1;
+                    }
+                } break;
+
+                case SDLK_DOWN: {
+                    editor.cursor_row += 1;
                 } break;
 
                 case SDLK_LEFT: {
-                    if (cursor > 0) {
-                        cursor -= 1;
+                    if (editor.cursor_col > 0) {
+                        editor.cursor_col -= 1;
                     }
                 }
                 break;
 
                 case SDLK_RIGHT: {
-                    if (cursor < line.size) {
-                        cursor += 1;
-                    }
+                    editor.cursor_col += 1;
                 }
                 break;
                 }
@@ -232,8 +254,7 @@ int main(int argc, char **argv)
             break;
 
             case SDL_TEXTINPUT: {
-                line_insert_text_before(&line, event.text.text, cursor);
-                cursor += strlen(event.text.text);
+                editor_insert_text_before_cursor(&editor, event.text.text);
             }
             break;
             }
@@ -242,7 +263,10 @@ int main(int argc, char **argv)
         scc(SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0));
         scc(SDL_RenderClear(renderer));
 
-        render_text_sized(renderer, &font, line.chars, line.size, vec2f(0.0, 0.0), 0xFFFFFFFF, FONT_SCALE);
+        for (size_t row = 0; row < editor.size; ++row) {
+            const Line *line = editor.lines + row;
+            render_text_sized(renderer, &font, line->chars, line->size, vec2f(0.0f, row * FONT_CHAR_HEIGHT * FONT_SCALE), 0xFFFFFFFF, FONT_SCALE);
+        }
         render_cursor(renderer, &font);
 
         SDL_RenderPresent(renderer);