commit f832146f20005c6ba56fff2d9271c716319a4cc6 from: Omar Polo date: Tue Mar 09 09:12:56 2021 UTC added an implementation of keymaps and added a bunch of keys, like C-x C-c to quit etc commit - 4d3785b1daec2139c584305f088d4eedce580920 commit + f832146f20005c6ba56fff2d9271c716319a4cc6 blob - 1a96ed6f7968f22cf4440e7204dc8b8617a67c33 blob + f7aa5c7218eb0be9887734be51bcdae32687792f --- ui.c +++ ui.c @@ -58,6 +58,7 @@ #include +#include #include #include #include @@ -65,16 +66,20 @@ #include #include #include +#include #define TAB_CURRENT 0x1 #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) -struct key; +struct kmap; static struct event stdioev, winchev; +static int kbd(const char*); +static void kmap_define_key(struct kmap*, const char*, void(*)(struct tab*)); +static void load_default_keys(void); static int push_line(struct tab*, const struct line*, const char*, size_t); static void empty_vlist(struct tab*); static void restore_cursor(struct tab *); @@ -87,7 +92,6 @@ static void cmd_scroll_down(struct tab*); static void cmd_scroll_up(struct tab*); static void cmd_kill_telescope(struct tab*); static void cmd_push_button(struct tab*); -static void cmd_unbound(struct key); static struct line *nth_line(struct tab*, size_t); static struct tab *current_tab(void); static void dispatch_stdio(int, short, void*); @@ -108,8 +112,6 @@ static void stop_loading_anim(struct tab*); static void load_url_in_tab(struct tab*, const char*); static void new_tab(void); -typedef void (*interactivefn)(struct tab*); - static WINDOW *tabline, *body, *modeline, *minibuf; static int body_lines, body_cols; @@ -133,39 +135,147 @@ struct ui_state { TAILQ_HEAD(, line) head; }; -struct key { - int meta; - int key; +#define CTRL(n) ((n)&0x1F) + +static TAILQ_HEAD(kmap, keymap) global_map, *current_map; +struct keymap { + int meta; + int key; + struct kmap map; + void (*fn)(struct tab*); + + TAILQ_ENTRY(keymap) keymaps; }; -#define KEY(n) ((struct key){0, n}) -#define CKEY(n) ((struct key){0, (n) & 0x1F}) -#define MKEY(n) ((struct key){1, n}) -#define CMKEY(n) ((struct key){1, (n) & 0x1F}) +static int +kbd(const char *key) +{ + struct table { + char *p; + int k; + } table[] = { + { "", KEY_UP }, + { "", KEY_DOWN }, + { "", KEY_LEFT }, + { "", KEY_RIGHT }, + /* ... */ + { "space", ' ' }, + { "spc", ' ' }, + { "enter", CTRL('m') }, + { "tab", CTRL('i') }, + /* ... */ + { NULL, 0 }, + }, *t; -struct binding { - struct key key; - interactivefn fn; -} bindings[] = { - { CKEY('p'), cmd_previous_line, }, - { CKEY('n'), cmd_next_line, }, - { CKEY('f'), cmd_forward_char, }, - { CKEY('b'), cmd_backward_char, }, + for (t = table; t->p != NULL; ++t) { + if (has_prefix(key, t->p)) + return t->k; + } - { {0,KEY_UP}, cmd_previous_line, }, - { {0,KEY_DOWN}, cmd_next_line, }, + return *key; +} - { CKEY('L'), cmd_redraw, }, +static void +kmap_define_key(struct kmap *map, const char *key, void (*fn)(struct tab*)) +{ + int ctrl, meta, k; + struct keymap *entry; - { KEY('J'), cmd_scroll_down, }, - { KEY('K'), cmd_scroll_up, }, +again: + if ((ctrl = has_prefix(key, "C-"))) + key += 2; + if ((meta = has_prefix(key, "M-"))) + key += 2; + if (*key == '\0') + _exit(1); + k = kbd(key); - { KEY('q'), cmd_kill_telescope, }, - { CKEY('m'), cmd_push_button, }, + if (ctrl) + k = CTRL(k); - { {0, 0}, NULL, }, -}; + /* skip key & spaces */ + while (*key != '\0' && !isspace(*key)) + ++key; + while (*key != '\0' && isspace(*key)) + ++key; + TAILQ_FOREACH(entry, map, keymaps) { + if (entry->meta == meta && entry->key == k) { + if (*key == '\0') { + entry->fn = fn; + return; + } + map = &entry->map; + goto again; + } + } + + if ((entry = calloc(1, sizeof(*entry))) == NULL) + abort(); + + entry->meta = meta; + entry->key = k; + TAILQ_INIT(&entry->map); + + if (TAILQ_EMPTY(map)) + TAILQ_INSERT_HEAD(map, entry, keymaps); + else + TAILQ_INSERT_TAIL(map, entry, keymaps); + + if (*key != '\0') { + map = &entry->map; + goto again; + } + + entry->fn = fn; +} + +static inline void +global_set_key(const char *key, void (*fn)(struct tab*)) +{ + kmap_define_key(&global_map, key, fn); +} + +static void +load_default_keys(void) +{ + /* emacs */ + global_set_key("C-p", cmd_previous_line); + global_set_key("C-n", cmd_next_line); + global_set_key("C-f", cmd_forward_char); + global_set_key("C-b", cmd_backward_char); + + /* tmp */ + global_set_key("M-v", cmd_scroll_up); + global_set_key("C-v", cmd_scroll_down); + + global_set_key("C-x C-c", cmd_kill_telescope); + + /* vi/vi-like */ + global_set_key("k", cmd_previous_line); + global_set_key("j", cmd_next_line); + global_set_key("l", cmd_forward_char); + global_set_key("h", cmd_backward_char); + + global_set_key("K", cmd_scroll_up); + global_set_key("J", cmd_scroll_down); + + /* tmp */ + global_set_key("q", cmd_kill_telescope); + + /* cua */ + global_set_key("", cmd_previous_line); + global_set_key("", cmd_next_line); + global_set_key("", cmd_forward_char); + global_set_key("", cmd_backward_char); + + /* "ncurses standard" */ + global_set_key("C-l", cmd_redraw); + + /* global */ + global_set_key("C-m", cmd_push_button); +} + static int push_line(struct tab *tab, const struct line *l, const char *buf, size_t len) { @@ -312,14 +422,6 @@ cmd_push_button(struct tab *tab) load_url_in_tab(tab, l->alt); } -static void -cmd_unbound(struct key k) -{ - message("%s%c is undefined", - k.meta ? "M-" : "", - k.key); -} - static struct line * nth_line(struct tab *tab, size_t n) { @@ -354,40 +456,39 @@ current_tab(void) static void dispatch_stdio(int fd, short ev, void *d) { - struct binding *b; - struct key key; - int k, j; + struct keymap *k; + int meta, key; - k = wgetch(body); - - if (k == ERR) + key = wgetch(body); + if (key == ERR) return; + if (key == 27) { + /* TODO: make escape-time customizable */ - /* look for a M-key */ - if (k == 27) { - wtimeout(body, 0); /* TODO: make escape-time customizable */ - j = wgetch(body); - if (j != ERR) { - k = j; - key.meta = 1; - } else { - key.meta = 0; - } + meta = 1; + key = wgetch(body); + if (key == ERR) + key = 27; } else - key.meta = 0; + meta = 0; - key.key = k; - - for (b = bindings; b->fn != NULL; ++b) { - if (key.meta == b->key.meta && - key.key == b->key.key) { - b->fn(current_tab()); + TAILQ_FOREACH(k, current_map, keymaps) { + if (k->meta == meta && k->key == key) { + if (k->fn == NULL) + current_map = &k->map; + else { + current_map = &global_map; + k->fn(current_tab()); + } goto done; } } - cmd_unbound(key); + current_map = &global_map; + message("%s%c is undefined", + meta ? "M-" : "", key); + done: restore_cursor(current_tab()); wrefresh(tabline); @@ -829,6 +930,10 @@ ui_init(void) { setlocale(LC_ALL, ""); + TAILQ_INIT(&global_map); + current_map = &global_map; + load_default_keys(); + initscr(); raw(); noecho();