summaryrefslogtreecommitdiff
path: root/src/main/bindings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/bindings.c')
-rw-r--r--src/main/bindings.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/main/bindings.c b/src/main/bindings.c
new file mode 100644
index 0000000..10436d6
--- /dev/null
+++ b/src/main/bindings.c
@@ -0,0 +1,207 @@
+#include "dged/binding.h"
+#include "dged/buffer.h"
+#include "dged/minibuffer.h"
+#include "dged/vec.h"
+
+static struct keymap g_global_keymap, g_ctrlx_map, g_windows_keymap,
+ g_buffer_default_keymap;
+
+struct buffer_keymap {
+ struct buffer *buffer;
+ bool active;
+ struct keymap keymap;
+};
+
+static VEC(struct buffer_keymap) g_buffer_keymaps;
+
+void set_default_buffer_bindings(struct keymap *keymap) {
+ struct binding buffer_bindings[] = {
+ BINDING(Ctrl, 'B', "backward-char"),
+ BINDING(LEFT, "backward-char"),
+ BINDING(Ctrl, 'F', "forward-char"),
+ BINDING(RIGHT, "forward-char"),
+
+ BINDING(Ctrl, 'P', "backward-line"),
+ BINDING(UP, "backward-line"),
+ BINDING(Ctrl, 'N', "forward-line"),
+ BINDING(DOWN, "forward-line"),
+
+ BINDING(Meta, 'f', "forward-word"),
+ BINDING(Meta, 'b', "backward-word"),
+
+ BINDING(Ctrl, 'A', "beginning-of-line"),
+ BINDING(Ctrl, 'E', "end-of-line"),
+
+ BINDING(Ctrl, 'S', "find-next"),
+ BINDING(Ctrl, 'R', "find-prev"),
+
+ BINDING(Meta, '<', "goto-beginning"),
+ BINDING(Meta, '>', "goto-end"),
+
+ BINDING(Ctrl, 'V', "scroll-down"),
+ BINDING(Meta, 'v', "scroll-up"),
+
+ BINDING(ENTER, "newline"),
+ BINDING(TAB, "indent"),
+
+ BINDING(Ctrl, 'K', "kill-line"),
+ BINDING(DELETE, "delete-char"),
+ BINDING(Ctrl, 'D', "delete-char"),
+ BINDING(BACKSPACE, "backward-delete-char"),
+
+ BINDING(Ctrl, '@', "set-mark"),
+
+ BINDING(Ctrl, 'W', "cut"),
+ BINDING(Ctrl, 'Y', "paste"),
+ BINDING(Meta, 'y', "paste-older"),
+ BINDING(Meta, 'w', "copy"),
+
+ BINDING(Ctrl, '_', "undo"),
+ };
+
+ keymap_bind_keys(keymap, buffer_bindings,
+ sizeof(buffer_bindings) / sizeof(buffer_bindings[0]));
+}
+
+struct keymap *register_bindings() {
+ g_global_keymap = keymap_create("global", 32);
+ g_ctrlx_map = keymap_create("c-x", 32);
+ g_windows_keymap = keymap_create("c-x w", 32);
+
+ struct binding global_binds[] = {
+ PREFIX(Ctrl, 'X', &g_ctrlx_map),
+ BINDING(Ctrl, 'G', "abort"),
+ BINDING(Meta, 'x', "run-command-interactive"),
+ };
+
+ struct binding ctrlx_bindings[] = {
+ BINDING(Ctrl, 'C', "exit"),
+ BINDING(Ctrl, 'S', "buffer-write-to-file"),
+ BINDING(Ctrl, 'F', "find-file"),
+ BINDING(Ctrl, 'W', "write-file"),
+ BINDING(None, 'b', "switch-buffer"),
+
+ BINDING(None, '0', "window-close"),
+ BINDING(None, '1', "window-close-others"),
+ BINDING(None, '2', "window-split-horizontal"),
+ BINDING(None, '3', "window-split-vertical"),
+ BINDING(None, 'o', "window-focus-next"),
+
+ PREFIX(None, 'w', &g_windows_keymap),
+ };
+
+ // windows
+ struct binding window_subbinds[] = {
+ BINDING(None, '0', "window-focus-0"),
+ BINDING(None, '1', "window-focus-1"),
+ BINDING(None, '2', "window-focus-2"),
+ BINDING(None, '3', "window-focus-3"),
+ BINDING(None, '4', "window-focus-4"),
+ BINDING(None, '5', "window-focus-5"),
+ BINDING(None, '6', "window-focus-6"),
+ BINDING(None, '7', "window-focus-7"),
+ BINDING(None, '8', "window-focus-8"),
+ BINDING(None, '9', "window-focus-9"),
+ };
+
+ // buffers
+ g_buffer_default_keymap = keymap_create("buffer-default", 128);
+ set_default_buffer_bindings(&g_buffer_default_keymap);
+
+ keymap_bind_keys(&g_windows_keymap, window_subbinds,
+ sizeof(window_subbinds) / sizeof(window_subbinds[0]));
+ keymap_bind_keys(&g_global_keymap, global_binds,
+ sizeof(global_binds) / sizeof(global_binds[0]));
+ keymap_bind_keys(&g_ctrlx_map, ctrlx_bindings,
+ sizeof(ctrlx_bindings) / sizeof(ctrlx_bindings[0]));
+
+ VEC_INIT(&g_buffer_keymaps, 32);
+
+ return &g_global_keymap;
+}
+
+struct keymap *buffer_default_bindings() {
+ return &g_buffer_default_keymap;
+}
+
+int32_t execute(struct command_ctx ctx, int argc, const char *argv[]) {
+ // TODO: this should be more lib-like
+ return minibuffer_execute();
+}
+
+static struct command execute_minibuffer_command = {
+ .fn = execute,
+ .name = "minibuffer-execute",
+ .userdata = NULL,
+};
+
+void buffer_bind_keys(struct buffer *buffer, struct binding *bindings,
+ uint32_t nbindings) {
+ struct buffer_keymap *target = NULL;
+ VEC_FOR_EACH(&g_buffer_keymaps, struct buffer_keymap * km) {
+ if (buffer == km->buffer) {
+ target = km;
+ }
+ }
+
+ if (target == NULL) {
+ struct buffer_keymap new = (struct buffer_keymap){
+ .buffer = buffer,
+ .active = false,
+ };
+ VEC_PUSH(&g_buffer_keymaps, new);
+ target = VEC_BACK(&g_buffer_keymaps);
+ }
+
+ if (!target->active) {
+ target->keymap = keymap_create("buffer-overlay-keys", 32);
+ target->active = true;
+ set_default_buffer_bindings(&target->keymap);
+ }
+
+ keymap_bind_keys(&target->keymap, bindings, nbindings);
+}
+
+// TODO: do something better
+void reset_buffer_keys(struct buffer *buffer) {
+ VEC_FOR_EACH(&g_buffer_keymaps, struct buffer_keymap * km) {
+ if (buffer == km->buffer) {
+ keymap_destroy(&km->keymap);
+ km->active = false;
+ }
+ }
+}
+
+struct keymap *buffer_keymap(struct buffer *buffer) {
+ VEC_FOR_EACH(&g_buffer_keymaps, struct buffer_keymap * km) {
+ if (buffer == km->buffer && km->active) {
+ return &km->keymap;
+ }
+ }
+
+ return &g_buffer_default_keymap;
+}
+
+void reset_minibuffer_keys(struct buffer *minibuffer) {
+ reset_buffer_keys(minibuffer);
+ struct binding bindings[] = {
+ ANONYMOUS_BINDING(ENTER, &execute_minibuffer_command),
+ };
+
+ buffer_bind_keys(minibuffer, bindings,
+ sizeof(bindings) / sizeof(bindings[0]));
+}
+
+void destroy_keymaps() {
+ keymap_destroy(&g_windows_keymap);
+ keymap_destroy(&g_global_keymap);
+ keymap_destroy(&g_ctrlx_map);
+ keymap_destroy(&g_buffer_default_keymap);
+
+ VEC_FOR_EACH(&g_buffer_keymaps, struct buffer_keymap * km) {
+ if (km->active) {
+ keymap_destroy(&km->keymap);
+ km->active = false;
+ }
+ }
+}