diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/binding.c | 19 | ||||
| -rw-r--r-- | src/binding.h | 21 | ||||
| -rw-r--r-- | src/buffer.c | 37 | ||||
| -rw-r--r-- | src/buffer.h | 13 | ||||
| -rw-r--r-- | src/buffers.c | 42 | ||||
| -rw-r--r-- | src/buffers.h | 17 | ||||
| -rw-r--r-- | src/command.c | 68 | ||||
| -rw-r--r-- | src/command.h | 15 | ||||
| -rw-r--r-- | src/keyboard.c | 18 | ||||
| -rw-r--r-- | src/keyboard.h | 11 | ||||
| -rw-r--r-- | src/main.c | 109 | ||||
| -rw-r--r-- | src/minibuffer.c | 100 | ||||
| -rw-r--r-- | src/minibuffer.h | 7 | ||||
| -rw-r--r-- | src/window.c | 9 | ||||
| -rw-r--r-- | src/window.h | 15 |
15 files changed, 388 insertions, 113 deletions
diff --git a/src/binding.c b/src/binding.c index 5147c97..a0946ee 100644 --- a/src/binding.c +++ b/src/binding.c @@ -36,26 +36,37 @@ void keymap_destroy(struct keymap *keymap) { struct lookup_result lookup_key(struct keymap *keymaps, uint32_t nkeymaps, struct key *key, struct commands *commands) { - // lookup in order in the keymaps - for (uint32_t kmi = 0; kmi < nkeymaps; ++kmi) { + // lookup in reverse order in the keymaps + uint32_t kmi = nkeymaps; + while (kmi > 0) { + --kmi; struct keymap *keymap = &keymaps[kmi]; for (uint32_t bi = 0; bi < keymap->nbindings; ++bi) { struct binding *binding = &keymap->bindings[bi]; if (key_equal(key, &binding->key)) { - if (binding->type == BindingType_Command) { + switch (binding->type) { + case BindingType_Command: { return (struct lookup_result){ .found = true, .type = BindingType_Command, .command = lookup_command_by_hash(commands, binding->command), }; - } else if (binding->type == BindingType_Keymap) { + } + case BindingType_Keymap: { return (struct lookup_result){ .found = true, .type = BindingType_Keymap, .keymap = binding->keymap, }; } + case BindingType_DirectCommand: + return (struct lookup_result){ + .found = true, + .type = BindingType_Command, + .command = binding->direct_command, + }; + } } } } diff --git a/src/binding.h b/src/binding.h index bfde9fc..18a7278 100644 --- a/src/binding.h +++ b/src/binding.h @@ -7,20 +7,34 @@ struct keymap { uint32_t capacity; }; -enum binding_type { BindingType_Command, BindingType_Keymap }; +enum binding_type { + BindingType_Command, + BindingType_Keymap, + BindingType_DirectCommand +}; -#define BINDING(mod_, c_, command_) \ +#define BINDING_INNER(mod_, c_, command_) \ (struct binding) { \ .key = {.mod = mod_, .key = c_}, .type = BindingType_Command, \ .command = hash_command_name(command_) \ } -#define PREFIX(mod_, c_, keymap_) \ +#define ANONYMOUS_BINDING_INNER(mod_, c_, command_) \ + (struct binding) { \ + .key = {.mod = mod_, .key = c_}, .type = BindingType_DirectCommand, \ + .direct_command = command_ \ + } + +#define PREFIX_INNER(mod_, c_, keymap_) \ (struct binding) { \ .key = {.mod = mod_, .key = c_}, .type = BindingType_Keymap, \ .keymap = keymap_ \ } +#define BINDING(...) BINDING_INNER(__VA_ARGS__) +#define PREFIX(...) PREFIX_INNER(__VA_ARGS__) +#define ANONYMOUS_BINDING(...) ANONYMOUS_BINDING_INNER(__VA_ARGS__) + struct binding { struct key key; @@ -28,6 +42,7 @@ struct binding { union { uint32_t command; + struct command *direct_command; struct keymap *keymap; }; }; diff --git a/src/buffer.c b/src/buffer.c index 5cf1cb8..c3d2925 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -6,6 +6,7 @@ #include "utf8.h" #include <fcntl.h> +#include <libgen.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -26,10 +27,10 @@ struct update_hook_result buffer_modeline_hook(struct buffer *buffer, uint64_t frame_time, void *userdata); -struct buffer buffer_create(const char *name, bool modeline) { +struct buffer buffer_create(char *name, bool modeline) { struct buffer b = (struct buffer){.filename = NULL, - .name = name, + .name = strdup(name), .text = text_create(10), .dot_col = 0, .dot_line = 0, @@ -43,14 +44,14 @@ struct buffer buffer_create(const char *name, bool modeline) { b.keymaps[0] = keymap_create("buffer-default", 128); struct binding bindings[] = { BINDING(Ctrl, 'B', "backward-char"), - BINDING(Spec, 'D', "backward-char"), + BINDING(LEFT, "backward-char"), BINDING(Ctrl, 'F', "forward-char"), - BINDING(Spec, 'C', "forward-char"), + BINDING(RIGHT, "forward-char"), BINDING(Ctrl, 'P', "backward-line"), - BINDING(Spec, 'A', "backward-line"), + BINDING(UP, "backward-line"), BINDING(Ctrl, 'N', "forward-line"), - BINDING(Spec, 'B', "forward-line"), + BINDING(DOWN, "forward-line"), BINDING(Ctrl, 'A', "beginning-of-line"), BINDING(Ctrl, 'E', "end-of-line"), @@ -59,8 +60,9 @@ struct buffer buffer_create(const char *name, bool modeline) { BINDING(Ctrl, 'I', "indent"), BINDING(Ctrl, 'K', "kill-line"), - BINDING(Spec, '3', "delete-char"), - BINDING(Ctrl, '?', "backward-delete-char"), + BINDING(DELETE, "delete-char"), + BINDING(Ctrl, 'D', "delete-char"), + BINDING(BACKSPACE, "backward-delete-char"), }; keymap_bind_keys(&b.keymaps[0], bindings, sizeof(bindings) / sizeof(bindings[0])); @@ -81,6 +83,8 @@ struct buffer buffer_create(const char *name, bool modeline) { void buffer_destroy(struct buffer *buffer) { text_destroy(buffer->text); free(buffer->text); + free(buffer->name); + free(buffer->filename); } void buffer_clear(struct buffer *buffer) { @@ -100,8 +104,9 @@ uint32_t buffer_keymaps(struct buffer *buffer, struct keymap **keymaps_out) { void buffer_add_keymap(struct buffer *buffer, struct keymap *keymap) { if (buffer->nkeymaps == buffer->nkeymaps_max) { - // TODO: better - return; + buffer->nkeymaps_max *= 2; + buffer->keymaps = + realloc(buffer->keymaps, sizeof(struct keymap) * buffer->nkeymaps_max); } buffer->keymaps[buffer->nkeymaps] = *keymap; ++buffer->nkeymaps; @@ -174,9 +179,9 @@ void buffer_end_of_line(struct buffer *buffer) { void buffer_beginning_of_line(struct buffer *buffer) { buffer->dot_col = 0; } -struct buffer buffer_from_file(const char *filename, struct reactor *reactor) { - struct buffer b = buffer_create(filename, true); - b.filename = filename; +struct buffer buffer_from_file(char *filename) { + struct buffer b = buffer_create(basename((char *)filename), true); + b.filename = strdup(filename); if (access(b.filename, F_OK) == 0) { FILE *file = fopen(filename, "r"); @@ -297,7 +302,7 @@ void render_line(struct text_chunk *line, void *userdata) { if (cmdbuf->width > line->nchars) { command_list_draw_repeated(cmdbuf->cmds, col, visual_line, ' ', - cmdbuf->width - line->nchars); + cmdbuf->width - col + cmdbuf->col_offset); } } @@ -520,3 +525,7 @@ void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height, *relline = rel_line < 0 ? 0 : (uint32_t)rel_line + total_margins.top; *relcol = rel_col < 0 ? 0 : (uint32_t)rel_col + total_margins.left; } + +struct text_chunk buffer_get_line(struct buffer *buffer, uint32_t line) { + return text_get_line(buffer->text, line); +} diff --git a/src/buffer.h b/src/buffer.h index cf9c269..dcc4a8c 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -4,6 +4,7 @@ #include "command.h" #include "text.h" +#include "window.h" struct keymap; struct reactor; @@ -48,8 +49,8 @@ struct modeline { }; struct buffer { - const char *name; - const char *filename; + char *name; + char *filename; struct text *text; @@ -67,7 +68,7 @@ struct buffer { struct update_hooks update_hooks; }; -struct buffer buffer_create(const char *name, bool modeline); +struct buffer buffer_create(char *name, bool modeline); void buffer_destroy(struct buffer *buffer); uint32_t buffer_keymaps(struct buffer *buffer, struct keymap **keymaps_out); @@ -89,10 +90,12 @@ void buffer_beginning_of_line(struct buffer *buffer); void buffer_newline(struct buffer *buffer); void buffer_indent(struct buffer *buffer); +struct text_chunk buffer_get_line(struct buffer *buffer, uint32_t line); + uint32_t buffer_add_update_hook(struct buffer *buffer, update_hook_cb hook, void *userdata); -struct buffer buffer_from_file(const char *filename, struct reactor *reactor); +struct buffer buffer_from_file(char *filename); void buffer_to_file(struct buffer *buffer); void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height, @@ -103,7 +106,7 @@ void buffer_update(struct buffer *buffer, uint32_t width, uint32_t height, #define BUFFER_WRAPCMD(fn) \ static int32_t fn##_cmd(struct command_ctx ctx, int argc, \ const char *argv[]) { \ - fn(ctx.current_buffer); \ + fn(ctx.active_window->buffer); \ return 0; \ } diff --git a/src/buffers.c b/src/buffers.c new file mode 100644 index 0000000..479caa5 --- /dev/null +++ b/src/buffers.c @@ -0,0 +1,42 @@ +#include "buffers.h" +#include "buffer.h" + +#include <stdlib.h> +#include <string.h> + +void buffers_init(struct buffers *buffers, uint32_t initial_capacity) { + buffers->buffers = calloc(initial_capacity, sizeof(struct buffer)); + buffers->nbuffers = 0; + buffers->capacity = initial_capacity; +} + +struct buffer *buffers_add(struct buffers *buffers, struct buffer buffer) { + if (buffers->nbuffers == buffers->capacity) { + buffers->capacity *= 2; + buffers->buffers = + realloc(buffers->buffers, sizeof(struct buffer) * buffers->capacity); + } + + buffers->buffers[buffers->nbuffers] = buffer; + ++buffers->nbuffers; + + return &buffers->buffers[buffers->nbuffers - 1]; +} + +struct buffer *buffers_find(struct buffers *buffers, const char *name) { + for (uint32_t bufi = 0; bufi < buffers->nbuffers; ++bufi) { + if (strcmp(name, buffers->buffers[bufi].name) == 0) { + return &buffers->buffers[bufi]; + } + } + + return NULL; +} + +void buffers_destroy(struct buffers *buffers) { + for (uint32_t bufi = 0; bufi < buffers->nbuffers; ++bufi) { + buffer_destroy(&buffers->buffers[bufi]); + } + + buffers->nbuffers = 0; +} diff --git a/src/buffers.h b/src/buffers.h new file mode 100644 index 0000000..edf772c --- /dev/null +++ b/src/buffers.h @@ -0,0 +1,17 @@ +#include <stdint.h> + +struct buffer; + +struct buffers { + // TODO: more buffers + struct buffer *buffers; + uint32_t nbuffers; + uint32_t capacity; +}; + +void buffers_init(struct buffers *buffers, uint32_t initial_capacity); + +struct buffer *buffers_add(struct buffers *buffers, struct buffer buffer); +struct buffer *buffers_find(struct buffers *buffers, const char *name); + +void buffers_destroy(struct buffers *buffers); diff --git a/src/command.c b/src/command.c index a667750..93ede01 100644 --- a/src/command.c +++ b/src/command.c @@ -1,4 +1,6 @@ -#include "command.h" +#include "buffer.h" +#include "buffers.h" +#include "minibuffer.h" #include <stdlib.h> @@ -65,10 +67,66 @@ struct command *lookup_command_by_hash(struct commands *commands, return NULL; } -int32_t execute_command(struct command *command, struct buffer *current_buffer, +int32_t execute_command(struct command *command, struct commands *commands, + struct window *active_window, struct buffers *buffers, int argc, const char *argv[]) { - return command->fn((struct command_ctx){.current_buffer = current_buffer, - .userdata = command->userdata}, - argc, argv); + return command->fn( + (struct command_ctx){ + .buffers = buffers, + .active_window = active_window, + .userdata = command->userdata, + .commands = commands, + .self = command, + }, + argc, argv); +} + +int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]) { + const char *pth = NULL; + if (argc == 1) { + pth = argv[0]; + ctx.active_window->buffer = + buffers_add(ctx.buffers, buffer_from_file((char *)pth)); + minibuffer_echo_timeout(4, "buffer %s loaded", + ctx.active_window->buffer->name); + } else { + minibuffer_prompt(ctx, "find file: "); + } + + return 0; +} + +int32_t run_interactive(struct command_ctx ctx, int argc, const char *argv[]) { + if (argc == 0) { + minibuffer_prompt(ctx, "execute: "); + return 0; + } + + struct command *cmd = lookup_command(ctx.commands, argv[0]); + if (cmd != NULL) { + return execute_command(cmd, ctx.commands, ctx.active_window, ctx.buffers, + argc - 1, argv + 1); + } else { + minibuffer_echo_timeout(4, "command %s not found", argv[0]); + return 11; + } +} + +int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { + if (argc == 0) { + minibuffer_prompt(ctx, "buffer: "); + return 0; + } + + const char *bufname = argv[0]; + struct buffer *buf = buffers_find(ctx.buffers, bufname); + + if (buf == NULL) { + minibuffer_echo_timeout(4, "buffer %s not found", bufname); + return 1; + } else { + ctx.active_window->buffer = buf; + return 0; + } } diff --git a/src/command.h b/src/command.h index fe998ae..719422e 100644 --- a/src/command.h +++ b/src/command.h @@ -1,9 +1,14 @@ #include <stdint.h> struct buffer; +struct buffers; +struct window; struct command_ctx { - struct buffer *current_buffer; + struct buffers *buffers; + struct window *active_window; + struct commands *commands; + struct command *self; void *userdata; }; @@ -34,7 +39,8 @@ uint32_t register_command(struct commands *commands, struct command *command); void register_commands(struct commands *command_list, struct command *commands, uint32_t ncommands); -int32_t execute_command(struct command *command, struct buffer *current_buffer, +int32_t execute_command(struct command *command, struct commands *commands, + struct window *active_window, struct buffers *buffers, int argc, const char *argv[]); uint32_t hash_command_name(const char *name); @@ -42,3 +48,8 @@ uint32_t hash_command_name(const char *name); struct command *lookup_command(struct commands *commands, const char *name); struct command *lookup_command_by_hash(struct commands *commands, uint32_t hash); + +// Common commands +int32_t find_file(struct command_ctx ctx, int argc, const char *argv[]); +int32_t run_interactive(struct command_ctx ctx, int argc, const char *argv[]); +int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]); diff --git a/src/keyboard.c b/src/keyboard.c index 03d0bd4..e76630e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -72,6 +72,18 @@ void parse_keys(uint8_t *bytes, uint32_t nbytes, struct key *out_keys, (kp->mod & Spec && !(has_more && bytes[bytei + 1] == '~'))) { ++nkps; } + } else if (utf8_byte_is_unicode_start(b)) { + kp->mod = None; + kp->key = 0; + kp->start = bytei; + kp->end = bytei + utf8_nbytes(bytes + bytei, nbytes - bytei, 1); + ++nkps; + } else { + kp->mod = None; + kp->key = b; + kp->start = bytei; + kp->end = bytei + 1; + ++nkps; } } } @@ -97,13 +109,13 @@ struct keyboard_update keyboard_update(struct keyboard *kbd, } } - int nbytes = read(STDIN_FILENO, upd.raw, 32); + int nbytes = read(STDIN_FILENO, upd.raw, 64); if (nbytes > 0) { upd.nbytes = nbytes; parse_keys(upd.raw, upd.nbytes, upd.keys, &upd.nkeys); - if (nbytes < 32) { + if (nbytes < 64) { kbd->has_data = false; } } else if (nbytes == EAGAIN) { @@ -118,7 +130,7 @@ bool key_equal_char(struct key *key, uint8_t mod, uint8_t c) { } bool key_equal(struct key *key1, struct key *key2) { - return key1->key == key2->key && key1->mod == key2->mod; + return key_equal_char(key1, key2->mod, key2->key); } void key_name(struct key *key, char *buf, size_t capacity) { diff --git a/src/keyboard.h b/src/keyboard.h index 72c61d5..9bf36de 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -3,11 +3,20 @@ #include <stdint.h> enum modifiers { + None = 0, Ctrl = 1 << 0, Meta = 1 << 1, Spec = 1 << 2, }; +#define BACKSPACE Ctrl, '?' +#define DELETE Spec, '3' + +#define UP Spec, 'A' +#define DOWN Spec, 'B' +#define RIGHT Spec, 'C' +#define LEFT Spec, 'D' + struct key { uint8_t key; uint8_t mod; @@ -24,7 +33,7 @@ struct keyboard_update { struct key keys[32]; uint32_t nkeys; - uint8_t raw[32]; + uint8_t raw[64]; uint32_t nbytes; }; @@ -8,6 +8,7 @@ #include "binding.h" #include "buffer.h" +#include "buffers.h" #include "display.h" #include "minibuffer.h" #include "reactor.h" @@ -56,6 +57,7 @@ void resized() { } int32_t _abort(struct command_ctx ctx, int argc, const char *argv[]) { + minibuffer_abort_prompt(); minibuffer_echo_timeout(4, "💣 aborted"); return 0; } @@ -72,16 +74,9 @@ int32_t exit_editor(struct command_ctx ctx, int argc, const char *argv[]) { } static struct command GLOBAL_COMMANDS[] = { - { - .name = "find-file", - .fn = unimplemented_command, - .userdata = (void *)"find-file", - }, - { - .name = "run-command-interactive", - .fn = unimplemented_command, - .userdata = (void *)"run-command-interactive", - }, + {.name = "find-file", .fn = find_file}, + {.name = "run-command-interactive", .fn = run_interactive}, + {.name = "switch-buffer", .fn = switch_buffer}, {.name = "abort", .fn = _abort}, {.name = "exit", .fn = exit_editor}}; @@ -99,44 +94,8 @@ uint64_t calc_frame_time_ns(struct timespec *timers, uint32_t num_timer_pairs) { return total; } -struct buffers { - // TODO: more buffers - struct buffer buffers[32]; - uint32_t nbuffers; -}; - -struct window { - uint32_t x; - uint32_t y; - uint32_t width; - uint32_t height; - struct buffer *buffer; -}; - -void window_update_buffer(struct window *window, struct command_list *commands, - uint64_t frame_time, uint32_t *relline, - uint32_t *relcol) { - buffer_update(window->buffer, window->width, window->height, commands, - frame_time, relline, relcol); -} - -void buffers_init(struct buffers *buffers) { buffers->nbuffers = 0; } - -void buffers_add(struct buffers *buffers, struct buffer buffer) { - buffers->buffers[buffers->nbuffers] = buffer; - ++buffers->nbuffers; -} - -void buffers_destroy(struct buffers *buffers) { - for (uint32_t bufi = 0; bufi < buffers->nbuffers; ++bufi) { - buffer_destroy(&buffers->buffers[bufi]); - } - - buffers->nbuffers = 0; -} - int main(int argc, char *argv[]) { - const char *filename = NULL; + char *filename = NULL; if (argc >= 1) { filename = argv[1]; } @@ -178,6 +137,7 @@ int main(int argc, char *argv[]) { BINDING(Ctrl, 'C', "exit"), BINDING(Ctrl, 'S', "buffer-write-to-file"), BINDING(Ctrl, 'F', "find-file"), + BINDING(None, 'b', "switch-buffer"), }; keymap_bind_keys(&global_keymap, global_binds, sizeof(global_binds) / sizeof(global_binds[0])); @@ -185,21 +145,19 @@ int main(int argc, char *argv[]) { sizeof(ctrlx_bindings) / sizeof(ctrlx_bindings[0])); struct buffers buflist = {0}; - buffers_init(&buflist); + buffers_init(&buflist, 32); struct buffer initial_buffer = buffer_create("welcome", true); if (filename != NULL) { - initial_buffer = buffer_from_file(filename, &reactor); + initial_buffer = buffer_from_file(filename); } else { const char *welcome_txt = "Welcome to the editor for datagubbar 👴\n"; buffer_add_text(&initial_buffer, (uint8_t *)welcome_txt, strlen(welcome_txt)); } - buffers_add(&buflist, initial_buffer); - // one main window struct window main_window = (struct window){ - .buffer = &initial_buffer, + .buffer = buffers_add(&buflist, initial_buffer), .height = display.height - 1, .width = display.width, .x = 0, @@ -207,12 +165,12 @@ int main(int argc, char *argv[]) { }; // and one for the minibuffer - struct buffer minibuffer = buffer_create("minibuffer", false); - buffers_add(&buflist, minibuffer); + struct buffer *minibuffer = + buffers_add(&buflist, buffer_create("minibuffer", false)); - minibuffer_init(&minibuffer); + minibuffer_init(minibuffer); struct window minibuffer_window = (struct window){ - .buffer = &minibuffer, + .buffer = minibuffer, .x = 0, .y = display.height - 1, .height = 1, @@ -289,20 +247,14 @@ int main(int argc, char *argv[]) { clock_gettime(CLOCK_MONOTONIC, &keyboard_begin); struct keymap *local_keymaps = NULL; - uint32_t nbuffer_keymaps = buffer_keymaps(&initial_buffer, &local_keymaps); + uint32_t nbuffer_keymaps = + buffer_keymaps(active_window->buffer, &local_keymaps); struct keyboard_update kbd_upd = keyboard_update(&kbd, &reactor); uint32_t input_data_idx = 0; for (uint32_t ki = 0; ki < kbd_upd.nkeys; ++ki) { struct key *k = &kbd_upd.keys[ki]; - // insert any data from last key - if (k->start > input_data_idx) { - buffer_add_text(active_window->buffer, &kbd_upd.raw[input_data_idx], - k->start - input_data_idx); - } - input_data_idx = k->end; - struct lookup_result res = {.found = false}; if (current_keymap != NULL) { res = lookup_key(current_keymap, 1, k, &commands); @@ -321,9 +273,9 @@ int main(int argc, char *argv[]) { minibuffer_echo_timeout( 4, "binding found for key %s but not command", k); } else { - int32_t ec = - execute_command(res.command, active_window->buffer, 0, NULL); - if (ec != 0) { + int32_t ec = execute_command(res.command, &commands, active_window, + &buflist, 0, NULL); + if (ec != 0 && !minibuffer_displaying()) { minibuffer_echo_timeout(4, "command %s failed with exit code %d", res.command->name, ec); } @@ -334,22 +286,26 @@ int main(int argc, char *argv[]) { case BindingType_Keymap: { char keyname[16]; key_name(k, keyname, 16); - minibuffer_echo("%s", keyname); current_keymap = res.keymap; + minibuffer_echo("%s", current_keymap->name); break; } } + } else if (k->mod == 0) { + buffer_add_text(active_window->buffer, &kbd_upd.raw[k->start], + k->end - k->start); } else { char keyname[16]; key_name(k, keyname, 16); - minibuffer_echo_timeout(4, "key \"%s\" is not bound!", keyname); + if (current_keymap == NULL) { + minibuffer_echo_timeout(4, "key \"%s\" is not bound!", keyname); + } else { + minibuffer_echo_timeout(4, "key \"%s %s\" is not bound!", + current_keymap->name, keyname); + } current_keymap = NULL; } } - if (input_data_idx < kbd_upd.nbytes) { - buffer_add_text(active_window->buffer, &kbd_upd.raw[input_data_idx], - kbd_upd.nbytes - input_data_idx); - } clock_gettime(CLOCK_MONOTONIC, &keyboard_end); // calculate frame time @@ -357,6 +313,13 @@ int main(int argc, char *argv[]) { display_end, keyboard_begin, keyboard_end}; frame_time = calc_frame_time_ns(timers, 3); + if (minibuffer_focused()) { + active_window = &minibuffer_window; + } else { + // TODO: no + active_window = &main_window; + } + frame_allocator_clear(&frame_allocator); } diff --git a/src/minibuffer.c b/src/minibuffer.c index b622ab0..a424af8 100644 --- a/src/minibuffer.c +++ b/src/minibuffer.c @@ -1,16 +1,77 @@ #include "minibuffer.h" +#include "binding.h" #include "buffer.h" #include "display.h" #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> static struct minibuffer { struct buffer *buffer; struct timespec expires; + char prompt[128]; + struct command_ctx prompt_command_ctx; + bool prompt_active; + struct keymap keymap; } g_minibuffer = {0}; +void draw_prompt(struct text_chunk *line_data, uint32_t line, + struct command_list *commands, void *userdata) { + uint32_t len = strlen(g_minibuffer.prompt); + command_list_set_index_color_fg(commands, 4); + command_list_draw_text(commands, 0, line, (uint8_t *)g_minibuffer.prompt, + len); + command_list_reset_color(commands); +} + +int32_t execute(struct command_ctx ctx, int argc, const char *argv[]) { + if (g_minibuffer.prompt_active) { + struct text_chunk line = buffer_get_line(g_minibuffer.buffer, 0); + char *l = (char *)malloc(line.nbytes + 1); + memcpy(l, line.text, line.nbytes); + + // split on ' ' + const char *argv[128] = {l}; + argc = 1; + for (uint32_t bytei = 0; bytei < line.nbytes; ++bytei) { + uint8_t byte = line.text[bytei]; + if (byte == ' ') { + l[bytei] = '\0'; + argv[argc] = l + bytei; + ++argc; + } + } + + minibuffer_abort_prompt(); + struct command_ctx *ctx = &g_minibuffer.prompt_command_ctx; + uint32_t res = execute_command(ctx->self, ctx->commands, ctx->active_window, + ctx->buffers, argc, argv); + + free(l); + return res; + } else { + return 0; + } +} + +struct command execute_minibuffer_command = { + .fn = execute, + .name = "minibuffer-execute", + .userdata = NULL, +}; + +int32_t complete(struct command_ctx ctx, int argc, const char *argv[]) { + return 0; +} + +struct command complete_minibuffer_command = { + .fn = complete, + .name = "minibuffer-complete", + .userdata = NULL, +}; + struct update_hook_result update(struct buffer *buffer, struct command_list *commands, uint32_t width, uint32_t height, uint64_t frame_time, @@ -18,19 +79,36 @@ struct update_hook_result update(struct buffer *buffer, struct timespec current; struct minibuffer *mb = (struct minibuffer *)userdata; clock_gettime(CLOCK_MONOTONIC, ¤t); - if (current.tv_sec >= mb->expires.tv_sec) { + if (!mb->prompt_active && current.tv_sec >= mb->expires.tv_sec) { buffer_clear(buffer); } - return (struct update_hook_result){0}; + struct update_hook_result res = {0}; + if (g_minibuffer.prompt_active) { + res.margins.left = strlen(g_minibuffer.prompt); + res.line_render_hook.callback = draw_prompt; + } + + return res; } void minibuffer_init(struct buffer *buffer) { g_minibuffer.buffer = buffer; + struct binding bindings[] = { + ANONYMOUS_BINDING(Ctrl, 'M', &execute_minibuffer_command), + ANONYMOUS_BINDING(Ctrl, 'I', &complete_minibuffer_command), + }; + keymap_bind_keys(&g_minibuffer.keymap, bindings, + sizeof(bindings) / sizeof(bindings[0])); + buffer_add_keymap(g_minibuffer.buffer, &g_minibuffer.keymap); buffer_add_update_hook(g_minibuffer.buffer, update, &g_minibuffer); } void echo(uint32_t timeout, const char *fmt, va_list args) { + if (g_minibuffer.prompt_active) { + return; + } + char buff[2048]; size_t nbytes = vsnprintf(buff, 2048, fmt, args); @@ -58,5 +136,21 @@ void minibuffer_echo_timeout(uint32_t timeout, const char *fmt, ...) { va_end(args); } +void minibuffer_prompt(struct command_ctx command_ctx, const char *fmt, ...) { + minibuffer_clear(); + g_minibuffer.prompt_active = true; + g_minibuffer.prompt_command_ctx = command_ctx; + va_list args; + va_start(args, fmt); + vsnprintf(g_minibuffer.prompt, sizeof(g_minibuffer.prompt), fmt, args); + va_end(args); +} + +void minibuffer_abort_prompt() { + minibuffer_clear(); + g_minibuffer.prompt_active = false; +} + bool minibuffer_displaying() { return !buffer_is_empty(g_minibuffer.buffer); } -void minibuffer_clear() { g_minibuffer.expires.tv_nsec = 0; } +void minibuffer_clear() { buffer_clear(g_minibuffer.buffer); } +bool minibuffer_focused() { return g_minibuffer.prompt_active; } diff --git a/src/minibuffer.h b/src/minibuffer.h index 9bdde8f..ec24f49 100644 --- a/src/minibuffer.h +++ b/src/minibuffer.h @@ -4,9 +4,16 @@ #include <time.h> struct buffer; +struct command_ctx; + void minibuffer_init(struct buffer *buffer); void minibuffer_echo(const char *fmt, ...); void minibuffer_echo_timeout(uint32_t timeout, const char *fmt, ...); + +void minibuffer_prompt(struct command_ctx command_ctx, const char *fmt, ...); +void minibuffer_abort_prompt(); + void minibuffer_clear(); bool minibuffer_displaying(); +bool minibuffer_focused(); diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..5f1911a --- /dev/null +++ b/src/window.c @@ -0,0 +1,9 @@ +#include "buffer.h" +#include "display.h" + +void window_update_buffer(struct window *window, struct command_list *commands, + uint64_t frame_time, uint32_t *relline, + uint32_t *relcol) { + buffer_update(window->buffer, window->width, window->height, commands, + frame_time, relline, relcol); +} diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..81535a0 --- /dev/null +++ b/src/window.h @@ -0,0 +1,15 @@ +#include <stdint.h> + +struct command_list; + +struct window { + uint32_t x; + uint32_t y; + uint32_t width; + uint32_t height; + struct buffer *buffer; +}; + +void window_update_buffer(struct window *window, struct command_list *commands, + uint64_t frame_time, uint32_t *relline, + uint32_t *relcol); |
