aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/ecex_api_completion_plugin.c415
-rw-r--r--docs/ccdjit-improvements.md7
-rw-r--r--docs/plugin-api.md14
-rw-r--r--include/ecex.h5
-rw-r--r--include/types.h1
-rw-r--r--src/config.c2
-rw-r--r--src/ecex.c97
7 files changed, 529 insertions, 12 deletions
diff --git a/config/ecex_api_completion_plugin.c b/config/ecex_api_completion_plugin.c
index dae5745..b806349 100644
--- a/config/ecex_api_completion_plugin.c
+++ b/config/ecex_api_completion_plugin.c
@@ -307,6 +307,403 @@
"ecex_path_cwd\n" \
"ecex_media_open\n" \
"ecex_media_toggle_playback\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_1 \
+ "ecex_t\ttypedef struct ecex ecex_t\n" \
+ "buffer_t\ttypedef struct buffer buffer_t\n" \
+ "ecex_window_t\ttypedef struct ecex_window ecex_window_t\n" \
+ "ecex_draw_context_t\ttypedef struct ecex_draw_context ecex_draw_context_t\n" \
+ "ecex_plugin_t\ttypedef struct ecex_plugin ecex_plugin_t\n" \
+ "ecex_plugin_runtime_t\ttypedef struct ecex_plugin_runtime ecex_plugin_runtime_t\n" \
+ "ecex_command_fn\tint (*ecex_command_fn)(ecex_t *ed)\n" \
+ "ecex_completion_provider_fn\tint (*ecex_completion_provider_fn)(ecex_t *ed, buffer_t *buffer, const char *prefix, char *out, size_t out_size, void *userdata)\n" \
+ "ecex_file_handler_fn\tint (*ecex_file_handler_fn)(ecex_t *ed, buffer_t *buffer)\n" \
+ "ECEX_CONFIG_BEGIN\tint ecex_config_init(ecex_t *ed) {\n" \
+ "ECEX_CONFIG_END\treturn 0; }\n" \
+ "ECEX_PLUGIN_BEGIN\tint plugin_name(ecex_t *ed) { ecex_plugin_t *plugin = ecex_plugin_require(...)\n" \
+ "ECEX_PLUGIN_END\treturn 0; }\n" \
+ "ECEX_CONFIG_TRY\tECEX_CONFIG_TRY(expr)\n" \
+ "ECEX_CONFIG_COMMAND\tECEX_CONFIG_COMMAND(name, fn)\n" \
+ "ECEX_CONFIG_BIND\tECEX_CONFIG_BIND(key, command)\n" \
+ "ECEX_CONFIG_MODE\tECEX_CONFIG_MODE(name)\n" \
+ "ECEX_CONFIG_MODE_BIND\tECEX_CONFIG_MODE_BIND(mode, key, command)\n" \
+ "ECEX_CONFIG_INCLUDE\tECEX_CONFIG_INCLUDE(plugin_init_fn)\n" \
+ "ECEX_RGB8\tECEX_RGB8(r, g, b)\n" \
+ "ECEX_ARRAY_COUNT\tECEX_ARRAY_COUNT(array)\n" \
+ "ecex_new\tecex_t *ecex_new(void)\n" \
+ "ecex_free\tvoid ecex_free(ecex_t *ed)\n" \
+ "ecex_config_alloc\tvoid *ecex_config_alloc(size_t size)\n" \
+ "ecex_config_calloc\tvoid *ecex_config_calloc(size_t count, size_t size)\n" \
+ "ecex_config_free\tvoid ecex_config_free(void *ptr)\n" \
+ "ecex_time_seconds\tdouble ecex_time_seconds(void)\n" \
+ "ecex_log\tvoid ecex_log(const char *message)\n" \
+ "ecex_logf\tvoid ecex_logf(const char *fmt, ...)\n" \
+ "ecex_log_group_begin\tvoid ecex_log_group_begin(const char *message)\n" \
+ "ecex_log_group_end\tvoid ecex_log_group_end(const char *message)\n" \
+ "ecex_log_int\tvoid ecex_log_int(const char *message, int value)\n" \
+ "ecex_log_double\tvoid ecex_log_double(const char *message, double value)\n" \
+ "ecex_log_ptr\tvoid ecex_log_ptr(const char *message, const void *ptr)\n" \
+ "ecex_log_flush\tvoid ecex_log_flush(void)\n" \
+ "ecex_mem_zero\tvoid ecex_mem_zero(void *ptr, size_t size)\n" \
+ "ecex_i32_get\tint ecex_i32_get(const int *items, size_t index)\n" \
+ "ecex_i32_set\tvoid ecex_i32_set(int *items, size_t index, int value)\n" \
+ "ecex_prng_next_bounded\tint ecex_prng_next_bounded(unsigned int *state, int bound)\n" \
+ "ecex_random_bounded\tint ecex_random_bounded(int bound)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_2 \
+ "ecex_plugin_register\tecex_plugin_t *ecex_plugin_register(ecex_t *ed, const char *id, int api_version)\n" \
+ "ecex_plugin_require\tecex_plugin_t *ecex_plugin_require(ecex_t *ed, const char *id, int api_version)\n" \
+ "ecex_plugin_find\tecex_plugin_t *ecex_plugin_find(ecex_t *ed, const char *id)\n" \
+ "ecex_plugin_id\tconst char *ecex_plugin_id(ecex_plugin_t *plugin)\n" \
+ "ecex_plugin_slot_alloc\tvoid *ecex_plugin_slot_alloc(ecex_plugin_t *plugin, const char *name, size_t count, size_t elem_size)\n" \
+ "ecex_plugin_slot_get\tvoid *ecex_plugin_slot_get(ecex_plugin_t *plugin, const char *name)\n" \
+ "ecex_plugin_slot_free\tint ecex_plugin_slot_free(ecex_plugin_t *plugin, const char *name)\n" \
+ "ecex_plugin_slot_set_export_flags\tint ecex_plugin_slot_set_export_flags(ecex_plugin_t *plugin, const char *name, int type, int flags)\n" \
+ "ecex_plugin_slot_read_exported\tint ecex_plugin_slot_read_exported(ecex_t *ed, const char *plugin_id, const char *name, void *out, size_t out_cap, size_t *out_len)\n" \
+ "ecex_plugin_slot_i32_get_scalar\tint ecex_plugin_slot_i32_get_scalar(ecex_plugin_t *plugin, const char *name, int fallback)\n" \
+ "ecex_plugin_slot_i32_get\tint ecex_plugin_slot_i32_get(ecex_plugin_t *plugin, const char *name, size_t index, int fallback)\n" \
+ "ecex_plugin_slot_i32_set\tint ecex_plugin_slot_i32_set(ecex_plugin_t *plugin, const char *name, size_t index, int value)\n" \
+ "ecex_plugin_slot_i32_get_2d\tint ecex_plugin_slot_i32_get_2d(ecex_plugin_t *plugin, const char *name, size_t width, size_t x, size_t y, int fallback)\n" \
+ "ecex_plugin_slot_i32_set_2d\tint ecex_plugin_slot_i32_set_2d(ecex_plugin_t *plugin, const char *name, size_t width, size_t x, size_t y, int value)\n" \
+ "ecex_plugin_slot_i32_set_scalar\tint ecex_plugin_slot_i32_set_scalar(ecex_plugin_t *plugin, const char *name, int value)\n" \
+ "ecex_plugin_object_alloc\tvoid *ecex_plugin_object_alloc(ecex_plugin_t *plugin, const char *name, size_t size)\n" \
+ "ecex_plugin_object_calloc\tvoid *ecex_plugin_object_calloc(ecex_plugin_t *plugin, const char *name, size_t count, size_t size)\n" \
+ "ecex_plugin_object_free\tint ecex_plugin_object_free(ecex_plugin_t *plugin, void *object)\n" \
+ "ecex_plugin_object_valid\tint ecex_plugin_object_valid(ecex_plugin_t *plugin, void *object)\n" \
+ "ecex_plugin_object_i32_get\tint ecex_plugin_object_i32_get(ecex_plugin_t *plugin, void *object, size_t byte_offset, int fallback)\n" \
+ "ecex_plugin_object_i32_set\tint ecex_plugin_object_i32_set(ecex_plugin_t *plugin, void *object, size_t byte_offset, int value)\n" \
+ "ecex_plugin_object_ptr_get\tvoid *ecex_plugin_object_ptr_get(ecex_plugin_t *plugin, void *object, size_t byte_offset)\n" \
+ "ecex_plugin_object_ptr_set\tint ecex_plugin_object_ptr_set(ecex_plugin_t *plugin, void *object, size_t byte_offset, void *value)\n" \
+ "ecex_plugin_text_set\tint ecex_plugin_text_set(ecex_plugin_t *plugin, int id, const char *text, int len)\n" \
+ "ecex_plugin_text_set_from_buffer_title\tint ecex_plugin_text_set_from_buffer_title(ecex_plugin_t *plugin, int id, buffer_t *buffer)\n" \
+ "ecex_plugin_text_free\tint ecex_plugin_text_free(ecex_plugin_t *plugin, int id)\n" \
+ "ecex_plugin_text_free_all\tint ecex_plugin_text_free_all(ecex_plugin_t *plugin)\n" \
+ "ecex_plugin_text_get_drawable\tconst char *ecex_plugin_text_get_drawable(ecex_t *ed, void *owner, int id)\n" \
+ "ecex_plugin_file_handler_register\tint ecex_plugin_file_handler_register(ecex_plugin_t *plugin, const char *extension, ecex_file_handler_fn fn)\n" \
+ "ecex_plugin_file_handlers_run\tint ecex_plugin_file_handlers_run(ecex_t *ed, buffer_t *buffer)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_3 \
+ "ecex_buffer_text_len\tint ecex_buffer_text_len(buffer_t *buffer)\n" \
+ "ecex_buffer_scroll_line_index\tint ecex_buffer_scroll_line_index(buffer_t *buffer)\n" \
+ "ecex_buffer_line_count_int\tint ecex_buffer_line_count_int(buffer_t *buffer)\n" \
+ "ecex_buffer_line_copy_text\tint ecex_buffer_line_copy_text(buffer_t *buffer, int line, char *out, int out_cap)\n" \
+ "ecex_markdown_draw_buffer_line_i\tint ecex_markdown_draw_buffer_line_i(ecex_draw_context_t *ctx, void *owner, buffer_t *buffer, int line, int y, int in_code)\n" \
+ "ecex_markdown_body_y_px\tint ecex_markdown_body_y_px(ecex_draw_context_t *ctx)\n" \
+ "ecex_draw_context_height_px\tint ecex_draw_context_height_px(ecex_draw_context_t *ctx)\n" \
+ "ecex_draw_context_line_height_px\tint ecex_draw_context_line_height_px(ecex_draw_context_t *ctx)\n" \
+ "ecex_run_plugin_file_handlers\tint ecex_run_plugin_file_handlers(ecex_t *ed, buffer_t *buffer)\n" \
+ "ecex_reserve_buffers\tint ecex_reserve_buffers(ecex_t *ed, size_t needed)\n" \
+ "ecex_add_buffer\tint ecex_add_buffer(ecex_t *ed, buffer_t *buffer)\n" \
+ "ecex_create_buffer\tbuffer_t *ecex_create_buffer(ecex_t *ed, const char *name, const char *path, int read_only)\n" \
+ "ecex_find_buffer\tbuffer_t *ecex_find_buffer(ecex_t *ed, const char *name)\n" \
+ "ecex_switch_buffer\tint ecex_switch_buffer(ecex_t *ed, const char *name)\n" \
+ "ecex_current_buffer\tbuffer_t *ecex_current_buffer(ecex_t *ed)\n" \
+ "ecex_other_buffer\tbuffer_t *ecex_other_buffer(ecex_t *ed)\n" \
+ "ecex_current_window\tecex_window_t *ecex_current_window(ecex_t *ed)\n" \
+ "ecex_window_count\tsize_t ecex_window_count(ecex_t *ed)\n" \
+ "ecex_sync_current_buffer\tint ecex_sync_current_buffer(ecex_t *ed)\n" \
+ "ecex_split_window_vertically\tint ecex_split_window_vertically(ecex_t *ed)\n" \
+ "ecex_split_window_horizontally\tint ecex_split_window_horizontally(ecex_t *ed)\n" \
+ "ecex_other_window\tint ecex_other_window(ecex_t *ed)\n" \
+ "ecex_previous_window\tint ecex_previous_window(ecex_t *ed)\n" \
+ "ecex_delete_window\tint ecex_delete_window(ecex_t *ed)\n" \
+ "ecex_delete_other_windows\tint ecex_delete_other_windows(ecex_t *ed)\n" \
+ "ecex_balance_windows\tint ecex_balance_windows(ecex_t *ed)\n" \
+ "ecex_next_buffer\tint ecex_next_buffer(ecex_t *ed)\n" \
+ "ecex_previous_buffer\tint ecex_previous_buffer(ecex_t *ed)\n" \
+ "ecex_kill_buffer\tint ecex_kill_buffer(ecex_t *ed, const char *name)\n" \
+ "ecex_kill_buffer_force\tint ecex_kill_buffer_force(ecex_t *ed, const char *name)\n" \
+ "ecex_has_modified_buffers\tint ecex_has_modified_buffers(ecex_t *ed)\n" \
+ "ecex_validate_bindings\tint ecex_validate_bindings(ecex_t *ed)\n" \
+ "ecex_keep_jit_module\tint ecex_keep_jit_module(ecex_t *ed, void *module)\n" \
+ "ecex_set_config_path\tint ecex_set_config_path(ecex_t *ed, const char *path)\n" \
+ "ecex_config_path\tconst char *ecex_config_path(ecex_t *ed)\n" \
+ "ecex_reload_config\tint ecex_reload_config(ecex_t *ed)\n" \
+ "ecex_config_register_commands\tint ecex_config_register_commands(ecex_t *ed, const ecex_config_command_t *commands, size_t count)\n" \
+ "ecex_config_bind_keys\tint ecex_config_bind_keys(ecex_t *ed, const ecex_config_keybind_t *bindings, size_t count)\n" \
+ "ecex_config_bind_mode_keys\tint ecex_config_bind_mode_keys(ecex_t *ed, const ecex_config_mode_keybind_t *bindings, size_t count)\n" \
+ "ecex_config_define_modes\tint ecex_config_define_modes(ecex_t *ed, const char *const *modes, size_t count)\n" \
+ "ecex_apply_theme\tint ecex_apply_theme(ecex_t *ed, const ecex_theme_t *theme)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_4 \
+ "ecex_register_command\tint ecex_register_command(ecex_t *ed, const char *name, ecex_command_fn fn)\n" \
+ "ecex_execute_command\tint ecex_execute_command(ecex_t *ed, const char *name)\n" \
+ "ecex_add_command_hook\tint ecex_add_command_hook(ecex_t *ed, const char *name, ecex_command_hook_fn fn, void *userdata, ecex_hook_free_fn free_fn)\n" \
+ "ecex_remove_command_hook\tint ecex_remove_command_hook(ecex_t *ed, const char *name)\n" \
+ "ecex_add_prefix_hook\tint ecex_add_prefix_hook(ecex_t *ed, const char *name, ecex_prefix_hook_fn fn, void *userdata, ecex_hook_free_fn free_fn)\n" \
+ "ecex_remove_prefix_hook\tint ecex_remove_prefix_hook(ecex_t *ed, const char *name)\n" \
+ "ecex_notify_prefix_hooks\tvoid ecex_notify_prefix_hooks(ecex_t *ed, const char *prefix, int event)\n" \
+ "ecex_add_buffer_hook\tint ecex_add_buffer_hook(ecex_t *ed, const char *name, ecex_buffer_hook_fn fn, void *userdata, ecex_hook_free_fn free_fn)\n" \
+ "ecex_remove_buffer_hook\tint ecex_remove_buffer_hook(ecex_t *ed, const char *name)\n" \
+ "ecex_notify_buffer_hooks\tvoid ecex_notify_buffer_hooks(ecex_t *ed, buffer_t *buffer, int event)\n" \
+ "ecex_message\tvoid ecex_message(ecex_t *ed, const char *message)\n" \
+ "ecex_dependency_available\tint ecex_dependency_available(const char *program)\n" \
+ "ecex_plugin_require_dependency\tint ecex_plugin_require_dependency(ecex_t *ed, const char *plugin_id, const char *program)\n" \
+ "ecex_add_completion_provider\tint 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)\n" \
+ "ecex_add_word_completion_provider\tint 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)\n" \
+ "ecex_define_word_completion_provider\tint ecex_define_word_completion_provider(ecex_t *ed, const char *name, const char *mode_name, int flags)\n" \
+ "ecex_completion_provider_add_word\tint ecex_completion_provider_add_word(ecex_t *ed, const char *name, const char *word)\n" \
+ "ecex_completion_provider_add_word_detail\tint ecex_completion_provider_add_word_detail(ecex_t *ed, const char *name, const char *word, const char *detail)\n" \
+ "ecex_completion_provider_add_words\tint ecex_completion_provider_add_words(ecex_t *ed, const char *name, const char *words)\n" \
+ "ecex_completion_provider_add_entries\tint ecex_completion_provider_add_entries(ecex_t *ed, const char *name, const char *entries)\n" \
+ "ecex_completion_provider_set_detail\tint ecex_completion_provider_set_detail(ecex_t *ed, const char *name, const char *detail)\n" \
+ "ecex_add_clangd_completion_provider\tint ecex_add_clangd_completion_provider(ecex_t *ed, const char *name, const char *mode_name)\n" \
+ "ecex_remove_completion_provider\tint ecex_remove_completion_provider(ecex_t *ed, const char *name)\n" \
+ "ecex_buffer_identifier_prefix\tint ecex_buffer_identifier_prefix(buffer_t *buffer, char *out, size_t out_size)\n" \
+ "ecex_complete_at_point\tint ecex_complete_at_point(ecex_t *ed)\n" \
+ "ecex_set_clipboard_callbacks\tvoid ecex_set_clipboard_callbacks(ecex_t *ed, ecex_clipboard_get_fn get_fn, ecex_clipboard_set_fn set_fn, void *userdata)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_5 \
+ "ecex_clipboard_get\tconst char *ecex_clipboard_get(ecex_t *ed)\n" \
+ "ecex_clipboard_set\tint ecex_clipboard_set(ecex_t *ed, const char *text)\n" \
+ "ecex_bind_key\tint ecex_bind_key(ecex_t *ed, const char *key, const char *command)\n" \
+ "ecex_lookup_key\tconst char *ecex_lookup_key(ecex_t *ed, const char *key)\n" \
+ "ecex_define_major_mode\tint ecex_define_major_mode(ecex_t *ed, const char *name)\n" \
+ "ecex_major_mode_by_name\tint ecex_major_mode_by_name(ecex_t *ed, const char *name)\n" \
+ "ecex_major_mode_name\tconst char *ecex_major_mode_name(ecex_t *ed, int mode)\n" \
+ "ecex_buffer_set_major_mode\tint ecex_buffer_set_major_mode(buffer_t *buffer, int mode)\n" \
+ "ecex_buffer_set_major_mode_by_name\tint ecex_buffer_set_major_mode_by_name(ecex_t *ed, buffer_t *buffer, const char *name)\n" \
+ "ecex_buffer_major_mode_name\tconst char *ecex_buffer_major_mode_name(ecex_t *ed, buffer_t *buffer)\n" \
+ "ecex_bind_mode_key\tint ecex_bind_mode_key(ecex_t *ed, const char *mode_name, const char *key, const char *command)\n" \
+ "ecex_lookup_key_for_buffer\tconst char *ecex_lookup_key_for_buffer(ecex_t *ed, buffer_t *buffer, const char *key)\n" \
+ "ecex_key_sequence_has_prefix_for_buffer\tint ecex_key_sequence_has_prefix_for_buffer(ecex_t *ed, buffer_t *buffer, const char *prefix)\n" \
+ "ecex_describe_key_prefix\tint ecex_describe_key_prefix(ecex_t *ed, buffer_t *buffer, const char *prefix, char *out, size_t out_size, size_t max_items)\n" \
+ "ecex_auto_set_major_mode\tint ecex_auto_set_major_mode(ecex_t *ed, buffer_t *buffer)\n" \
+ "ecex_list_commands\tint ecex_list_commands(ecex_t *ed)\n" \
+ "ecex_list_buffers\tint ecex_list_buffers(ecex_t *ed)\n" \
+ "ecex_create_interactive_buffer\tbuffer_t *ecex_create_interactive_buffer(ecex_t *ed, const char *name)\n" \
+ "ecex_interactive_append_line\tint ecex_interactive_append_line(ecex_t *ed, buffer_t *buffer, const char *text, ecex_interactive_line_fn fn, const char *payload, void *userdata)\n" \
+ "ecex_interactive_activate_current_line\tint ecex_interactive_activate_current_line(ecex_t *ed)\n" \
+ "ecex_buffer_set_renderer\tint ecex_buffer_set_renderer(buffer_t *buffer, ecex_buffer_render_fn fn, void *userdata, ecex_buffer_userdata_free_fn free_fn, int flags)\n" \
+ "ecex_buffer_clear_renderer\tint ecex_buffer_clear_renderer(buffer_t *buffer)\n" \
+ "ecex_buffer_has_renderer\tint ecex_buffer_has_renderer(buffer_t *buffer)\n" \
+ "ecex_buffer_renderer_userdata\tvoid *ecex_buffer_renderer_userdata(buffer_t *buffer)\n" \
+ "ecex_buffer_set_mouse_handler\tint ecex_buffer_set_mouse_handler(buffer_t *buffer, ecex_buffer_mouse_fn fn, void *userdata, ecex_buffer_userdata_free_fn free_fn)\n" \
+ "ecex_buffer_clear_mouse_handler\tint ecex_buffer_clear_mouse_handler(buffer_t *buffer)\n" \
+ "ecex_buffer_has_mouse_handler\tint ecex_buffer_has_mouse_handler(buffer_t *buffer)\n" \
+ "ecex_buffer_mouse_userdata\tvoid *ecex_buffer_mouse_userdata(buffer_t *buffer)\n" \
+ "ecex_buffer_set_animation\tint ecex_buffer_set_animation(buffer_t *buffer, ecex_buffer_tick_fn fn, void *userdata, ecex_buffer_userdata_free_fn free_fn, double fps)\n" \
+ "ecex_buffer_set_animation_ms\tint ecex_buffer_set_animation_ms(buffer_t *buffer, ecex_buffer_tick_ms_fn fn, void *userdata, ecex_buffer_userdata_free_fn free_fn, int fps)\n" \
+ "ecex_buffer_clear_animation\tint ecex_buffer_clear_animation(buffer_t *buffer)\n" \
+ "ecex_buffer_is_animating\tint ecex_buffer_is_animating(buffer_t *buffer)\n" \
+ "ecex_buffer_animation_userdata\tvoid *ecex_buffer_animation_userdata(buffer_t *buffer)\n" \
+ "ecex_tick_animations\tint ecex_tick_animations(ecex_t *ed, double now_seconds)\n" \
+ "ecex_buffer_replace_text\tint ecex_buffer_replace_text(buffer_t *buffer, const char *text)\n" \
+ "ecex_buffer_set_modified\tvoid ecex_buffer_set_modified(buffer_t *buffer, int modified)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_6 \
+ "ecex_draw_set_color\tvoid ecex_draw_set_color(ecex_draw_context_t *ctx, float r, float g, float b, float a)\n" \
+ "ecex_draw_rect\tvoid ecex_draw_rect(ecex_draw_context_t *ctx, float x, float y, float w, float h)\n" \
+ "ecex_draw_rect_outline\tvoid ecex_draw_rect_outline(ecex_draw_context_t *ctx, float x, float y, float w, float h, float thickness)\n" \
+ "ecex_draw_line\tvoid ecex_draw_line(ecex_draw_context_t *ctx, float x1, float y1, float x2, float y2, float thickness)\n" \
+ "ecex_draw_text\tvoid ecex_draw_text(ecex_draw_context_t *ctx, float x, float y, const char *text)\n" \
+ "ecex_draw_text_aligned\tvoid ecex_draw_text_aligned(ecex_draw_context_t *ctx, float x, float y, float w, const char *text, int align)\n" \
+ "ecex_draw_text_width\tfloat ecex_draw_text_width(ecex_draw_context_t *ctx, const char *text)\n" \
+ "ecex_draw_rgba\tvoid ecex_draw_rgba(ecex_draw_context_t *ctx, float x, float y, float w, float h, const unsigned char *rgba, int image_w, int image_h)\n" \
+ "ecex_draw_color_rgba8_i\tvoid ecex_draw_color_rgba8_i(ecex_draw_context_t *ctx, int r, int g, int b, int a)\n" \
+ "ecex_draw_rect_i\tvoid ecex_draw_rect_i(ecex_draw_context_t *ctx, int x, int y, int w, int h)\n" \
+ "ecex_draw_rect_outline_i\tvoid ecex_draw_rect_outline_i(ecex_draw_context_t *ctx, int x, int y, int w, int h, int thickness)\n" \
+ "ecex_draw_line_i\tvoid ecex_draw_line_i(ecex_draw_context_t *ctx, int x1, int y1, int x2, int y2, int thickness)\n" \
+ "ecex_draw_text_i\tvoid ecex_draw_text_i(ecex_draw_context_t *ctx, int x, int y, const char *text)\n" \
+ "ecex_draw_plugin_text_i\tvoid ecex_draw_plugin_text_i(ecex_draw_context_t *ctx, void *owner, int id, int x, int y)\n" \
+ "ecex_draw_plugin_text_rect_i\tvoid 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)\n" \
+ "ecex_draw_markdown_canvas_i\tvoid ecex_draw_markdown_canvas_i(ecex_draw_context_t *ctx, void *owner, int title_id, int x, int y, int w, int line_h)\n" \
+ "ecex_draw_markdown_text_i\tvoid 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)\n" \
+ "ecex_draw_markdown_canvas_auto_i\tvoid ecex_draw_markdown_canvas_auto_i(ecex_draw_context_t *ctx, void *owner, int title_id)\n" \
+ "ecex_draw_markdown_line_auto_i\tvoid ecex_draw_markdown_line_auto_i(ecex_draw_context_t *ctx, void *owner, int text_id, int y, int style)\n" \
+ "ecex_draw_label_i\tvoid ecex_draw_label_i(ecex_draw_context_t *ctx, int x, int y, int label_id)\n" \
+ "ecex_draw_stat_i\tvoid ecex_draw_stat_i(ecex_draw_context_t *ctx, int x, int y, int label_id, int value)\n" \
+ "ecex_draw_tetris_preview_i\tvoid ecex_draw_tetris_preview_i(ecex_draw_context_t *ctx, int piece, int x, int y, int cell, int alpha)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_7 \
+ "ecex_find_file\tint ecex_find_file(ecex_t *ed, const char *path)\n" \
+ "ecex_save_current_buffer\tint ecex_save_current_buffer(ecex_t *ed)\n" \
+ "ecex_write_current_buffer\tint ecex_write_current_buffer(ecex_t *ed, const char *path)\n" \
+ "ecex_compile\tint ecex_compile(ecex_t *ed, const char *command)\n" \
+ "ecex_grep\tint ecex_grep(ecex_t *ed, const char *command)\n" \
+ "ecex_rerun_compile\tint ecex_rerun_compile(ecex_t *ed)\n" \
+ "ecex_rerun_grep\tint ecex_rerun_grep(ecex_t *ed)\n" \
+ "ecex_next_interactive_action\tint ecex_next_interactive_action(ecex_t *ed)\n" \
+ "ecex_previous_interactive_action\tint ecex_previous_interactive_action(ecex_t *ed)\n" \
+ "ecex_indent_line_to\tint ecex_indent_line_to(buffer_t *buffer, int target_cols)\n" \
+ "ecex_comment_region\tint ecex_comment_region(ecex_t *ed)\n" \
+ "ecex_uncomment_region\tint ecex_uncomment_region(ecex_t *ed)\n" \
+ "ecex_request_prompt\tvoid ecex_request_prompt(ecex_t *ed, ecex_prompt_request_t request, const char *message)\n" \
+ "ecex_clear_prompt_request\tvoid ecex_clear_prompt_request(ecex_t *ed)\n" \
+ "ecex_complete_command\tconst char *ecex_complete_command(ecex_t *ed, const char *query)\n" \
+ "ecex_set_font\tint ecex_set_font(ecex_t *ed, const char *path)\n" \
+ "ecex_get_font_size\tfloat ecex_get_font_size(ecex_t *ed)\n" \
+ "ecex_set_font_size\tint ecex_set_font_size(ecex_t *ed, float size)\n" \
+ "ecex_adjust_font_size\tint ecex_adjust_font_size(ecex_t *ed, float delta)\n" \
+ "ecex_set_bg_color\tvoid ecex_set_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_fg_color\tvoid ecex_set_fg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_status_bg_color\tvoid ecex_set_status_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_status_fg_color\tvoid ecex_set_status_fg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_status_border_color\tvoid ecex_set_status_border_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_cursor_color\tvoid ecex_set_cursor_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_region_bg_color\tvoid ecex_set_region_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_minibuffer_bg_color\tvoid ecex_set_minibuffer_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_minibuffer_fg_color\tvoid ecex_set_minibuffer_fg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_completion_fg_color\tvoid ecex_set_completion_fg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_completion_enabled\tvoid ecex_set_completion_enabled(ecex_t *ed, int enabled)\n" \
+ "ecex_set_interactive_highlight_bg_color\tvoid ecex_set_interactive_highlight_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_interactive_highlight_fg_color\tvoid ecex_set_interactive_highlight_fg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_current_line_bg_color\tvoid ecex_set_current_line_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_search_bg_color\tvoid ecex_set_search_bg_color(ecex_t *ed, float r, float g, float b)\n" \
+ "ecex_set_line_numbers_enabled\tvoid ecex_set_line_numbers_enabled(ecex_t *ed, int enabled)\n" \
+ "ecex_set_current_line_enabled\tvoid ecex_set_current_line_enabled(ecex_t *ed, int enabled)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_8 \
+ "buffer_new\tbuffer_t *buffer_new(const char *name, const char *path, int read_only)\n" \
+ "buffer_free\tvoid buffer_free(buffer_t *buffer)\n" \
+ "buffer_reserve\tint buffer_reserve(buffer_t *buffer, size_t needed)\n" \
+ "buffer_clear\tint buffer_clear(buffer_t *buffer)\n" \
+ "buffer_set_text\tint buffer_set_text(buffer_t *buffer, const char *text)\n" \
+ "buffer_insert_at\tint buffer_insert_at(buffer_t *buffer, size_t pos, const char *text)\n" \
+ "buffer_insert\tint buffer_insert(buffer_t *buffer, const char *text)\n" \
+ "buffer_append\tint buffer_append(buffer_t *buffer, const char *text)\n" \
+ "buffer_prepend\tint buffer_prepend(buffer_t *buffer, const char *text)\n" \
+ "buffer_insert_char_at\tint buffer_insert_char_at(buffer_t *buffer, size_t pos, char c)\n" \
+ "buffer_insert_char\tint buffer_insert_char(buffer_t *buffer, char c)\n" \
+ "buffer_delete_range\tint buffer_delete_range(buffer_t *buffer, size_t start, size_t end)\n" \
+ "buffer_delete_selection\tint buffer_delete_selection(buffer_t *buffer)\n" \
+ "buffer_replace_selection\tint buffer_replace_selection(buffer_t *buffer, const char *text)\n" \
+ "buffer_backspace\tint buffer_backspace(buffer_t *buffer)\n" \
+ "buffer_delete_forward\tint buffer_delete_forward(buffer_t *buffer)\n" \
+ "buffer_kill_line\tint buffer_kill_line(buffer_t *buffer)\n" \
+ "buffer_undo\tint buffer_undo(buffer_t *buffer)\n" \
+ "buffer_redo\tint buffer_redo(buffer_t *buffer)\n" \
+ "buffer_clear_undo\tvoid buffer_clear_undo(buffer_t *buffer)\n" \
+ "buffer_set_point\tvoid buffer_set_point(buffer_t *buffer, size_t point)\n" \
+ "buffer_move_left\tvoid buffer_move_left(buffer_t *buffer)\n" \
+ "buffer_move_right\tvoid buffer_move_right(buffer_t *buffer)\n" \
+ "buffer_move_up\tvoid buffer_move_up(buffer_t *buffer)\n" \
+ "buffer_move_down\tvoid buffer_move_down(buffer_t *buffer)\n" \
+ "buffer_move_word_left\tvoid buffer_move_word_left(buffer_t *buffer)\n" \
+ "buffer_move_word_right\tvoid buffer_move_word_right(buffer_t *buffer)\n" \
+ "buffer_move_beginning_of_line\tvoid buffer_move_beginning_of_line(buffer_t *buffer)\n" \
+ "buffer_move_end_of_line\tvoid buffer_move_end_of_line(buffer_t *buffer)\n" \
+ "buffer_move_beginning_of_buffer\tvoid buffer_move_beginning_of_buffer(buffer_t *buffer)\n" \
+ "buffer_move_end_of_buffer\tvoid buffer_move_end_of_buffer(buffer_t *buffer)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_9 \
+ "buffer_search_forward\tint buffer_search_forward(buffer_t *buffer, const char *query, size_t start, size_t *out_pos)\n" \
+ "buffer_search_backward\tint buffer_search_backward(buffer_t *buffer, const char *query, size_t start, size_t *out_pos)\n" \
+ "buffer_set_mark\tvoid buffer_set_mark(buffer_t *buffer, size_t mark)\n" \
+ "buffer_clear_mark\tvoid buffer_clear_mark(buffer_t *buffer)\n" \
+ "buffer_has_selection\tint buffer_has_selection(buffer_t *buffer)\n" \
+ "buffer_selection_range\tvoid buffer_selection_range(buffer_t *buffer, size_t *out_start, size_t *out_end)\n" \
+ "buffer_line_start_at\tsize_t buffer_line_start_at(buffer_t *buffer, size_t pos)\n" \
+ "buffer_line_end_at\tsize_t buffer_line_end_at(buffer_t *buffer, size_t pos)\n" \
+ "buffer_current_line_start\tsize_t buffer_current_line_start(buffer_t *buffer)\n" \
+ "buffer_current_line_end\tsize_t buffer_current_line_end(buffer_t *buffer)\n" \
+ "buffer_current_column\tsize_t buffer_current_column(buffer_t *buffer)\n" \
+ "buffer_current_line_number\tsize_t buffer_current_line_number(buffer_t *buffer)\n" \
+ "buffer_line_count\tsize_t buffer_line_count(buffer_t *buffer)\n" \
+ "buffer_substring\tchar *buffer_substring(buffer_t *buffer, size_t start, size_t end)\n" \
+ "buffer_current_line_copy\tchar *buffer_current_line_copy(buffer_t *buffer)\n" \
+ "buffer_load_file\tint buffer_load_file(buffer_t *buffer, const char *path)\n" \
+ "buffer_save\tint buffer_save(buffer_t *buffer)\n" \
+ "buffer_save_as\tint buffer_save_as(buffer_t *buffer, const char *path)\n" \
+ "buffer_set_interactive\tvoid buffer_set_interactive(buffer_t *buffer, int interactive)\n" \
+ "buffer_is_interactive\tint buffer_is_interactive(buffer_t *buffer)\n" \
+ "buffer_clear_interactive_actions\tint buffer_clear_interactive_actions(buffer_t *buffer)\n" \
+ "buffer_add_interactive_action\tint buffer_add_interactive_action(buffer_t *buffer, size_t line, ecex_interactive_line_fn fn, const char *payload, void *userdata)\n" \
+ "buffer_interactive_action_at_line\tecex_interactive_line_action_t *buffer_interactive_action_at_line(buffer_t *buffer, size_t line)\n"
+
+#define ECEX_API_SIGNATURE_ENTRIES_10 \
+ "ecex_path_copy\tint ecex_path_copy(char *out, size_t out_size, const char *text)\n" \
+ "ecex_path_expand_user\tchar *ecex_path_expand_user(const char *path)\n" \
+ "ecex_path_join\tchar *ecex_path_join(const char *dir, const char *name)\n" \
+ "ecex_path_dirname\tchar *ecex_path_dirname(const char *path)\n" \
+ "ecex_path_basename_dup\tchar *ecex_path_basename_dup(const char *path)\n" \
+ "ecex_path_normalize\tchar *ecex_path_normalize(const char *path)\n" \
+ "ecex_path_is_dir\tint ecex_path_is_dir(const char *path)\n" \
+ "ecex_path_is_file\tint ecex_path_is_file(const char *path)\n" \
+ "ecex_path_exists\tint ecex_path_exists(const char *path)\n" \
+ "ecex_path_file_size\tlong long ecex_path_file_size(const char *path)\n" \
+ "ecex_path_is_image\tint ecex_path_is_image(const char *path)\n" \
+ "ecex_path_is_previewable_image\tint ecex_path_is_previewable_image(const char *path)\n" \
+ "ecex_path_is_video\tint ecex_path_is_video(const char *path)\n" \
+ "ecex_path_is_media\tint ecex_path_is_media(const char *path)\n" \
+ "ecex_path_cwd\tint ecex_path_cwd(char *out, size_t out_size)\n" \
+ "ecex_media_open\tint ecex_media_open(ecex_t *ed, const char *path)\n" \
+ "ecex_media_load_into_buffer\tint ecex_media_load_into_buffer(ecex_t *ed, const char *path, buffer_t *buffer)\n" \
+ "ecex_media_toggle_playback\tint ecex_media_toggle_playback(ecex_t *ed)\n" \
+ "ecex_media_tick\tint ecex_media_tick(ecex_t *ed, double now_seconds)\n" \
+ "ecex_media_buffer_clear\tvoid ecex_media_buffer_clear(buffer_t *buffer)\n" \
+ "ecex_media_buffer_has_pixels\tint ecex_media_buffer_has_pixels(buffer_t *buffer)\n" \
+ "ecex_eval_source\tint ecex_eval_source(ecex_t *ed, const char *source, const char *filename, int wrap_as_statements)\n" \
+ "ecex_eval_current_buffer\tint ecex_eval_current_buffer(ecex_t *ed)\n" \
+ "ecex_eval_current_line\tint ecex_eval_current_line(ecex_t *ed)\n" \
+ "ecex_eval_current_region\tint ecex_eval_current_region(ecex_t *ed)\n" \
+ "ecex_eval_file\tint ecex_eval_file(ecex_t *ed, const char *path)\n" \
+ "ecex_eval_rerun_last\tint ecex_eval_rerun_last(ecex_t *ed)\n"
+
+#define ECEX_API_ED_FIELD_ENTRIES \
+ "buffers\tbuffer_t **buffers\n" \
+ "buffer_cap\tsize_t buffer_cap\n" \
+ "buffer_count\tsize_t buffer_count\n" \
+ "current_buffer_index\tsize_t current_buffer_index\n" \
+ "current_buffer\tbuffer_t *current_buffer\n" \
+ "previous_buffer\tbuffer_t *previous_buffer\n" \
+ "windows\tecex_window_t *windows\n" \
+ "window_cap\tsize_t window_cap\n" \
+ "window_count\tsize_t window_count\n" \
+ "current_window_index\tsize_t current_window_index\n" \
+ "jit_modules\tvoid **jit_modules\n" \
+ "jit_module_cap\tsize_t jit_module_cap\n" \
+ "jit_module_count\tsize_t jit_module_count\n" \
+ "commands\tecex_command_t *commands\n" \
+ "command_cap\tsize_t command_cap\n" \
+ "command_count\tsize_t command_count\n" \
+ "keybinds\tecex_keybind_t *keybinds\n" \
+ "keybind_cap\tsize_t keybind_cap\n" \
+ "keybind_count\tsize_t keybind_count\n" \
+ "mode_keybinds\tecex_mode_keybind_t *mode_keybinds\n" \
+ "mode_keybind_cap\tsize_t mode_keybind_cap\n" \
+ "mode_keybind_count\tsize_t mode_keybind_count\n" \
+ "command_hooks\tecex_command_hook_t *command_hooks\n" \
+ "command_hook_cap\tsize_t command_hook_cap\n" \
+ "command_hook_count\tsize_t command_hook_count\n" \
+ "prefix_hooks\tecex_prefix_hook_t *prefix_hooks\n" \
+ "prefix_hook_cap\tsize_t prefix_hook_cap\n" \
+ "prefix_hook_count\tsize_t prefix_hook_count\n" \
+ "buffer_hooks\tecex_buffer_hook_t *buffer_hooks\n" \
+ "buffer_hook_cap\tsize_t buffer_hook_cap\n" \
+ "buffer_hook_count\tsize_t buffer_hook_count\n" \
+ "completion_providers\tecex_completion_provider_t *completion_providers\n" \
+ "completion_provider_cap\tsize_t completion_provider_cap\n" \
+ "completion_provider_count\tsize_t completion_provider_count\n" \
+ "completion_cycle_active\tint completion_cycle_active\n" \
+ "completion_cycle_buffer\tbuffer_t *completion_cycle_buffer\n" \
+ "completion_cycle_start\tsize_t completion_cycle_start\n" \
+ "completion_cycle_index\tsize_t completion_cycle_index\n" \
+ "completion_cycle_prefix\tchar completion_cycle_prefix[256]\n" \
+ "completion_cycle_current\tchar completion_cycle_current[256]\n" \
+ "major_modes\tecex_major_mode_t *major_modes\n" \
+ "major_mode_cap\tsize_t major_mode_cap\n" \
+ "major_mode_count\tsize_t major_mode_count\n" \
+ "next_major_mode_id\tint next_major_mode_id\n" \
+ "plugins\tecex_plugin_runtime_t *plugins\n" \
+ "last_eval_source\tchar *last_eval_source\n" \
+ "last_eval_filename\tchar *last_eval_filename\n" \
+ "last_eval_wrap_as_statements\tint last_eval_wrap_as_statements\n" \
+ "last_compile_command\tchar *last_compile_command\n" \
+ "last_grep_command\tchar *last_grep_command\n" \
+ "prompt_request\tecex_prompt_request_t prompt_request\n" \
+ "prompt_message\tchar prompt_message[128]\n" \
+ "config_path\tchar *config_path\n" \
+ "message\tchar message[1024]\n" \
+ "message_revision\tunsigned long message_revision\n" \
+ "clipboard_get\tecex_clipboard_get_fn clipboard_get\n" \
+ "clipboard_set\tecex_clipboard_set_fn clipboard_set\n" \
+ "clipboard_userdata\tvoid *clipboard_userdata\n" \
+ "clipboard_text\tchar *clipboard_text\n" \
+ "should_quit\tint should_quit\n" \
+ "ui_revision\tunsigned long ui_revision\n" \
+ "font_revision\tunsigned long font_revision\n" \
+ "theme\tecex_theme_t theme\n"
#define ECEX_API_ED_FIELD_WORDS \
"buffers\n" \
"buffer_cap\n" \
@@ -712,6 +1109,20 @@ static int ecex_api_enabled(ecex_plugin_t *plugin) {
return ecex_plugin_slot_i32_get_scalar(plugin, ECEX_API_SLOT_ENABLED, 1) != 0;
}
+static int ecex_api_register_symbol_entries(ecex_t *ed) {
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_1) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_2) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_3) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_4) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_5) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_6) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_7) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_8) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_9) != 0) return -1;
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SIGNATURE_ENTRIES_10) != 0) return -1;
+ return 0;
+}
+
static int ecex_api_register_providers(ecex_t *ed) {
if (ecex_define_word_completion_provider(ed,
ECEX_API_SYMBOLS_PROVIDER,
@@ -720,7 +1131,7 @@ static int ecex_api_register_providers(ecex_t *ed) {
return -1;
}
- if (ecex_completion_provider_add_words(ed, ECEX_API_SYMBOLS_PROVIDER, ECEX_API_SYMBOL_WORDS) != 0) {
+ if (ecex_api_register_symbol_entries(ed) != 0) {
ecex_remove_completion_provider(ed, ECEX_API_SYMBOLS_PROVIDER);
return -1;
}
@@ -737,7 +1148,7 @@ static int ecex_api_register_providers(ecex_t *ed) {
return -1;
}
- if (ecex_completion_provider_add_words(ed, ECEX_API_ED_FIELDS_PROVIDER, ECEX_API_ED_FIELD_WORDS) != 0) {
+ if (ecex_completion_provider_add_entries(ed, ECEX_API_ED_FIELDS_PROVIDER, ECEX_API_ED_FIELD_ENTRIES) != 0) {
ecex_remove_completion_provider(ed, ECEX_API_SYMBOLS_PROVIDER);
ecex_remove_completion_provider(ed, ECEX_API_ED_FIELDS_PROVIDER);
return -1;
diff --git a/docs/ccdjit-improvements.md b/docs/ccdjit-improvements.md
index 4b48589..ef4469e 100644
--- a/docs/ccdjit-improvements.md
+++ b/docs/ccdjit-improvements.md
@@ -37,9 +37,10 @@ currently favors integer-only plugin helpers, host-owned objects, and copy-based
text because those paths are predictable.
Static completion lists should use `ecex_define_word_completion_provider` plus
-`ecex_completion_provider_add_words`. That passes one string literal blob over
-the host boundary and avoids depending on JIT-side `const char *` array
-indexing.
+`ecex_completion_provider_add_words`, or `ecex_completion_provider_add_entries`
+when each candidate needs its own signature/detail. Both forms pass one string
+literal blob over the host boundary and avoid depending on JIT-side
+`const char *` array indexing.
Runtime plugin callbacks should avoid variadic C library calls such as
`snprintf`. Build strings with fixed-arity helpers or host APIs instead; the C
diff --git a/docs/plugin-api.md b/docs/plugin-api.md
index 04851ed..76051f9 100644
--- a/docs/plugin-api.md
+++ b/docs/plugin-api.md
@@ -221,14 +221,24 @@ ecex_completion_provider_set_detail(ed, "demo-words", "C runtime symbol");
`ecex_completion_provider_add_words` accepts a whitespace-separated string
literal, copies the words on the host, and avoids depending on JIT string-array
indexing. Provider details are optional minibuffer labels shown while cycling.
+Use `ecex_completion_provider_add_word_detail` for one word with its own label,
+or `ecex_completion_provider_add_entries` for newline-separated entries in
+`word<TAB>detail` form:
+
+```c
+ecex_completion_provider_add_entries(ed,
+ "demo-words",
+ "malloc\tvoid *malloc(size_t size)\n"
+ "free\tvoid free(void *ptr)\n");
+```
The built-in `indent-for-tab-command` is bound to `TAB`; `config/c_mode_plugin.c`
defines `c-mode`, overrides `TAB` with `c-indent-line`, registers C-family file
handlers, and adds clangd completion when `clangd` is installed. Clangd
completions use label details when available, so functions display signatures
and return types. `config/ecex_api_completion_plugin.c` is the `ecex-mode`
-plugin; it registers global ecex API completions and special-cases `ed->` field
-names using word completion providers.
+plugin; it registers global ecex API completions with signature details and
+special-cases `ed->` field names using typed word completion entries.
```c
ecex_add_clangd_completion_provider(ed, "c-mode-clangd", "c-mode");
diff --git a/include/ecex.h b/include/ecex.h
index 085c3d2..3e0048e 100644
--- a/include/ecex.h
+++ b/include/ecex.h
@@ -154,7 +154,12 @@ int ecex_define_word_completion_provider(ecex_t *ed,
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_word_detail(ecex_t *ed,
+ const char *name,
+ const char *word,
+ const char *detail);
int ecex_completion_provider_add_words(ecex_t *ed, const char *name, const char *words);
+int ecex_completion_provider_add_entries(ecex_t *ed, const char *name, const char *entries);
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);
diff --git a/include/types.h b/include/types.h
index 2b63ad3..008bd98 100644
--- a/include/types.h
+++ b/include/types.h
@@ -260,6 +260,7 @@ typedef struct ecex_completion_provider {
ecex_hook_free_fn free_fn;
char *detail;
char **words;
+ char **word_details;
size_t word_count;
int flags;
} ecex_completion_provider_t;
diff --git a/src/config.c b/src/config.c
index e9bba5d..9c885ff 100644
--- a/src/config.c
+++ b/src/config.c
@@ -137,7 +137,9 @@ static const host_symbol_t host_symbols[] = {
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_word_detail),
HOST_SYMBOL(ecex_completion_provider_add_words),
+ HOST_SYMBOL(ecex_completion_provider_add_entries),
HOST_SYMBOL(ecex_completion_provider_set_detail),
HOST_SYMBOL(ecex_add_clangd_completion_provider),
HOST_SYMBOL(ecex_remove_completion_provider),
diff --git a/src/ecex.c b/src/ecex.c
index 7206b96..a40a792 100644
--- a/src/ecex.c
+++ b/src/ecex.c
@@ -1521,8 +1521,10 @@ static void ecex_completion_provider_clear(ecex_completion_provider_t *provider)
if (provider->free_fn && provider->userdata) provider->free_fn(provider->userdata);
for (size_t i = 0; i < provider->word_count; i++) {
free(provider->words[i]);
+ if (provider->word_details) free(provider->word_details[i]);
}
free(provider->words);
+ free(provider->word_details);
free(provider->detail);
free(provider->name);
memset(provider, 0, sizeof(*provider));
@@ -2266,20 +2268,53 @@ int ecex_define_word_completion_provider(ecex_t *ed,
return ECEX_OK;
}
-int ecex_completion_provider_add_word(ecex_t *ed, const char *name, const char *word) {
+int ecex_completion_provider_add_word_detail(ecex_t *ed,
+ const char *name,
+ const char *word,
+ const char *detail) {
if (!ed || !name || !word || !word[0]) return ECEX_ERR;
for (size_t i = 0; i < ed->completion_provider_count; i++) {
ecex_completion_provider_t *provider = &ed->completion_providers[i];
if (strcmp(provider->name, name) != 0) continue;
+ char *word_copy = ecex_strdup(word);
+ if (!word_copy) return ECEX_ERR;
+
+ char *detail_copy = NULL;
+ if (detail && detail[0]) {
+ detail_copy = ecex_strdup(detail);
+ if (!detail_copy) {
+ free(word_copy);
+ return ECEX_ERR;
+ }
+ }
+
char **grown = realloc(provider->words,
(provider->word_count + 1) * sizeof(*provider->words));
- if (!grown) return ECEX_ERR;
+ if (!grown) {
+ free(word_copy);
+ free(detail_copy);
+ return ECEX_ERR;
+ }
provider->words = grown;
- provider->words[provider->word_count] = ecex_strdup(word);
- if (!provider->words[provider->word_count]) return ECEX_ERR;
+ char **grown_details = NULL;
+ if (provider->word_details) {
+ grown_details = realloc(provider->word_details,
+ (provider->word_count + 1) * sizeof(*provider->word_details));
+ } else {
+ grown_details = calloc(provider->word_count + 1, sizeof(*provider->word_details));
+ }
+ if (!grown_details) {
+ free(word_copy);
+ free(detail_copy);
+ return ECEX_ERR;
+ }
+ provider->word_details = grown_details;
+
+ provider->words[provider->word_count] = word_copy;
+ provider->word_details[provider->word_count] = detail_copy;
provider->word_count++;
return ECEX_OK;
}
@@ -2287,6 +2322,10 @@ int ecex_completion_provider_add_word(ecex_t *ed, const char *name, const char *
return ECEX_ERR;
}
+int ecex_completion_provider_add_word(ecex_t *ed, const char *name, const char *word) {
+ return ecex_completion_provider_add_word_detail(ed, name, word, NULL);
+}
+
int ecex_completion_provider_add_words(ecex_t *ed, const char *name, const char *words) {
if (!ed || !name || !words) return ECEX_ERR;
@@ -2311,6 +2350,48 @@ int ecex_completion_provider_add_words(ecex_t *ed, const char *name, const char
return ECEX_OK;
}
+int ecex_completion_provider_add_entries(ecex_t *ed, const char *name, const char *entries) {
+ if (!ed || !name || !entries) return ECEX_ERR;
+
+ const char *p = entries;
+ while (*p) {
+ while (*p == '\n' || *p == '\r') p++;
+ if (!*p) break;
+
+ char word[256];
+ char detail[512];
+ size_t word_len = 0;
+ size_t detail_len = 0;
+
+ while (*p && *p != '\t' && *p != '\n' && *p != '\r') {
+ if (word_len + 1 < sizeof(word)) word[word_len++] = *p;
+ p++;
+ }
+ word[word_len] = '\0';
+
+ if (*p == '\t') {
+ p++;
+ while (*p && *p != '\n' && *p != '\r') {
+ if (detail_len + 1 < sizeof(detail)) detail[detail_len++] = *p;
+ p++;
+ }
+ }
+ detail[detail_len] = '\0';
+
+ while (*p == '\n' || *p == '\r') p++;
+
+ if (word_len > 0 &&
+ ecex_completion_provider_add_word_detail(ed,
+ name,
+ word,
+ detail_len > 0 ? detail : NULL) != ECEX_OK) {
+ return ECEX_ERR;
+ }
+ }
+
+ return ECEX_OK;
+}
+
int ecex_completion_provider_set_detail(ecex_t *ed, const char *name, const char *detail) {
if (!ed || !name || !name[0]) return ECEX_ERR;
@@ -4059,7 +4140,13 @@ static void ecex_completion_collect_from_provider(ecex_t *ed,
for (size_t i = 0; i < provider->word_count; i++) {
int score = ecex_fuzzy_score(provider->words[i], prefix);
if (score < 0) continue;
- ecex_completion_candidates_add(items, cap, count, provider->words[i], detail, score);
+ const char *word_detail = detail;
+ if (provider->word_details &&
+ provider->word_details[i] &&
+ provider->word_details[i][0]) {
+ word_detail = provider->word_details[i];
+ }
+ ecex_completion_candidates_add(items, cap, count, provider->words[i], word_detail, score);
}
return;
}