summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlbert Cervin <albert@acervin.com>2024-04-03 11:43:49 +0200
committerAlbert Cervin <albert@acervin.com>2024-04-03 11:43:49 +0200
commit1ed6000dd2a995bcd67e99b1c89aa1e2c4a6f1e6 (patch)
treedff73302ddb932b1355df8cff4fcb2557a748a8e /src
parent80e6ab5ec9fdb0f4a3b3fa35e4ea502a54b85e1a (diff)
downloaddged-1ed6000dd2a995bcd67e99b1c89aa1e2c4a6f1e6.tar.gz
dged-1ed6000dd2a995bcd67e99b1c89aa1e2c4a6f1e6.tar.xz
dged-1ed6000dd2a995bcd67e99b1c89aa1e2c4a6f1e6.zip
Add completion to execute
Completes on the command, not on following arguments if written directly at the prompt.
Diffstat (limited to 'src')
-rw-r--r--src/dged/command.c8
-rw-r--r--src/dged/command.h4
-rw-r--r--src/main/cmds.c12
-rw-r--r--src/main/completion.c84
-rw-r--r--src/main/completion.h4
-rw-r--r--src/main/main.c2
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;