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