Mercurial > vim
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 */ |