Browse Source

Merge pull request #5 from tsoding/multiple-lines

Multiple lines
Alexey Kutepov 4 years ago
parent
commit
0cf2620d2b
5 changed files with 260 additions and 62 deletions
  1. 1 1
      Makefile
  2. 2 2
      build_msvc.bat
  3. 184 0
      editor.c
  4. 31 0
      editor.h
  5. 42 59
      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
 LIBS=`pkg-config --libs sdl2` -lm
 
 
 te: main.c
 te: main.c
-	$(CC) $(CFLAGS) -o te main.c la.c $(LIBS)
+	$(CC) $(CFLAGS) -o te main.c la.c editor.c $(LIBS)

+ 2 - 2
build_msvc.bat

@@ -1,8 +1,8 @@
 @echo off
 @echo off
 rem launch this from msvc-enabled console
 rem launch this from msvc-enabled console
 
 
-set CFLAGS=/W4 /WX /std:c11 /FC /TC /Zi /nologo
+set CFLAGS=/W4 /WX /std:c11 /wd4996 /FC /TC /Zi /nologo
 set INCLUDES=/I SDL2\include
 set INCLUDES=/I SDL2\include
 set LIBS=SDL2\lib\x64\SDL2.lib SDL2\lib\x64\SDL2main.lib Shell32.lib
 set LIBS=SDL2\lib\x64\SDL2.lib SDL2\lib\x64\SDL2main.lib Shell32.lib
 
 
-cl.exe %CFLAGS% %INCLUDES% /Fete main.c la.c /link %LIBS% -SUBSYSTEM:windows
+cl.exe %CFLAGS% %INCLUDES% /Fete main.c la.c editor.c /link %LIBS% -SUBSYSTEM:windows

+ 184 - 0
editor.c

@@ -0,0 +1,184 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.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;
+}
+
+void editor_save_to_file(const Editor *editor, const char *file_path)
+{
+    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);
+    }
+
+    for (size_t row = 0; row < editor->size; ++row) {
+        fwrite(editor->lines[row].chars, 1, editor->lines[row].size, f);
+        fputc('\n', f);
+    }
+
+    fclose(f);
+}

+ 31 - 0
editor.h

@@ -0,0 +1,31 @@
+#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_save_to_file(const Editor *editor, const char *file_path);
+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_

+ 42 - 59
main.c

@@ -9,6 +9,8 @@
 #define STB_IMAGE_IMPLEMENTATION
 #define STB_IMAGE_IMPLEMENTATION
 #include "./stb_image.h"
 #include "./stb_image.h"
 
 
+#include "./editor.h"
+
 #define FONT_WIDTH 128
 #define FONT_WIDTH 128
 #define FONT_HEIGHT 64
 #define FONT_HEIGHT 64
 #define FONT_COLS 18
 #define FONT_COLS 18
@@ -136,47 +138,7 @@ void render_text_sized(SDL_Renderer *renderer, Font *font, const char *text, siz
     }
     }
 }
 }
 
 
-#define BUFFER_CAPACITY 1024
-
-char buffer[BUFFER_CAPACITY];
-size_t buffer_cursor = 0;
-size_t buffer_size = 0;
-
-void buffer_insert_text_before_cursor(const char *text)
-{
-    size_t text_size = strlen(text);
-    const size_t free_space = BUFFER_CAPACITY - buffer_size;
-    if (text_size > free_space) {
-        text_size = free_space;
-    }
-    memmove(buffer + buffer_cursor + text_size,
-            buffer + buffer_cursor,
-            buffer_size - buffer_cursor);
-    memcpy(buffer + buffer_cursor, text, text_size);
-    buffer_size += text_size;
-    buffer_cursor += text_size;
-}
-
-void buffer_backspace(void)
-{
-    if (buffer_cursor > 0 && buffer_size > 0) {
-        memmove(buffer + buffer_cursor - 1,
-                buffer + buffer_cursor,
-                buffer_size - buffer_cursor);
-        buffer_size -= 1;
-        buffer_cursor -= 1;
-    }
-}
-
-void buffer_delete(void)
-{
-    if (buffer_cursor < buffer_size && buffer_size > 0) {
-        memmove(buffer + buffer_cursor,
-                buffer + buffer_cursor + 1,
-                buffer_size - buffer_cursor);
-        buffer_size -= 1;
-    }
-}
+Editor editor = {0};
 
 
 #define UNHEX(color) \
 #define UNHEX(color) \
     ((color) >> (8 * 0)) & 0xFF, \
     ((color) >> (8 * 0)) & 0xFF, \
