diff options
| -rw-r--r-- | src/dged/command.c | 8 | ||||
| -rw-r--r-- | src/dged/command.h | 4 | ||||
| -rw-r--r-- | src/main/cmds.c | 12 | ||||
| -rw-r--r-- | src/main/completion.c | 84 | ||||
| -rw-r--r-- | src/main/completion.h | 4 | ||||
| -rw-r--r-- | src/main/main.c | 2 |
6 files changed, 108 insertions, 6 deletions
diff --git a/src/dged/command.c b/src/dged/command.c index 9144058..2775286 100644 --- a/src/dged/command.c +++ b/src/dged/command.c @@ -63,6 +63,14 @@ int32_t execute_command(struct command *command, struct commands *commands, argc, argv); } +void commands_for_each(struct commands *commands, + void (*callback)(struct command *, void *), + void *userdata) { + HASHMAP_FOR_EACH(&commands->commands, struct command_entry * entry) { + callback(&entry->value, userdata); + } +} + void command_ctx_push_arg(struct command_ctx *ctx, const char *argv) { if (ctx->saved_argc < 64) { ctx->saved_argv[ctx->saved_argc] = strdup(argv); diff --git a/src/dged/command.h b/src/dged/command.h index 956c10a..2b0f074 100644 --- a/src/dged/command.h +++ b/src/dged/command.h @@ -183,6 +183,10 @@ struct command *lookup_command(struct commands *commands, const char *name); struct command *lookup_command_by_hash(struct commands *commands, uint32_t hash); +void commands_for_each(struct commands *commands, + void (*callback)(struct command *, void *), + void *userdata); + void command_ctx_push_arg(struct command_ctx *ctx, const char *argv); void command_ctx_free(struct command_ctx *ctx); diff --git a/src/main/cmds.c b/src/main/cmds.c index d28924b..4dc84ed 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -54,11 +54,23 @@ int32_t write_file(struct command_ctx ctx, int argc, const char *argv[]) { return 0; } +static void run_interactive_comp_inserted() { minibuffer_execute(); } + int32_t run_interactive(struct command_ctx ctx, int argc, const char *argv[]) { if (argc == 0) { + struct completion_provider providers[] = {commands_provider()}; + enable_completion(minibuffer_buffer(), + ((struct completion_trigger){ + .kind = CompletionTrigger_Input, + .input = + (struct completion_trigger_input){ + .nchars = 0, .trigger_initially = false}}), + providers, 1, run_interactive_comp_inserted); + return minibuffer_prompt(ctx, "execute: "); } + disable_completion(minibuffer_buffer()); struct command *cmd = lookup_command(ctx.commands, argv[0]); if (cmd != NULL) { return execute_command(cmd, ctx.commands, ctx.active_window, ctx.buffers, diff --git a/src/main/completion.c b/src/main/completion.c index 4735c87..b2170e7 100644 --- a/src/main/completion.c +++ b/src/main/completion.c @@ -54,6 +54,14 @@ static struct completion_provider g_buffer_provider = { .userdata = NULL, }; +static uint32_t complete_commands(struct completion_context ctx, + void *userdata); +static struct completion_provider g_commands_provider = { + .name = "commands", + .complete = complete_commands, + .userdata = NULL, +}; + struct completion_provider path_provider() { return g_path_provider; } @@ -62,6 +70,10 @@ struct completion_provider buffer_provider() { return g_buffer_provider; } +struct completion_provider commands_provider() { + return g_commands_provider; +} + struct active_completion { struct buffer *buffer; uint32_t insert_hook_id; @@ -267,13 +279,14 @@ static void update_completion_buffer(struct buffer *buffer, void *userdata) { }}); } -void init_completion(struct buffers *buffers) { +void init_completion(struct buffers *buffers, struct commands *commands) { if (g_target_buffer == NULL) { g_target_buffer = buffers_add(buffers, buffer_create("*completions*")); buffer_add_update_hook(g_target_buffer, update_completion_buffer, NULL); } g_buffer_provider.userdata = buffers; + g_commands_provider.userdata = commands; VEC_INIT(&g_active_completions, 32); } @@ -511,7 +524,7 @@ done: return n; } -struct buffer_match_ctx { +struct needle_match_ctx { const char *needle; struct completion *completions; uint32_t max_ncompletions; @@ -519,7 +532,7 @@ struct buffer_match_ctx { }; static void buffer_matches(struct buffer *buffer, void *userdata) { - struct buffer_match_ctx *ctx = (struct buffer_match_ctx *)userdata; + struct needle_match_ctx *ctx = (struct needle_match_ctx *)userdata; if (strncmp(ctx->needle, buffer->name, strlen(ctx->needle)) == 0 && ctx->ncompletions < ctx->max_ncompletions) { @@ -568,7 +581,7 @@ static uint32_t complete_buffers(struct completion_context ctx, free(txt.text); } - struct buffer_match_ctx match_ctx = (struct buffer_match_ctx){ + struct needle_match_ctx match_ctx = (struct needle_match_ctx){ .needle = needle, .max_ncompletions = ctx.max_ncompletions, .completions = ctx.completions, @@ -579,3 +592,66 @@ static uint32_t complete_buffers(struct completion_context ctx, free(needle); return match_ctx.ncompletions; } + +static void command_matches(struct command *command, void *userdata) { + struct needle_match_ctx *ctx = (struct needle_match_ctx *)userdata; + + if (strncmp(ctx->needle, command->name, strlen(ctx->needle)) == 0 && + ctx->ncompletions < ctx->max_ncompletions) { + ctx->completions[ctx->ncompletions] = (struct completion){ + .display = strdup(command->name), + .insert = strdup(command->name + strlen(ctx->needle)), + .complete = true, + }; + ++ctx->ncompletions; + } +} + +static uint32_t complete_commands(struct completion_context ctx, + void *userdata) { + + struct commands *commands = (struct commands *)userdata; + if (commands == NULL) { + return 0; + } + + struct text_chunk txt = {0}; + uint32_t start_idx = 0; + if (ctx.buffer == minibuffer_buffer()) { + txt = minibuffer_content(); + } else { + txt = buffer_line(ctx.buffer, ctx.location.line); + uint32_t end_idx = text_col_to_byteindex( + ctx.buffer->text, ctx.location.line, ctx.location.col); + for (uint32_t bytei = end_idx; bytei > 0; --bytei) { + if (txt.text[bytei] == ' ') { + start_idx = bytei + 1; + break; + } + } + + if (start_idx >= end_idx) { + return 0; + } + + txt.nbytes = end_idx - start_idx; + } + + char *needle = calloc(txt.nbytes + 1, sizeof(uint8_t)); + memcpy(needle, txt.text + start_idx, txt.nbytes); + + if (txt.allocated) { + free(txt.text); + } + + struct needle_match_ctx match_ctx = (struct needle_match_ctx){ + .needle = needle, + .max_ncompletions = ctx.max_ncompletions, + .completions = ctx.completions, + .ncompletions = 0, + }; + commands_for_each(commands, command_matches, &match_ctx); + + free(needle); + return match_ctx.ncompletions; +} diff --git a/src/main/completion.h b/src/main/completion.h index b53c942..776ef9b 100644 --- a/src/main/completion.h +++ b/src/main/completion.h @@ -5,6 +5,7 @@ struct buffer; struct buffers; +struct commands; struct completion { const char *display; @@ -46,7 +47,7 @@ struct completion_trigger { }; }; -void init_completion(struct buffers *buffers); +void init_completion(struct buffers *buffers, struct commands *commands); void destroy_completion(); typedef void (*insert_cb)(); @@ -65,6 +66,7 @@ void enable_completion(struct buffer *source, struct completion_trigger trigger, struct completion_provider path_provider(); struct completion_provider buffer_provider(); +struct completion_provider commands_provider(); /** * Abort any active completion. diff --git a/src/main/main.c b/src/main/main.c index 6048b63..a020b9f 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -310,7 +310,7 @@ int main(int argc, char *argv[]) { struct keymap *current_keymap = NULL; init_bindings(); - init_completion(&buflist); + init_completion(&buflist, &commands); timers_init(); float frame_time = 0.f; |
