diff options
Diffstat (limited to 'ted.c')
-rw-r--r-- | ted.c | 201 |
1 files changed, 201 insertions, 0 deletions
@@ -0,0 +1,201 @@ +// this is a macro so we get -Wformat warnings +#define ted_seterr(buffer, ...) \ + snprintf(ted->error, sizeof ted->error - 1, __VA_ARGS__) + +void ted_seterr_to_buferr(Ted *ted, TextBuffer *buffer) { + size_t size = sizeof ted->error; + if (sizeof buffer->error < size) size = sizeof buffer->error; + memcpy(ted->error, buffer->error, size); +} + +bool ted_haserr(Ted *ted) { + return ted->error[0] != '\0'; +} + +char const *ted_geterr(Ted *ted) { + return ted->error; +} + +void ted_clearerr(Ted *ted) { + ted->error[0] = '\0'; +} + +static void ted_out_of_mem(Ted *ted) { + ted_seterr(ted, "Out of memory."); +} + +static void *ted_malloc(Ted *ted, size_t size) { + void *ret = malloc(size); + if (!ret) ted_out_of_mem(ted); + return ret; +} + +static void *ted_calloc(Ted *ted, size_t n, size_t size) { + void *ret = calloc(n, size); + if (!ret) ted_out_of_mem(ted); + return ret; +} + +static void *ted_realloc(Ted *ted, void *p, size_t new_size) { + void *ret = realloc(p, new_size); + if (!ret) ted_out_of_mem(ted); + return ret; +} + +// Check the various places a file could be, and return the full path. +static Status ted_get_file(Ted const *ted, char const *name, char *out, size_t outsz) { + if (ted->search_cwd && fs_file_exists(name)) { + // check in current working directory + str_cpy(out, outsz, name); + return true; + } + if (*ted->local_data_dir) { + str_printf(out, outsz, "%s" PATH_SEPARATOR_STR "%s", ted->local_data_dir, name); + if (fs_file_exists(out)) + return true; + } + if (*ted->global_data_dir) { + str_printf(out, outsz, "%s" PATH_SEPARATOR_STR "%s", ted->global_data_dir, name); + if (fs_file_exists(out)) + return true; + } + return false; +} + +// Loads font from filename into *out, freeing any font that was previously there. +// *out is left unchanged on failure. +static void ted_load_font(Ted *ted, char const *filename, Font **out) { + char font_filename[TED_PATH_MAX]; + if (ted_get_file(ted, filename, font_filename, sizeof font_filename)) { + Font *font = text_font_load(font_filename, ted->settings.text_size); + if (font) { + if (*out) { + text_font_free(*out); + } + *out = font; + } else { + ted_seterr(ted, "Couldn't load font: %s", text_get_err()); + text_clear_err(); + } + } else { + ted_seterr(ted, "Couldn't find font file. There is probably a problem with your ted installation."); + } + +} + +// Load all the fonts ted will use. +static void ted_load_fonts(Ted *ted) { + ted_load_font(ted, "assets/font.ttf", &ted->font); + ted_load_font(ted, "assets/font-bold.ttf", &ted->font_bold); +} + +// returns the index of an available buffer, or -1 if none are available +static i32 ted_new_buffer(Ted *ted) { + bool *buffers_used = ted->buffers_used; + for (i32 i = 0; i < TED_MAX_BUFFERS; ++i) { + if (!buffers_used[i]) { + buffers_used[i] = true; + buffer_create(&ted->buffers[i], ted); + return i; + } + } + return -1; +} + +// Opposite of ted_new_buffer +// Make sure you set active_buffer to something else if you delete it! +static void ted_delete_buffer(Ted *ted, u16 index) { + TextBuffer *buffer = &ted->buffers[index]; + if (buffer == ted->active_buffer) + ted->active_buffer = NULL; // make sure we don't set the active buffer to something invalid + buffer_free(buffer); + ted->buffers_used[index] = false; +} + +// Returns the index of an available node, or -1 if none are available +static i32 ted_new_node(Ted *ted) { + bool *nodes_used = ted->nodes_used; + for (i32 i = 0; i < TED_MAX_NODES; ++i) { + if (!nodes_used[i]) { + nodes_used[i] = true; + return i; + } + } + ted_seterr(ted, "Too many nodes."); + return -1; + +} + +static void node_tab_close(Ted *ted, Node *node, u16 index); + +// Open a new buffer. Fills out *tab to the index of the tab used, and *buffer_idx to the index of the buffer. +// Returns true on success. +static Status ted_open_buffer(Ted *ted, u16 *buffer_idx, u16 *tab) { + i32 new_buffer_index = ted_new_buffer(ted); + if (new_buffer_index >= 0) { + Node *node = ted->active_node; + if (!node) { + // no active node; let's create one! + i32 node_idx = ted_new_node(ted); + if (node_idx >= 0) { + node = &ted->nodes[node_idx]; + ted->active_node = node; + } else { + ted_delete_buffer(ted, (u16)new_buffer_index); + return false; + } + } + if (arr_len(node->tabs) < TED_MAX_TABS) { + arr_add(node->tabs, (u16)new_buffer_index); + TextBuffer *new_buffer = &ted->buffers[new_buffer_index]; + ted->active_buffer = new_buffer; + node->active_tab = (u16)(arr_len(node->tabs) - 1); + *buffer_idx = (u16)new_buffer_index; + *tab = node->active_tab; + return true; + } else { + ted_seterr(ted, "Too many tabs."); + ted_delete_buffer(ted, (u16)new_buffer_index); + return false; + } + } else { + return false; + } +} + +// Returns true on success +static bool ted_open_file(Ted *ted, char const *filename) { + u16 buffer_idx, tab_idx; + if (ted_open_buffer(ted, &buffer_idx, &tab_idx)) { + TextBuffer *buffer = &ted->buffers[buffer_idx]; + if (buffer_load_file(buffer, filename)) { + return true; + } else { + node_tab_close(ted, ted->active_node, tab_idx); + ted_delete_buffer(ted, (u16)buffer_idx); + return false; + } + } else { + return false; + } +} + +static bool ted_new_file(Ted *ted) { + u16 buffer_idx, tab_idx; + if (ted_open_buffer(ted, &buffer_idx, &tab_idx)) { + TextBuffer *buffer = &ted->buffers[buffer_idx]; + buffer_new_file(buffer, TED_UNTITLED); + if (!buffer_haserr(buffer)) { + return true; + } else { + node_tab_close(ted, ted->active_node, tab_idx); + ted_delete_buffer(ted, (u16)buffer_idx); + return false; + } + } else { + return false; + } +} + +static void menu_open(Ted *ted, Menu menu); +static void menu_escape(Ted *ted); |