From 1b888cc723792ec0e49c7e5aaa78c3c5486a95b9 Mon Sep 17 00:00:00 2001 From: Albert Cervin Date: Tue, 26 Mar 2024 10:59:06 +0100 Subject: Implement kill-buffer command Can be killed with the command `kill-buffer`, the shortcut `C-x k` or from the buffer menu. --- src/dged/buffer_view.c | 3 ++ src/dged/buffers.c | 96 +++++++++++++++++++++++++++++++++++++++++++------- src/dged/buffers.h | 11 +++++- src/dged/window.c | 95 ++++++++++++++++++++++++++++++++++++++++++------- src/dged/window.h | 8 +++-- 5 files changed, 184 insertions(+), 29 deletions(-) (limited to 'src/dged') 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 #include - #include +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 #include 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); -- cgit v1.2.3