URI: 
       tFix crash on closing view - ledit - Text editor (WIP)
  HTML git clone git://lumidify.org/ledit.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit b4b11228f9a7851bd47ceb8e9e31d8a3a857af79
   DIR parent d3e5c88151dca9a99f6c62bd0526391eecfc15cd
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Sun, 26 Dec 2021 19:10:08 +0100
       
       Fix crash on closing view
       
       Diffstat:
         M buffer.c                            |       2 +-
         M keys_command.c                      |      12 ++++++++----
         M ledit.1                             |       4 ++++
         M ledit.c                             |      23 +++++++++++++++++++++++
         M view.c                              |       1 +
         M view.h                              |       1 +
       
       6 files changed, 38 insertions(+), 5 deletions(-)
       ---
   DIR diff --git a/buffer.c b/buffer.c
       t@@ -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 *));
                }
        }
        
   DIR diff --git a/keys_command.c b/keys_command.c
       t@@ -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;
        }
   DIR diff --git a/ledit.1 b/ledit.1
       t@@ -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.
   DIR diff --git a/ledit.c b/ledit.c
       t@@ -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) {
   DIR diff --git a/view.c b/view.c
       t@@ -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;
   DIR diff --git a/view.h b/view.h
       t@@ -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 */