commit 7796355fec129ac0a272ca81d88573ebee307921
parent 44712c3ff857fc0fc24988d2d5f5de9bd6060ce6
Author: Alexey Kutepov <reximkut@gmail.com>
Date: Sat, 3 Jul 2021 21:27:59 +0700
Merge pull request #7 from tsoding/load-cli
Load from CLI
Diffstat:
| M | README.md | | | 2 | +- |
| M | editor.c | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
| M | editor.h | | | 5 | +++++ |
| M | main.c | | | 44 | ++++++++++++++++++++++++++++++++++++-------- |
| A | sv.h | | | 268 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 371 insertions(+), 36 deletions(-)
diff --git a/README.md b/README.md
@@ -4,5 +4,5 @@
```console
$ make
-$ ./te
+$ ./te main.c
```
diff --git a/editor.c b/editor.c
@@ -4,10 +4,13 @@
#include <errno.h>
#include <string.h>
#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)
{
size_t new_capacity = line->capacity;
@@ -27,13 +30,23 @@ static void line_grow(Line *line, size_t n)
}
}
-void line_insert_text_before(Line *line, const char *text, size_t *col)
+void line_append_text(Line *line, const char *text)
+{
+ line_append_text_sized(line, text, strlen(text));
+}
+
+void line_append_text_sized(Line *line, const char *text, size_t text_size)
+{
+ size_t col = line->size;
+ line_insert_text_sized_before(line, text, text_size, &col);
+}
+
+void line_insert_text_sized_before(Line *line, const char *text, size_t text_size, 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,
@@ -44,6 +57,11 @@ void line_insert_text_before(Line *line, const char *text, size_t *col)
*col += text_size;
}
+void line_insert_text_before(Line *line, const char *text, size_t *col)
+{
+ line_insert_text_sized_before(line, text, strlen(text), col);
+}
+
void line_backspace(Line *line, size_t *col)
{
if (*col > line->size) {
@@ -110,49 +128,34 @@ void editor_insert_new_line(Editor *editor)
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)
+static void editor_create_first_new_line(Editor *editor)
{
if (editor->cursor_row >= editor->size) {
if (editor->size > 0) {
editor->cursor_row = editor->size - 1;
} else {
- editor_push_new_line(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)
+{
+ editor_create_first_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);
- }
- }
-
+ editor_create_first_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);
- }
- }
-
+ editor_create_first_new_line(editor);
line_delete(&editor->lines[editor->cursor_row], &editor->cursor_col);
}
@@ -182,3 +185,34 @@ void editor_save_to_file(const Editor *editor, const char *file_path)
fclose(f);
}
+
+void editor_load_from_file(Editor *editor, FILE *file)
+{
+ 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_sized(line, chunk_line.data, chunk_line.count);
+ editor_insert_new_line(editor);
+ } else {
+ line_append_text_sized(line, chunk_sv.data, chunk_sv.count);
+ chunk_sv = SV_NULL;
+ }
+ }
+ }
+
+ editor->cursor_row = 0;
+}
diff --git a/editor.h b/editor.h
@@ -9,7 +9,10 @@ typedef struct {
char *chars;
} Line;
+void line_append_text(Line *line, const char *text);
+void line_append_text_sized(Line *line, const char *text, size_t text_size);
void line_insert_text_before(Line *line, const char *text, size_t *col);
+void line_insert_text_sized_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);
@@ -22,6 +25,8 @@ typedef struct {
} 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);
diff --git a/main.c b/main.c
@@ -169,7 +169,14 @@ void render_cursor(SDL_Renderer *renderer, const Font *font)
}
}
-// TODO: Save/Load file
+void usage(FILE *stream)
+{
+ fprintf(stream, "Usage: te [FILE-PATH]\n");
+}
+
+// TODO: Save file
+// TODO: ncurses renderer
+// TODO: scrolling
// TODO: Jump forward/backward by a word
// TODO: Delete a word
// TODO: Blinking cursor
@@ -178,8 +185,19 @@ void render_cursor(SDL_Renderer *renderer, const Font *font)
int main(int argc, char **argv)
{
- (void) argc;
- (void) argv;
+ const char *file_path = NULL;
+
+ if (argc > 1) {
+ file_path = argv[1];
+ }
+
+ if (file_path) {
+ FILE *file = fopen(file_path, "r");
+ if (file != NULL) {
+ editor_load_from_file(&editor, file);
+ fclose(file);
+ }
+ }
scc(SDL_Init(SDL_INIT_VIDEO));
@@ -211,12 +229,16 @@ int main(int argc, char **argv)
break;
case SDLK_F2: {
- editor_save_to_file(&editor, "output");
- } break;
+ if (file_path) {
+ editor_save_to_file(&editor, file_path);
+ }
+ }
+ break;
case SDLK_RETURN: {
editor_insert_new_line(&editor);
- } break;
+ }
+ break;
case SDLK_DELETE: {
editor_delete(&editor);
@@ -227,11 +249,13 @@ int main(int argc, char **argv)
if (editor.cursor_row > 0) {
editor.cursor_row -= 1;
}
- } break;
+ }
+ break;
case SDLK_DOWN: {
editor.cursor_row += 1;
- } break;
+ }
+ break;
case SDLK_LEFT: {
if (editor.cursor_col > 0) {
@@ -271,3 +295,7 @@ int main(int argc, char **argv)
return 0;
}
+
+#define SV_IMPLEMENTATION
+#include "./sv.h"
+
diff --git a/sv.h b/sv.h
@@ -0,0 +1,268 @@
+// Copyright 2021 Alexey Kutepov <reximkut@gmail.com>
+
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef SV_H_
+#define SV_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+
+typedef struct {
+ size_t count;
+ const char *data;
+} String_View;
+
+#define SV(cstr_lit) \
+ ((String_View) { \
+ .count = sizeof(cstr_lit) - 1, \
+ .data = (cstr_lit) \
+ })
+
+#define SV_STATIC(cstr_lit) \
+ { \
+ .count = sizeof(cstr_lit) - 1, \
+ .data = (cstr_lit) \
+ }
+
+#define SV_NULL (String_View) {0}
+
+// printf macros for String_View
+#define SV_Fmt "%.*s"
+#define SV_Arg(sv) (int) (sv).count, (sv).data
+// USAGE:
+// String_View name = ...;
+// printf("Name: "SV_Fmt"\n", SV_Arg(name));
+
+String_View sv_from_cstr(const char *cstr);
+String_View sv_trim_left(String_View sv);
+String_View sv_trim_right(String_View sv);
+String_View sv_trim(String_View sv);
+String_View sv_chop_by_delim(String_View *sv, char delim);
+bool sv_try_chop_by_delim(String_View *sv, char delim, String_View *chunk);
+String_View sv_chop_left(String_View *sv, size_t n);
+String_View sv_chop_right(String_View *sv, size_t n);
+String_View sv_chop_left_while(String_View *sv, bool (*predicate)(char x));
+bool sv_index_of(String_View sv, char c, size_t *index);
+bool sv_eq(String_View a, String_View b);
+bool sv_starts_with(String_View sv, String_View prefix);
+bool sv_ends_with(String_View sv, String_View suffix);
+uint64_t sv_to_u64(String_View sv);
+
+#endif // SV_H_
+
+#ifdef SV_IMPLEMENTATION
+String_View sv_from_cstr(const char *cstr)
+{
+ return (String_View) {
+ .count = strlen(cstr),
+ .data = cstr,
+ };
+}
+
+String_View sv_trim_left(String_View sv)
+{
+ size_t i = 0;
+ while (i < sv.count && isspace(sv.data[i])) {
+ i += 1;
+ }
+
+ return (String_View) {
+ .count = sv.count - i,
+ .data = sv.data + i,
+ };
+}
+
+String_View sv_trim_right(String_View sv)
+{
+ size_t i = 0;
+ while (i < sv.count && isspace(sv.data[sv.count - 1 - i])) {
+ i += 1;
+ }
+
+ return (String_View) {
+ .count = sv.count - i,
+ .data = sv.data
+ };
+}
+
+String_View sv_trim(String_View sv)
+{
+ return sv_trim_right(sv_trim_left(sv));
+}
+
+String_View sv_chop_left(String_View *sv, size_t n)
+{
+ if (n > sv->count) {
+ n = sv->count;
+ }
+
+ String_View result = {
+ .data = sv->data,
+ .count = n,
+ };
+
+ sv->data += n;
+ sv->count -= n;
+
+ return result;
+}
+
+String_View sv_chop_right(String_View *sv, size_t n)
+{
+ if (n > sv->count) {
+ n = sv->count;
+ }
+
+ String_View result = {
+ .data = sv->data + sv->count - n,
+ .count = n
+ };
+
+ sv->count -= n;
+
+ return result;
+}
+
+bool sv_index_of(String_View sv, char c, size_t *index)
+{
+ size_t i = 0;
+ while (i < sv.count && sv.data[i] != c) {
+ i += 1;
+ }
+
+ if (i < sv.count) {
+ if (index) {
+ *index = i;
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool sv_try_chop_by_delim(String_View *sv, char delim, String_View *chunk)
+{
+ size_t i = 0;
+ while (i < sv->count && sv->data[i] != delim) {
+ i += 1;
+ }
+
+ String_View result = {
+ .count = i,
+ .data = sv->data,
+ };
+
+ if (i < sv->count) {
+ sv->count -= i + 1;
+ sv->data += i + 1;
+ if (chunk) {
+ *chunk = result;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+String_View sv_chop_by_delim(String_View *sv, char delim)
+{
+ size_t i = 0;
+ while (i < sv->count && sv->data[i] != delim) {
+ i += 1;
+ }
+
+ String_View result = {
+ .count = i,
+ .data = sv->data,
+ };
+
+ if (i < sv->count) {
+ sv->count -= i + 1;
+ sv->data += i + 1;
+ } else {
+ sv->count -= i;
+ sv->data += i;
+ }
+
+ return result;
+}
+
+bool sv_starts_with(String_View sv, String_View expected_prefix)
+{
+ if (expected_prefix.count <= sv.count) {
+ String_View actual_prefix = {
+ .data = sv.data,
+ .count = expected_prefix.count,
+ };
+
+ return sv_eq(expected_prefix, actual_prefix);
+ }
+
+ return false;
+}
+
+bool sv_ends_with(String_View sv, String_View expected_suffix)
+{
+ if (expected_suffix.count <= sv.count) {
+ String_View actual_suffix = {
+ .data = sv.data + sv.count - expected_suffix.count,
+ .count = expected_suffix.count
+ };
+
+ return sv_eq(expected_suffix, actual_suffix);
+ }
+
+ return false;
+}
+
+bool sv_eq(String_View a, String_View b)
+{
+ if (a.count != b.count) {
+ return false;
+ } else {
+ return memcmp(a.data, b.data, a.count) == 0;
+ }
+}
+
+uint64_t sv_to_u64(String_View sv)
+{
+ uint64_t result = 0;
+
+ for (size_t i = 0; i < sv.count && isdigit(sv.data[i]); ++i) {
+ result = result * 10 + (uint64_t) sv.data[i] - '0';
+ }
+
+ return result;
+}
+
+String_View sv_chop_left_while(String_View *sv, bool (*predicate)(char x))
+{
+ size_t i = 0;
+ while (i < sv->count && predicate(sv->data[i])) {
+ i += 1;
+ }
+ return sv_chop_left(sv, i);
+}
+
+#endif // SV_IMPLEMENTATION