Patch 8.1.1756
Problem:    Autocommand that splits window messes up window layout.
Solution:   Disallow splitting a window while closing one.  In ":all" give an
            error when moving a window will not work.
Files:      src/buffer.c, src/window.c, src/testdir/test_window_cmd.vim


*** ../vim-8.1.1755/src/buffer.c        2019-07-21 19:25:16.650609440 +0200
--- src/buffer.c        2019-07-27 17:23:37.408727673 +0200
***************
*** 5101,5106 ****
--- 5101,5113 ----
                            new_curwin = wpnext;
                            new_curtab = curtab;
                        }
+                       else if (wpnext->w_frame->fr_parent
+                                                != curwin->w_frame->fr_parent)
+                       {
+                           emsg(_("E249: window layout changed unexpectedly"));
+                           i = count;
+                           break;
+                       }
                        else
                            win_move_after(wpnext, curwin);
                        break;
*** ../vim-8.1.1755/src/window.c        2019-07-26 22:22:34.468383292 +0200
--- src/window.c        2019-07-27 17:26:26.068802167 +0200
***************
*** 66,71 ****
--- 66,103 ----
  
  static char *m_onlyone = N_("Already only one window");
  
+ // When non-zero splitting a window is forbidden.  Used to avoid that nasty
+ // autocommands mess up the window structure.
+ static int split_disallowed = 0;
+ 
+ // #define WIN_DEBUG
+ #ifdef WIN_DEBUG
+ /*
+  * Call this method to log the current window layout.
+  */
+     static void
+ log_frame_layout(frame_T *frame)
+ {
+     ch_log(NULL, "layout %s, wi: %d, he: %d, wwi: %d, whe: %d, id: %d",
+           frame->fr_layout == FR_LEAF ? "LEAF"
+                                 : frame->fr_layout == FR_ROW ? "ROW" : "COL",
+           frame->fr_width,
+           frame->fr_height,
+           frame->fr_win == NULL ? -1 : frame->fr_win->w_width,
+           frame->fr_win == NULL ? -1 : frame->fr_win->w_height,
+           frame->fr_win == NULL ? -1 : frame->fr_win->w_id);
+     if (frame->fr_child != NULL)
+     {
+       ch_log(NULL, "children");
+       log_frame_layout(frame->fr_child);
+       if (frame->fr_next != NULL)
+           ch_log(NULL, "END of children");
+     }
+     if (frame->fr_next != NULL)
+       log_frame_layout(frame->fr_next);
+ }
+ #endif
+ 
  /*
   * All CTRL-W window commands are handled here, called from normal_cmd().
   */
***************
*** 718,723 ****
--- 750,770 ----
  }
  
  /*
+  * If "split_disallowed" is set given an error and return FAIL.
+  * Otherwise return OK.
+  */
+     static int
+ check_split_disallowed()
+ {
+     if (split_disallowed > 0)
+     {
+       emsg(_("E242: Can't split a window while closing another"));
+       return FAIL;
+     }
+     return OK;
+ }
+ 
+ /*
   * split the current window, implements CTRL-W s and :split
   *
   * "size" is the height or width for the new window, 0 to use half of current
***************
*** 749,754 ****
--- 796,803 ----
        emsg(_("E442: Can't split topleft and botright at the same time"));
        return FAIL;
      }
+     if (check_split_disallowed() == FAIL)
+       return FAIL;
  
      /* When creating the help window make a snapshot of the window layout.
       * Otherwise clear the snapshot, it's now invalid. */
***************
*** 882,888 ****
        /* Only make all windows the same width if one of them (except oldwin)
         * is wider than one of the split windows. */
        if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
!          && oldwin->w_frame->fr_parent != NULL)
        {
            frp = oldwin->w_frame->fr_parent->fr_child;
            while (frp != NULL)
--- 931,937 ----
        /* Only make all windows the same width if one of them (except oldwin)
         * is wider than one of the split windows. */
        if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
!                                        && oldwin->w_frame->fr_parent != NULL)
        {
            frp = oldwin->w_frame->fr_parent->fr_child;
            while (frp != NULL)
***************
*** 1711,1716 ****
--- 1760,1767 ----
        beep_flush();
        return;
      }
+     if (check_split_disallowed() == FAIL)
+       return;
  
      /* Remove the window and frame from the tree of frames. */
      (void)winframe_remove(curwin, &dir, NULL);
***************
*** 1750,1755 ****
--- 1801,1812 ----
      /* check if there is something to do */
      if (win2->w_next != win1)
      {
+       if (win1->w_frame->fr_parent != win2->w_frame->fr_parent)
+       {
+           iemsg("INTERNAL: trying to move a window into another frame");
+           return;
+       }
+ 
        /* may need move the status line/vertical separator of the last window
         * */
        if (win1 == lastwin)
***************
*** 2490,2495 ****
--- 2547,2556 ----
            || close_last_window_tabpage(win, free_buf, prev_curtab))
        return FAIL;
  
+     // Now we are really going to close the window.  Disallow any autocommand
+     // to split a window to avoid trouble.
+     ++split_disallowed;
+ 
      /* Free the memory used for the window and get the window that received
       * the screen space. */
      wp = win_free_mem(win, &dir, NULL);
***************
*** 2544,2549 ****
--- 2605,2612 ----
            apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
      }
  
+     --split_disallowed;
+ 
      /*
       * If last window has a status line now and we don't want one,
       * remove the status line.
*** ../vim-8.1.1755/src/testdir/test_window_cmd.vim     2019-07-13 
18:08:56.182316876 +0200
--- src/testdir/test_window_cmd.vim     2019-07-27 17:23:09.224684983 +0200
***************
*** 531,544 ****
  endfunc
  
  func Test_access_freed_mem()
    " This was accessing freed memory
    au * 0 vs xxx
    arg 0
    argadd
!   all
!   all
    au!
    bwipe xxx
  endfunc
  
  func Test_visual_cleared_after_window_split()
--- 531,545 ----
  endfunc
  
  func Test_access_freed_mem()
+   call assert_equal(&columns, winwidth(0))
    " This was accessing freed memory
    au * 0 vs xxx
    arg 0
    argadd
!   call assert_fails("all", "E249:")
    au!
    bwipe xxx
+   call assert_equal(&columns, winwidth(0))
  endfunc
  
  func Test_visual_cleared_after_window_split()
*** ../vim-8.1.1755/src/version.c       2019-07-26 22:22:34.468383292 +0200
--- src/version.c       2019-07-27 16:11:18.682053334 +0200
***************
*** 779,780 ****
--- 779,782 ----
  {   /* Add new patch number below this line */
+ /**/
+     1756,
  /**/

-- 
            |

Ceci n'est pas une pipe.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201907271532.x6RFW4i3011944%40masaka.moolenaar.net.

Raspunde prin e-mail lui