comparison src/autocmd.c @ 31263:d8e7d725a666 v9.0.0965

patch 9.0.0965: using one window for executing autocommands is insufficient Commit: https://github.com/vim/vim/commit/e76062c078debed0df818f70e4db14ad7a7cb53a Author: Bram Moolenaar <Bram@vim.org> Date: Mon Nov 28 18:51:43 2022 +0000 patch 9.0.0965: using one window for executing autocommands is insufficient Problem: Using one window for executing autocommands is insufficient. Solution: Use up to five windows for executing autocommands.
author Bram Moolenaar <Bram@vim.org>
date Mon, 28 Nov 2022 20:00:05 +0100
parents a86ee6c0309e
children 4bc9cd62d378
comparison
equal deleted inserted replaced
31262:7f766b7e17d5 31263:d8e7d725a666
627 msg_clr_eos(); 627 msg_clr_eos();
628 msg_end(); 628 msg_end();
629 } 629 }
630 } 630 }
631 631
632 void
633 autocmd_init(void)
634 {
635 CLEAR_FIELD(aucmd_win);
636 }
637
632 #if defined(EXITFREE) || defined(PROTO) 638 #if defined(EXITFREE) || defined(PROTO)
633 void 639 void
634 free_all_autocmds(void) 640 free_all_autocmds(void)
635 { 641 {
636 int i;
637 char_u *s; 642 char_u *s;
638 643
639 for (current_augroup = -1; current_augroup < augroups.ga_len; 644 for (current_augroup = -1; current_augroup < augroups.ga_len;
640 ++current_augroup) 645 ++current_augroup)
641 do_autocmd(NULL, (char_u *)"", TRUE); 646 do_autocmd(NULL, (char_u *)"", TRUE);
642 647
643 for (i = 0; i < augroups.ga_len; ++i) 648 for (int i = 0; i < augroups.ga_len; ++i)
644 { 649 {
645 s = ((char_u **)(augroups.ga_data))[i]; 650 s = ((char_u **)(augroups.ga_data))[i];
646 if (s != get_deleted_augroup()) 651 if (s != get_deleted_augroup())
647 vim_free(s); 652 vim_free(s);
648 } 653 }
649 ga_clear(&augroups); 654 ga_clear(&augroups);
655
656 for (int i = 0; i < AUCMD_WIN_COUNT; ++i)
657 if (aucmd_win[i].auc_win_used)
658 {
659 aucmd_win[i].auc_win_used = FALSE;
660 win_remove(aucmd_win[i].auc_win, NULL);
661 }
650 } 662 }
651 #endif 663 #endif
664
665 /*
666 * Return TRUE if "win" is an active entry in aucmd_win[].
667 */
668 int
669 is_aucmd_win(win_T *win)
670 {
671 for (int i = 0; i < AUCMD_WIN_COUNT; ++i)
672 if (aucmd_win[i].auc_win_used && aucmd_win[i].auc_win == win)
673 return TRUE;
674 return FALSE;
675 }
652 676
653 /* 677 /*
654 * Return the event number for event name "start". 678 * Return the event number for event name "start".
655 * Return NUM_EVENTS if the event name was not found. 679 * Return NUM_EVENTS if the event name was not found.
656 * Return a pointer to the next event name in "end". 680 * Return a pointer to the next event name in "end".
1436 { 1460 {
1437 // Only do loaded buffers and skip the current buffer, it's done last. 1461 // Only do loaded buffers and skip the current buffer, it's done last.
1438 if (buf->b_ml.ml_mfp == NULL || buf == curbuf) 1462 if (buf->b_ml.ml_mfp == NULL || buf == curbuf)
1439 continue; 1463 continue;
1440 1464
1441 // find a window for this buffer and save some values 1465 // Find a window for this buffer and save some values.
1442 aucmd_prepbuf(&aco, buf); 1466 aucmd_prepbuf(&aco, buf);
1467 if (curbuf != buf)
1468 {
1469 // Failed to find a window for this buffer. Better not execute
1470 // autocommands then.
1471 retval = FAIL;
1472 break;
1473 }
1474
1443 set_bufref(&bufref, buf); 1475 set_bufref(&bufref, buf);
1444 1476
1445 // execute the autocommands for this buffer 1477 // execute the autocommands for this buffer
1446 retval = do_doautocmd(arg, FALSE, &did_aucmd); 1478 retval = do_doautocmd(arg, FALSE, &did_aucmd);
1447 1479
1448 if (call_do_modelines && did_aucmd) 1480 if (call_do_modelines && did_aucmd)
1449 // Execute the modeline settings, but don't set window-local 1481 // Execute the modeline settings, but don't set window-local
1450 // options if we are using the current window for another 1482 // options if we are using the current window for another
1451 // buffer. 1483 // buffer.
1452 do_modelines(curwin == aucmd_win ? OPT_NOWIN : 0); 1484 do_modelines(is_aucmd_win(curwin) ? OPT_NOWIN : 0);
1453 1485
1454 // restore the current window 1486 // restore the current window
1455 aucmd_restbuf(&aco); 1487 aucmd_restbuf(&aco);
1456 1488
1457 // stop if there is some error or buffer was deleted 1489 // stop if there is some error or buffer was deleted
1488 } 1520 }
1489 1521
1490 /* 1522 /*
1491 * Prepare for executing autocommands for (hidden) buffer "buf". 1523 * Prepare for executing autocommands for (hidden) buffer "buf".
1492 * Search for a visible window containing the current buffer. If there isn't 1524 * Search for a visible window containing the current buffer. If there isn't
1493 * one then use "aucmd_win". 1525 * one then use an entry in "aucmd_win[]".
1494 * Set "curbuf" and "curwin" to match "buf". 1526 * Set "curbuf" and "curwin" to match "buf".
1527 * When this fails "curbuf" is not equal "buf".
1495 */ 1528 */
1496 void 1529 void
1497 aucmd_prepbuf( 1530 aucmd_prepbuf(
1498 aco_save_T *aco, // structure to save values in 1531 aco_save_T *aco, // structure to save values in
1499 buf_T *buf) // new curbuf 1532 buf_T *buf) // new curbuf
1510 else 1543 else
1511 FOR_ALL_WINDOWS(win) 1544 FOR_ALL_WINDOWS(win)
1512 if (win->w_buffer == buf) 1545 if (win->w_buffer == buf)
1513 break; 1546 break;
1514 1547
1515 // Allocate "aucmd_win" when needed. If this fails (out of memory) fall 1548 // Allocate a window when needed.
1516 // back to using the current window. 1549 win_T *auc_win = NULL;
1517 if (win == NULL && aucmd_win == NULL) 1550 int auc_idx = AUCMD_WIN_COUNT;
1518 { 1551 if (win == NULL)
1519 aucmd_win = win_alloc_popup_win(); 1552 {
1520 if (aucmd_win == NULL) 1553 for (auc_idx = 0; auc_idx < AUCMD_WIN_COUNT; ++auc_idx)
1521 win = curwin; 1554 if (!aucmd_win[auc_idx].auc_win_used)
1522 } 1555 {
1523 if (win == NULL && aucmd_win_used) 1556 auc_win = win_alloc_popup_win();
1524 // Strange recursive autocommand, fall back to using the current 1557 if (auc_win != NULL)
1525 // window. Expect a few side effects... 1558 {
1526 win = curwin; 1559 aucmd_win[auc_idx].auc_win = auc_win;
1560 aucmd_win[auc_idx].auc_win_used = TRUE;
1561 }
1562 break;
1563 }
1564
1565 // If this fails (out of memory or using all AUCMD_WIN_COUNT
1566 // entries) then we can't reliable execute the autocmd, return with
1567 // "curbuf" unequal "buf".
1568 if (auc_win == NULL)
1569 return;
1570 }
1527 1571
1528 aco->save_curwin_id = curwin->w_id; 1572 aco->save_curwin_id = curwin->w_id;
1529 aco->save_curbuf = curbuf; 1573 aco->save_curbuf = curbuf;
1530 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id; 1574 aco->save_prevwin_id = prevwin == NULL ? 0 : prevwin->w_id;
1531 if (win != NULL) 1575 if (win != NULL)
1532 { 1576 {
1533 // There is a window for "buf" in the current tab page, make it the 1577 // There is a window for "buf" in the current tab page, make it the
1534 // curwin. This is preferred, it has the least side effects (esp. if 1578 // curwin. This is preferred, it has the least side effects (esp. if
1535 // "buf" is curbuf). 1579 // "buf" is curbuf).
1536 aco->use_aucmd_win = FALSE; 1580 aco->use_aucmd_win_idx = -1;
1537 curwin = win; 1581 curwin = win;
1538 } 1582 }
1539 else 1583 else
1540 { 1584 {
1541 // There is no window for "buf", use "aucmd_win". To minimize the side 1585 // There is no window for "buf", use "auc_win". To minimize the side
1542 // effects, insert it in the current tab page. 1586 // effects, insert it in the current tab page.
1543 // Anything related to a window (e.g., setting folds) may have 1587 // Anything related to a window (e.g., setting folds) may have
1544 // unexpected results. 1588 // unexpected results.
1545 aco->use_aucmd_win = TRUE; 1589 aco->use_aucmd_win_idx = auc_idx;
1546 aucmd_win_used = TRUE; 1590
1547 1591 win_init_popup_win(auc_win, buf);
1548 win_init_popup_win(aucmd_win, buf);
1549 1592
1550 aco->globaldir = globaldir; 1593 aco->globaldir = globaldir;
1551 globaldir = NULL; 1594 globaldir = NULL;
1552 1595
1553 // Split the current window, put the aucmd_win in the upper half. 1596 // Split the current window, put the auc_win in the upper half.
1554 // We don't want the BufEnter or WinEnter autocommands. 1597 // We don't want the BufEnter or WinEnter autocommands.
1555 block_autocmds(); 1598 block_autocmds();
1556 make_snapshot(SNAP_AUCMD_IDX); 1599 make_snapshot(SNAP_AUCMD_IDX);
1557 save_ea = p_ea; 1600 save_ea = p_ea;
1558 p_ea = FALSE; 1601 p_ea = FALSE;
1563 p_acd = FALSE; 1606 p_acd = FALSE;
1564 #endif 1607 #endif
1565 1608
1566 // no redrawing and don't set the window title 1609 // no redrawing and don't set the window title
1567 ++RedrawingDisabled; 1610 ++RedrawingDisabled;
1568 (void)win_split_ins(0, WSP_TOP, aucmd_win, 0); 1611 (void)win_split_ins(0, WSP_TOP, auc_win, 0);
1569 --RedrawingDisabled; 1612 --RedrawingDisabled;
1570 (void)win_comp_pos(); // recompute window positions 1613 (void)win_comp_pos(); // recompute window positions
1571 p_ea = save_ea; 1614 p_ea = save_ea;
1572 #ifdef FEAT_AUTOCHDIR 1615 #ifdef FEAT_AUTOCHDIR
1573 p_acd = save_acd; 1616 p_acd = save_acd;
1574 #endif 1617 #endif
1575 unblock_autocmds(); 1618 unblock_autocmds();
1576 curwin = aucmd_win; 1619 curwin = auc_win;
1577 } 1620 }
1578 curbuf = buf; 1621 curbuf = buf;
1579 aco->new_curwin_id = curwin->w_id; 1622 aco->new_curwin_id = curwin->w_id;
1580 set_bufref(&aco->new_curbuf, curbuf); 1623 set_bufref(&aco->new_curbuf, curbuf);
1581 1624
1593 aco_save_T *aco) // structure holding saved values 1636 aco_save_T *aco) // structure holding saved values
1594 { 1637 {
1595 int dummy; 1638 int dummy;
1596 win_T *save_curwin; 1639 win_T *save_curwin;
1597 1640
1598 if (aco->use_aucmd_win) 1641 if (aco->use_aucmd_win_idx >= 0)
1599 { 1642 {
1643 win_T *awp = aucmd_win[aco->use_aucmd_win_idx].auc_win;
1644
1600 --curbuf->b_nwindows; 1645 --curbuf->b_nwindows;
1601 // Find "aucmd_win", it can't be closed, but it may be in another tab 1646 // Find "awp", it can't be closed, but it may be in another tab
1602 // page. Do not trigger autocommands here. 1647 // page. Do not trigger autocommands here.
1603 block_autocmds(); 1648 block_autocmds();
1604 if (curwin != aucmd_win) 1649 if (curwin != awp)
1605 { 1650 {
1606 tabpage_T *tp; 1651 tabpage_T *tp;
1607 win_T *wp; 1652 win_T *wp;
1608 1653
1609 FOR_ALL_TAB_WINDOWS(tp, wp) 1654 FOR_ALL_TAB_WINDOWS(tp, wp)
1610 { 1655 {
1611 if (wp == aucmd_win) 1656 if (wp == awp)
1612 { 1657 {
1613 if (tp != curtab) 1658 if (tp != curtab)
1614 goto_tabpage_tp(tp, TRUE, TRUE); 1659 goto_tabpage_tp(tp, TRUE, TRUE);
1615 win_goto(aucmd_win); 1660 win_goto(awp);
1616 goto win_found; 1661 goto win_found;
1617 } 1662 }
1618 } 1663 }
1619 } 1664 }
1620 win_found: 1665 win_found:
1621 1666
1622 // Remove the window and frame from the tree of frames. 1667 // Remove the window and frame from the tree of frames.
1623 (void)winframe_remove(curwin, &dummy, NULL); 1668 (void)winframe_remove(curwin, &dummy, NULL);
1624 win_remove(curwin, NULL); 1669 win_remove(curwin, NULL);
1625 aucmd_win_used = FALSE; 1670 aucmd_win[aco->use_aucmd_win_idx].auc_win_used = FALSE;
1626 last_status(FALSE); // may need to remove last status line 1671 last_status(FALSE); // may need to remove last status line
1627 1672
1628 if (!valid_tabpage_win(curtab)) 1673 if (!valid_tabpage_win(curtab))
1629 // no valid window in current tabpage 1674 // no valid window in current tabpage
1630 close_tabpage(curtab); 1675 close_tabpage(curtab);
1644 // May need to restore insert mode for a prompt buffer. 1689 // May need to restore insert mode for a prompt buffer.
1645 entering_window(curwin); 1690 entering_window(curwin);
1646 #endif 1691 #endif
1647 prevwin = win_find_by_id(aco->save_prevwin_id); 1692 prevwin = win_find_by_id(aco->save_prevwin_id);
1648 #ifdef FEAT_EVAL 1693 #ifdef FEAT_EVAL
1649 vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables 1694 vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables
1650 hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab 1695 hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab
1651 #endif 1696 #endif
1652 vim_free(globaldir); 1697 vim_free(globaldir);
1653 globaldir = aco->globaldir; 1698 globaldir = aco->globaldir;
1654 1699
1655 // the buffer contents may have changed 1700 // the buffer contents may have changed
1662 #endif 1707 #endif
1663 } 1708 }
1664 #if defined(FEAT_GUI) 1709 #if defined(FEAT_GUI)
1665 if (gui.in_use) 1710 if (gui.in_use)
1666 { 1711 {
1667 // Hide the scrollbars from the aucmd_win and update. 1712 // Hide the scrollbars from the "awp" and update.
1668 gui_mch_enable_scrollbar( 1713 gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_LEFT], FALSE);
1669 &aucmd_win->w_scrollbars[SBAR_LEFT], FALSE); 1714 gui_mch_enable_scrollbar(&awp->w_scrollbars[SBAR_RIGHT], FALSE);
1670 gui_mch_enable_scrollbar(
1671 &aucmd_win->w_scrollbars[SBAR_RIGHT], FALSE);
1672 gui_may_update_scrollbars(); 1715 gui_may_update_scrollbars();
1673 } 1716 }
1674 #endif 1717 #endif
1675 } 1718 }
1676 else 1719 else