commit 0cf2620d2bd992a62648ed2388070d6920aba051
parent 5f96463537ee5b750ce72138ef7d990cceed72c4
Author: Alexey Kutepov <reximkut@gmail.com>
Date: Fri, 2 Jul 2021 21:52:50 +0700
Merge pull request #5 from tsoding/multiple-lines
Multiple lines
Diffstat:
| M | Makefile | | | 2 | +- |
| M | build_msvc.bat | | | 4 | ++-- |
| A | editor.c | | | 184 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | editor.h | | | 31 | +++++++++++++++++++++++++++++++ |
| M | main.c | | | 101 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
5 files changed, 260 insertions(+), 62 deletions(-)
diff --git a/Makefile b/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 $(LIBS)
+ $(CC) $(CFLAGS) -o te main.c la.c editor.c $(LIBS)
diff --git a/build_msvc.bat b/build_msvc.bat
@@ -1,8 +1,8 @@
@echo off
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 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
diff --git a/editor.c b/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);
+}
diff --git a/editor.h b/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_
diff --git a/main.c b/main.c
@@ -9,6 +9,8 @@
#define STB_IMAGE_IMPLEMENTATION
#include "./stb_image.h"
+#include "./editor.h"
+
#define FONT_WIDTH 128
#define FONT_HEIGHT 64
#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) \
((color) >> (8 * 0)) & 0xFF, \
@@ -186,7 +148,9 @@ void buffer_delete(void)
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 = {
.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_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: Delete a word
// 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)
{
(void) argc;
(void) argv;
- buffer_insert_text_before_cursor("Hello, World");
-
scc(SDL_Init(SDL_INIT_VIDEO));
SDL_Window *window =
@@ -243,25 +206,42 @@ int main(int argc, char **argv)
case SDL_KEYDOWN: {
switch (event.key.keysym.sym) {
case SDLK_BACKSPACE: {
- buffer_backspace();
+ editor_backspace(&editor);
}
break;
+ case SDLK_F2: {
+ editor_save_to_file(&editor, "output");
+ } break;
+
+ case SDLK_RETURN: {
+ editor_insert_new_line(&editor);
+ } break;
+
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;
case SDLK_LEFT: {
- if (buffer_cursor > 0) {
- buffer_cursor -= 1;
+ if (editor.cursor_col > 0) {
+ editor.cursor_col -= 1;
}
}
break;
case SDLK_RIGHT: {
- if (buffer_cursor < buffer_size) {
- buffer_cursor += 1;
- }
+ editor.cursor_col += 1;
}
break;
}
@@ -269,7 +249,7 @@ int main(int argc, char **argv)
break;
case SDL_TEXTINPUT: {
- buffer_insert_text_before_cursor(event.text.text);
+ editor_insert_text_before_cursor(&editor, event.text.text);
}
break;
}
@@ -278,7 +258,10 @@ int main(int argc, char **argv)
scc(SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0));
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);
SDL_RenderPresent(renderer);