comparison src/window.c @ 17516:711db62c8aca v8.1.1756

patch 8.1.1756: autocommand that splits window messes up window layout commit https://github.com/vim/vim/commit/1417c766f55e5959b31da488417b7d9b141404af Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jul 27 17:31:36 2019 +0200 patch 8.1.1756: autocommand that splits window messes up window layout 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.
author Bram Moolenaar <Bram@vim.org>
date Sat, 27 Jul 2019 17:45:06 +0200
parents 984cc7258468
children 1be29c149103
comparison
equal deleted inserted replaced
17515:ea9798fcdb36 17516:711db62c8aca
64 64
65 #define ROWS_AVAIL (Rows - p_ch - tabline_height()) 65 #define ROWS_AVAIL (Rows - p_ch - tabline_height())
66 66
67 static char *m_onlyone = N_("Already only one window"); 67 static char *m_onlyone = N_("Already only one window");
68 68
69 // When non-zero splitting a window is forbidden. Used to avoid that nasty
70 // autocommands mess up the window structure.
71 static int split_disallowed = 0;
72
73 // #define WIN_DEBUG
74 #ifdef WIN_DEBUG
75 /*
76 * Call this method to log the current window layout.
77 */
78 static void
79 log_frame_layout(frame_T *frame)
80 {
81 ch_log(NULL, "layout %s, wi: %d, he: %d, wwi: %d, whe: %d, id: %d",
82 frame->fr_layout == FR_LEAF ? "LEAF"
83 : frame->fr_layout == FR_ROW ? "ROW" : "COL",
84 frame->fr_width,
85 frame->fr_height,
86 frame->fr_win == NULL ? -1 : frame->fr_win->w_width,
87 frame->fr_win == NULL ? -1 : frame->fr_win->w_height,
88 frame->fr_win == NULL ? -1 : frame->fr_win->w_id);
89 if (frame->fr_child != NULL)
90 {
91 ch_log(NULL, "children");
92 log_frame_layout(frame->fr_child);
93 if (frame->fr_next != NULL)
94 ch_log(NULL, "END of children");
95 }
96 if (frame->fr_next != NULL)
97 log_frame_layout(frame->fr_next);
98 }
99 #endif
100
69 /* 101 /*
70 * All CTRL-W window commands are handled here, called from normal_cmd(). 102 * All CTRL-W window commands are handled here, called from normal_cmd().
71 */ 103 */
72 void 104 void
73 do_window( 105 do_window(
716 if (Prenum > 0) 748 if (Prenum > 0)
717 vim_snprintf((char *)bufp + len, bufsize - len, "%ld", Prenum); 749 vim_snprintf((char *)bufp + len, bufsize - len, "%ld", Prenum);
718 } 750 }
719 751
720 /* 752 /*
753 * If "split_disallowed" is set given an error and return FAIL.
754 * Otherwise return OK.
755 */
756 static int
757 check_split_disallowed()
758 {
759 if (split_disallowed > 0)
760 {
761 emsg(_("E242: Can't split a window while closing another"));
762 return FAIL;
763 }
764 return OK;
765 }
766
767 /*
721 * split the current window, implements CTRL-W s and :split 768 * split the current window, implements CTRL-W s and :split
722 * 769 *
723 * "size" is the height or width for the new window, 0 to use half of current 770 * "size" is the height or width for the new window, 0 to use half of current
724 * height or width. 771 * height or width.
725 * 772 *
747 if ((flags & WSP_TOP) && (flags & WSP_BOT)) 794 if ((flags & WSP_TOP) && (flags & WSP_BOT))
748 { 795 {
749 emsg(_("E442: Can't split topleft and botright at the same time")); 796 emsg(_("E442: Can't split topleft and botright at the same time"));
750 return FAIL; 797 return FAIL;
751 } 798 }
799 if (check_split_disallowed() == FAIL)
800 return FAIL;
752 801
753 /* When creating the help window make a snapshot of the window layout. 802 /* When creating the help window make a snapshot of the window layout.
754 * Otherwise clear the snapshot, it's now invalid. */ 803 * Otherwise clear the snapshot, it's now invalid. */
755 if (flags & WSP_HELP) 804 if (flags & WSP_HELP)
756 make_snapshot(SNAP_HELP_IDX); 805 make_snapshot(SNAP_HELP_IDX);
880 win_setwidth_win(oldwin->w_width + new_size + 1, oldwin); 929 win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
881 930
882 /* Only make all windows the same width if one of them (except oldwin) 931 /* Only make all windows the same width if one of them (except oldwin)
883 * is wider than one of the split windows. */ 932 * is wider than one of the split windows. */
884 if (!do_equal && p_ea && size == 0 && *p_ead != 'v' 933 if (!do_equal && p_ea && size == 0 && *p_ead != 'v'
885 && oldwin->w_frame->fr_parent != NULL) 934 && oldwin->w_frame->fr_parent != NULL)
886 { 935 {
887 frp = oldwin->w_frame->fr_parent->fr_child; 936 frp = oldwin->w_frame->fr_parent->fr_child;
888 while (frp != NULL) 937 while (frp != NULL)
889 { 938 {
890 if (frp->fr_win != oldwin && frp->fr_win != NULL 939 if (frp->fr_win != oldwin && frp->fr_win != NULL
1709 if (ONE_WINDOW) 1758 if (ONE_WINDOW)
1710 { 1759 {
1711 beep_flush(); 1760 beep_flush();
1712 return; 1761 return;
1713 } 1762 }
1763 if (check_split_disallowed() == FAIL)
1764 return;
1714 1765
1715 /* Remove the window and frame from the tree of frames. */ 1766 /* Remove the window and frame from the tree of frames. */
1716 (void)winframe_remove(curwin, &dir, NULL); 1767 (void)winframe_remove(curwin, &dir, NULL);
1717 win_remove(curwin, NULL); 1768 win_remove(curwin, NULL);
1718 last_status(FALSE); /* may need to remove last status line */ 1769 last_status(FALSE); /* may need to remove last status line */
1748 return; 1799 return;
1749 1800
1750 /* check if there is something to do */ 1801 /* check if there is something to do */
1751 if (win2->w_next != win1) 1802 if (win2->w_next != win1)
1752 { 1803 {
1804 if (win1->w_frame->fr_parent != win2->w_frame->fr_parent)
1805 {
1806 iemsg("INTERNAL: trying to move a window into another frame");
1807 return;
1808 }
1809
1753 /* may need move the status line/vertical separator of the last window 1810 /* may need move the status line/vertical separator of the last window
1754 * */ 1811 * */
1755 if (win1 == lastwin) 1812 if (win1 == lastwin)
1756 { 1813 {
1757 height = win1->w_prev->w_status_height; 1814 height = win1->w_prev->w_status_height;
2488 * other window. */ 2545 * other window. */
2489 if (!win_valid(win) || last_window() 2546 if (!win_valid(win) || last_window()
2490 || close_last_window_tabpage(win, free_buf, prev_curtab)) 2547 || close_last_window_tabpage(win, free_buf, prev_curtab))
2491 return FAIL; 2548 return FAIL;
2492 2549
2550 // Now we are really going to close the window. Disallow any autocommand
2551 // to split a window to avoid trouble.
2552 ++split_disallowed;
2553
2493 /* Free the memory used for the window and get the window that received 2554 /* Free the memory used for the window and get the window that received
2494 * the screen space. */ 2555 * the screen space. */
2495 wp = win_free_mem(win, &dir, NULL); 2556 wp = win_free_mem(win, &dir, NULL);
2496 2557
2497 /* Make sure curwin isn't invalid. It can cause severe trouble when 2558 /* Make sure curwin isn't invalid. It can cause severe trouble when
2541 win_enter_ext(wp, FALSE, TRUE, FALSE, TRUE, TRUE); 2602 win_enter_ext(wp, FALSE, TRUE, FALSE, TRUE, TRUE);
2542 if (other_buffer) 2603 if (other_buffer)
2543 /* careful: after this wp and win may be invalid! */ 2604 /* careful: after this wp and win may be invalid! */
2544 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); 2605 apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
2545 } 2606 }
2607
2608 --split_disallowed;
2546 2609
2547 /* 2610 /*
2548 * If last window has a status line now and we don't want one, 2611 * If last window has a status line now and we don't want one,
2549 * remove the status line. 2612 * remove the status line.
2550 */ 2613 */