patch 9.1.0256: Finding autocmd events is inefficient

Problem:  Finding autocmd events is inefficient
Solution: Use binary search to find events, cache last found events,
          avoid use of strlen(), add SessionWritePost autocmd,
          fix test_codestyle and avoid endless loop
          (John Marriott)

closes: #14287

Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
John Marriott
2024-04-02 20:26:01 +02:00
committed by Christian Brabandt
parent 16cdfa69e0
commit 78d742ab88
6 changed files with 308 additions and 161 deletions

View File

@ -74,153 +74,166 @@ typedef struct AutoPat
char last; // last pattern for apply_autocmds()
} AutoPat;
static struct event_name
{
char *name; // event name
event_T event; // event number
} event_names[] =
{
{"BufAdd", EVENT_BUFADD},
{"BufCreate", EVENT_BUFADD},
{"BufDelete", EVENT_BUFDELETE},
{"BufEnter", EVENT_BUFENTER},
{"BufFilePost", EVENT_BUFFILEPOST},
{"BufFilePre", EVENT_BUFFILEPRE},
{"BufHidden", EVENT_BUFHIDDEN},
{"BufLeave", EVENT_BUFLEAVE},
{"BufNew", EVENT_BUFNEW},
{"BufNewFile", EVENT_BUFNEWFILE},
{"BufRead", EVENT_BUFREADPOST},
{"BufReadCmd", EVENT_BUFREADCMD},
{"BufReadPost", EVENT_BUFREADPOST},
{"BufReadPre", EVENT_BUFREADPRE},
{"BufUnload", EVENT_BUFUNLOAD},
{"BufWinEnter", EVENT_BUFWINENTER},
{"BufWinLeave", EVENT_BUFWINLEAVE},
{"BufWipeout", EVENT_BUFWIPEOUT},
{"BufWrite", EVENT_BUFWRITEPRE},
{"BufWritePost", EVENT_BUFWRITEPOST},
{"BufWritePre", EVENT_BUFWRITEPRE},
{"BufWriteCmd", EVENT_BUFWRITECMD},
{"CmdlineChanged", EVENT_CMDLINECHANGED},
{"CmdlineEnter", EVENT_CMDLINEENTER},
{"CmdlineLeave", EVENT_CMDLINELEAVE},
{"CmdwinEnter", EVENT_CMDWINENTER},
{"CmdwinLeave", EVENT_CMDWINLEAVE},
{"CmdUndefined", EVENT_CMDUNDEFINED},
{"ColorScheme", EVENT_COLORSCHEME},
{"ColorSchemePre", EVENT_COLORSCHEMEPRE},
{"CompleteChanged", EVENT_COMPLETECHANGED},
{"CompleteDone", EVENT_COMPLETEDONE},
{"CompleteDonePre", EVENT_COMPLETEDONEPRE},
{"CursorHold", EVENT_CURSORHOLD},
{"CursorHoldI", EVENT_CURSORHOLDI},
{"CursorMoved", EVENT_CURSORMOVED},
{"CursorMovedI", EVENT_CURSORMOVEDI},
{"DiffUpdated", EVENT_DIFFUPDATED},
{"DirChanged", EVENT_DIRCHANGED},
{"DirChangedPre", EVENT_DIRCHANGEDPRE},
{"EncodingChanged", EVENT_ENCODINGCHANGED},
{"ExitPre", EVENT_EXITPRE},
{"FileEncoding", EVENT_ENCODINGCHANGED},
{"FileAppendPost", EVENT_FILEAPPENDPOST},
{"FileAppendPre", EVENT_FILEAPPENDPRE},
{"FileAppendCmd", EVENT_FILEAPPENDCMD},
{"FileChangedShell",EVENT_FILECHANGEDSHELL},
{"FileChangedShellPost",EVENT_FILECHANGEDSHELLPOST},
{"FileChangedRO", EVENT_FILECHANGEDRO},
{"FileReadPost", EVENT_FILEREADPOST},
{"FileReadPre", EVENT_FILEREADPRE},
{"FileReadCmd", EVENT_FILEREADCMD},
{"FileType", EVENT_FILETYPE},
{"FileWritePost", EVENT_FILEWRITEPOST},
{"FileWritePre", EVENT_FILEWRITEPRE},
{"FileWriteCmd", EVENT_FILEWRITECMD},
{"FilterReadPost", EVENT_FILTERREADPOST},
{"FilterReadPre", EVENT_FILTERREADPRE},
{"FilterWritePost", EVENT_FILTERWRITEPOST},
{"FilterWritePre", EVENT_FILTERWRITEPRE},
{"FocusGained", EVENT_FOCUSGAINED},
{"FocusLost", EVENT_FOCUSLOST},
{"FuncUndefined", EVENT_FUNCUNDEFINED},
{"GUIEnter", EVENT_GUIENTER},
{"GUIFailed", EVENT_GUIFAILED},
{"InsertChange", EVENT_INSERTCHANGE},
{"InsertEnter", EVENT_INSERTENTER},
{"InsertLeave", EVENT_INSERTLEAVE},
{"InsertLeavePre", EVENT_INSERTLEAVEPRE},
{"InsertCharPre", EVENT_INSERTCHARPRE},
{"MenuPopup", EVENT_MENUPOPUP},
{"ModeChanged", EVENT_MODECHANGED},
{"OptionSet", EVENT_OPTIONSET},
{"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
{"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
{"QuitPre", EVENT_QUITPRE},
{"RemoteReply", EVENT_REMOTEREPLY},
{"SafeState", EVENT_SAFESTATE},
{"SafeStateAgain", EVENT_SAFESTATEAGAIN},
{"SessionLoadPost", EVENT_SESSIONLOADPOST},
{"SessionWritePost",EVENT_SESSIONWRITEPOST},
{"ShellCmdPost", EVENT_SHELLCMDPOST},
{"ShellFilterPost", EVENT_SHELLFILTERPOST},
{"SigUSR1", EVENT_SIGUSR1},
{"SourceCmd", EVENT_SOURCECMD},
{"SourcePre", EVENT_SOURCEPRE},
{"SourcePost", EVENT_SOURCEPOST},
{"SpellFileMissing",EVENT_SPELLFILEMISSING},
{"StdinReadPost", EVENT_STDINREADPOST},
{"StdinReadPre", EVENT_STDINREADPRE},
{"SwapExists", EVENT_SWAPEXISTS},
{"Syntax", EVENT_SYNTAX},
{"TabNew", EVENT_TABNEW},
{"TabClosed", EVENT_TABCLOSED},
{"TabEnter", EVENT_TABENTER},
{"TabLeave", EVENT_TABLEAVE},
{"TermChanged", EVENT_TERMCHANGED},
{"TerminalOpen", EVENT_TERMINALOPEN},
{"TerminalWinOpen", EVENT_TERMINALWINOPEN},
{"TermResponse", EVENT_TERMRESPONSE},
{"TermResponseAll", EVENT_TERMRESPONSEALL},
{"TextChanged", EVENT_TEXTCHANGED},
{"TextChangedI", EVENT_TEXTCHANGEDI},
{"TextChangedP", EVENT_TEXTCHANGEDP},
{"TextChangedT", EVENT_TEXTCHANGEDT},
{"User", EVENT_USER},
{"VimEnter", EVENT_VIMENTER},
{"VimLeave", EVENT_VIMLEAVE},
{"VimLeavePre", EVENT_VIMLEAVEPRE},
{"WinNewPre", EVENT_WINNEWPRE},
{"WinNew", EVENT_WINNEW},
{"WinClosed", EVENT_WINCLOSED},
{"WinEnter", EVENT_WINENTER},
{"WinLeave", EVENT_WINLEAVE},
{"WinResized", EVENT_WINRESIZED},
{"WinScrolled", EVENT_WINSCROLLED},
{"VimResized", EVENT_VIMRESIZED},
{"TextYankPost", EVENT_TEXTYANKPOST},
{"VimSuspend", EVENT_VIMSUSPEND},
{"VimResume", EVENT_VIMRESUME},
{NULL, (event_T)0}
//
// special cases:
// BufNewFile and BufRead are searched for ALOT (especially at startup)
// so we pre-determine their index into the event_tab[] table for fast access.
// Keep these values in sync with event_tab[]!
#define BUFNEWFILE_INDEX 9
#define BUFREAD_INDEX 10
// must be sorted by the 'value' field because it is used by bsearch()!
static keyvalue_T event_tab[] = {
KEYVALUE_ENTRY(EVENT_BUFADD, "BufAdd"),
KEYVALUE_ENTRY(EVENT_BUFADD, "BufCreate"),
KEYVALUE_ENTRY(EVENT_BUFDELETE, "BufDelete"),
KEYVALUE_ENTRY(EVENT_BUFENTER, "BufEnter"),
KEYVALUE_ENTRY(EVENT_BUFFILEPOST, "BufFilePost"),
KEYVALUE_ENTRY(EVENT_BUFFILEPRE, "BufFilePre"),
KEYVALUE_ENTRY(EVENT_BUFHIDDEN, "BufHidden"),
KEYVALUE_ENTRY(EVENT_BUFLEAVE, "BufLeave"),
KEYVALUE_ENTRY(EVENT_BUFNEW, "BufNew"),
KEYVALUE_ENTRY(EVENT_BUFNEWFILE, "BufNewFile"), // BUFNEWFILE_INDEX
KEYVALUE_ENTRY(EVENT_BUFREADPOST, "BufRead"), // BUFREAD_INDEX
KEYVALUE_ENTRY(EVENT_BUFREADCMD, "BufReadCmd"),
KEYVALUE_ENTRY(EVENT_BUFREADPOST, "BufReadPost"),
KEYVALUE_ENTRY(EVENT_BUFREADPRE, "BufReadPre"),
KEYVALUE_ENTRY(EVENT_BUFUNLOAD, "BufUnload"),
KEYVALUE_ENTRY(EVENT_BUFWINENTER, "BufWinEnter"),
KEYVALUE_ENTRY(EVENT_BUFWINLEAVE, "BufWinLeave"),
KEYVALUE_ENTRY(EVENT_BUFWIPEOUT, "BufWipeout"),
KEYVALUE_ENTRY(EVENT_BUFWRITEPRE, "BufWrite"),
KEYVALUE_ENTRY(EVENT_BUFWRITECMD, "BufWriteCmd"),
KEYVALUE_ENTRY(EVENT_BUFWRITEPOST, "BufWritePost"),
KEYVALUE_ENTRY(EVENT_BUFWRITEPRE, "BufWritePre"),
KEYVALUE_ENTRY(EVENT_CMDLINECHANGED, "CmdlineChanged"),
KEYVALUE_ENTRY(EVENT_CMDLINEENTER, "CmdlineEnter"),
KEYVALUE_ENTRY(EVENT_CMDLINELEAVE, "CmdlineLeave"),
KEYVALUE_ENTRY(EVENT_CMDUNDEFINED, "CmdUndefined"),
KEYVALUE_ENTRY(EVENT_CMDWINENTER, "CmdwinEnter"),
KEYVALUE_ENTRY(EVENT_CMDWINLEAVE, "CmdwinLeave"),
KEYVALUE_ENTRY(EVENT_COLORSCHEME, "ColorScheme"),
KEYVALUE_ENTRY(EVENT_COLORSCHEMEPRE, "ColorSchemePre"),
KEYVALUE_ENTRY(EVENT_COMPLETECHANGED, "CompleteChanged"),
KEYVALUE_ENTRY(EVENT_COMPLETEDONE, "CompleteDone"),
KEYVALUE_ENTRY(EVENT_COMPLETEDONEPRE, "CompleteDonePre"),
KEYVALUE_ENTRY(EVENT_CURSORHOLD, "CursorHold"),
KEYVALUE_ENTRY(EVENT_CURSORHOLDI, "CursorHoldI"),
KEYVALUE_ENTRY(EVENT_CURSORMOVED, "CursorMoved"),
KEYVALUE_ENTRY(EVENT_CURSORMOVEDI, "CursorMovedI"),
KEYVALUE_ENTRY(EVENT_DIFFUPDATED, "DiffUpdated"),
KEYVALUE_ENTRY(EVENT_DIRCHANGED, "DirChanged"),
KEYVALUE_ENTRY(EVENT_DIRCHANGEDPRE, "DirChangedPre"),
KEYVALUE_ENTRY(EVENT_ENCODINGCHANGED, "EncodingChanged"),
KEYVALUE_ENTRY(EVENT_EXITPRE, "ExitPre"),
KEYVALUE_ENTRY(EVENT_FILEAPPENDCMD, "FileAppendCmd"),
KEYVALUE_ENTRY(EVENT_FILEAPPENDPOST, "FileAppendPost"),
KEYVALUE_ENTRY(EVENT_FILEAPPENDPRE, "FileAppendPre"),
KEYVALUE_ENTRY(EVENT_FILECHANGEDRO, "FileChangedRO"),
KEYVALUE_ENTRY(EVENT_FILECHANGEDSHELL, "FileChangedShell"),
KEYVALUE_ENTRY(EVENT_FILECHANGEDSHELLPOST, "FileChangedShellPost"),
KEYVALUE_ENTRY(EVENT_ENCODINGCHANGED, "FileEncoding"),
KEYVALUE_ENTRY(EVENT_FILEREADCMD, "FileReadCmd"),
KEYVALUE_ENTRY(EVENT_FILEREADPOST, "FileReadPost"),
KEYVALUE_ENTRY(EVENT_FILEREADPRE, "FileReadPre"),
KEYVALUE_ENTRY(EVENT_FILETYPE, "FileType"),
KEYVALUE_ENTRY(EVENT_FILEWRITECMD, "FileWriteCmd"),
KEYVALUE_ENTRY(EVENT_FILEWRITEPOST, "FileWritePost"),
KEYVALUE_ENTRY(EVENT_FILEWRITEPRE, "FileWritePre"),
KEYVALUE_ENTRY(EVENT_FILTERREADPOST, "FilterReadPost"),
KEYVALUE_ENTRY(EVENT_FILTERREADPRE, "FilterReadPre"),
KEYVALUE_ENTRY(EVENT_FILTERWRITEPOST, "FilterWritePost"),
KEYVALUE_ENTRY(EVENT_FILTERWRITEPRE, "FilterWritePre"),
KEYVALUE_ENTRY(EVENT_FOCUSGAINED, "FocusGained"),
KEYVALUE_ENTRY(EVENT_FOCUSLOST, "FocusLost"),
KEYVALUE_ENTRY(EVENT_FUNCUNDEFINED, "FuncUndefined"),
KEYVALUE_ENTRY(EVENT_GUIENTER, "GUIEnter"),
KEYVALUE_ENTRY(EVENT_GUIFAILED, "GUIFailed"),
KEYVALUE_ENTRY(EVENT_INSERTCHANGE, "InsertChange"),
KEYVALUE_ENTRY(EVENT_INSERTCHARPRE, "InsertCharPre"),
KEYVALUE_ENTRY(EVENT_INSERTENTER, "InsertEnter"),
KEYVALUE_ENTRY(EVENT_INSERTLEAVE, "InsertLeave"),
KEYVALUE_ENTRY(EVENT_INSERTLEAVEPRE, "InsertLeavePre"),
KEYVALUE_ENTRY(EVENT_MENUPOPUP, "MenuPopup"),
KEYVALUE_ENTRY(EVENT_MODECHANGED, "ModeChanged"),
KEYVALUE_ENTRY(EVENT_OPTIONSET, "OptionSet"),
KEYVALUE_ENTRY(EVENT_QUICKFIXCMDPOST, "QuickFixCmdPost"),
KEYVALUE_ENTRY(EVENT_QUICKFIXCMDPRE, "QuickFixCmdPre"),
KEYVALUE_ENTRY(EVENT_QUITPRE, "QuitPre"),
KEYVALUE_ENTRY(EVENT_REMOTEREPLY, "RemoteReply"),
KEYVALUE_ENTRY(EVENT_SAFESTATE, "SafeState"),
KEYVALUE_ENTRY(EVENT_SAFESTATEAGAIN, "SafeStateAgain"),
KEYVALUE_ENTRY(EVENT_SESSIONLOADPOST, "SessionLoadPost"),
KEYVALUE_ENTRY(EVENT_SESSIONWRITEPOST, "SessionWritePost"),
KEYVALUE_ENTRY(EVENT_SHELLCMDPOST, "ShellCmdPost"),
KEYVALUE_ENTRY(EVENT_SHELLFILTERPOST, "ShellFilterPost"),
KEYVALUE_ENTRY(EVENT_SIGUSR1, "SigUSR1"),
KEYVALUE_ENTRY(EVENT_SOURCECMD, "SourceCmd"),
KEYVALUE_ENTRY(EVENT_SOURCEPOST, "SourcePost"),
KEYVALUE_ENTRY(EVENT_SOURCEPRE, "SourcePre"),
KEYVALUE_ENTRY(EVENT_SPELLFILEMISSING, "SpellFileMissing"),
KEYVALUE_ENTRY(EVENT_STDINREADPOST, "StdinReadPost"),
KEYVALUE_ENTRY(EVENT_STDINREADPRE, "StdinReadPre"),
KEYVALUE_ENTRY(EVENT_SWAPEXISTS, "SwapExists"),
KEYVALUE_ENTRY(EVENT_SYNTAX, "Syntax"),
KEYVALUE_ENTRY(EVENT_TABCLOSED, "TabClosed"),
KEYVALUE_ENTRY(EVENT_TABENTER, "TabEnter"),
KEYVALUE_ENTRY(EVENT_TABLEAVE, "TabLeave"),
KEYVALUE_ENTRY(EVENT_TABNEW, "TabNew"),
KEYVALUE_ENTRY(EVENT_TERMCHANGED, "TermChanged"),
KEYVALUE_ENTRY(EVENT_TERMINALOPEN, "TerminalOpen"),
KEYVALUE_ENTRY(EVENT_TERMINALWINOPEN, "TerminalWinOpen"),
KEYVALUE_ENTRY(EVENT_TERMRESPONSE, "TermResponse"),
KEYVALUE_ENTRY(EVENT_TERMRESPONSEALL, "TermResponseAll"),
KEYVALUE_ENTRY(EVENT_TEXTCHANGED, "TextChanged"),
KEYVALUE_ENTRY(EVENT_TEXTCHANGEDI, "TextChangedI"),
KEYVALUE_ENTRY(EVENT_TEXTCHANGEDP, "TextChangedP"),
KEYVALUE_ENTRY(EVENT_TEXTCHANGEDT, "TextChangedT"),
KEYVALUE_ENTRY(EVENT_TEXTYANKPOST, "TextYankPost"),
KEYVALUE_ENTRY(EVENT_USER, "User"),
KEYVALUE_ENTRY(EVENT_VIMENTER, "VimEnter"),
KEYVALUE_ENTRY(EVENT_VIMLEAVE, "VimLeave"),
KEYVALUE_ENTRY(EVENT_VIMLEAVEPRE, "VimLeavePre"),
KEYVALUE_ENTRY(EVENT_VIMRESIZED, "VimResized"),
KEYVALUE_ENTRY(EVENT_VIMRESUME, "VimResume"),
KEYVALUE_ENTRY(EVENT_VIMSUSPEND, "VimSuspend"),
KEYVALUE_ENTRY(EVENT_WINCLOSED, "WinClosed"),
KEYVALUE_ENTRY(EVENT_WINENTER, "WinEnter"),
KEYVALUE_ENTRY(EVENT_WINLEAVE, "WinLeave"),
KEYVALUE_ENTRY(EVENT_WINNEW, "WinNew"),
KEYVALUE_ENTRY(EVENT_WINNEWPRE, "WinNewPre"),
KEYVALUE_ENTRY(EVENT_WINRESIZED, "WinResized"),
KEYVALUE_ENTRY(EVENT_WINSCROLLED, "WinScrolled")
};
static AutoPat *first_autopat[NUM_EVENTS] =
{
static AutoPat *first_autopat[NUM_EVENTS] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
static AutoPat *last_autopat[NUM_EVENTS] =
{
static AutoPat *last_autopat[NUM_EVENTS] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL
};
#define AUGROUP_DEFAULT (-1) // default autocmd group
@ -266,6 +279,7 @@ static int current_augroup = AUGROUP_DEFAULT;
static int au_need_clean = FALSE; // need to delete marked patterns
static event_T event_name2nr(char_u *start, char_u **end);
static char_u *event_nr2name(event_T event);
static int au_get_grouparg(char_u **argp);
static int do_autocmd_event(event_T event, char_u *pat, int once, int nested, char_u *cmd, int forceit, int group, int flags);
@ -681,24 +695,35 @@ is_aucmd_win(win_T *win)
event_name2nr(char_u *start, char_u **end)
{
char_u *p;
int i;
int len;
keyvalue_T target;
keyvalue_T *entry;
static keyvalue_T *bufnewfile = &event_tab[BUFNEWFILE_INDEX];
static keyvalue_T *bufread = &event_tab[BUFREAD_INDEX];
// the event name ends with end of line, '|', a blank or a comma
for (p = start; *p && !VIM_ISWHITE(*p) && *p != ',' && *p != '|'; ++p)
;
for (i = 0; event_names[i].name != NULL; ++i)
{
len = (int)STRLEN(event_names[i].name);
if (len == p - start && STRNICMP(event_names[i].name, start, len) == 0)
break;
}
target.key = 0;
target.value = (char *)start;
target.length = (size_t)(p - start);
// special cases:
// BufNewFile and BufRead are searched for ALOT (especially at startup)
// so we check for them first.
if (cmp_keyvalue_value_ni(&target, bufnewfile) == 0)
entry = bufnewfile;
else
if (cmp_keyvalue_value_ni(&target, bufread) == 0)
entry = bufread;
else
entry = (keyvalue_T *)bsearch(&target, &event_tab, ARRAY_LENGTH(event_tab), sizeof(event_tab[0]), cmp_keyvalue_value_ni);
if (*p == ',')
++p;
*end = p;
if (event_names[i].name == NULL)
return NUM_EVENTS;
return event_names[i].event;
return (entry == NULL) ? NUM_EVENTS : (event_T)entry->key;
}
/*
@ -708,11 +733,52 @@ event_name2nr(char_u *start, char_u **end)
event_nr2name(event_T event)
{
int i;
#define CACHE_SIZE 12
static int cache_tab[CACHE_SIZE];
static int cache_last_index = -1;
for (i = 0; event_names[i].name != NULL; ++i)
if (event_names[i].event == event)
return (char_u *)event_names[i].name;
return (char_u *)"Unknown";
if (cache_last_index < 0)
{
for (i = 0; i < (int)ARRAY_LENGTH(cache_tab); ++i)
cache_tab[i] = -1;
cache_last_index = ARRAY_LENGTH(cache_tab) - 1;
}
// first look in the cache
// the cache is circular. to search it we start at the most recent entry
// and go backwards wrapping around when we get to index 0.
for (i = cache_last_index; cache_tab[i] >= 0; )
{
if ((event_T)event_tab[cache_tab[i]].key == event)
return (char_u *)event_tab[cache_tab[i]].value;
if (i == 0)
i = ARRAY_LENGTH(cache_tab) - 1;
else
--i;
// are we back at the start?
if (i == cache_last_index)
break;
}
// look in the event table itself
for (i = 0; i < (int)ARRAY_LENGTH(event_tab); ++i)
{
if ((event_T)event_tab[i].key == event)
{
// store the found entry in the next position in the cache,
// wrapping around when we get to the maximum index.
if (cache_last_index == ARRAY_LENGTH(cache_tab) - 1)
cache_last_index = 0;
else
++cache_last_index;
cache_tab[cache_last_index] = i;
break;
}
}
return (i == (int)ARRAY_LENGTH(event_tab)) ? (char_u *)"Unknown" : (char_u *)event_tab[i].value;
}
/*
@ -806,12 +872,14 @@ au_event_disable(char *what)
{
char_u *new_ei;
char_u *save_ei;
size_t p_ei_len;
save_ei = vim_strsave(p_ei);
p_ei_len = STRLEN(p_ei);
save_ei = vim_strnsave(p_ei, p_ei_len);
if (save_ei == NULL)
return NULL;
new_ei = vim_strnsave(p_ei, STRLEN(p_ei) + STRLEN(what));
new_ei = vim_strnsave(p_ei, p_ei_len + STRLEN(what));
if (new_ei == NULL)
{
vim_free(save_ei);
@ -2774,6 +2842,8 @@ set_context_in_autocmd(
char_u *
get_event_name(expand_T *xp UNUSED, int idx)
{
int i;
if (idx < augroups.ga_len) // First list group names, if wanted
{
if (!include_groups || AUGROUP_NAME(idx) == NULL
@ -2781,7 +2851,12 @@ get_event_name(expand_T *xp UNUSED, int idx)
return (char_u *)""; // skip deleted entries
return AUGROUP_NAME(idx); // return a name
}
return (char_u *)event_names[idx - augroups.ga_len].name;
i = idx - augroups.ga_len;
if (i < 0 || i >= (int)ARRAY_LENGTH(event_tab))
return NULL;
return (char_u *)event_tab[i].value;
}
/*
@ -2791,7 +2866,10 @@ get_event_name(expand_T *xp UNUSED, int idx)
char_u *
get_event_name_no_group(expand_T *xp UNUSED, int idx)
{
return (char_u *)event_names[idx].name;
if (idx < 0 || idx >= (int)ARRAY_LENGTH(event_tab))
return NULL;
return (char_u *)event_tab[idx].value;
}
@ -3251,8 +3329,6 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
// return only the autocmds for the specified event
if (dict_has_key(argvars[0].vval.v_dict, "event"))
{
int i;
name = dict_get_string(argvars[0].vval.v_dict, "event", TRUE);
if (name == NULL)
return;
@ -3261,16 +3337,20 @@ f_autocmd_get(typval_T *argvars, typval_T *rettv)
event_arg = NUM_EVENTS;
else
{
for (i = 0; event_names[i].name != NULL; i++)
if (STRICMP(event_names[i].name, name) == 0)
break;
if (event_names[i].name == NULL)
keyvalue_T target;
keyvalue_T *entry;
target.key = 0;
target.value = (char *)name;
target.length = (int)STRLEN(target.value);
entry = (keyvalue_T *)bsearch(&target, &event_tab, ARRAY_LENGTH(event_tab), sizeof(event_tab[0]), cmp_keyvalue_value_ni);
if (entry == NULL)
{
semsg(_(e_no_such_event_str), name);
vim_free(name);
return;
}
event_arg = event_names[i].event;
event_arg = (event_T)entry->key;
}
vim_free(name);
}

View File

@ -3069,3 +3069,45 @@ get_special_pty_type(void)
return 0;
#endif
}
// compare two keyvalue_T structs by case sensitive value
int
cmp_keyvalue_value(const void *a, const void *b)
{
keyvalue_T *kv1 = (keyvalue_T *)a;
keyvalue_T *kv2 = (keyvalue_T *)b;
return STRCMP(kv1->value, kv2->value);
}
// compare two keyvalue_T structs by value with length
int
cmp_keyvalue_value_n(const void *a, const void *b)
{
keyvalue_T *kv1 = (keyvalue_T *)a;
keyvalue_T *kv2 = (keyvalue_T *)b;
return STRNCMP(kv1->value, kv2->value, MAX(kv1->length, kv2->length));
}
// compare two keyvalue_T structs by case insensitive value
int
cmp_keyvalue_value_i(const void *a, const void *b)
{
keyvalue_T *kv1 = (keyvalue_T *)a;
keyvalue_T *kv2 = (keyvalue_T *)b;
return STRICMP(kv1->value, kv2->value);
}
// compare two keyvalue_T structs by case insensitive value
// with length
int
cmp_keyvalue_value_ni(const void *a, const void *b)
{
keyvalue_T *kv1 = (keyvalue_T *)a;
keyvalue_T *kv2 = (keyvalue_T *)b;
return STRNICMP(kv1->value, kv2->value, MAX(kv1->length, kv2->length));
}

View File

@ -61,4 +61,8 @@ int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
int build_argv_from_string(char_u *cmd, char ***argv, int *argc);
int build_argv_from_list(list_T *l, char ***argv, int *argc);
int get_special_pty_type(void);
int cmp_keyvalue_value(const void *a, const void *b);
int cmp_keyvalue_value_n(const void *a, const void *b);
int cmp_keyvalue_value_i(const void *a, const void *b);
int cmp_keyvalue_value_ni(const void *a, const void *b);
/* vim: set ft=c : */

View File

@ -5060,3 +5060,18 @@ typedef struct {
linenr_T spv_capcol_lnum; // line number for "cap_col"
#endif
} spellvars_T;
// Return the length of a string literal
#define STRLEN_LITERAL(s) (sizeof(s) - 1)
// Store a key/value pair
typedef struct
{
int key; // the key
char *value; // the value string
size_t length; // length of the value string
} keyvalue_T;
#define KEYVALUE_ENTRY(k, v) \
{(k), (v), STRLEN_LITERAL(v)}

View File

@ -7,13 +7,17 @@ def s:ReportError(fname: string, lnum: number, msg: string)
enddef
def s:PerformCheck(fname: string, pattern: string, msg: string, skip: string)
var prev_lnum = 1
var lnum = 1
while (lnum > 0)
cursor(lnum, 1)
lnum = search(pattern, 'W', 0, 0, skip)
ReportError(fname, lnum, msg)
if (prev_lnum == lnum)
break
endif
prev_lnum = lnum
if (lnum > 0)
lnum += 1
ReportError(fname, lnum, msg)
endif
endwhile
enddef

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
256,
/**/
255,
/**/