aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/app.h7
-rw-r--r--include/buffers.h10
-rw-r--r--include/ccdjit.h262
-rw-r--r--include/ecex.h127
-rw-r--r--include/libccdjit.abin507906 -> 613206 bytes
-rwxr-xr-xinclude/libccdjit.sobin369144 -> 431632 bytes
-rw-r--r--include/plugin.h110
-rw-r--r--include/types.h138
8 files changed, 552 insertions, 102 deletions
diff --git a/include/app.h b/include/app.h
index a420f00..9db977e 100644
--- a/include/app.h
+++ b/include/app.h
@@ -7,7 +7,8 @@
#include <GLFW/glfw3.h>
#include <stddef.h>
-#define ECEX_MINIBUFFER_SIZE 256
+#define ECEX_MINIBUFFER_SIZE 1024
+#define ECEX_MINIBUFFER_MAX_ROWS 6
#define ECEX_PREFIX_SIZE 128
typedef enum app_mode {
@@ -89,11 +90,15 @@ typedef struct app {
font_t font;
char font_path[4096];
+ unsigned long ui_revision_seen;
+ unsigned long font_revision_seen;
+ unsigned long message_revision_seen;
} app_t;
void app_init(app_t *app, ecex_t *ed);
void app_set_window(app_t *app, GLFWwindow *window);
void app_install_callbacks(app_t *app);
+void app_sync_editor_ui(app_t *app);
void app_message(app_t *app, const char *msg);
#endif
diff --git a/include/buffers.h b/include/buffers.h
index 148d718..8ffc5e9 100644
--- a/include/buffers.h
+++ b/include/buffers.h
@@ -5,6 +5,10 @@
#include <stddef.h>
+void ecex_logf(const char *fmt, ...);
+void ecex_log_group_begin(const char *message);
+void ecex_log_group_end(const char *message);
+
buffer_t *buffer_new(const char *name, const char *path, int read_only);
void buffer_free(buffer_t *buffer);
@@ -107,8 +111,8 @@ int ecex_tick_animations(ecex_t *ed, double now_seconds);
int ecex_buffer_replace_text(buffer_t *buffer, const char *text);
void ecex_buffer_set_modified(buffer_t *buffer, int modified);
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_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);
#endif
diff --git a/include/ccdjit.h b/include/ccdjit.h
index f8a212b..7999125 100644
--- a/include/ccdjit.h
+++ b/include/ccdjit.h
@@ -33,26 +33,48 @@
* Function pointers returned by ccdjit_module_symbol() are invalid after
* ccdjit_module_free().
*
+ * Runtime policy:
+ * Module calls, symbol lookup, and emission intentionally consult the
+ * current context options, sandbox settings, resource limits, registered
+ * symbols, resolver callback, and loaded libraries. Machine code that
+ * has already been compiled may contain resolved external addresses; use
+ * a new module or function-handle replacement when changing symbol
+ * bindings must affect already compiled call sites.
+ *
* Threads:
- * Independent contexts may compile and run from different threads. Do
- * not mutate or use the same context or module concurrently from multiple
- * threads unless the host provides its own synchronization.
+ * Public API entry points are internally serialized, and module calls,
+ * symbol lookup, emission, and lazy compilation take a module lock. Raw
+ * function pointers returned by ccdjit_module_symbol() are still host
+ * pointers: do not free or replace their module while those pointers may
+ * run, and prefer typed handle/call helpers for dynamic bindings.
*
* Safety:
* Normal calls run in the host process. Set sandbox_execution to
* CCDJIT_SANDBOX_PROCESS to run ccdjit_module_call_main() in a child
- * process with optional resource, syscall, and filesystem limits.
+ * process with optional resource, syscall, and filesystem limits. Child
+ * crashes are reported through ccdjit_diagnostic.
*/
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
+#define CCDJIT_VERSION_MAJOR 1
+#define CCDJIT_VERSION_MINOR 0
+#define CCDJIT_VERSION_PATCH 0
+#define CCDJIT_VERSION_STRING "1.0.0"
+#define CCDJIT_API_ABI_VERSION 1
+#define CCDJITB2_FORMAT_VERSION 2
+#define CCDJITB2_FLAG_DEBUG_INFO 1u
+
typedef struct ccdjit_context ccdjit_context;
typedef struct ccdjit_module ccdjit_module;
+typedef struct ccdjit_function_handle ccdjit_function_handle;
+typedef struct ccdjit_execution_result ccdjit_execution_result;
typedef struct {
/* Host compiler or linker driver. NULL uses $CC, then cc. */
@@ -64,6 +86,12 @@ typedef struct {
/* Print the host linker command to stderr when nonzero. */
int verbose;
+
+ /* Wall-clock driver timeout. Zero uses the default. */
+ unsigned int timeout_ms;
+
+ /* Captured driver stdout/stderr cap. Zero uses the default. */
+ size_t output_limit_bytes;
} ccdjit_link_options;
/*
@@ -158,6 +186,9 @@ typedef struct {
*/
size_t sandbox_output_limit_bytes;
+ /* Emit and retain optional debug/source mapping metadata. */
+ int debug_info;
+
/*
* Preprocessor output byte cap. Zero uses the default currently 128
* MiB.
@@ -169,6 +200,18 @@ typedef struct {
/* Nested include cap. Zero uses the default. */
unsigned int preprocessor_include_depth_limit;
+
+ /*
+ * Optional compiler driver used for host system include and builtin
+ * macro probes. NULL auto-detects from $CC, then common cc drivers.
+ */
+ const char *preprocessor_compiler;
+
+ /* Wall-clock timeout for one compiler probe. Zero uses the default. */
+ unsigned int preprocessor_probe_timeout_ms;
+
+ /* Captured compiler-probe output cap. Zero uses the default. */
+ size_t preprocessor_probe_output_limit_bytes;
} ccdjit_options;
typedef struct {
@@ -189,18 +232,114 @@ typedef struct {
int line;
int column;
+ /* ccdjit_diagnostic_code plus optional code-specific detail. */
+ int code;
+ int subcode;
+
/* Raw child wait status or errno-style value for sandbox/API failures.
*/
int status;
/* Signal that terminated the sandbox child, or zero. */
int signal_number;
+
+ /* Faulting address for sandboxed crash diagnostics, when available. */
+ int has_fault_address;
+ uintptr_t fault_address;
} ccdjit_diagnostic;
-/* Create a compiler context. Passing NULL uses permissive CLI-like defaults.
+typedef enum {
+ CCDJIT_DIAG_NONE = 0,
+ CCDJIT_DIAG_LEXER = 1,
+ CCDJIT_DIAG_PARSER = 2,
+ CCDJIT_DIAG_PREPROCESSOR = 3,
+ CCDJIT_DIAG_TYPE = 4,
+ CCDJIT_DIAG_JIT = 5,
+ CCDJIT_DIAG_UNRESOLVED_SYMBOL = 6,
+ CCDJIT_DIAG_SANDBOX = 7,
+ CCDJIT_DIAG_SANDBOX_TIMEOUT = 8,
+ CCDJIT_DIAG_SANDBOX_FORBIDDEN_SYSCALL = 9,
+ CCDJIT_DIAG_SANDBOX_CRASH = 10,
+ CCDJIT_DIAG_INVALID_OPTIONS = 11,
+ CCDJIT_DIAG_INVALID_ARGUMENT = 12,
+ CCDJIT_DIAG_UNSUPPORTED_ABI = 13,
+ CCDJIT_DIAG_MALFORMED_BINARY = 14,
+ CCDJIT_DIAG_HOST_LINKER = 15,
+ CCDJIT_DIAG_OUT_OF_MEMORY = 16,
+} ccdjit_diagnostic_code;
+
+typedef enum {
+ CCDJIT_SYMBOL_UNKNOWN = 0,
+ CCDJIT_SYMBOL_FUNCTION = 1,
+ CCDJIT_SYMBOL_OBJECT = 2,
+} ccdjit_symbol_kind;
+
+typedef enum {
+ CCDJIT_TYPE_INT = 0,
+ CCDJIT_TYPE_CHAR = 1,
+ CCDJIT_TYPE_BOOL = 2,
+ CCDJIT_TYPE_VOID = 3,
+ CCDJIT_TYPE_FLOAT = 4,
+ CCDJIT_TYPE_DOUBLE = 5,
+ CCDJIT_TYPE_LONG = 6,
+ CCDJIT_TYPE_SHORT = 7,
+ CCDJIT_TYPE_STRUCT = 8,
+ CCDJIT_TYPE_ENUM = 9,
+ CCDJIT_TYPE_UNION = 10,
+ CCDJIT_TYPE_FLOAT128 = 11,
+} ccdjit_type_base;
+
+typedef struct {
+ int has_type;
+ int base;
+ int pointer_level;
+ int array_size;
+ int is_unsigned;
+ int is_complex;
+ int is_atomic;
+} ccdjit_type_info;
+
+typedef struct {
+ int kind;
+ int has_signature;
+ ccdjit_type_info type;
+ ccdjit_type_info return_type;
+ size_t parameter_count;
+ int is_variadic;
+ size_t size;
+} ccdjit_symbol_info;
+
+typedef struct {
+ int process;
+ int seccomp;
+ int landlock;
+} ccdjit_sandbox_capabilities;
+
+typedef struct {
+ const char *filename;
+ const char *function;
+ int line;
+ int column;
+ uintptr_t address;
+ size_t size;
+} ccdjit_debug_location;
+
+/*
+ * Create a compiler context. Passing NULL uses permissive CLI-like defaults.
+ * Invalid options return NULL; call ccdjit_context_last_error(NULL) for the
+ * thread-local creation diagnostic.
*/
ccdjit_context *ccdjit_context_new(const ccdjit_options *options);
+int ccdjit_version_major(void);
+int ccdjit_version_minor(void);
+int ccdjit_version_patch(void);
+const char *ccdjit_version_string(void);
+int ccdjit_api_abi_version(void);
+int ccdjit_binary_format_version(void);
+const char *ccdjit_git_commit(void);
+int ccdjit_sandbox_capabilities_query(ccdjit_sandbox_capabilities *out);
+
/* Free the context and all context-owned diagnostics/options/lists. */
void ccdjit_context_free(ccdjit_context *ctx);
@@ -239,6 +378,24 @@ int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx,
size_t output_limit_bytes, unsigned int macro_depth,
unsigned int include_depth);
+/* Select the compiler driver used by system include and builtin macro probes.
+ */
+int ccdjit_context_set_preprocessor_compiler(ccdjit_context *ctx,
+ const char *compiler);
+
+/* Update compiler-probe timeout/output limits. Passing zero keeps defaults. */
+int ccdjit_context_set_preprocessor_probe_limits(ccdjit_context *ctx,
+ unsigned int timeout_ms, size_t output_limit_bytes);
+
+/* Free this thread's cached compiler probe results and system include paths. */
+void ccdjit_preprocessor_free_probe_cache(void);
+
+/* Enable or disable executable memory for future compile/load/call paths. */
+int ccdjit_context_set_executable_memory(ccdjit_context *ctx, int allow);
+
+/* Enable or disable optional debug/source mapping metadata. */
+int ccdjit_context_set_debug_info(ccdjit_context *ctx, int enable);
+
/*
* Add a Landlock filesystem root for sandboxed execution.
*
@@ -249,13 +406,40 @@ int ccdjit_context_set_preprocessor_limits(ccdjit_context *ctx,
int ccdjit_context_add_sandbox_filesystem_root(ccdjit_context *ctx,
const char *path, int writable);
-/* Return the last error for this context. The pointer is context-owned. */
+/*
+ * Return the last error for this context. Passing NULL returns the
+ * thread-local diagnostic for context creation or NULL-context API failures.
+ * The pointer is context-owned or thread-local.
+ */
const ccdjit_diagnostic *ccdjit_context_last_error(ccdjit_context *ctx);
/* Return captured sandbox stdout/stderr from the last sandboxed main call. */
const char *ccdjit_context_last_stdout(ccdjit_context *ctx);
const char *ccdjit_context_last_stderr(ccdjit_context *ctx);
+/*
+ * Owned execution result snapshot for bindings and concurrent hosts.
+ *
+ * Result objects keep copies of the call status, integer result, diagnostic,
+ * captured stdout, and captured stderr. They are not invalidated by later
+ * calls on the same context.
+ */
+void ccdjit_execution_result_free(ccdjit_execution_result *result);
+int ccdjit_execution_result_status(const ccdjit_execution_result *result);
+int ccdjit_execution_result_has_value(const ccdjit_execution_result *result);
+int ccdjit_execution_result_value(const ccdjit_execution_result *result);
+const ccdjit_diagnostic *ccdjit_execution_result_diagnostic(
+ const ccdjit_execution_result *result);
+const char *ccdjit_execution_result_stdout(
+ const ccdjit_execution_result *result);
+const char *ccdjit_execution_result_stderr(
+ const ccdjit_execution_result *result);
+int ccdjit_execution_result_signal(const ccdjit_execution_result *result);
+int ccdjit_execution_result_has_fault_address(
+ const ccdjit_execution_result *result);
+uintptr_t ccdjit_execution_result_fault_address(
+ const ccdjit_execution_result *result);
+
/* Compile a source file into a live JIT module. */
int ccdjit_compile_file(ccdjit_context *ctx, const char *path,
ccdjit_module **out);
@@ -291,9 +475,75 @@ int ccdjit_eval_string(ccdjit_context *ctx, const char *source,
*/
void *ccdjit_module_symbol(ccdjit_module *module, const char *name);
+/*
+ * Inspect a module symbol without forcing the caller to cast blindly.
+ *
+ * JIT functions expose return type, parameter count, variadic flag, and
+ * per-parameter metadata through ccdjit_module_function_parameter_type().
+ * Object symbols expose their object type and size. Loaded CCDJITB2 binaries
+ * expose function/object kind and size but not full C signatures.
+ */
+int ccdjit_module_symbol_info(ccdjit_module *module, const char *name,
+ ccdjit_symbol_info *out);
+
+int ccdjit_module_function_parameter_type(ccdjit_module *module,
+ const char *name, size_t index, ccdjit_type_info *out);
+
+/*
+ * Return a callable function pointer only when the JIT signature exactly
+ * matches the expected return and parameter types.
+ */
+void *ccdjit_module_function_symbol_checked(ccdjit_module *module,
+ const char *name, const ccdjit_type_info *return_type,
+ const ccdjit_type_info *parameter_types, size_t parameter_count,
+ int allow_variadic);
+
+/* Map a live JIT instruction address to lightweight module-owned debug info. */
+int ccdjit_module_debug_location(ccdjit_module *module, const void *address,
+ ccdjit_debug_location *out);
+
/* Call module main(argc, argv). Honors CCDJIT_SANDBOX_PROCESS. */
int ccdjit_module_call_main(ccdjit_module *module, int argc, char **argv,
int *result_out);
+int ccdjit_module_call_main_result(ccdjit_module *module, int argc, char **argv,
+ ccdjit_execution_result **out);
+
+/*
+ * Call an exported JIT function with signature int name(int).
+ *
+ * Honors CCDJIT_SANDBOX_PROCESS like ccdjit_module_call_main(). Other
+ * signatures and binary modules are rejected with a diagnostic.
+ */
+int ccdjit_module_call_i32(ccdjit_module *module, const char *symbol, int arg,
+ int *result_out);
+int ccdjit_module_call_i32_result(ccdjit_module *module, const char *symbol,
+ int arg, ccdjit_execution_result **out);
+
+/*
+ * Compile and publish a named function behind a stable handle.
+ *
+ * The initial source and every replacement must define the same function
+ * signature. Calls through the handle do not expose raw function pointers, so
+ * replacements can wait for active callers and then free old generated code.
+ */
+int ccdjit_function_handle_new(ccdjit_context *ctx, const char *source,
+ const char *filename, const char *symbol, ccdjit_function_handle **out);
+
+/*
+ * Compile replacement source and atomically publish it on success.
+ *
+ * On compile failure or signature mismatch the old implementation remains
+ * active and the context diagnostic describes the failure.
+ */
+int ccdjit_function_handle_replace(ccdjit_function_handle *handle,
+ const char *source, const char *filename);
+
+/* Call a handle whose published function has signature int name(int). */
+int ccdjit_function_handle_call_i32(ccdjit_function_handle *handle, int arg,
+ int *result_out);
+
+/* Free a function handle and the currently published implementation. */
+void ccdjit_function_handle_free(ccdjit_function_handle *handle);
/* Emit textual assembly-like bytes for inspection. */
int ccdjit_module_emit_assembly(ccdjit_module *module, FILE *out);
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 { \
diff --git a/include/libccdjit.a b/include/libccdjit.a
index 3045696..d062f38 100644
--- a/include/libccdjit.a
+++ b/include/libccdjit.a
Binary files differ
diff --git a/include/libccdjit.so b/include/libccdjit.so
index 40456db..c3d9203 100755
--- a/include/libccdjit.so
+++ b/include/libccdjit.so
Binary files differ
diff --git a/include/plugin.h b/include/plugin.h
new file mode 100644
index 0000000..50aad33
--- /dev/null
+++ b/include/plugin.h
@@ -0,0 +1,110 @@
+#ifndef ECEX_PLUGIN_H
+#define ECEX_PLUGIN_H
+
+#include "types.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define ECEX_PLUGIN_API_VERSION 1
+#define ECEX_PLUGIN_EXPORT_READ 1
+
+typedef struct ecex_plugin ecex_plugin_t;
+typedef struct ecex_plugin_runtime ecex_plugin_runtime_t;
+
+typedef enum ecex_plugin_value_type {
+ ECEX_PLUGIN_BYTES = 0,
+ ECEX_PLUGIN_I32 = 1,
+ ECEX_PLUGIN_U32 = 2,
+ ECEX_PLUGIN_I64 = 3,
+ ECEX_PLUGIN_PTR = 4,
+} ecex_plugin_value_type_t;
+
+ecex_plugin_runtime_t *ecex_plugin_runtime_new(void);
+void ecex_plugin_runtime_free(ecex_plugin_runtime_t *runtime);
+
+ecex_plugin_t *ecex_plugin_register(ecex_t *ed, const char *id, int api_version);
+ecex_plugin_t *ecex_plugin_require(ecex_t *ed, const char *id, int api_version);
+ecex_plugin_t *ecex_plugin_find(ecex_t *ed, const char *id);
+const char *ecex_plugin_id(ecex_plugin_t *plugin);
+
+/* Plugin slots are named, plugin-private arrays unless explicitly exported. */
+void *ecex_plugin_slot_alloc(ecex_plugin_t *plugin,
+ const char *name,
+ size_t count,
+ size_t elem_size);
+void *ecex_plugin_slot_get(ecex_plugin_t *plugin, const char *name);
+int ecex_plugin_slot_free(ecex_plugin_t *plugin, const char *name);
+int ecex_plugin_slot_set_export_flags(ecex_plugin_t *plugin,
+ const char *name,
+ int type,
+ int flags);
+int 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);
+
+int ecex_plugin_slot_i32_get_scalar(ecex_plugin_t *plugin, const char *name, int fallback);
+int ecex_plugin_slot_i32_get(ecex_plugin_t *plugin,
+ const char *name,
+ size_t index,
+ int fallback);
+int ecex_plugin_slot_i32_set(ecex_plugin_t *plugin,
+ const char *name,
+ size_t index,
+ int value);
+int ecex_plugin_slot_i32_get_2d(ecex_plugin_t *plugin,
+ const char *name,
+ size_t width,
+ size_t x,
+ size_t y,
+ int fallback);
+int ecex_plugin_slot_i32_set_2d(ecex_plugin_t *plugin,
+ const char *name,
+ size_t width,
+ size_t x,
+ size_t y,
+ int value);
+int ecex_plugin_slot_i32_set_scalar(ecex_plugin_t *plugin,
+ const char *name,
+ int value);
+
+/* Plugin objects are tracked allocations intended for callback userdata. */
+void *ecex_plugin_object_alloc(ecex_plugin_t *plugin, const char *name, size_t size);
+void *ecex_plugin_object_calloc(ecex_plugin_t *plugin,
+ const char *name,
+ size_t count,
+ size_t size);
+int ecex_plugin_object_free(ecex_plugin_t *plugin, void *object);
+int ecex_plugin_object_valid(ecex_plugin_t *plugin, void *object);
+int ecex_plugin_object_i32_get(ecex_plugin_t *plugin,
+ void *object,
+ size_t byte_offset,
+ int fallback);
+int ecex_plugin_object_i32_set(ecex_plugin_t *plugin,
+ void *object,
+ size_t byte_offset,
+ int value);
+void *ecex_plugin_object_ptr_get(ecex_plugin_t *plugin,
+ void *object,
+ size_t byte_offset);
+int ecex_plugin_object_ptr_set(ecex_plugin_t *plugin,
+ void *object,
+ size_t byte_offset,
+ void *value);
+
+/* Plugin text stores host-owned strings for later draw-time lookup. */
+int ecex_plugin_text_set(ecex_plugin_t *plugin, int id, const char *text, int len);
+int ecex_plugin_text_set_from_buffer_title(ecex_plugin_t *plugin, int id, buffer_t *buffer);
+int ecex_plugin_text_free(ecex_plugin_t *plugin, int id);
+int ecex_plugin_text_free_all(ecex_plugin_t *plugin);
+const char *ecex_plugin_text_get_drawable(ecex_t *ed, void *owner, int id);
+
+int ecex_plugin_file_handler_register(ecex_plugin_t *plugin,
+ const char *extension,
+ ecex_file_handler_fn fn);
+int ecex_plugin_file_handlers_run(ecex_t *ed, buffer_t *buffer);
+
+#endif
diff --git a/include/types.h b/include/types.h
index 800c3d6..2b63ad3 100644
--- a/include/types.h
+++ b/include/types.h
@@ -7,6 +7,7 @@ typedef struct ecex ecex_t;
typedef struct buffer buffer_t;
typedef struct ecex_window ecex_window_t;
typedef struct ecex_draw_context ecex_draw_context_t;
+typedef struct ecex_plugin_runtime ecex_plugin_runtime_t;
typedef int (*ecex_command_fn)(ecex_t *ed);
typedef int (*ecex_interactive_line_fn)(ecex_t *ed, buffer_t *buffer, size_t line, const char *payload, void *userdata);
@@ -18,6 +19,37 @@ typedef int (*ecex_buffer_tick_ms_fn)(ecex_t *ed, buffer_t *buffer, int now_ms,
typedef int (*ecex_buffer_mouse_fn)(ecex_t *ed, buffer_t *buffer, int event, int x, int y, int button, void *userdata);
typedef int (*ecex_file_handler_fn)(ecex_t *ed, buffer_t *buffer);
typedef void (*ecex_buffer_userdata_free_fn)(void *userdata);
+typedef void (*ecex_hook_free_fn)(void *userdata);
+typedef void (*ecex_command_hook_fn)(ecex_t *ed, const char *command, int event, int result, void *userdata);
+typedef void (*ecex_prefix_hook_fn)(ecex_t *ed, const char *prefix, int event, void *userdata);
+typedef void (*ecex_buffer_hook_fn)(ecex_t *ed, buffer_t *buffer, int event, void *userdata);
+typedef int (*ecex_completion_provider_fn)(ecex_t *ed,
+ buffer_t *buffer,
+ const char *prefix,
+ char *out,
+ size_t out_size,
+ void *userdata);
+
+typedef enum ecex_command_hook_event {
+ ECEX_COMMAND_HOOK_BEFORE = 1,
+ ECEX_COMMAND_HOOK_AFTER = 2,
+} ecex_command_hook_event_t;
+
+typedef enum ecex_prefix_hook_event {
+ ECEX_PREFIX_HOOK_BEGIN = 1,
+ ECEX_PREFIX_HOOK_UPDATE = 2,
+ ECEX_PREFIX_HOOK_CANCEL = 3,
+ ECEX_PREFIX_HOOK_FINISH = 4,
+ ECEX_PREFIX_HOOK_UNDEFINED = 5,
+} ecex_prefix_hook_event_t;
+
+typedef enum ecex_buffer_hook_event {
+ ECEX_BUFFER_HOOK_CREATE = 1,
+ ECEX_BUFFER_HOOK_SWITCH = 2,
+ ECEX_BUFFER_HOOK_SAVE = 3,
+ ECEX_BUFFER_HOOK_KILL = 4,
+ ECEX_BUFFER_HOOK_MODE_CHANGE = 5,
+} ecex_buffer_hook_event_t;
typedef enum ecex_prompt_request {
ECEX_PROMPT_NONE = 0,
@@ -154,6 +186,7 @@ struct buffer {
void *media_pipe;
double media_last_frame_time;
int media_playing;
+ int media_audio_pid;
char media_status[256];
ecex_buffer_render_fn render_fn;
@@ -198,42 +231,43 @@ typedef struct ecex_mode_keybind {
char *command;
} ecex_mode_keybind_t;
-typedef struct ecex_major_mode {
- int id;
+typedef struct ecex_command_hook {
char *name;
-} ecex_major_mode_t;
+ ecex_command_hook_fn fn;
+ void *userdata;
+ ecex_hook_free_fn free_fn;
+} ecex_command_hook_t;
-typedef enum ecex_var_kind {
- ECEX_VAR_BYTES = 0,
- ECEX_VAR_I32 = 1,
-} ecex_var_kind_t;
+typedef struct ecex_prefix_hook {
+ char *name;
+ ecex_prefix_hook_fn fn;
+ void *userdata;
+ ecex_hook_free_fn free_fn;
+} ecex_prefix_hook_t;
-typedef struct ecex_var_entry {
- void *owner;
+typedef struct ecex_buffer_hook {
char *name;
- void *data;
- size_t elem_size;
- size_t count;
- int kind;
- int dynamic;
-} ecex_var_entry_t;
-
-typedef struct ecex_text_entry {
- void *owner;
- int id;
- char *text;
- size_t len;
-} ecex_text_entry_t;
+ ecex_buffer_hook_fn fn;
+ void *userdata;
+ ecex_hook_free_fn free_fn;
+} ecex_buffer_hook_t;
-typedef struct ecex_file_handler {
- char *extension;
- ecex_file_handler_fn fn;
-} ecex_file_handler_t;
+typedef struct ecex_completion_provider {
+ char *name;
+ int mode;
+ ecex_completion_provider_fn fn;
+ void *userdata;
+ ecex_hook_free_fn free_fn;
+ char *detail;
+ char **words;
+ size_t word_count;
+ int flags;
+} ecex_completion_provider_t;
-typedef struct ecex_object_entry {
- void *ptr;
- size_t size;
-} ecex_object_entry_t;
+typedef struct ecex_major_mode {
+ int id;
+ char *name;
+} ecex_major_mode_t;
struct ecex_window {
buffer_t *buffer;
@@ -273,26 +307,34 @@ struct ecex {
size_t mode_keybind_cap;
size_t mode_keybind_count;
+ ecex_command_hook_t *command_hooks;
+ size_t command_hook_cap;
+ size_t command_hook_count;
+
+ ecex_prefix_hook_t *prefix_hooks;
+ size_t prefix_hook_cap;
+ size_t prefix_hook_count;
+
+ ecex_buffer_hook_t *buffer_hooks;
+ size_t buffer_hook_cap;
+ size_t buffer_hook_count;
+
+ ecex_completion_provider_t *completion_providers;
+ size_t completion_provider_cap;
+ size_t completion_provider_count;
+ int completion_cycle_active;
+ buffer_t *completion_cycle_buffer;
+ size_t completion_cycle_start;
+ size_t completion_cycle_index;
+ char completion_cycle_prefix[256];
+ char completion_cycle_current[256];
+
ecex_major_mode_t *major_modes;
size_t major_mode_cap;
size_t major_mode_count;
int next_major_mode_id;
- ecex_var_entry_t *vars;
- size_t var_cap;
- size_t var_count;
-
- ecex_text_entry_t *texts;
- size_t text_cap;
- size_t text_count;
-
- ecex_file_handler_t *file_handlers;
- size_t file_handler_cap;
- size_t file_handler_count;
-
- ecex_object_entry_t *objects;
- size_t object_cap;
- size_t object_count;
+ ecex_plugin_runtime_t *plugins;
char *last_eval_source;
char *last_eval_filename;
@@ -305,13 +347,19 @@ struct ecex {
char prompt_message[128];
char *config_path;
+ char message[1024];
+ unsigned long message_revision;
ecex_clipboard_get_fn clipboard_get;
ecex_clipboard_set_fn clipboard_set;
void *clipboard_userdata;
+ char *clipboard_text;
int should_quit;
+ unsigned long ui_revision;
+ unsigned long font_revision;
+
ecex_theme_t theme;
};