commit b4b11228f9a7851bd47ceb8e9e31d8a3a857af79
parent d3e5c88151dca9a99f6c62bd0526391eecfc15cd
Author: lumidify <nobody@lumidify.org>
Date: Sun, 26 Dec 2021 19:10:08 +0100
Fix crash on closing view
Diffstat:
6 files changed, 38 insertions(+), 5 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -311,7 +311,7 @@ buffer_remove_view(ledit_buffer *buffer, ledit_view *view) {
buffer->views + i + 1,
(buffer->views_num - i - 1) * sizeof(ledit_view *)
);
- ledit_reallocarray(buffer->views, --buffer->views_num, sizeof(ledit_view *));
+ buffer->views = ledit_reallocarray(buffer->views, --buffer->views_num, sizeof(ledit_view *));
}
}
diff --git a/keys_command.c b/keys_command.c
@@ -199,11 +199,15 @@ close_view(ledit_view *view, char *cmd, size_t l1, size_t l2) {
(void)l2;
/* FIXME: This will lead to problems if I add something that
requires access to the view after the command is handled. */
+ cmd++;
+ int force = 0;
+ if (*cmd == '!')
+ force = 1;
ledit_buffer *buffer = view->buffer;
- buffer_remove_view(buffer, view);
- if (buffer->views_num == 0) {
- ledit_cleanup();
- exit(0);
+ if (buffer->views_num == 1 && buffer->modified && !force) {
+ window_show_message(view->window, "File modified; write or use ! to override", -1);
+ } else {
+ view->destroy = 1;
}
return 0;
}
diff --git a/ledit.1 b/ledit.1
@@ -801,6 +801,10 @@ Confirm each substitution before performing it.
Open a new view.
Each view is a window that shows the text in the current buffer,
which is synced between the views.
+.It Cm :c
+Close a view.
+.It Cm :c\&!
+Close a view, even if it is the last one and there are unsaved changes.
.El
.Sh MOUSE ACTIONS
There currently are not many mouse actions.
diff --git a/ledit.c b/ledit.c
@@ -84,6 +84,29 @@ mainloop(void) {
clock_gettime(CLOCK_MONOTONIC, &last);
sleep_time.tv_sec = 0;
while (running) {
+ /* This "lazy destroying" is not entirely ideal yet, but it's
+ necessary to avoid a crash when closing a view (I'm not
+ entirely sure what exactly causes the crash)
+ -> Update: The cause of the crash was something different,
+ but I'm still leaving it as is for now because there
+ may be other reasons for doing it lazily. */
+ for (size_t i = 0; i < buffer->views_num; i++) {
+ if (buffer->views[i]->destroy) {
+ buffer_remove_view(buffer, buffer->views[i]);
+ if (buffer->views_num == 0) {
+ ledit_cleanup();
+ exit(0);
+ }
+ /* only delete one - otherwise,
+ the loop would need to be
+ modified
+ I guess it's unrealistic to
+ assume that the deletion cmd
+ will be called multiple times
+ in such a short time anyways */
+ break;
+ }
+ }
while (XPending(common.dpy)) {
XNextEvent(common.dpy, &event);
if (event.type == xkb_event_type) {
diff --git a/view.c b/view.c
@@ -131,6 +131,7 @@ view_create(ledit_buffer *buffer, ledit_theme *theme, ledit_mode mode, size_t li
view->display_offset = 0;
view->sel.line1 = view->sel.byte1 = 0;
view->sel.line2 = view->sel.byte2 = 0;
+ view->destroy = 0;
view->button2_pressed = 0;
view->selecting = 0;
view->sel_valid = 0;
diff --git a/view.h b/view.h
@@ -77,6 +77,7 @@ struct ledit_view {
long display_offset; /* current pixel offset of viewport */
ledit_range sel; /* current selection */
ledit_mode mode; /* current mode of this view */
+ char destroy; /* whether the view should be destroyed at the next possible time */
char selecting; /* whether user is currently selecting text with mouse */
char button2_pressed; /* whether button 2 (middle button) is pressed */
char sel_valid; /* whether there is currently a valid selection */