diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffers.c | 18 | ||||
| -rw-r--r-- | src/config.c | 13 | ||||
| -rw-r--r-- | src/ecex.c | 106 | ||||
| -rw-r--r-- | src/log.c | 22 | ||||
| -rw-r--r-- | src/path.c | 22 |
5 files changed, 160 insertions, 21 deletions
diff --git a/src/buffers.c b/src/buffers.c index 1e42bfc..c2e94e2 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -302,15 +302,25 @@ int buffer_delete_selection(buffer_t *buffer) { int buffer_replace_selection(buffer_t *buffer, const char *text) { if (!buffer || !text) return ECEX_ERR; if (!buffer_has_selection(buffer)) return buffer_insert(buffer, text); + if (buffer_record_undo(buffer) != ECEX_OK) return ECEX_ERR; size_t start = 0; size_t end = 0; buffer_selection_range(buffer, &start, &end); - if (buffer_delete_range(buffer, start, end) != ECEX_OK) return ECEX_ERR; - buffer->point = start; - buffer_clear_mark(buffer); - return buffer_insert(buffer, text); + int undo_disabled = buffer->undo_disabled; + int result = ECEX_OK; + buffer->undo_disabled = 1; + + result = buffer_delete_range(buffer, start, end); + if (result == ECEX_OK) { + buffer->point = start; + buffer_clear_mark(buffer); + result = buffer_insert(buffer, text); + } + + buffer->undo_disabled = undo_disabled; + return result; } int buffer_backspace(buffer_t *buffer) { diff --git a/src/config.c b/src/config.c index 9c885ff..6e4b84f 100644 --- a/src/config.c +++ b/src/config.c @@ -339,9 +339,18 @@ static int add_include_path(ccdjit_context *ctx, const char *path) { return ECEX_ERR; } +static int add_existing_include_path(ccdjit_context *ctx, const char *path) { + if (!path || !path[0] || !ecex_path_is_dir(path)) return ECEX_OK; + return add_include_path(ctx, path); +} + int ecex_add_ccdjit_include_paths(ccdjit_context *ctx) { - if (add_include_path(ctx, "include") != ECEX_OK) return ECEX_ERR; - if (add_include_path(ctx, "../include") != ECEX_OK) return ECEX_ERR; + if (add_existing_include_path(ctx, "include") != ECEX_OK) return ECEX_ERR; + if (add_existing_include_path(ctx, "../include") != ECEX_OK) return ECEX_ERR; + +#ifdef ECEX_SYSTEM_INCLUDE_DIR + if (add_existing_include_path(ctx, ECEX_SYSTEM_INCLUDE_DIR) != ECEX_OK) return ECEX_ERR; +#endif const char *env_include = getenv("ECEX_INCLUDE"); if (env_include && env_include[0]) { @@ -33,6 +33,9 @@ extern int kill(pid_t pid, int sig); #define ECEX_INITIAL_MODE_CAP 8 #define ECEX_INITIAL_MODE_KEYBIND_CAP 16 #define ECEX_INITIAL_HOOK_CAP 8 +#define ECEX_MESSAGES_BUFFER_NAME "*Messages*" +#define ECEX_MESSAGES_MAX_BYTES (1024u * 1024u) +#define ECEX_MESSAGES_TRIM_BYTES (256u * 1024u) ecex_window_t *ecex_current_window(ecex_t *ed); static void ecex_clear_command_hooks(ecex_t *ed); @@ -41,6 +44,10 @@ static void ecex_clear_buffer_hooks(ecex_t *ed); static void ecex_clear_completion_providers(ecex_t *ed); static int ecex_complete_at_point_direction(ecex_t *ed, int direction); static int ecex_indent_for_tab(ecex_t *ed); +static int ecex_buffer_index_of(ecex_t *ed, buffer_t *buffer, size_t *out_index); +static buffer_t *ecex_ensure_messages_buffer(ecex_t *ed); +static int ecex_messages_append(ecex_t *ed, const char *prefix, const char *message); +static void ecex_log_messages_sink(const char *line, int depth, void *userdata); void *ecex_config_alloc(size_t size) { @@ -769,10 +776,16 @@ static int cmd_file_browser_history_forward(ecex_t *ed) { } static int cmd_media_play_pause(ecex_t *ed) { return ecex_media_toggle_playback(ed); } +static int cmd_messages(ecex_t *ed) { + buffer_t *buffer = ecex_ensure_messages_buffer(ed); + return buffer ? ecex_switch_buffer(ed, buffer->name) : ECEX_ERR; +} static int ecex_register_builtins(ecex_t *ed) { ECEX_COMMAND("quit", cmd_quit); ECEX_COMMAND("force-quit", cmd_force_quit); + ECEX_COMMAND("messages", cmd_messages); + ECEX_COMMAND("view-messages", cmd_messages); ECEX_COMMAND("find-file", cmd_find_file); ECEX_COMMAND("file-browser", cmd_file_browser); ECEX_COMMAND("file-browser-here", cmd_file_browser_here); @@ -1011,12 +1024,18 @@ ecex_t *ecex_new(void) { } ecex_buffer_set_major_mode_by_name(ed, scratch, "fundamental-mode"); + if (!ecex_ensure_messages_buffer(ed)) { + ecex_free(ed); + return NULL; + } + ecex_log_set_sink(ecex_log_messages_sink, ed); return ed; } void ecex_free(ecex_t *ed) { if (!ed) return; + ecex_log_clear_sink(ed); /* Buffers may hold renderer/animation callbacks and userdata destructors * compiled by CCDJIT config modules. Run those destructors while their JIT @@ -1109,6 +1128,91 @@ int ecex_add_buffer(ecex_t *ed, buffer_t *buffer) { return ECEX_OK; } +static void ecex_messages_trim(buffer_t *buffer) { + if (!buffer || buffer->len <= ECEX_MESSAGES_MAX_BYTES) return; + + size_t trim = buffer->len - ECEX_MESSAGES_MAX_BYTES + ECEX_MESSAGES_TRIM_BYTES; + if (trim > buffer->len) trim = buffer->len; + while (trim < buffer->len && buffer->data[trim] != '\n') trim++; + if (trim < buffer->len) trim++; + + memmove(buffer->data, buffer->data + trim, buffer->len - trim + 1); + buffer->len -= trim; + buffer->point = buffer->len; + buffer->mark = 0; + buffer->mark_active = 0; + buffer->scroll_line = 0; + buffer->scroll_col = 0; +} + +static buffer_t *ecex_ensure_messages_buffer(ecex_t *ed) { + if (!ed) return NULL; + + buffer_t *buffer = ed->messages_buffer; + if (!buffer || ecex_buffer_index_of(ed, buffer, NULL) != ECEX_OK) { + buffer = ecex_find_buffer(ed, ECEX_MESSAGES_BUFFER_NAME); + } + + if (!buffer) { + buffer = ecex_create_buffer(ed, ECEX_MESSAGES_BUFFER_NAME, NULL, 0); + if (!buffer) return NULL; + } + + ed->messages_buffer = buffer; + buffer_set_interactive(buffer, 1); + if (buffer->major_mode == 0) { + ecex_buffer_set_major_mode_by_name(ed, buffer, "special-mode"); + } + buffer->read_only = 1; + buffer->modified = 0; + return buffer; +} + +static int ecex_messages_append(ecex_t *ed, const char *prefix, const char *message) { + if (!ed || ed->messages_append_active) return ECEX_ERR; + + buffer_t *buffer = ecex_ensure_messages_buffer(ed); + if (!buffer) return ECEX_ERR; + + int old_read_only = buffer->read_only; + int old_undo_disabled = buffer->undo_disabled; + ed->messages_append_active = 1; + buffer->read_only = 0; + buffer->undo_disabled = 1; + + int result = ECEX_OK; + if (prefix && prefix[0]) result = buffer_append(buffer, prefix); + if (result == ECEX_OK) result = buffer_append(buffer, message ? message : ""); + if (result == ECEX_OK) result = buffer_append(buffer, "\n"); + if (result == ECEX_OK) ecex_messages_trim(buffer); + + buffer->read_only = old_read_only; + buffer->undo_disabled = old_undo_disabled; + buffer->modified = 0; + buffer_clear_undo(buffer); + ed->messages_append_active = 0; + ecex_mark_ui_changed(ed); + return result; +} + +static void ecex_log_messages_sink(const char *line, int depth, void *userdata) { + ecex_t *ed = (ecex_t *)userdata; + char prefix[64]; + size_t pos = 0; + + if (!ed) return; + int written = snprintf(prefix, sizeof(prefix), "ecex-log: "); + if (written < 0) return; + pos = (size_t)written; + if (pos >= sizeof(prefix)) pos = sizeof(prefix) - 1; + for (int i = 0; i < depth && pos + 2 < sizeof(prefix); i++) { + prefix[pos++] = ' '; + prefix[pos++] = ' '; + } + prefix[pos < sizeof(prefix) ? pos : sizeof(prefix) - 1] = '\0'; + ecex_messages_append(ed, prefix, line); +} + buffer_t *ecex_create_buffer(ecex_t *ed, const char *name, const char *path, @@ -1382,6 +1486,7 @@ static int ecex_kill_buffer_impl(ecex_t *ed, const char *name, int force) { buffer_t *victim = ed->buffers[index]; if (ed->previous_buffer == victim) ed->previous_buffer = NULL; + if (ed->messages_buffer == victim) ed->messages_buffer = NULL; if (!force && victim->modified && !victim->read_only) { fprintf(stderr, "ecex: refusing to kill modified buffer '%s'; save it or use force-kill-buffer.\n", @@ -2100,6 +2205,7 @@ void ecex_message(ecex_t *ed, const char *message) { if (!ed) return; snprintf(ed->message, sizeof(ed->message), "%s", message ? message : ""); ed->message_revision++; + ecex_messages_append(ed, "message: ", message ? message : ""); ecex_mark_ui_changed(ed); } @@ -31,6 +31,22 @@ static char ecex_frame_group_start[1024]; static char ecex_frame_repeat_start[1024]; static char ecex_frame_repeat_end[1024]; static unsigned long ecex_frame_repeat_count = 0; +static ecex_log_sink_fn ecex_log_sink = NULL; +static void *ecex_log_sink_userdata = NULL; +static int ecex_log_sink_active = 0; + +void ecex_log_set_sink(ecex_log_sink_fn fn, void *userdata) { + ecex_log_sink = fn; + ecex_log_sink_userdata = userdata; +} + +void ecex_log_clear_sink(void *userdata) { + if (!userdata || userdata == ecex_log_sink_userdata) { + ecex_log_sink = NULL; + ecex_log_sink_userdata = NULL; + ecex_log_sink_active = 0; + } +} static size_t ecex_strn_copy(char *out, size_t out_cap, const char *in) { size_t i = 0; @@ -157,6 +173,12 @@ static void ecex_log_emit_raw_depth(const char *line, int depth) { } ecex_write_all(line ? line : "(null)", line ? len : 6); ecex_write_all("\n", 1); + + if (ecex_log_sink && !ecex_log_sink_active) { + ecex_log_sink_active = 1; + ecex_log_sink(line ? line : "(null)", depth, ecex_log_sink_userdata); + ecex_log_sink_active = 0; + } } static void ecex_log_emit_raw_counted(const char *line, int depth, unsigned long count) { @@ -1,5 +1,7 @@ #include "path.h" +#include "util.h" + #include <ctype.h> #include <stdio.h> #include <stdlib.h> @@ -25,16 +27,12 @@ int ecex_path_copy(char *out, size_t out_size, const char *text) { char *ecex_path_expand_user(const char *path) { if (!path) return NULL; if (path[0] != '~' || (path[1] != '\0' && path[1] != '/')) { - char *copy = malloc(strlen(path) + 1); - if (copy) strcpy(copy, path); - return copy; + return ecex_strdup(path); } const char *home = getenv("HOME"); if (!home || !home[0]) { - char *copy = malloc(strlen(path) + 1); - if (copy) strcpy(copy, path); - return copy; + return ecex_strdup(path); } size_t home_len = strlen(home); @@ -49,9 +47,7 @@ char *ecex_path_expand_user(const char *path) { char *ecex_path_join(const char *dir, const char *name) { if (!name) return NULL; if (name[0] == '/') { - char *copy = malloc(strlen(name) + 1); - if (copy) strcpy(copy, name); - return copy; + return ecex_strdup(name); } if (!dir || !dir[0]) dir = "."; @@ -68,9 +64,7 @@ char *ecex_path_join(const char *dir, const char *name) { char *ecex_path_dirname(const char *path) { if (!path || !path[0]) { - char *dot = malloc(2); - if (dot) strcpy(dot, "."); - return dot; + return ecex_strdup("."); } char *expanded = ecex_path_expand_user(path); @@ -98,9 +92,7 @@ char *ecex_path_basename_dup(const char *path) { else if (slash && slash == path) base = "/"; else base = path; } - char *out = malloc(strlen(base) + 1); - if (out) strcpy(out, base); - return out; + return ecex_strdup(base); } char *ecex_path_normalize(const char *path) { |
