diff options
| -rw-r--r-- | src/dged/buffer_view.c | 3 | ||||
| -rw-r--r-- | src/dged/buffers.c | 96 | ||||
| -rw-r--r-- | src/dged/buffers.h | 11 | ||||
| -rw-r--r-- | src/dged/window.c | 95 | ||||
| -rw-r--r-- | src/dged/window.h | 8 | ||||
| -rw-r--r-- | src/main/bindings.c | 1 | ||||
| -rw-r--r-- | src/main/cmds.c | 100 | ||||
| -rw-r--r-- | src/main/main.c | 6 | ||||
| -rw-r--r-- | test/minibuffer.c | 2 |
9 files changed, 277 insertions, 45 deletions
diff --git a/src/dged/buffer_view.c b/src/dged/buffer_view.c index 49d938a..0ba269c 100644 --- a/src/dged/buffer_view.c +++ b/src/dged/buffer_view.c @@ -70,7 +70,10 @@ void buffer_view_destroy(struct buffer_view *view) { if (view->modeline != NULL) { free(view->modeline->buffer); free(view->modeline); + view->modeline = NULL; } + + view->buffer = NULL; } void buffer_view_add(struct buffer_view *view, uint8_t *txt, uint32_t nbytes) { diff --git a/src/dged/buffers.c b/src/dged/buffers.c index 99dad9a..f591385 100644 --- a/src/dged/buffers.c +++ b/src/dged/buffers.c @@ -1,24 +1,42 @@ #include "buffers.h" #include "buffer.h" +#include <stdbool.h> #include <stdlib.h> - #include <string.h> +struct buffer_entry { + struct buffer buffer; + bool empty; +}; + void buffers_init(struct buffers *buffers, uint32_t initial_capacity) { VEC_INIT(&buffers->buffers, initial_capacity); VEC_INIT(&buffers->add_hooks, 32); + VEC_INIT(&buffers->remove_hooks, 32); } struct buffer *buffers_add(struct buffers *buffers, struct buffer buffer) { - VEC_PUSH(&buffers->buffers, buffer); + struct buffer_entry *slot = NULL; + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (e->empty) { + slot = e; + } + } + + if (slot == NULL) { + VEC_APPEND(&buffers->buffers, struct buffer_entry * new); + slot = new; + } + + slot->buffer = buffer; + slot->empty = false; - struct buffer *slot = VEC_BACK(&buffers->buffers); VEC_FOR_EACH(&buffers->add_hooks, struct buffers_hook * hook) { - hook->callback(slot, hook->userdata); + hook->callback(&slot->buffer, hook->userdata); } - return slot; + return &slot->buffer; } uint32_t buffers_add_add_hook(struct buffers *buffers, buffers_hook_cb callback, @@ -31,10 +49,20 @@ uint32_t buffers_add_add_hook(struct buffers *buffers, buffers_hook_cb callback, return VEC_SIZE(&buffers->add_hooks) - 1; } +uint32_t buffers_add_remove_hook(struct buffers *buffers, + buffers_hook_cb callback, void *userdata) { + VEC_PUSH(&buffers->remove_hooks, ((struct buffers_hook){ + .callback = callback, + .userdata = userdata, + })); + + return VEC_SIZE(&buffers->remove_hooks) - 1; +} + struct buffer *buffers_find(struct buffers *buffers, const char *name) { - VEC_FOR_EACH(&buffers->buffers, struct buffer * b) { - if (strcmp(name, b->name) == 0) { - return b; + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (!e->empty && strcmp(name, e->buffer.name) == 0) { + return &e->buffer; } } @@ -43,23 +71,65 @@ struct buffer *buffers_find(struct buffers *buffers, const char *name) { struct buffer *buffers_find_by_filename(struct buffers *buffers, const char *path) { - VEC_FOR_EACH(&buffers->buffers, struct buffer * b) { - if (b->filename != NULL && strcmp(path, b->filename) == 0) { - return b; + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (!e->empty && e->buffer.filename != NULL && + strcmp(path, e->buffer.filename) == 0) { + return &e->buffer; } } return NULL; } +bool buffers_remove(struct buffers *buffers, const char *name) { + struct buffer_entry *buf_entry = NULL; + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (!e->empty && strcmp(name, e->buffer.name) == 0) { + buf_entry = e; + } + } + + if (buf_entry == NULL) { + return false; + } + + VEC_FOR_EACH(&buffers->remove_hooks, struct buffers_hook * hook) { + hook->callback(&buf_entry->buffer, hook->userdata); + } + + buf_entry->empty = true; + buffer_destroy(&buf_entry->buffer); + return true; +} + void buffers_for_each(struct buffers *buffers, buffers_hook_cb callback, void *userdata) { - VEC_FOR_EACH(&buffers->buffers, struct buffer * b) { callback(b, userdata); } + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (!e->empty) { + callback(&e->buffer, userdata); + } + } +} + +uint32_t buffers_num_buffers(struct buffers *buffers) { + return VEC_SIZE(&buffers->buffers); +} + +struct buffer *buffers_first(struct buffers *buffers) { + return buffers_num_buffers(buffers) > 0 + ? &VEC_ENTRIES(&buffers->buffers)[0].buffer + : NULL; } void buffers_destroy(struct buffers *buffers) { - VEC_FOR_EACH(&buffers->buffers, struct buffer * b) { buffer_destroy(b); } + VEC_FOR_EACH(&buffers->buffers, struct buffer_entry * e) { + if (!e->empty) { + buffer_destroy(&e->buffer); + e->empty = true; + } + } VEC_DESTROY(&buffers->buffers); VEC_DESTROY(&buffers->add_hooks); + VEC_DESTROY(&buffers->remove_hooks); } diff --git a/src/dged/buffers.h b/src/dged/buffers.h index f4c0a37..d521a78 100644 --- a/src/dged/buffers.h +++ b/src/dged/buffers.h @@ -1,5 +1,6 @@ #include "vec.h" +#include <stdbool.h> #include <stdint.h> struct buffer; @@ -11,9 +12,12 @@ struct buffers_hook { void *userdata; }; +struct buffer_entry; + struct buffers { - VEC(struct buffer) buffers; + VEC(struct buffer_entry) buffers; VEC(struct buffers_hook) add_hooks; + VEC(struct buffers_hook) remove_hooks; }; void buffers_init(struct buffers *buffers, uint32_t initial_capacity); @@ -23,6 +27,8 @@ struct buffer *buffers_find(struct buffers *buffers, const char *name); struct buffer *buffers_find_by_filename(struct buffers *buffers, const char *path); +bool buffers_remove(struct buffers *buffers, const char *name); + uint32_t buffers_add_add_hook(struct buffers *buffers, buffers_hook_cb callback, void *userdata); uint32_t buffers_add_remove_hook(struct buffers *buffers, @@ -31,4 +37,7 @@ uint32_t buffers_add_remove_hook(struct buffers *buffers, void buffers_for_each(struct buffers *buffers, buffers_hook_cb callback, void *userdata); +uint32_t buffers_num_buffers(struct buffers *buffers); +struct buffer *buffers_first(struct buffers *buffers); + void buffers_destroy(struct buffers *buffers); diff --git a/src/dged/window.c b/src/dged/window.c index 8fcd51c..20cb22f 100644 --- a/src/dged/window.c +++ b/src/dged/window.c @@ -2,6 +2,7 @@ #include "btree.h" #include "buffer.h" #include "buffer_view.h" +#include "buffers.h" #include "command.h" #include "display.h" #include "minibuffer.h" @@ -21,7 +22,8 @@ struct window { uint32_t height; enum window_type type; struct buffer_view buffer_view; - struct buffer *prev_buffer; + struct buffer_view prev_buffer_view; + bool has_prev_buffer_view; struct command_list *commands; uint32_t relline; uint32_t relcol; @@ -40,13 +42,52 @@ static struct window g_minibuffer_window; static struct window g_popup_window = {0}; static bool g_popup_visible = false; +static void buffer_removed(struct buffer *buffer, void *userdata) { + struct window_node *n = BINTREE_ROOT(&g_windows.windows); + BINTREE_FIRST(n); + while (n != NULL) { + struct window *w = &BINTREE_VALUE(n); + if (window_prev_buffer_view(w)->buffer == buffer) { + buffer_view_destroy(&w->prev_buffer_view); + w->has_prev_buffer_view = false; + } + + if (window_buffer(w) == buffer) { + if (window_has_prev_buffer_view(w)) { + window_set_buffer(w, window_prev_buffer_view(w)->buffer); + buffer_view_destroy(&w->prev_buffer_view); + w->has_prev_buffer_view = false; + } else { + struct buffers *buffers = (struct buffers *)userdata; + struct buffer *b = buffers_find(buffers, "*messages*"); + + if (b != NULL) { + window_set_buffer(w, b); + } else { + b = buffers_first(buffers); + + // if there are no more buffers, not sure what to do? + if (b != NULL) { + window_set_buffer(w, b); + } + } + buffer_view_destroy(&w->prev_buffer_view); + w->has_prev_buffer_view = false; + } + } + + BINTREE_NEXT(n); + } +} + void windows_init(uint32_t height, uint32_t width, - struct buffer *initial_buffer, struct buffer *minibuffer) { + struct buffer *initial_buffer, struct buffer *minibuffer, + struct buffers *buffers) { BINTREE_INIT(&g_windows.windows); g_minibuffer_window = (struct window){ .buffer_view = buffer_view_create(minibuffer, false, false), - .prev_buffer = NULL, + .has_prev_buffer_view = false, .x = 0, .y = height - 1, .height = 1, @@ -55,7 +96,7 @@ void windows_init(uint32_t height, uint32_t width, struct window root_window = (struct window){ .buffer_view = buffer_view_create(initial_buffer, true, true), - .prev_buffer = NULL, + .has_prev_buffer_view = false, .height = height - 1, .width = width, .x = 0, @@ -63,6 +104,8 @@ void windows_init(uint32_t height, uint32_t width, }; BINTREE_SET_ROOT(&g_windows.windows, root_window); g_windows.active = &BINTREE_VALUE(BINTREE_ROOT(&g_windows.windows)); + + buffers_add_remove_hook(buffers, buffer_removed, buffers); } static void window_tree_clear_sub(struct window_node *root_node) { @@ -72,6 +115,9 @@ static void window_tree_clear_sub(struct window_node *root_node) { struct window *w = &BINTREE_VALUE(n); if (w->type == Window_Buffer) { buffer_view_destroy(&w->buffer_view); + if (w->has_prev_buffer_view) { + buffer_view_destroy(&w->prev_buffer_view); + } } BINTREE_NEXT(n); } @@ -377,8 +423,23 @@ void window_set_buffer(struct window *window, struct buffer *buffer) { void window_set_buffer_e(struct window *window, struct buffer *buffer, bool modeline, bool line_numbers) { if (buffer != window->buffer_view.buffer) { - window->prev_buffer = window->buffer_view.buffer; - buffer_view_destroy(&window->buffer_view); + if (window->has_prev_buffer_view) { + + if (window->prev_buffer_view.buffer == buffer) { + + struct buffer_view tmp = window->prev_buffer_view; + window->prev_buffer_view = window->buffer_view; + window->has_prev_buffer_view = true; + window->buffer_view = tmp; + return; + + } else { + buffer_view_destroy(&window->prev_buffer_view); + } + } + + window->prev_buffer_view = window->buffer_view; + window->has_prev_buffer_view = true; window->buffer_view = buffer_view_create(buffer, modeline, line_numbers); } } @@ -391,12 +452,12 @@ struct buffer_view *window_buffer_view(struct window *window) { return &window->buffer_view; } -struct buffer *window_prev_buffer(struct window *window) { - return window->prev_buffer; +struct buffer_view *window_prev_buffer_view(struct window *window) { + return &window->prev_buffer_view; } -bool window_has_prev_buffer(struct window *window) { - return window->prev_buffer != NULL; +bool window_has_prev_buffer_view(struct window *window) { + return window->has_prev_buffer_view; } void window_close(struct window *window) { @@ -417,6 +478,7 @@ void window_close(struct window *window) { : BINTREE_RIGHT(target); buffer_view_destroy(&window->buffer_view); + buffer_view_destroy(&window->prev_buffer_view); BINTREE_REMOVE(to_delete); BINTREE_FREE_NODE(to_delete); @@ -454,6 +516,11 @@ void window_close_others(struct window *window) { new_root.x = 0; new_root.y = 0; new_root.buffer_view = buffer_view_clone(&window->buffer_view); + new_root.has_prev_buffer_view = false; + if (window->has_prev_buffer_view) { + new_root.has_prev_buffer_view = true; + new_root.prev_buffer_view = buffer_view_clone(&window->prev_buffer_view); + } new_root.width = BINTREE_VALUE(root).width; new_root.height = BINTREE_VALUE(root).height; @@ -495,7 +562,9 @@ void window_hsplit(struct window *window, struct window **new_window_a, buffer_view_goto(&new_window.buffer_view, (struct location){.line = w.buffer_view.dot.line, .col = w.buffer_view.dot.col}); - new_window.prev_buffer = w.prev_buffer; + if (w.has_prev_buffer_view) { + new_window.prev_buffer_view = buffer_view_clone(&w.prev_buffer_view); + } new_window.x = w.x; new_window.y = w.y + w.height; new_window.width = w.width; @@ -539,7 +608,9 @@ void window_vsplit(struct window *window, struct window **new_window_a, (struct location){.line = w.buffer_view.dot.line, .col = w.buffer_view.dot.col}); - new_window.prev_buffer = w.prev_buffer; + if (w.has_prev_buffer_view) { + new_window.prev_buffer_view = buffer_view_clone(&w.prev_buffer_view); + } new_window.x = w.x + w.width; new_window.y = w.y; new_window.width = parent.width - w.width; diff --git a/src/dged/window.h b/src/dged/window.h index 3841475..e1b1d25 100644 --- a/src/dged/window.h +++ b/src/dged/window.h @@ -11,6 +11,7 @@ struct display; struct keymap; struct commands; struct buffer; +struct buffers; struct window; struct windows; @@ -21,7 +22,8 @@ struct window_position { }; void windows_init(uint32_t height, uint32_t width, - struct buffer *initial_buffer, struct buffer *minibuffer); + struct buffer *initial_buffer, struct buffer *minibuffer, + struct buffers *buffers); void windows_destroy(); void windows_resize(uint32_t height, uint32_t width); @@ -44,8 +46,8 @@ void window_set_buffer_e(struct window *window, struct buffer *buffer, bool modeline, bool line_numbers); struct buffer *window_buffer(struct window *window); struct buffer_view *window_buffer_view(struct window *window); -struct buffer *window_prev_buffer(struct window *window); -bool window_has_prev_buffer(struct window *window); +struct buffer_view *window_prev_buffer_view(struct window *window); +bool window_has_prev_buffer_view(struct window *window); uint32_t window_width(const struct window *window); uint32_t window_height(const struct window *window); struct window_position window_position(const struct window *window); diff --git a/src/main/bindings.c b/src/main/bindings.c index b49a45e..7b25c7b 100644 --- a/src/main/bindings.c +++ b/src/main/bindings.c @@ -100,6 +100,7 @@ void init_bindings() { BINDING(Ctrl, 'G', "find-file-relative"), BINDING(Ctrl, 'W', "write-file"), BINDING(None, 'b', "switch-buffer"), + BINDING(None, 'k', "kill-buffer"), BINDING(Ctrl, 'B', "buffer-list"), BINDING(None, '0', "window-close"), diff --git a/src/main/cmds.c b/src/main/cmds.c index c668116..d28924b 100644 --- a/src/main/cmds.c +++ b/src/main/cmds.c @@ -74,8 +74,8 @@ int32_t do_switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { const char *bufname = NULL; if (argc == 0) { // switch back to prev buffer - if (window_has_prev_buffer(ctx.active_window)) { - bufname = window_prev_buffer(ctx.active_window)->name; + if (window_has_prev_buffer_view(ctx.active_window)) { + bufname = window_prev_buffer_view(ctx.active_window)->buffer->name; } else { return 0; } @@ -110,9 +110,10 @@ int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { providers, 1, switch_buffer_comp_inserted); ctx.self = &do_switch_buffer_command; - if (window_has_prev_buffer(ctx.active_window)) { - return minibuffer_prompt(ctx, "buffer (default %s): ", - window_prev_buffer(ctx.active_window)->name); + if (window_has_prev_buffer_view(ctx.active_window)) { + return minibuffer_prompt( + ctx, "buffer (default %s): ", + window_prev_buffer_view(ctx.active_window)->buffer->name); } else { return minibuffer_prompt(ctx, "buffer: "); } @@ -124,6 +125,51 @@ int32_t switch_buffer(struct command_ctx ctx, int argc, const char *argv[]) { ctx.active_window, ctx.buffers, argc, argv); } +int32_t do_kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) { + disable_completion(minibuffer_buffer()); + const char *bufname = NULL; + if (argc == 0) { + // kill current buffer + bufname = window_buffer(ctx.active_window)->name; + } else { + bufname = argv[0]; + } + + if (buffers_remove(ctx.buffers, bufname)) { + return 0; + } else { + minibuffer_echo_timeout(4, "buffer %s not found", bufname); + return 1; + } +} + +COMMAND_FN("do-kill-buffer", do_kill_buffer, do_kill_buffer, NULL); + +static void kill_buffer_comp_inserted() { minibuffer_execute(); } + +int32_t kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) { + if (argc == 0) { + minibuffer_clear(); + struct completion_provider providers[] = {buffer_provider()}; + enable_completion(minibuffer_buffer(), + ((struct completion_trigger){ + .kind = CompletionTrigger_Input, + .input = + (struct completion_trigger_input){ + .nchars = 0, .trigger_initially = false}}), + providers, 1, kill_buffer_comp_inserted); + + ctx.self = &do_kill_buffer_command; + return minibuffer_prompt(ctx, "kill buffer (default %s): ", + window_buffer(ctx.active_window)->name); + } + + disable_completion(minibuffer_buffer()); + + return execute_command(&do_switch_buffer_command, ctx.commands, + ctx.active_window, ctx.buffers, argc, argv); +} + void timer_to_list_line(const struct timer *timer, void *userdata) { struct buffer *target = (struct buffer *)userdata; @@ -241,6 +287,34 @@ int32_t buflist_refresh_cmd(struct command_ctx ctx, int argc, return 0; } +static struct command buflist_refresh_command = { + .name = "buflist-refresh", + .fn = buflist_refresh_cmd, +}; + +int32_t buflist_kill_cmd(struct command_ctx ctx, int argc, const char *argv[]) { + struct window *w = ctx.active_window; + + struct buffer_view *bv = window_buffer_view(w); + struct text_chunk text = buffer_line(bv->buffer, bv->dot.line); + + char *end = (char *)memchr(text.text, ' ', text.nbytes); + + if (end != NULL) { + uint32_t len = end - (char *)text.text; + char *bufname = (char *)malloc(len + 1); + strncpy(bufname, (const char *)text.text, len); + bufname[len] = '\0'; + + buffers_remove(ctx.buffers, bufname); + free(bufname); + execute_command(&buflist_refresh_command, ctx.commands, ctx.active_window, + ctx.buffers, 0, NULL); + } + + return 0; +} + int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { struct buffer *b = buffers_find(ctx.buffers, "*buffers*"); if (b == NULL) { @@ -258,20 +332,21 @@ int32_t buffer_list(struct command_ctx ctx, int argc, const char *argv[]) { .fn = buflist_visit_cmd, }; + static struct command buflist_kill = { + .name = "buflist-kill", + .fn = buflist_kill_cmd, + }; + static struct command buflist_close = { .name = "buflist-close", .fn = buflist_close_cmd, }; - static struct command buflist_refresh = { - .name = "buflist-refresh", - .fn = buflist_refresh_cmd, - }; - struct binding bindings[] = { - ANONYMOUS_BINDING(Ctrl, 'M', &buflist_visit), + ANONYMOUS_BINDING(ENTER, &buflist_visit), + ANONYMOUS_BINDING(None, 'k', &buflist_kill), ANONYMOUS_BINDING(None, 'q', &buflist_close), - ANONYMOUS_BINDING(None, 'g', &buflist_refresh), + ANONYMOUS_BINDING(None, 'g', &buflist_refresh_command), }; struct keymap km = keymap_create("buflist", 8); keymap_bind_keys(&km, bindings, sizeof(bindings) / sizeof(bindings[0])); @@ -396,6 +471,7 @@ void register_global_commands(struct commands *commands, {.name = "write-file", .fn = write_file}, {.name = "run-command-interactive", .fn = run_interactive}, {.name = "switch-buffer", .fn = switch_buffer}, + {.name = "kill-buffer", .fn = kill_buffer}, {.name = "abort", .fn = _abort}, {.name = "timers", .fn = timers}, {.name = "buffer-list", .fn = buffer_list}, diff --git a/src/main/main.c b/src/main/main.c index 927785e..6048b63 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -61,7 +61,7 @@ void segfault() { display_destroy(display); } - printf("Segfault encountered...\n"); + fprintf(stderr, "Segfault encountered...\n"); abort(); } @@ -289,8 +289,8 @@ int main(int argc, char *argv[]) { struct buffer *ib = buffers_add(&buflist, initial_buffer); - windows_init(display_height(display), display_width(display), ib, - &minibuffer); + windows_init(display_height(display), display_width(display), ib, &minibuffer, + &buflist); struct window *active = windows_get_active(); if (goto_end) { buffer_view_goto_end(window_buffer_view(active)); diff --git a/test/minibuffer.c b/test/minibuffer.c index 5243b6c..28ee277 100644 --- a/test/minibuffer.c +++ b/test/minibuffer.c @@ -28,7 +28,7 @@ void init() { } minibuffer_init(&b, &bufs); - windows_init(100, 100, &b, &b); + windows_init(100, 100, &b, &b, &bufs); } void destroy() { |
