Skip to content

Commit 2c0d7bf

Browse files
committed
Fix sporadic crash when pressing enter
What happened here is that when a buffer (like for example the choice-buffer) is killed, it left keybindings behind. Since the buffer list is a pool, the next opened buffer would get the same buffer pointer and therefore also inherit the keybindings. This makes sure that when buffers are removed, their keymaps are cleared. Also, make sure that completion state for a buffer is removed when the buffer is removed.
1 parent 522ddb0 commit 2c0d7bf

6 files changed

Lines changed: 120 additions & 12 deletions

File tree

src/main/bindings.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ struct buffer_keymap {
1919
struct keymap keymap;
2020
};
2121

22-
static VEC(struct buffer_keymap) g_buffer_keymaps;
22+
typedef VEC(struct buffer_keymap) buffer_keymap_vec;
23+
24+
static buffer_keymap_vec g_buffer_keymaps;
2325
static buffer_keymap_id g_current_keymap_id;
2426

2527
struct keymap *buffer_default_keymap(void) { return &g_buffer_default_keymap; }
@@ -194,6 +196,19 @@ void buffer_remove_keymap(buffer_keymap_id id) {
194196
}
195197
}
196198

199+
void buffer_remove_keymaps(struct buffer *buffer) {
200+
buffer_keymap_vec new;
201+
VEC_INIT(&new, VEC_SIZE(&g_buffer_keymaps));
202+
VEC_FOR_EACH_INDEXED(&g_buffer_keymaps, struct buffer_keymap * km, i) {
203+
if (km->buffer != buffer) {
204+
VEC_PUSH(&new, *km);
205+
}
206+
}
207+
208+
VEC_DESTROY(&g_buffer_keymaps);
209+
g_buffer_keymaps = new;
210+
}
211+
197212
uint32_t buffer_keymaps(struct buffer *buffer, struct keymap *keymaps[],
198213
uint32_t max_nkeymaps) {
199214
uint32_t nkeymaps = 0;

src/main/bindings.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#ifndef _BINDINGS_H
2+
#define _BINDINGS_H
3+
14
#include <stdint.h>
25

36
#include "dged/hook.h"
@@ -6,19 +9,89 @@ struct keymap;
69
struct buffer;
710
struct binding;
811

12+
/**
13+
* Intialize all structures for bindings and set
14+
* default bindings up.
15+
*/
916
void init_bindings(void);
1017

18+
/**
19+
* Get the default keymap for buffers.
20+
*
21+
* @returns The default buffer keymap.
22+
*/
1123
struct keymap *buffer_default_keymap(void);
1224

25+
/** Id for a keymap currently added to a buffer. */
1326
typedef uint64_t buffer_keymap_id;
27+
28+
/**
29+
* Add a keymap to a buffer.
30+
*
31+
* @param [in] buffer The buffer to add the keymap to.
32+
* @param [in] keymap The keymap to add.
33+
*
34+
* @returns A keymap id that can be used to refer to this keymap-buffer
35+
* combination.
36+
*/
1437
buffer_keymap_id buffer_add_keymap(struct buffer *buffer, struct keymap keymap);
38+
39+
/**
40+
* Remove a keymap for a buffer.
41+
*
42+
* @param [in] id The id for the buffer keymap to remove.
43+
*/
1544
void buffer_remove_keymap(buffer_keymap_id id);
45+
46+
/**
47+
* Retrieve keymaps for a buffer.
48+
*
49+
* @param [in] buffer The buffer to get applicable keymaps for.
50+
* @param [in] keymaps An array to store keymaps in.
51+
* @param [in] The capacity of @ref keymaps.
52+
* @returns The number of keymaps stored in @ref keymaps.
53+
*/
1654
uint32_t buffer_keymaps(struct buffer *buffer, struct keymap *keymaps[],
1755
uint32_t max_nkeymaps);
1856

57+
/**
58+
* Remove all keymaps for a buffer.
59+
*
60+
* @param [in] buffer The buffer to remove keymaps for.
61+
*/
62+
void buffer_remove_keymaps(struct buffer *buffer);
63+
64+
/** Callback for a buffer keymaps hook */
1965
typedef uint32_t (*buffer_keymaps_cb)(struct buffer *, struct keymap **,
2066
uint32_t, void *);
67+
68+
/**
69+
* Add a hook for buffer keymaps
70+
*
71+
* This makes it possible to programatically append to the list that
72+
* is returned by @ref buffer_keymaps.
73+
*
74+
* @param [in] callback The callback function to call.
75+
* @param [in] userdata The userdata to pass to the callback function.
76+
*
77+
@ @returns The hook id.
78+
*/
2179
uint32_t buffer_add_keymaps_hook(buffer_keymaps_cb callback, void *userdata);
80+
81+
/**
82+
* Remove a previously added hook for buffer keymaps.
83+
*
84+
* @param [in] id The id of the hook to remove.
85+
* @param [in] callback A callback function called with the userdata of the
86+
* original hook for doing cleanup.
87+
*/
2288
void buffer_remove_keymaps_hook(uint32_t id, remove_hook_cb callback);
2389

90+
/**
91+
* Tear down the structures for bindings.
92+
*
93+
* Symmetric to @ref init_bindings.
94+
*/
2495
void destroy_bindings(void);
96+
97+
#endif

src/main/cmds.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ int32_t do_kill_buffer(struct command_ctx ctx, int argc, const char *argv[]) {
184184
bufname = argv[0];
185185
}
186186

187-
if (buffers_remove(ctx.buffers, bufname)) {
188-
return 0;
189-
} else {
187+
if (!buffers_remove(ctx.buffers, bufname)) {
190188
minibuffer_echo_timeout(4, "buffer %s not found", bufname);
191189
return 1;
192190
}
191+
192+
return 0;
193193
}
194194

195195
COMMAND_FN("do-kill-buffer", do_kill_buffer, do_kill_buffer, NULL)

src/main/completion.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,14 @@ static void on_buffer_delete(struct buffer *buffer, struct edit_location edit,
388388
on_buffer_changed(buffer, edit, true, userdata);
389389
}
390390

391+
static void on_buffer_destroy(struct buffer *buffer,
392+
struct completion_state *state) {
393+
(void)state;
394+
395+
// remove the buffer from our state
396+
disable_completion(buffer);
397+
}
398+
391399
static void completions_buffer_deleted(struct buffer *buffer, void *userdata) {
392400
(void)buffer;
393401
struct completion_state *state = (struct completion_state *)userdata;
@@ -441,6 +449,9 @@ void add_completion_providers(struct buffer *source,
441449
uint32_t remove_hook_id =
442450
buffer_add_delete_hook(source, on_buffer_delete, &g_state);
443451

452+
buffer_add_destroy_hook(source, (destroy_hook_cb)on_buffer_destroy,
453+
&g_state);
454+
444455
new_comp->buffer = source;
445456
new_comp->insert_hook_id = insert_hook_id;
446457
new_comp->remove_hook_id = remove_hook_id;

src/main/lsp/choice-buffer.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ struct choice_buffer {
3030

3131
struct command enter_pressed;
3232
struct command q_pressed;
33+
34+
buffer_keymap_id keymap_id;
3335
};
3436

3537
static void delete_choice_buffer(struct choice_buffer *buffer,
@@ -126,7 +128,7 @@ choice_buffer_create(struct s8 title, struct buffers *buffers,
126128

127129
struct keymap km = keymap_create("choice_buffer", 8);
128130
keymap_bind_keys(&km, bindings, sizeof(bindings) / sizeof(bindings[0]));
129-
buffer_add_keymap(b->buffer, km);
131+
b->keymap_id = buffer_add_keymap(b->buffer, km);
130132

131133
struct location begin = buffer_end(b->buffer);
132134
buffer_add(b->buffer, buffer_end(b->buffer), title.s, title.l);
@@ -195,6 +197,7 @@ static void delete_choice_buffer(struct choice_buffer *buffer,
195197
if (delete_underlying) {
196198
buffer_remove_destroy_hook(buffer->buffer, buffer->buffer_removed_hook,
197199
NULL);
200+
buffer_remove_keymap(buffer->keymap_id);
198201
buffers_remove(buffer->buffers, buffer->buffer->name);
199202
}
200203

src/main/main.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ void *frame_alloc(size_t sz) {
5858

5959
static bool running = true;
6060

61-
void terminate(void) { running = false; }
62-
void terminate2(int sig) {
61+
static void terminate(void) { running = false; }
62+
static void terminate2(int sig) {
6363
(void)sig;
6464
running = false;
6565
}
6666

6767
static struct display *display = NULL;
6868
static bool display_resized = false;
69-
void resized(int sig) {
69+
static void resized(int sig) {
7070
(void)sig;
7171
if (display != NULL) {
7272
display_resize(display);
@@ -76,7 +76,7 @@ void resized(int sig) {
7676
signal(SIGWINCH, resized);
7777
}
7878

79-
void terminal_stop(int sig) {
79+
static void terminal_stop(int sig) {
8080
(void)sig;
8181
if (display != NULL) {
8282
display_clear(display);
@@ -88,14 +88,14 @@ void terminal_stop(int sig) {
8888
#endif
8989
}
9090

91-
void suspend() { terminal_stop(0); }
91+
static void suspend() { terminal_stop(0); }
9292

93-
void resume(int sig) {
93+
static void resume(int sig) {
9494
(void)sig;
9595
display_initialize(display);
9696
}
9797

98-
void handle_crash(int sig) {
98+
static void handle_crash(int sig) {
9999
(void)sig;
100100

101101
// make an effort to restore the
@@ -116,6 +116,11 @@ void handle_crash(int sig) {
116116
}
117117
}
118118

119+
static void cleanup_buffer_bindings(struct buffer *buffer, void *userdata) {
120+
(void)userdata;
121+
buffer_remove_keymaps(buffer);
122+
}
123+
119124
#define INVALID_WATCH (uint32_t) - 1
120125

121126
struct watched_file {
@@ -322,6 +327,7 @@ int main(int argc, char *argv[]) {
322327
minibuffer_init(&minibuffer, &buflist);
323328

324329
buffers_add_add_hook(&buflist, watch_file, (void *)reactor);
330+
buffers_add_remove_hook(&buflist, cleanup_buffer_bindings, NULL);
325331

326332
init_bindings();
327333

0 commit comments

Comments
 (0)