mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 04:39:07 +00:00
feat(api): mark nvim_create_autocmd as api-fast #40836
Problem: nvim_create_autocmd() isn't |api-fast|, so modules that create autocmds (e.g. vim.treesitter.query) can't be require()d in a fast event context. Solution: Mark it |api-fast|. Compile autocmd patterns with RE_NOBREAK so aucmd_next() won't os_breakcheck() mid-iteration, where a fast nvim_create_autocmd() could realloc the autocmds vector and dangle the caller's AutoPat/AutoCmd. RE_NOBREAK is low-risk because: - aucmd_next()'s loop checks CTRL-C: `(for (… i < apc->ausize && !got_int; …)`. - `line_breakcheck()` (`autocmd.c:1912`) runs once per matched autocmd. - Each autocmd _execution_ runs through `do_cmdline`, which has its own breakchecks. However this does admit risk of a pathological case: a catastrophic-backtracking glob matched against a very long `User` event-pattern. Co-authored-by: Riley Bruins <ribru17@hotmail.com> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
@@ -2159,6 +2159,7 @@ nvim_create_autocmd({event}, {opts}) *nvim_create_autocmd()*
|
||||
<
|
||||
|
||||
Attributes: ~
|
||||
|api-fast|
|
||||
Since: 0.7.0
|
||||
|
||||
Parameters: ~
|
||||
|
||||
@@ -179,6 +179,8 @@ API
|
||||
• |nvim_set_option_value()| accepts a new `operation` field to modify the
|
||||
existing option value.
|
||||
• |nvim_set_option_value()| returns the new option value.
|
||||
• |nvim_create_autocmd()| is now |api-fast|, so it can be called from a fast
|
||||
event context (e.g. |vim.uv| callbacks).
|
||||
|
||||
BUILD
|
||||
|
||||
|
||||
@@ -391,6 +391,7 @@ cleanup:
|
||||
Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autocmd) *opts,
|
||||
Arena *arena, Error *err)
|
||||
FUNC_API_SINCE(9)
|
||||
FUNC_API_FAST
|
||||
{
|
||||
int64_t autocmd_id = -1;
|
||||
char *desc = NULL;
|
||||
|
||||
@@ -1022,7 +1022,8 @@ int autocmd_register(int64_t id, event_T event, const char *pat, int patlen, int
|
||||
ap->buflocal_nr = 0;
|
||||
char *reg_pat = file_pat_to_reg_pat(pat, pat + patlen, &ap->allow_dirs, true);
|
||||
if (reg_pat != NULL) {
|
||||
ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC);
|
||||
// RE_NOBREAK: autocmd-pattern matching (aucmd_next()) must not os_breakcheck(). #35071
|
||||
ap->reg_prog = vim_regcomp(reg_pat, RE_MAGIC | RE_NOBREAK);
|
||||
}
|
||||
xfree(reg_pat);
|
||||
if (reg_pat == NULL || ap->reg_prog == NULL) {
|
||||
|
||||
@@ -24,7 +24,11 @@ describe('|api-fast| functions', function()
|
||||
keycode = vim.keycode('<C-a>'),
|
||||
keytrans = vim.fn.keytrans(vim.keycode('<C-Home>')),
|
||||
nr2char = vim.fn.nr2char(65),
|
||||
replace_termcodes = vim.api.nvim_replace_termcodes('<Esc>', true, true, true),
|
||||
nvim_create_autocmd = vim.api.nvim_create_autocmd('User', {
|
||||
pattern = 'Fast',
|
||||
callback = function() end,
|
||||
}) > 0,
|
||||
nvim_replace_termcodes = vim.api.nvim_replace_termcodes('<Esc>', true, true, true),
|
||||
str2list = vim.fn.str2list('AB'),
|
||||
strcharlen = vim.fn.strcharlen('abc'),
|
||||
strcharpart = vim.fn.strcharpart('héllo', 1, 2),
|
||||
@@ -53,7 +57,8 @@ describe('|api-fast| functions', function()
|
||||
keycode = '\1', -- <C-a>
|
||||
keytrans = '<C-Home>',
|
||||
nr2char = 'A',
|
||||
replace_termcodes = '\27', -- <Esc>
|
||||
nvim_create_autocmd = true,
|
||||
nvim_replace_termcodes = '\27', -- <Esc>
|
||||
str2list = { 65, 66 },
|
||||
strcharlen = 3,
|
||||
strcharpart = 'él',
|
||||
@@ -87,6 +92,9 @@ describe('|api-fast| functions', function()
|
||||
-- for `veryfast_breakcheck`). Small input could pass (false negative).
|
||||
local big = ('héllo wörld '):rep(100000) -- 1.2M chars.
|
||||
|
||||
local aupat = ('a'):rep(80000) -- Must stay under the "E339: Pattern too long" limit.
|
||||
vim.api.nvim_create_autocmd('User', { pattern = aupat, callback = function() end })
|
||||
|
||||
local cases = {
|
||||
byteidx = function()
|
||||
vim.fn.byteidx(big, 500000)
|
||||
@@ -106,7 +114,10 @@ describe('|api-fast| functions', function()
|
||||
nr2char = function()
|
||||
vim.fn.nr2char(65)
|
||||
end,
|
||||
replace_termcodes = function()
|
||||
nvim_create_autocmd = function()
|
||||
vim.api.nvim_exec_autocmds('User', { pattern = aupat })
|
||||
end,
|
||||
nvim_replace_termcodes = function()
|
||||
vim.api.nvim_replace_termcodes('<Esc>', true, true, true)
|
||||
end,
|
||||
str2list = function()
|
||||
|
||||
Reference in New Issue
Block a user