From cebb280fe546190e55e071b6adbf37cd47950f34 Mon Sep 17 00:00:00 2001 From: Collin Williams <96917990+bluedragon1221@users.noreply.github.com> Date: Mon, 11 May 2026 15:07:55 -0500 Subject: initial commit --- src/core/editor.c | 466 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100644 src/core/editor.c (limited to 'src/core/editor.c') 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 +#include +#include + +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]); +} -- cgit v1.3.1