@@ -186,7 +148,9 @@ void buffer_delete(void)
 
 
 void render_cursor(SDL_Renderer *renderer, const Font *font)
 void render_cursor(SDL_Renderer *renderer, const Font *font)
 {
 {
-    const Vec2f pos = vec2f((float) buffer_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 = {
     const SDL_Rect rect = {
         .x = (int) floorf(pos.x),
         .x = (int) floorf(pos.x),
@@ -198,26 +162,25 @@ void render_cursor(SDL_Renderer *renderer, const Font *font)
     scc(SDL_SetRenderDrawColor(renderer, UNHEX(0xFFFFFFFF)));
     scc(SDL_SetRenderDrawColor(renderer, UNHEX(0xFFFFFFFF)));
     scc(SDL_RenderFillRect(renderer, &rect));
     scc(SDL_RenderFillRect(renderer, &rect));
 
 
-    set_texture_color(font->spritesheet, 0xFF000000);
-    if (buffer_cursor < buffer_size) {
-        render_char(renderer, font, buffer[buffer_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);
     }
     }
 }
 }
 
 
-
+// TODO: Save/Load file
 // TODO: Jump forward/backward by a word
 // TODO: Jump forward/backward by a word
 // TODO: Delete a word
 // TODO: Delete a word
 // TODO: Blinking cursor
 // TODO: Blinking cursor
-// TODO: Multiple lines
-// TODO: Save/Load file
+// TODO: Delete line
+// TODO: Split the line on Enter
 
 
 int main(int argc, char **argv)
 int main(int argc, char **argv)
 {
 {
     (void) argc;
     (void) argc;
     (void) argv;
     (void) argv;
 
 
-    buffer_insert_text_before_cursor("Hello, World");
-
     scc(SDL_Init(SDL_INIT_VIDEO));
     scc(SDL_Init(SDL_INIT_VIDEO));
 
 
     SDL_Window *window =
     SDL_Window *window =
@@ -243,25 +206,42 @@ int main(int argc, char **argv)
             case SDL_KEYDOWN: {
             case SDL_KEYDOWN: {
                 switch (event.key.keysym.sym) {
                 switch (event.key.keysym.sym) {
                 case SDLK_BACKSPACE: {
                 case SDLK_BACKSPACE: {
-                    buffer_backspace();
+                    editor_backspace(&editor);
                 }
                 }
                 break;
                 break;
 
 
+                case SDLK_F2: {
+                    editor_save_to_file(&editor, "output");
+                } break;
+
+                case SDLK_RETURN: {
+                    editor_insert_new_line(&editor);
+                } break;
+
                 case SDLK_DELETE: {
                 case SDLK_DELETE: {
-                    buffer_delete();
+                    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;
                 } break;
 
 
                 case SDLK_LEFT: {
                 case SDLK_LEFT: {
-                    if (buffer_cursor > 0) {
-                        buffer_cursor -= 1;
+                    if (editor.cursor_col > 0) {
+                        editor.cursor_col -= 1;
                     }
                     }
                 }
                 }
                 break;
                 break;
 
 
                 case SDLK_RIGHT: {
                 case SDLK_RIGHT: {
-                    if (buffer_cursor < buffer_size) {
-                        buffer_cursor += 1;
-                    }
+                    editor.cursor_col += 1;
                 }
                 }
                 break;
                 break;
                 }
                 }
@@ -269,7 +249,7 @@ int main(int argc, char **argv)
             break;
             break;
 
 
             case SDL_TEXTINPUT: {
             case SDL_TEXTINPUT: {
-                buffer_insert_text_before_cursor(event.text.text);
+                editor_insert_text_before_cursor(&editor, event.text.text);
             }
             }
             break;
             break;
             }
             }
@@ -278,7 +258,10 @@ int main(int argc, char **argv)
         scc(SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0));
         scc(SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0));
         scc(SDL_RenderClear(renderer));
         scc(SDL_RenderClear(renderer));
 
 
-        render_text_sized(renderer, &font, buffer, buffer_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, (float) row * FONT_CHAR_HEIGHT * FONT_SCALE), 0xFFFFFFFF, FONT_SCALE);
+        }
         render_cursor(renderer, &font);
         render_cursor(renderer, &font);
 
 
         SDL_RenderPresent(renderer);
         SDL_RenderPresent(renderer);