From a15cb041654ae307add0b998b526c87c3f42bf5f Mon Sep 17 00:00:00 2001 From: David Moc Date: Tue, 2 Jun 2026 13:50:21 +0200 Subject: Add plugin hooks and mode plugins --- include/ecex.h | 127 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 47 deletions(-) (limited to 'include/ecex.h') diff --git a/include/ecex.h b/include/ecex.h index efcbe5a..085c3d2 100644 --- a/include/ecex.h +++ b/include/ecex.h @@ -6,6 +6,7 @@ #include "eval.h" #include "path.h" #include "media.h" +#include "plugin.h" typedef struct ecex_config_command { @@ -24,6 +25,9 @@ typedef struct ecex_config_mode_keybind { const char *command; } ecex_config_mode_keybind_t; +#define ECEX_COMPLETION_DEFAULT 0 +#define ECEX_COMPLETION_ED_ARROW 1 + ecex_t *ecex_new(void); void ecex_free(ecex_t *ed); @@ -35,61 +39,34 @@ void *ecex_config_calloc(size_t count, size_t size); void ecex_config_free(void *ptr); double ecex_time_seconds(void); void ecex_log(const char *message); +void ecex_logf(const char *fmt, ...); +void ecex_log_group_begin(const char *message); +void ecex_log_group_end(const char *message); void ecex_log_int(const char *message, int value); void ecex_log_double(const char *message, double value); void ecex_log_ptr(const char *message, const void *ptr); +void ecex_log_flush(void); void ecex_mem_zero(void *ptr, size_t size); int ecex_i32_get(const int *items, size_t index); void ecex_i32_set(int *items, size_t index, int value); int ecex_prng_next_bounded(unsigned int *state, int bound); int ecex_random_bounded(int bound); -int ecex_tetris_shape_cell(int piece, int rot, int col, int row); - -/* Host-owned variable registry for JIT plugins. Plugins can keep persistent - * scalar values, dynamic arrays, or static host buffers behind a stable owner - * pointer and a name instead of relying on fragile JIT struct/array storage. */ -void *ecex_var_get(ecex_t *ed, void *owner, const char *name); -void *ecex_var_get_or_alloc(ecex_t *ed, void *owner, const char *name, size_t count, size_t elem_size); -int ecex_var_bind_static(ecex_t *ed, void *owner, const char *name, void *data, size_t count, size_t elem_size); -int ecex_var_free(ecex_t *ed, void *owner, const char *name); -int ecex_var_free_owner(ecex_t *ed, void *owner); -int ecex_var_i32_get(ecex_t *ed, void *owner, const char *name, size_t index, int fallback); -int ecex_var_i32_set(ecex_t *ed, void *owner, const char *name, size_t index, int value); -int ecex_var_i32(ecex_t *ed, void *owner, const char *name, int fallback); -int ecex_var_i32_set_scalar(ecex_t *ed, void *owner, const char *name, int value); - -/* Host-owned object allocator for plugin state. Returned pointers are tracked - * by the editor and can be freed through the API. Prefer this for callback - * userdata over plugin/local allocations when the object has callback lifetime. - */ -void *ecex_object_alloc(ecex_t *ed, size_t size); -void *ecex_object_calloc(ecex_t *ed, size_t count, size_t size); -int ecex_object_free(ecex_t *ed, void *object); -int ecex_object_valid(ecex_t *ed, void *object); -int ecex_object_i32_get(ecex_t *ed, void *object, size_t byte_offset, int fallback); -int ecex_object_i32_set(ecex_t *ed, void *object, size_t byte_offset, int value); -void *ecex_object_ptr_get(ecex_t *ed, void *object, size_t byte_offset); -int ecex_object_ptr_set(ecex_t *ed, void *object, size_t byte_offset, void *value); - -/* Host-owned text registry for plugins that need to render arbitrary text. - * Plugins copy text into host storage, then draw by owner/id. This avoids - * passing JIT-owned literals or stack strings into the normal text renderer. */ -int ecex_text_set(ecex_t *ed, void *owner, int id, const char *text, int len); -int ecex_text_set_buffer_title(ecex_t *ed, void *owner, int id, buffer_t *buffer); -int ecex_text_free(ecex_t *ed, void *owner, int id); -int ecex_text_free_owner(ecex_t *ed, void *owner); + +/* The plugin runtime owns long-lived JIT/plugin state. Plugins must register a + * stable id and then allocate slots, objects, text, and file handlers through + * the returned opaque handle. Slots are private unless explicitly exported, + * and cross-plugin reads are copy-only. */ int ecex_buffer_text_len(buffer_t *buffer); -int ecex_buffer_scroll_line(buffer_t *buffer); -int ecex_buffer_line_count_i(buffer_t *buffer); -int ecex_buffer_line_copy(buffer_t *buffer, int line, char *out, int out_cap); -int ecex_markdown_draw_line_from_buffer_i(ecex_draw_context_t *ctx, void *owner, buffer_t *buffer, int line, int y, int in_code); -int ecex_markdown_body_y_i(ecex_draw_context_t *ctx); -int ecex_draw_context_height_i(ecex_draw_context_t *ctx); -int ecex_draw_context_line_height_i(ecex_draw_context_t *ctx); +int ecex_buffer_scroll_line_index(buffer_t *buffer); +int ecex_buffer_line_count_int(buffer_t *buffer); +int ecex_buffer_line_copy_text(buffer_t *buffer, int line, char *out, int out_cap); +int ecex_markdown_draw_buffer_line_i(ecex_draw_context_t *ctx, void *owner, buffer_t *buffer, int line, int y, int in_code); +int ecex_markdown_body_y_px(ecex_draw_context_t *ctx); +int ecex_draw_context_height_px(ecex_draw_context_t *ctx); +int ecex_draw_context_line_height_px(ecex_draw_context_t *ctx); -int ecex_register_file_handler(ecex_t *ed, const char *extension, ecex_file_handler_fn fn); -int ecex_run_file_handlers(ecex_t *ed, buffer_t *buffer); +int ecex_run_plugin_file_handlers(ecex_t *ed, buffer_t *buffer); int ecex_reserve_buffers(ecex_t *ed, size_t needed); int ecex_add_buffer(ecex_t *ed, buffer_t *buffer); @@ -137,6 +114,52 @@ int ecex_apply_theme(ecex_t *ed, const ecex_theme_t *theme); int ecex_register_command(ecex_t *ed, const char *name, ecex_command_fn fn); int ecex_execute_command(ecex_t *ed, const char *name); +int ecex_add_command_hook(ecex_t *ed, + const char *name, + ecex_command_hook_fn fn, + void *userdata, + ecex_hook_free_fn free_fn); +int ecex_remove_command_hook(ecex_t *ed, const char *name); +int ecex_add_prefix_hook(ecex_t *ed, + const char *name, + ecex_prefix_hook_fn fn, + void *userdata, + ecex_hook_free_fn free_fn); +int ecex_remove_prefix_hook(ecex_t *ed, const char *name); +void ecex_notify_prefix_hooks(ecex_t *ed, const char *prefix, int event); +int ecex_add_buffer_hook(ecex_t *ed, + const char *name, + ecex_buffer_hook_fn fn, + void *userdata, + ecex_hook_free_fn free_fn); +int ecex_remove_buffer_hook(ecex_t *ed, const char *name); +void ecex_notify_buffer_hooks(ecex_t *ed, buffer_t *buffer, int event); +void ecex_message(ecex_t *ed, const char *message); +int ecex_dependency_available(const char *program); +int ecex_plugin_require_dependency(ecex_t *ed, const char *plugin_id, const char *program); +int ecex_add_completion_provider(ecex_t *ed, + const char *name, + const char *mode_name, + ecex_completion_provider_fn fn, + void *userdata, + ecex_hook_free_fn free_fn); +int ecex_add_word_completion_provider(ecex_t *ed, + const char *name, + const char *mode_name, + const char *const *words, + size_t word_count, + int flags); +int ecex_define_word_completion_provider(ecex_t *ed, + const char *name, + const char *mode_name, + int flags); +int ecex_completion_provider_add_word(ecex_t *ed, const char *name, const char *word); +int ecex_completion_provider_add_words(ecex_t *ed, const char *name, const char *words); +int ecex_completion_provider_set_detail(ecex_t *ed, const char *name, const char *detail); +int ecex_add_clangd_completion_provider(ecex_t *ed, const char *name, const char *mode_name); +int ecex_remove_completion_provider(ecex_t *ed, const char *name); +int ecex_buffer_identifier_prefix(buffer_t *buffer, char *out, size_t out_size); +int ecex_complete_at_point(ecex_t *ed); void ecex_set_clipboard_callbacks(ecex_t *ed, ecex_clipboard_get_fn get_fn, ecex_clipboard_set_fn set_fn, @@ -156,6 +179,12 @@ const char *ecex_buffer_major_mode_name(ecex_t *ed, buffer_t *buffer); int ecex_bind_mode_key(ecex_t *ed, const char *mode_name, const char *key, const char *command); const char *ecex_lookup_key_for_buffer(ecex_t *ed, buffer_t *buffer, const char *key); int ecex_key_sequence_has_prefix_for_buffer(ecex_t *ed, buffer_t *buffer, const char *prefix); +int ecex_describe_key_prefix(ecex_t *ed, + buffer_t *buffer, + const char *prefix, + char *out, + size_t out_size, + size_t max_items); int ecex_auto_set_major_mode(ecex_t *ed, buffer_t *buffer); int ecex_list_commands(ecex_t *ed); @@ -244,12 +273,13 @@ void ecex_draw_rgba(ecex_draw_context_t *ctx, /* CCDJIT-safe integer drawing wrappers. Prefer these from plugins when the * JIT ABI is known to be fragile with float/double arguments. Colors are * 0..255 RGBA and coordinates are integer pixels local to the buffer window. */ -void ecex_draw_color_rgba8(ecex_draw_context_t *ctx, int r, int g, int b, int a); +void ecex_draw_color_rgba8_i(ecex_draw_context_t *ctx, int r, int g, int b, int a); void ecex_draw_rect_i(ecex_draw_context_t *ctx, int x, int y, int w, int h); void ecex_draw_rect_outline_i(ecex_draw_context_t *ctx, int x, int y, int w, int h, int thickness); void ecex_draw_line_i(ecex_draw_context_t *ctx, int x1, int y1, int x2, int y2, int thickness); void ecex_draw_text_i(ecex_draw_context_t *ctx, int x, int y, const char *text); -void ecex_draw_text_id_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y); +void ecex_draw_plugin_text_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y); +void ecex_draw_plugin_text_rect_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y, int w, int h, int padding, unsigned int bg_rgba, unsigned int fg_rgba); void ecex_draw_markdown_canvas_i(ecex_draw_context_t *ctx, void *owner, int title_id, int x, int y, int w, int line_h); void ecex_draw_markdown_text_i(ecex_draw_context_t *ctx, void *owner, int text_id, int x, int y, int w, int line_h, int style); @@ -273,6 +303,7 @@ int ecex_rerun_compile(ecex_t *ed); int ecex_rerun_grep(ecex_t *ed); int ecex_next_interactive_action(ecex_t *ed); int ecex_previous_interactive_action(ecex_t *ed); +int ecex_indent_line_to(buffer_t *buffer, int target_cols); int ecex_comment_region(ecex_t *ed); int ecex_uncomment_region(ecex_t *ed); void ecex_request_prompt(ecex_t *ed, ecex_prompt_request_t request, const char *message); @@ -320,7 +351,9 @@ void ecex_set_current_line_enabled(ecex_t *ed, int enabled); #define ECEX_RGB8(r, g, b) ((float)(r) / 255.0f), ((float)(g) / 255.0f), ((float)(b) / 255.0f) #define ECEX_CONFIG_BEGIN int ecex_config_init(ecex_t *ed) { #define ECEX_CONFIG_END return 0; } -#define ECEX_PLUGIN_BEGIN(name) int name(ecex_t *ed) { +#define ECEX_PLUGIN_BEGIN(name, id) int name(ecex_t *ed) { \ + ecex_plugin_t *plugin = ecex_plugin_require(ed, (id), ECEX_PLUGIN_API_VERSION); \ + if (!plugin) return -1; #define ECEX_PLUGIN_END return 0; } #define ECEX_CONFIG_TRY(expr) \ do { \ -- cgit v1.2.3