summaryrefslogtreecommitdiff
path: root/src/core/editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/editor.c')
-rw-r--r--src/core/editor.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/src/core/editor.c b/src/core/editor.c
new file mode 100644
index 0000000..43c28c7
--- /dev/null
+++ b/src/core/editor.c
@@ -0,0 +1,466 @@
+#include "core/editor.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+static EditorColor make_color(int r, int g, int b, int a) {
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+ if (a < 0) a = 0;
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+ if (a > 255) a = 255;
+
+ EditorColor c;
+ c.r = (uint8_t)r;
+ c.g = (uint8_t)g;
+ c.b = (uint8_t)b;
+ c.a = (uint8_t)a;
+ return c;
+}
+
+static Buffer *active_buffer(Editor *editor) {
+ if (editor->current_buffer < 0 || editor->current_buffer >= editor->buffer_count) {
+ return NULL;
+ }
+ return &editor->buffers[editor->current_buffer];
+}
+
+static const Buffer *active_buffer_const(const Editor *editor) {
+ if (editor->current_buffer < 0 || editor->current_buffer >= editor->buffer_count) {
+ return NULL;
+ }
+ return &editor->buffers[editor->current_buffer];
+}
+
+static void clamp_point(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ size_t len = buffer_length(buffer);
+ if (point > len) {
+ buffer_set_point(buffer, len);
+ }
+}
+
+static bool valid_aux_index(const Editor *editor, int aux_index) {
+ return aux_index >= 0 && aux_index < editor->aux_buffer_count;
+}
+
+static bool valid_buffer_index(const Editor *editor, int index) {
+ return index >= 0 && index < editor->buffer_count;
+}
+
+bool editor_init(Editor *editor) {
+ editor->buffer_count = 0;
+ editor->current_buffer = 0;
+
+ if (!buffer_init(&editor->buffers[0])) {
+ return false;
+ }
+
+ editor->buffer_count = 1;
+ editor->aux_buffer_count = 0;
+ editor->desired_col = -1;
+ editor->scroll_line = 0;
+ snprintf(editor->font_query, sizeof(editor->font_query), "%s", "monospace:size=14");
+ editor->font_dirty = true;
+ editor->bg_top = make_color(248, 248, 248, 255);
+ editor->bg_bottom = make_color(238, 238, 238, 255);
+ editor->text = make_color(56, 60, 67, 255);
+ editor->cursor = make_color(176, 65, 11, 255);
+ editor->cursor_shape = LEMACS_CURSOR_BAR;
+ editor->cursor_thickness = 2;
+ editor->view_count = 0;
+ editor->should_quit = false;
+ return true;
+}
+
+void editor_free(Editor *editor) {
+ for (int i = 0; i < editor->buffer_count; ++i) {
+ buffer_free(&editor->buffers[i]);
+ }
+
+ for (int i = 0; i < editor->aux_buffer_count; ++i) {
+ buffer_free(&editor->aux_buffers[i]);
+ }
+
+ editor->buffer_count = 0;
+ editor->current_buffer = 0;
+ editor->aux_buffer_count = 0;
+ editor->view_count = 0;
+}
+
+void editor_set_font_query(Editor *editor, const char *query) {
+ snprintf(editor->font_query, sizeof(editor->font_query), "%s", (query && query[0] != '\0') ? query : "monospace:size=14");
+ editor->font_dirty = true;
+}
+
+const char *editor_font_query(const Editor *editor) {
+ return editor->font_query;
+}
+
+bool editor_consume_font_dirty(Editor *editor) {
+ bool dirty = editor->font_dirty;
+ editor->font_dirty = false;
+ return dirty;
+}
+
+bool editor_set_theme_color(Editor *editor, const char *name, int r, int g, int b, int a) {
+ EditorColor c = make_color(r, g, b, a);
+
+ if (strcmp(name, "bg_top") == 0) {
+ editor->bg_top = c;
+ return true;
+ }
+ if (strcmp(name, "bg_bottom") == 0) {
+ editor->bg_bottom = c;
+ return true;
+ }
+ if (strcmp(name, "text") == 0) {
+ editor->text = c;
+ return true;
+ }
+ if (strcmp(name, "cursor") == 0) {
+ editor->cursor = c;
+ return true;
+ }
+ if (strcmp(name, "accent") == 0) {
+ editor->cursor = c;
+ return true;
+ }
+
+ return false;
+}
+
+bool editor_set_cursor_shape(Editor *editor, int shape) {
+ if (shape < LEMACS_CURSOR_BAR || shape > LEMACS_CURSOR_UNDERLINE) {
+ return false;
+ }
+ editor->cursor_shape = shape;
+ return true;
+}
+
+void editor_set_cursor_thickness(Editor *editor, int thickness) {
+ if (thickness < 1) {
+ thickness = 1;
+ }
+ if (thickness > 24) {
+ thickness = 24;
+ }
+ editor->cursor_thickness = thickness;
+}
+
+int editor_cursor_shape(const Editor *editor) {
+ return editor->cursor_shape;
+}
+
+int editor_cursor_thickness(const Editor *editor) {
+ return editor->cursor_thickness;
+}
+
+int editor_aux_buffer_new(Editor *editor) {
+ if (editor->aux_buffer_count >= LEMACS_MAX_AUX_BUFFERS) {
+ return -1;
+ }
+
+ int index = editor->aux_buffer_count;
+ if (!buffer_init(&editor->aux_buffers[index])) {
+ return -1;
+ }
+
+ editor->aux_buffer_count++;
+ return index;
+}
+
+bool editor_aux_buffer_set_text(Editor *editor, int aux_index, const char *text) {
+ if (!valid_aux_index(editor, aux_index)) {
+ return false;
+ }
+
+ Buffer *buffer = &editor->aux_buffers[aux_index];
+ buffer->gap_start = 0;
+ buffer->gap_end = buffer->capacity;
+ buffer->path[0] = '\0';
+ buffer->modified = false;
+
+ if (!text || text[0] == '\0') {
+ return true;
+ }
+
+ return buffer_insert_cstr(buffer, text);
+}
+
+Buffer *editor_aux_buffer_get(Editor *editor, int aux_index) {
+ if (!valid_aux_index(editor, aux_index)) {
+ return NULL;
+ }
+ return &editor->aux_buffers[aux_index];
+}
+
+void editor_layout_reset(Editor *editor) {
+ editor->view_count = 0;
+}
+
+bool editor_layout_add_view(Editor *editor, int source_type, int source_index, int x, int y, int width, int height, bool show_cursor, EditorColor bg, EditorColor fg) {
+ if (editor->view_count >= LEMACS_MAX_VIEWS) {
+ return false;
+ }
+
+ if (width <= 0 || height <= 0) {
+ return false;
+ }
+
+ if (source_type == 1 && !valid_aux_index(editor, source_index)) {
+ return false;
+ }
+
+ if (source_type != 0 && source_type != 1) {
+ return false;
+ }
+
+ EditorView *view = &editor->views[editor->view_count++];
+ view->x = x;
+ view->y = y;
+ view->width = width;
+ view->height = height;
+ view->source_type = source_type;
+ view->source_index = source_index;
+ view->show_cursor = show_cursor;
+ view->bg = bg;
+ view->fg = fg;
+ return true;
+}
+
+void editor_move_left(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ if (point > 0) {
+ buffer_set_point(buffer, point - 1);
+ }
+ editor->desired_col = -1;
+}
+
+void editor_move_right(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ size_t len = buffer_length(buffer);
+ if (point < len) {
+ buffer_set_point(buffer, point + 1);
+ }
+ editor->desired_col = -1;
+}
+
+void editor_move_up(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ int line = 0;
+ int col = 0;
+ buffer_index_to_line_col(buffer, point, &line, &col);
+ if (editor->desired_col < 0) {
+ editor->desired_col = col;
+ }
+ if (line > 0) {
+ size_t new_point = buffer_line_col_to_index(buffer, line - 1, editor->desired_col);
+ buffer_set_point(buffer, new_point);
+ }
+ clamp_point(editor);
+}
+
+void editor_move_down(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ int line = 0;
+ int col = 0;
+ buffer_index_to_line_col(buffer, point, &line, &col);
+ if (editor->desired_col < 0) {
+ editor->desired_col = col;
+ }
+
+ size_t len = buffer_length(buffer);
+ int last_line = 0;
+ int last_col = 0;
+ buffer_index_to_line_col(buffer, len, &last_line, &last_col);
+ if (line < last_line) {
+ size_t new_point = buffer_line_col_to_index(buffer, line + 1, editor->desired_col);
+ buffer_set_point(buffer, new_point);
+ }
+ clamp_point(editor);
+}
+
+void editor_move_beginning_of_line(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ while (point > 0) {
+ char ch = buffer_char_at(buffer, point - 1);
+ if (ch == '\n') {
+ break;
+ }
+ point--;
+ }
+ buffer_set_point(buffer, point);
+ editor->desired_col = -1;
+}
+
+void editor_move_end_of_line(Editor *editor) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ size_t point = buffer_point(buffer);
+ size_t len = buffer_length(buffer);
+ while (point < len) {
+ char ch = buffer_char_at(buffer, point);
+ if (ch == '\n') {
+ break;
+ }
+ point++;
+ }
+ buffer_set_point(buffer, point);
+ editor->desired_col = -1;
+}
+
+void editor_set_point(Editor *editor, size_t point) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return;
+ }
+
+ buffer_set_point(buffer, point);
+ editor->desired_col = -1;
+}
+
+char editor_char_at(const Editor *editor, size_t index) {
+ const Buffer *buffer = active_buffer_const(editor);
+ if (!buffer) {
+ return '\0';
+ }
+ return buffer_char_at(buffer, index);
+}
+
+bool editor_open_file(Editor *editor, const char *path) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return false;
+ }
+
+ if (!path || path[0] == '\0') {
+ return false;
+ }
+
+ if (!buffer_load_file(buffer, path)) {
+ if (errno != ENOENT) {
+ return false;
+ }
+
+ buffer->gap_start = 0;
+ buffer->gap_end = buffer->capacity;
+ buffer->modified = false;
+ strncpy(buffer->path, path, sizeof(buffer->path) - 1);
+ buffer->path[sizeof(buffer->path) - 1] = '\0';
+ }
+
+ buffer_set_point(buffer, 0);
+ editor->desired_col = -1;
+ editor->scroll_line = 0;
+
+ return true;
+}
+
+bool editor_save_file(Editor *editor, const char *path) {
+ Buffer *buffer = active_buffer(editor);
+ if (!buffer) {
+ return false;
+ }
+ return buffer_save_file(buffer, path);
+}
+
+Buffer *editor_current_buffer(Editor *editor) {
+ return active_buffer(editor);
+}
+
+const Buffer *editor_current_buffer_const(const Editor *editor) {
+ return active_buffer_const(editor);
+}
+
+int editor_buffer_count(const Editor *editor) {
+ return editor->buffer_count;
+}
+
+int editor_current_buffer_index(const Editor *editor) {
+ return editor->current_buffer;
+}
+
+bool editor_switch_buffer(Editor *editor, int index) {
+ if (!valid_buffer_index(editor, index)) {
+ return false;
+ }
+
+ editor->current_buffer = index;
+ editor->desired_col = -1;
+ editor->scroll_line = 0;
+ return true;
+}
+
+int editor_new_buffer(Editor *editor) {
+ if (editor->buffer_count >= LEMACS_MAX_BUFFERS) {
+ return -1;
+ }
+
+ int index = editor->buffer_count;
+ if (!buffer_init(&editor->buffers[index])) {
+ return -1;
+ }
+
+ editor->buffer_count++;
+ editor->current_buffer = index;
+ editor->desired_col = -1;
+ editor->scroll_line = 0;
+ return index;
+}
+
+const char *editor_buffer_path_at(const Editor *editor, int index) {
+ if (!valid_buffer_index(editor, index)) {
+ return NULL;
+ }
+
+ const char *path = buffer_path(&editor->buffers[index]);
+ if (!path || path[0] == '\0') {
+ return NULL;
+ }
+ return path;
+}
+
+bool editor_buffer_modified_at(const Editor *editor, int index) {
+ if (!valid_buffer_index(editor, index)) {
+ return false;
+ }
+ return buffer_modified(&editor->buffers[index]);
+}