aboutsummaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
authorDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
committerDavid Moc <personal@cdatgoose.org>2026-06-02 13:50:21 +0200
commita15cb041654ae307add0b998b526c87c3f42bf5f (patch)
tree225bb4b70e9fa05aa5f4d2722a1a9cf5fc6fca7f /src/config.c
parent6aeaa171dc1ca43392f53cbd02097f76e1b1c5a0 (diff)
Add plugin hooks and mode plugins
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c195
1 files changed, 123 insertions, 72 deletions
diff --git a/src/config.c b/src/config.c
index 1b0b5ed..e9bba5d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -5,7 +5,6 @@
#include "common.h"
#include "ecex.h"
#include "eval.h"
-#include "util.h"
#include "path.h"
#include <stdio.h>
@@ -65,46 +64,56 @@ static const host_symbol_t host_symbols[] = {
HOST_SYMBOL(ecex_config_free),
HOST_SYMBOL(ecex_time_seconds),
HOST_SYMBOL(ecex_log),
+ HOST_SYMBOL(ecex_logf),
+ HOST_SYMBOL(ecex_log_group_begin),
+ HOST_SYMBOL(ecex_log_group_end),
HOST_SYMBOL(ecex_log_int),
HOST_SYMBOL(ecex_log_double),
HOST_SYMBOL(ecex_log_ptr),
+ HOST_SYMBOL(ecex_log_flush),
HOST_SYMBOL(ecex_mem_zero),
HOST_SYMBOL(ecex_i32_get),
HOST_SYMBOL(ecex_i32_set),
HOST_SYMBOL(ecex_prng_next_bounded),
HOST_SYMBOL(ecex_random_bounded),
- HOST_SYMBOL(ecex_tetris_shape_cell),
- HOST_SYMBOL(ecex_var_get),
- HOST_SYMBOL(ecex_var_get_or_alloc),
- HOST_SYMBOL(ecex_var_bind_static),
- HOST_SYMBOL(ecex_var_free),
- HOST_SYMBOL(ecex_var_free_owner),
- HOST_SYMBOL(ecex_var_i32_get),
- HOST_SYMBOL(ecex_var_i32_set),
- HOST_SYMBOL(ecex_var_i32),
- HOST_SYMBOL(ecex_var_i32_set_scalar),
- HOST_SYMBOL(ecex_object_alloc),
- HOST_SYMBOL(ecex_object_calloc),
- HOST_SYMBOL(ecex_object_free),
- HOST_SYMBOL(ecex_object_valid),
- HOST_SYMBOL(ecex_object_i32_get),
- HOST_SYMBOL(ecex_object_i32_set),
- HOST_SYMBOL(ecex_object_ptr_get),
- HOST_SYMBOL(ecex_object_ptr_set),
- HOST_SYMBOL(ecex_text_set),
- HOST_SYMBOL(ecex_text_set_buffer_title),
- HOST_SYMBOL(ecex_text_free),
- HOST_SYMBOL(ecex_text_free_owner),
+ HOST_SYMBOL(ecex_plugin_register),
+ HOST_SYMBOL(ecex_plugin_require),
+ HOST_SYMBOL(ecex_plugin_find),
+ HOST_SYMBOL(ecex_plugin_id),
+ HOST_SYMBOL(ecex_plugin_slot_alloc),
+ HOST_SYMBOL(ecex_plugin_slot_get),
+ HOST_SYMBOL(ecex_plugin_slot_free),
+ HOST_SYMBOL(ecex_plugin_slot_set_export_flags),
+ HOST_SYMBOL(ecex_plugin_slot_read_exported),
+ HOST_SYMBOL(ecex_plugin_slot_i32_get),
+ HOST_SYMBOL(ecex_plugin_slot_i32_set),
+ HOST_SYMBOL(ecex_plugin_slot_i32_get_2d),
+ HOST_SYMBOL(ecex_plugin_slot_i32_set_2d),
+ HOST_SYMBOL(ecex_plugin_slot_i32_get_scalar),
+ HOST_SYMBOL(ecex_plugin_slot_i32_set_scalar),
+ HOST_SYMBOL(ecex_plugin_object_alloc),
+ HOST_SYMBOL(ecex_plugin_object_calloc),
+ HOST_SYMBOL(ecex_plugin_object_free),
+ HOST_SYMBOL(ecex_plugin_object_valid),
+ HOST_SYMBOL(ecex_plugin_object_i32_get),
+ HOST_SYMBOL(ecex_plugin_object_i32_set),
+ HOST_SYMBOL(ecex_plugin_object_ptr_get),
+ HOST_SYMBOL(ecex_plugin_object_ptr_set),
+ HOST_SYMBOL(ecex_plugin_text_set),
+ HOST_SYMBOL(ecex_plugin_text_set_from_buffer_title),
+ HOST_SYMBOL(ecex_plugin_text_free),
+ HOST_SYMBOL(ecex_plugin_text_free_all),
+ HOST_SYMBOL(ecex_plugin_text_get_drawable),
HOST_SYMBOL(ecex_buffer_text_len),
- HOST_SYMBOL(ecex_buffer_scroll_line),
- HOST_SYMBOL(ecex_buffer_line_count_i),
- HOST_SYMBOL(ecex_buffer_line_copy),
- HOST_SYMBOL(ecex_markdown_draw_line_from_buffer_i),
- HOST_SYMBOL(ecex_markdown_body_y_i),
- HOST_SYMBOL(ecex_draw_context_height_i),
- HOST_SYMBOL(ecex_draw_context_line_height_i),
- HOST_SYMBOL(ecex_register_file_handler),
- HOST_SYMBOL(ecex_run_file_handlers),
+ HOST_SYMBOL(ecex_buffer_scroll_line_index),
+ HOST_SYMBOL(ecex_buffer_line_count_int),
+ HOST_SYMBOL(ecex_buffer_line_copy_text),
+ HOST_SYMBOL(ecex_markdown_draw_buffer_line_i),
+ HOST_SYMBOL(ecex_markdown_body_y_px),
+ HOST_SYMBOL(ecex_draw_context_height_px),
+ HOST_SYMBOL(ecex_draw_context_line_height_px),
+ HOST_SYMBOL(ecex_plugin_file_handler_register),
+ HOST_SYMBOL(ecex_plugin_file_handlers_run),
HOST_SYMBOL(ecex_config_register_commands),
HOST_SYMBOL(ecex_config_bind_keys),
@@ -113,6 +122,27 @@ static const host_symbol_t host_symbols[] = {
HOST_SYMBOL(ecex_apply_theme),
HOST_SYMBOL(ecex_register_command),
HOST_SYMBOL(ecex_execute_command),
+ HOST_SYMBOL(ecex_add_command_hook),
+ HOST_SYMBOL(ecex_remove_command_hook),
+ HOST_SYMBOL(ecex_add_prefix_hook),
+ HOST_SYMBOL(ecex_remove_prefix_hook),
+ HOST_SYMBOL(ecex_notify_prefix_hooks),
+ HOST_SYMBOL(ecex_add_buffer_hook),
+ HOST_SYMBOL(ecex_remove_buffer_hook),
+ HOST_SYMBOL(ecex_notify_buffer_hooks),
+ HOST_SYMBOL(ecex_message),
+ HOST_SYMBOL(ecex_dependency_available),
+ HOST_SYMBOL(ecex_plugin_require_dependency),
+ HOST_SYMBOL(ecex_add_completion_provider),
+ HOST_SYMBOL(ecex_add_word_completion_provider),
+ HOST_SYMBOL(ecex_define_word_completion_provider),
+ HOST_SYMBOL(ecex_completion_provider_add_word),
+ HOST_SYMBOL(ecex_completion_provider_add_words),
+ HOST_SYMBOL(ecex_completion_provider_set_detail),
+ HOST_SYMBOL(ecex_add_clangd_completion_provider),
+ HOST_SYMBOL(ecex_remove_completion_provider),
+ HOST_SYMBOL(ecex_buffer_identifier_prefix),
+ HOST_SYMBOL(ecex_complete_at_point),
HOST_SYMBOL(ecex_bind_key),
HOST_SYMBOL(ecex_lookup_key),
HOST_SYMBOL(ecex_define_major_mode),
@@ -124,6 +154,7 @@ static const host_symbol_t host_symbols[] = {
HOST_SYMBOL(ecex_bind_mode_key),
HOST_SYMBOL(ecex_lookup_key_for_buffer),
HOST_SYMBOL(ecex_key_sequence_has_prefix_for_buffer),
+ HOST_SYMBOL(ecex_describe_key_prefix),
HOST_SYMBOL(ecex_auto_set_major_mode),
HOST_SYMBOL(ecex_list_commands),
HOST_SYMBOL(ecex_list_buffers),
@@ -153,12 +184,13 @@ static const host_symbol_t host_symbols[] = {
HOST_SYMBOL(ecex_draw_text),
HOST_SYMBOL(ecex_draw_text_aligned),
HOST_SYMBOL(ecex_draw_text_width),
- HOST_SYMBOL(ecex_draw_color_rgba8),
+ HOST_SYMBOL(ecex_draw_color_rgba8_i),
HOST_SYMBOL(ecex_draw_rect_i),
HOST_SYMBOL(ecex_draw_rect_outline_i),
HOST_SYMBOL(ecex_draw_line_i),
HOST_SYMBOL(ecex_draw_text_i),
- HOST_SYMBOL(ecex_draw_text_id_i),
+ HOST_SYMBOL(ecex_draw_plugin_text_i),
+ HOST_SYMBOL(ecex_draw_plugin_text_rect_i),
HOST_SYMBOL(ecex_draw_markdown_canvas_i),
HOST_SYMBOL(ecex_draw_markdown_text_i),
HOST_SYMBOL(ecex_draw_markdown_canvas_auto_i),
@@ -170,6 +202,15 @@ static const host_symbol_t host_symbols[] = {
HOST_SYMBOL(ecex_find_file),
HOST_SYMBOL(ecex_save_current_buffer),
HOST_SYMBOL(ecex_write_current_buffer),
+ HOST_SYMBOL(ecex_compile),
+ HOST_SYMBOL(ecex_grep),
+ HOST_SYMBOL(ecex_rerun_compile),
+ HOST_SYMBOL(ecex_rerun_grep),
+ HOST_SYMBOL(ecex_next_interactive_action),
+ HOST_SYMBOL(ecex_previous_interactive_action),
+ HOST_SYMBOL(ecex_indent_line_to),
+ HOST_SYMBOL(ecex_comment_region),
+ HOST_SYMBOL(ecex_uncomment_region),
HOST_SYMBOL(ecex_request_prompt),
HOST_SYMBOL(ecex_clear_prompt_request),
HOST_SYMBOL(ecex_complete_command),
@@ -308,32 +349,48 @@ int ecex_add_ccdjit_include_paths(ccdjit_context *ctx) {
return ECEX_OK;
}
-static char *make_config_source_with_forced_main(const char *path) {
- size_t source_size = 0;
- char *source = ecex_read_entire_file(path, &source_size);
- if (!source) return NULL;
-
- const char *forced_main =
- "\n"
- "\n"
- "int main(int argc, char **argv) {\n"
- " (void)argc;\n"
- " (void)argv;\n"
- " return ecex_config_init((ecex_t *)0);\n"
- "}\n";
-
- size_t forced_main_len = strlen(forced_main);
- char *combined = malloc(source_size + forced_main_len + 1);
- if (!combined) {
- free(source);
- return NULL;
- }
+static int ccdjit_type_is_int(ccdjit_type_info type) {
+ return type.has_type &&
+ type.base == CCDJIT_TYPE_INT &&
+ type.pointer_level == 0;
+}
+
+static int ccdjit_type_is_pointer(ccdjit_type_info type) {
+ return type.has_type && type.pointer_level == 1;
+}
- memcpy(combined, source, source_size);
- memcpy(combined + source_size, forced_main, forced_main_len + 1);
+static ecex_config_init_fn ecex_config_init_symbol(ccdjit_context *ctx,
+ ccdjit_module *module,
+ const char *path) {
+ void *symbol = ccdjit_module_symbol(module, "ecex_config_init");
+ if (!symbol) return NULL;
+
+ ccdjit_symbol_info info;
+ memset(&info, 0, sizeof(info));
+ if (ccdjit_module_symbol_info(module, "ecex_config_init", &info) == 0 &&
+ info.has_signature) {
+ ccdjit_type_info param;
+ memset(&param, 0, sizeof(param));
+
+ if (info.kind != CCDJIT_SYMBOL_FUNCTION ||
+ !ccdjit_type_is_int(info.return_type) ||
+ info.parameter_count != 1 ||
+ info.is_variadic ||
+ ccdjit_module_function_parameter_type(module, "ecex_config_init", 0, &param) != 0 ||
+ !ccdjit_type_is_pointer(param)) {
+ fprintf(stderr,
+ "ecex: invalid config signature in %s; expected int ecex_config_init(ecex_t *ed)\n",
+ path ? path : "<config>");
+ return NULL;
+ }
+ } else if (ctx) {
+ const ccdjit_diagnostic *diag = ccdjit_context_last_error(ctx);
+ if (diag && diag->code != CCDJIT_DIAG_NONE) {
+ ecex_print_ccdjit_error(ctx);
+ }
+ }
- free(source);
- return combined;
+ return (ecex_config_init_fn)symbol;
}
int ecex_load_c_config(ecex_t *ed, const char *path) {
@@ -350,26 +407,15 @@ int ecex_load_c_config(ecex_t *ed, const char *path) {
return ECEX_ERR;
}
- char *source = make_config_source_with_forced_main(path);
- if (!source) {
- fprintf(stderr, "ecex: failed to read or prepare config: %s\n", path);
- ccdjit_context_free(ctx);
- return ECEX_ERR;
- }
-
ccdjit_module *module = NULL;
- if (ccdjit_compile_string(ctx, source, path, &module) != 0) {
+ if (ccdjit_compile_file_module(ctx, path, &module) != 0) {
fprintf(stderr, "ecex: failed to compile config: %s\n", path);
ecex_print_ccdjit_error(ctx);
- free(source);
ccdjit_context_free(ctx);
return ECEX_ERR;
}
- free(source);
-
- ecex_config_init_fn init =
- (ecex_config_init_fn)ccdjit_module_symbol(module, "ecex_config_init");
+ ecex_config_init_fn init = ecex_config_init_symbol(ctx, module, path);
if (!init) {
fprintf(stderr, "ecex: config missing function: ecex_config_init\n");
@@ -382,7 +428,12 @@ int ecex_load_c_config(ecex_t *ed, const char *path) {
int result = init(ed);
if (result != 0) {
fprintf(stderr, "ecex: config init failed with code: %d\n", result);
- ccdjit_module_free(module);
+ /* Config init may have registered hooks/renderers before returning an
+ * error. Keep the module alive so rollback can call any JIT-owned
+ * destructors safely. */
+ if (ecex_keep_jit_module(ed, module) != ECEX_OK) {
+ fprintf(stderr, "ecex: failed to retain failed config module; leaving it mapped for cleanup safety\n");
+ }
ccdjit_context_free(ctx);
return ECEX_ERR;
}