mirror of
https://github.com/vim/vim.git
synced 2025-07-04 23:07:33 -04:00
patch 9.1.0685: too many strlen() calls in usercmd.c
Problem: too many strlen() calls in usercmd.c Solution: refactor code to reduce the number or strlen() calls (John Marriott) closes: #15516 Signed-off-by: John Marriott <basilisk@internode.on.net> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
e44e64492c
commit
9e795852f3
@ -133,6 +133,10 @@ function Test_cmdmods()
|
||||
\ 'silent verbose aboveleft belowright botright tab topleft vertical',
|
||||
\ g:mods)
|
||||
|
||||
kee keep keepm keepma keepmar keepmarks keepa keepalt keepj keepjumps
|
||||
\ keepp keeppatterns MyCmd
|
||||
call assert_equal('keepalt keepjumps keepmarks keeppatterns', g:mods)
|
||||
|
||||
let g:mods = ''
|
||||
command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
|
||||
|
||||
|
517
src/usercmd.c
517
src/usercmd.c
@ -16,6 +16,7 @@
|
||||
typedef struct ucmd
|
||||
{
|
||||
char_u *uc_name; // The command name
|
||||
size_t uc_namelen; // The length of the command name (excluding the NUL)
|
||||
long_u uc_argt; // The argument type
|
||||
char_u *uc_rep; // The command's replacement string
|
||||
long uc_def; // The default value for a range/count
|
||||
@ -39,94 +40,100 @@ static int ucmd_locked = 0;
|
||||
|
||||
/*
|
||||
* List of names for completion for ":command" with the EXPAND_ flag.
|
||||
* Must be alphabetical for completion.
|
||||
* Must be alphabetical on the 'value' field for completion and because
|
||||
* it is used by bsearch()!
|
||||
*/
|
||||
static struct
|
||||
static keyvalue_T command_complete_tab[] =
|
||||
{
|
||||
int expand;
|
||||
char *name;
|
||||
} command_complete[] =
|
||||
{
|
||||
{EXPAND_ARGLIST, "arglist"},
|
||||
{EXPAND_AUGROUP, "augroup"},
|
||||
{EXPAND_BEHAVE, "behave"},
|
||||
{EXPAND_BUFFERS, "buffer"},
|
||||
{EXPAND_COLORS, "color"},
|
||||
{EXPAND_COMMANDS, "command"},
|
||||
{EXPAND_COMPILER, "compiler"},
|
||||
KEYVALUE_ENTRY(EXPAND_ARGLIST, "arglist"),
|
||||
KEYVALUE_ENTRY(EXPAND_AUGROUP, "augroup"),
|
||||
KEYVALUE_ENTRY(EXPAND_BEHAVE, "behave"),
|
||||
#if defined(FEAT_EVAL)
|
||||
KEYVALUE_ENTRY(EXPAND_BREAKPOINT, "breakpoint"),
|
||||
#endif
|
||||
KEYVALUE_ENTRY(EXPAND_BUFFERS, "buffer"),
|
||||
KEYVALUE_ENTRY(EXPAND_COLORS, "color"),
|
||||
KEYVALUE_ENTRY(EXPAND_COMMANDS, "command"),
|
||||
KEYVALUE_ENTRY(EXPAND_COMPILER, "compiler"),
|
||||
#if defined(FEAT_CSCOPE)
|
||||
{EXPAND_CSCOPE, "cscope"},
|
||||
KEYVALUE_ENTRY(EXPAND_CSCOPE, "cscope"),
|
||||
#endif
|
||||
#if defined(FEAT_EVAL)
|
||||
{EXPAND_USER_DEFINED, "custom"},
|
||||
{EXPAND_USER_LIST, "customlist"},
|
||||
KEYVALUE_ENTRY(EXPAND_USER_DEFINED, "custom"),
|
||||
KEYVALUE_ENTRY(EXPAND_USER_LIST, "customlist"),
|
||||
#endif
|
||||
{EXPAND_DIFF_BUFFERS, "diff_buffer"},
|
||||
{EXPAND_DIRECTORIES, "dir"},
|
||||
{EXPAND_ENV_VARS, "environment"},
|
||||
{EXPAND_EVENTS, "event"},
|
||||
{EXPAND_EXPRESSION, "expression"},
|
||||
{EXPAND_FILES, "file"},
|
||||
{EXPAND_FILES_IN_PATH, "file_in_path"},
|
||||
{EXPAND_FILETYPE, "filetype"},
|
||||
{EXPAND_FUNCTIONS, "function"},
|
||||
{EXPAND_HELP, "help"},
|
||||
{EXPAND_HIGHLIGHT, "highlight"},
|
||||
{EXPAND_HISTORY, "history"},
|
||||
KEYVALUE_ENTRY(EXPAND_DIFF_BUFFERS, "diff_buffer"),
|
||||
KEYVALUE_ENTRY(EXPAND_DIRECTORIES, "dir"),
|
||||
KEYVALUE_ENTRY(EXPAND_DIRS_IN_CDPATH, "dir_in_path"),
|
||||
KEYVALUE_ENTRY(EXPAND_ENV_VARS, "environment"),
|
||||
KEYVALUE_ENTRY(EXPAND_EVENTS, "event"),
|
||||
KEYVALUE_ENTRY(EXPAND_EXPRESSION, "expression"),
|
||||
KEYVALUE_ENTRY(EXPAND_FILES, "file"),
|
||||
KEYVALUE_ENTRY(EXPAND_FILES_IN_PATH, "file_in_path"),
|
||||
KEYVALUE_ENTRY(EXPAND_FILETYPE, "filetype"),
|
||||
KEYVALUE_ENTRY(EXPAND_FUNCTIONS, "function"),
|
||||
KEYVALUE_ENTRY(EXPAND_HELP, "help"),
|
||||
KEYVALUE_ENTRY(EXPAND_HIGHLIGHT, "highlight"),
|
||||
KEYVALUE_ENTRY(EXPAND_HISTORY, "history"),
|
||||
#if defined(FEAT_KEYMAP)
|
||||
{EXPAND_KEYMAP, "keymap"},
|
||||
KEYVALUE_ENTRY(EXPAND_KEYMAP, "keymap"),
|
||||
#endif
|
||||
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
|
||||
{EXPAND_LOCALES, "locale"},
|
||||
KEYVALUE_ENTRY(EXPAND_LOCALES, "locale"),
|
||||
#endif
|
||||
{EXPAND_MAPCLEAR, "mapclear"},
|
||||
{EXPAND_MAPPINGS, "mapping"},
|
||||
{EXPAND_MENUS, "menu"},
|
||||
{EXPAND_MESSAGES, "messages"},
|
||||
{EXPAND_OWNSYNTAX, "syntax"},
|
||||
#if defined(FEAT_PROFILE)
|
||||
{EXPAND_SYNTIME, "syntime"},
|
||||
#endif
|
||||
{EXPAND_SETTINGS, "option"},
|
||||
{EXPAND_PACKADD, "packadd"},
|
||||
{EXPAND_RUNTIME, "runtime"},
|
||||
{EXPAND_SHELLCMD, "shellcmd"},
|
||||
#if defined(FEAT_SIGNS)
|
||||
{EXPAND_SIGN, "sign"},
|
||||
#endif
|
||||
{EXPAND_TAGS, "tag"},
|
||||
{EXPAND_TAGS_LISTFILES, "tag_listfiles"},
|
||||
{EXPAND_USER, "user"},
|
||||
{EXPAND_USER_VARS, "var"},
|
||||
KEYVALUE_ENTRY(EXPAND_MAPCLEAR, "mapclear"),
|
||||
KEYVALUE_ENTRY(EXPAND_MAPPINGS, "mapping"),
|
||||
KEYVALUE_ENTRY(EXPAND_MENUS, "menu"),
|
||||
KEYVALUE_ENTRY(EXPAND_MESSAGES, "messages"),
|
||||
KEYVALUE_ENTRY(EXPAND_SETTINGS, "option"),
|
||||
KEYVALUE_ENTRY(EXPAND_PACKADD, "packadd"),
|
||||
KEYVALUE_ENTRY(EXPAND_RUNTIME, "runtime"),
|
||||
#if defined(FEAT_EVAL)
|
||||
{EXPAND_BREAKPOINT, "breakpoint"},
|
||||
{EXPAND_SCRIPTNAMES, "scriptnames"},
|
||||
KEYVALUE_ENTRY(EXPAND_SCRIPTNAMES, "scriptnames"),
|
||||
#endif
|
||||
{EXPAND_DIRS_IN_CDPATH, "dir_in_path"},
|
||||
{0, NULL}
|
||||
KEYVALUE_ENTRY(EXPAND_SHELLCMD, "shellcmd"),
|
||||
#if defined(FEAT_SIGNS)
|
||||
KEYVALUE_ENTRY(EXPAND_SIGN, "sign"),
|
||||
#endif
|
||||
KEYVALUE_ENTRY(EXPAND_OWNSYNTAX, "syntax"),
|
||||
#if defined(FEAT_PROFILE)
|
||||
KEYVALUE_ENTRY(EXPAND_SYNTIME, "syntime"),
|
||||
#endif
|
||||
KEYVALUE_ENTRY(EXPAND_TAGS, "tag"),
|
||||
KEYVALUE_ENTRY(EXPAND_TAGS_LISTFILES, "tag_listfiles"),
|
||||
KEYVALUE_ENTRY(EXPAND_USER, "user"),
|
||||
KEYVALUE_ENTRY(EXPAND_USER_VARS, "var")
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cmd_addr_T key;
|
||||
char *fullname;
|
||||
size_t fullnamelen;
|
||||
char *shortname;
|
||||
size_t shortnamelen;
|
||||
} addrtype_T;
|
||||
|
||||
/*
|
||||
* List of names of address types. Must be alphabetical for completion.
|
||||
* Must be sorted by the 'fullname' field because it is used by bsearch()!
|
||||
*/
|
||||
static struct
|
||||
#define ADDRTYPE_ENTRY(k, fn, sn) \
|
||||
{(k), (fn), STRLEN_LITERAL(fn), (sn), STRLEN_LITERAL(sn)}
|
||||
static addrtype_T addr_type_complete_tab[] =
|
||||
{
|
||||
cmd_addr_T expand;
|
||||
char *name;
|
||||
char *shortname;
|
||||
} addr_type_complete[] =
|
||||
{
|
||||
{ADDR_ARGUMENTS, "arguments", "arg"},
|
||||
{ADDR_LINES, "lines", "line"},
|
||||
{ADDR_LOADED_BUFFERS, "loaded_buffers", "load"},
|
||||
{ADDR_TABS, "tabs", "tab"},
|
||||
{ADDR_BUFFERS, "buffers", "buf"},
|
||||
{ADDR_WINDOWS, "windows", "win"},
|
||||
{ADDR_QUICKFIX, "quickfix", "qf"},
|
||||
{ADDR_OTHER, "other", "?"},
|
||||
{ADDR_NONE, NULL, NULL}
|
||||
ADDRTYPE_ENTRY(ADDR_ARGUMENTS, "arguments", "arg"),
|
||||
ADDRTYPE_ENTRY(ADDR_BUFFERS, "buffers", "buf"),
|
||||
ADDRTYPE_ENTRY(ADDR_LINES, "lines", "line"),
|
||||
ADDRTYPE_ENTRY(ADDR_LOADED_BUFFERS, "loaded_buffers", "load"),
|
||||
ADDRTYPE_ENTRY(ADDR_OTHER, "other", "?"),
|
||||
ADDRTYPE_ENTRY(ADDR_QUICKFIX, "quickfix", "qf"),
|
||||
ADDRTYPE_ENTRY(ADDR_TABS, "tabs", "tab"),
|
||||
ADDRTYPE_ENTRY(ADDR_WINDOWS, "windows", "win")
|
||||
};
|
||||
|
||||
static int cmp_addr_type(const void *a, const void *b);
|
||||
|
||||
/*
|
||||
* Search for a user command that matches "eap->cmd".
|
||||
* Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
|
||||
@ -272,19 +279,16 @@ set_context_in_user_cmd(expand_T *xp, char_u *arg_in)
|
||||
{
|
||||
xp->xp_context = EXPAND_USER_COMPLETE;
|
||||
xp->xp_pattern = p + 1;
|
||||
return NULL;
|
||||
}
|
||||
else if (STRNICMP(arg, "nargs", p - arg) == 0)
|
||||
{
|
||||
xp->xp_context = EXPAND_USER_NARGS;
|
||||
xp->xp_pattern = p + 1;
|
||||
return NULL;
|
||||
}
|
||||
else if (STRNICMP(arg, "addr", p - arg) == 0)
|
||||
{
|
||||
xp->xp_context = EXPAND_USER_ADDR_TYPE;
|
||||
xp->xp_pattern = p + 1;
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -417,7 +421,9 @@ get_user_command_name(int idx, int cmdidx)
|
||||
char_u *
|
||||
get_user_cmd_addr_type(expand_T *xp UNUSED, int idx)
|
||||
{
|
||||
return (char_u *)addr_type_complete[idx].name;
|
||||
if (idx < 0 || idx >= (int)ARRAY_LENGTH(addr_type_complete_tab))
|
||||
return NULL;
|
||||
return (char_u *)addr_type_complete_tab[idx].fullname;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -432,7 +438,7 @@ get_user_cmd_flags(expand_T *xp UNUSED, int idx)
|
||||
"count", "nargs", "range", "register", "keepscript"
|
||||
};
|
||||
|
||||
if (idx >= (int)ARRAY_LENGTH(user_cmd_flags))
|
||||
if (idx < 0 || idx >= (int)ARRAY_LENGTH(user_cmd_flags))
|
||||
return NULL;
|
||||
return (char_u *)user_cmd_flags[idx];
|
||||
}
|
||||
@ -445,7 +451,7 @@ get_user_cmd_nargs(expand_T *xp UNUSED, int idx)
|
||||
{
|
||||
static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"};
|
||||
|
||||
if (idx >= (int)ARRAY_LENGTH(user_cmd_nargs))
|
||||
if (idx < 0 || idx >= (int)ARRAY_LENGTH(user_cmd_nargs))
|
||||
return NULL;
|
||||
return (char_u *)user_cmd_nargs[idx];
|
||||
}
|
||||
@ -457,7 +463,24 @@ get_user_cmd_nargs(expand_T *xp UNUSED, int idx)
|
||||
char_u *
|
||||
get_user_cmd_complete(expand_T *xp UNUSED, int idx)
|
||||
{
|
||||
return (char_u *)command_complete[idx].name;
|
||||
if (idx < 0 || idx >= (int)ARRAY_LENGTH(command_complete_tab))
|
||||
return NULL;
|
||||
return (char_u *)command_complete_tab[idx].value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the row in the command_complete_tab table that contains the given key.
|
||||
*/
|
||||
static keyvalue_T *
|
||||
get_commandtype(int expand)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (int)ARRAY_LENGTH(command_complete_tab); ++i)
|
||||
if (command_complete_tab[i].key == expand)
|
||||
return &command_complete_tab[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
@ -467,13 +490,11 @@ get_user_cmd_complete(expand_T *xp UNUSED, int idx)
|
||||
char_u *
|
||||
cmdcomplete_type_to_str(int expand)
|
||||
{
|
||||
int i;
|
||||
keyvalue_T *kv;
|
||||
|
||||
for (i = 0; command_complete[i].expand != 0; i++)
|
||||
if (command_complete[i].expand == expand)
|
||||
return (char_u *)command_complete[i].name;
|
||||
kv = get_commandtype(expand);
|
||||
|
||||
return NULL;
|
||||
return (kv == NULL) ? NULL : (char_u *)kv->value;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -483,18 +504,35 @@ cmdcomplete_type_to_str(int expand)
|
||||
int
|
||||
cmdcomplete_str_to_type(char_u *complete_str)
|
||||
{
|
||||
int i;
|
||||
keyvalue_T target;
|
||||
keyvalue_T *entry;
|
||||
static keyvalue_T *last_entry = NULL; // cached result
|
||||
|
||||
if (STRNCMP(complete_str, "custom,", 7) == 0)
|
||||
return EXPAND_USER_DEFINED;
|
||||
if (STRNCMP(complete_str, "customlist,", 11) == 0)
|
||||
return EXPAND_USER_LIST;
|
||||
|
||||
for (i = 0; command_complete[i].expand != 0; ++i)
|
||||
if (STRCMP(complete_str, command_complete[i].name) == 0)
|
||||
return command_complete[i].expand;
|
||||
target.key = 0;
|
||||
target.value = (char *)complete_str;
|
||||
target.length = 0; // not used, see cmp_keyvalue_value()
|
||||
|
||||
return EXPAND_NOTHING;
|
||||
if (last_entry != NULL && cmp_keyvalue_value(&target, last_entry) == 0)
|
||||
entry = last_entry;
|
||||
else
|
||||
{
|
||||
entry = (keyvalue_T *)bsearch(&target,
|
||||
&command_complete_tab,
|
||||
ARRAY_LENGTH(command_complete_tab),
|
||||
sizeof(command_complete_tab[0]),
|
||||
cmp_keyvalue_value);
|
||||
if (entry == NULL)
|
||||
return EXPAND_NOTHING;
|
||||
|
||||
last_entry = entry;
|
||||
}
|
||||
|
||||
return entry->key;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -511,6 +549,7 @@ uc_list(char_u *name, size_t name_len)
|
||||
int over;
|
||||
long a;
|
||||
garray_T *gap;
|
||||
keyvalue_T *entry;
|
||||
|
||||
// don't allow for adding or removing user commands here
|
||||
++ucmd_locked;
|
||||
@ -564,7 +603,7 @@ uc_list(char_u *name, size_t name_len)
|
||||
msg_putchar(' ');
|
||||
|
||||
msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D));
|
||||
len = (int)STRLEN(cmd->uc_name) + 4;
|
||||
len = (int)cmd->uc_namelen + 4;
|
||||
|
||||
do {
|
||||
msg_putchar(' ');
|
||||
@ -596,16 +635,14 @@ uc_list(char_u *name, size_t name_len)
|
||||
if (a & EX_COUNT)
|
||||
{
|
||||
// -count=N
|
||||
sprintf((char *)IObuff + len, "%ldc", cmd->uc_def);
|
||||
len += (int)STRLEN(IObuff + len);
|
||||
len += vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ldc", cmd->uc_def);
|
||||
}
|
||||
else if (a & EX_DFLALL)
|
||||
IObuff[len++] = '%';
|
||||
else if (cmd->uc_def >= 0)
|
||||
{
|
||||
// -range=N
|
||||
sprintf((char *)IObuff + len, "%ld", cmd->uc_def);
|
||||
len += (int)STRLEN(IObuff + len);
|
||||
len += vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ld", cmd->uc_def);
|
||||
}
|
||||
else
|
||||
IObuff[len++] = '.';
|
||||
@ -616,12 +653,12 @@ uc_list(char_u *name, size_t name_len)
|
||||
} while (len < 8 - over);
|
||||
|
||||
// Address Type
|
||||
for (j = 0; addr_type_complete[j].expand != ADDR_NONE; ++j)
|
||||
if (addr_type_complete[j].expand != ADDR_LINES
|
||||
&& addr_type_complete[j].expand == cmd->uc_addr_type)
|
||||
for (j = 0; j < (int)ARRAY_LENGTH(addr_type_complete_tab); ++j)
|
||||
if (addr_type_complete_tab[j].key != ADDR_LINES
|
||||
&& addr_type_complete_tab[j].key == cmd->uc_addr_type)
|
||||
{
|
||||
STRCPY(IObuff + len, addr_type_complete[j].shortname);
|
||||
len += (int)STRLEN(IObuff + len);
|
||||
STRCPY(IObuff + len, addr_type_complete_tab[j].shortname);
|
||||
len += (int)addr_type_complete_tab[j].shortnamelen;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -630,28 +667,31 @@ uc_list(char_u *name, size_t name_len)
|
||||
} while (len < 13 - over);
|
||||
|
||||
// Completion
|
||||
for (j = 0; command_complete[j].expand != 0; ++j)
|
||||
if (command_complete[j].expand == cmd->uc_compl)
|
||||
{
|
||||
STRCPY(IObuff + len, command_complete[j].name);
|
||||
len += (int)STRLEN(IObuff + len);
|
||||
entry = get_commandtype(cmd->uc_compl);
|
||||
if (entry != NULL)
|
||||
{
|
||||
STRCPY(IObuff + len, entry->value);
|
||||
len += entry->length;
|
||||
#ifdef FEAT_EVAL
|
||||
if (p_verbose > 0 && cmd->uc_compl_arg != NULL
|
||||
&& STRLEN(cmd->uc_compl_arg) < 200)
|
||||
if (p_verbose > 0 && cmd->uc_compl_arg != NULL)
|
||||
{
|
||||
size_t uc_compl_arglen = STRLEN(cmd->uc_compl_arg);
|
||||
|
||||
if (uc_compl_arglen < 200)
|
||||
{
|
||||
IObuff[len] = ',';
|
||||
STRCPY(IObuff + len + 1, cmd->uc_compl_arg);
|
||||
len += (int)STRLEN(IObuff + len);
|
||||
IObuff[len++] = ',';
|
||||
STRCPY(IObuff + len, cmd->uc_compl_arg);
|
||||
len += uc_compl_arglen;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
do {
|
||||
IObuff[len++] = ' ';
|
||||
} while (len < 25 - over);
|
||||
|
||||
IObuff[len] = '\0';
|
||||
IObuff[len] = NUL;
|
||||
msg_outtrans(IObuff);
|
||||
|
||||
msg_outtrans_special(cmd->uc_rep, FALSE,
|
||||
@ -687,7 +727,7 @@ uc_fun_cmd(void)
|
||||
|
||||
for (i = 0; fcmd[i]; ++i)
|
||||
IObuff[i] = fcmd[i] - 0x40;
|
||||
IObuff[i] = 0;
|
||||
IObuff[i] = NUL;
|
||||
return (char *)IObuff;
|
||||
}
|
||||
|
||||
@ -700,33 +740,52 @@ parse_addr_type_arg(
|
||||
int vallen,
|
||||
cmd_addr_T *addr_type_arg)
|
||||
{
|
||||
int i, a, b;
|
||||
addrtype_T target;
|
||||
addrtype_T *entry;
|
||||
static addrtype_T *last_entry; // cached result
|
||||
|
||||
for (i = 0; addr_type_complete[i].expand != ADDR_NONE; ++i)
|
||||
target.key = 0;
|
||||
target.fullname = (char *)value;
|
||||
target.fullnamelen = vallen;
|
||||
|
||||
if (last_entry != NULL && cmp_addr_type(&target, last_entry) == 0)
|
||||
entry = last_entry;
|
||||
else
|
||||
{
|
||||
a = (int)STRLEN(addr_type_complete[i].name) == vallen;
|
||||
b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0;
|
||||
if (a && b)
|
||||
entry = (addrtype_T *)bsearch(&target,
|
||||
&addr_type_complete_tab,
|
||||
ARRAY_LENGTH(addr_type_complete_tab),
|
||||
sizeof(addr_type_complete_tab[0]),
|
||||
cmp_addr_type);
|
||||
if (entry == NULL)
|
||||
{
|
||||
*addr_type_arg = addr_type_complete[i].expand;
|
||||
break;
|
||||
int i;
|
||||
char_u *err = value;
|
||||
|
||||
for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++)
|
||||
;
|
||||
err[i] = NUL;
|
||||
semsg(_(e_invalid_address_type_value_str), err);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
last_entry = entry;
|
||||
}
|
||||
|
||||
if (addr_type_complete[i].expand == ADDR_NONE)
|
||||
{
|
||||
char_u *err = value;
|
||||
|
||||
for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++)
|
||||
;
|
||||
err[i] = NUL;
|
||||
semsg(_(e_invalid_address_type_value_str), err);
|
||||
return FAIL;
|
||||
}
|
||||
*addr_type_arg = entry->key;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_addr_type(const void *a, const void *b)
|
||||
{
|
||||
addrtype_T *at1 = (addrtype_T *)a;
|
||||
addrtype_T *at2 = (addrtype_T *)b;
|
||||
|
||||
return STRNCMP(at1->fullname, at2->fullname, MAX(at1->fullnamelen, at2->fullnamelen));
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a completion argument "value[vallen]".
|
||||
* The detected completion goes in "*complp", argument type in "*argt".
|
||||
@ -748,6 +807,9 @@ parse_compl_arg(
|
||||
# endif
|
||||
int i;
|
||||
int valend = vallen;
|
||||
keyvalue_T target;
|
||||
keyvalue_T *entry;
|
||||
static keyvalue_T *last_entry = NULL; // cached result
|
||||
|
||||
// Look for any argument part - which is the part after any ','
|
||||
for (i = 0; i < vallen; ++i)
|
||||
@ -763,33 +825,40 @@ parse_compl_arg(
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; command_complete[i].expand != 0; ++i)
|
||||
target.key = 0;
|
||||
target.value = (char *)value;
|
||||
target.length = valend;
|
||||
|
||||
if (last_entry != NULL && cmp_keyvalue_value_n(&target, last_entry) == 0)
|
||||
entry = last_entry;
|
||||
else
|
||||
{
|
||||
if ((int)STRLEN(command_complete[i].name) == valend
|
||||
&& STRNCMP(value, command_complete[i].name, valend) == 0)
|
||||
entry = (keyvalue_T *)bsearch(&target,
|
||||
&command_complete_tab,
|
||||
ARRAY_LENGTH(command_complete_tab),
|
||||
sizeof(command_complete_tab[0]),
|
||||
cmp_keyvalue_value_n);
|
||||
if (entry == NULL)
|
||||
{
|
||||
*complp = command_complete[i].expand;
|
||||
if (command_complete[i].expand == EXPAND_BUFFERS)
|
||||
*argt |= EX_BUFNAME;
|
||||
else if (command_complete[i].expand == EXPAND_DIRECTORIES
|
||||
|| command_complete[i].expand == EXPAND_FILES)
|
||||
*argt |= EX_XFILE;
|
||||
break;
|
||||
semsg(_(e_invalid_complete_value_str), value);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
last_entry = entry;
|
||||
}
|
||||
|
||||
if (command_complete[i].expand == 0)
|
||||
{
|
||||
semsg(_(e_invalid_complete_value_str), value);
|
||||
return FAIL;
|
||||
}
|
||||
*complp = entry->key;
|
||||
if (*complp == EXPAND_BUFFERS)
|
||||
*argt |= EX_BUFNAME;
|
||||
else if (*complp == EXPAND_DIRECTORIES || *complp == EXPAND_FILES)
|
||||
*argt |= EX_XFILE;
|
||||
|
||||
if (
|
||||
# if defined(FEAT_EVAL)
|
||||
if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST
|
||||
&& arg != NULL)
|
||||
# else
|
||||
if (arg != NULL)
|
||||
*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST
|
||||
&&
|
||||
# endif
|
||||
arg != NULL)
|
||||
{
|
||||
emsg(_(e_completion_argument_only_allowed_for_custom_completion));
|
||||
return FAIL;
|
||||
@ -806,6 +875,7 @@ parse_compl_arg(
|
||||
if (arg != NULL)
|
||||
*compl_arg = vim_strnsave(arg, arglen);
|
||||
# endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -1023,16 +1093,13 @@ uc_add_command(
|
||||
// Search for the command in the already defined commands.
|
||||
for (i = 0; i < gap->ga_len; ++i)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
cmd = USER_CMD_GA(gap, i);
|
||||
len = STRLEN(cmd->uc_name);
|
||||
cmp = STRNCMP(name, cmd->uc_name, name_len);
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (name_len < len)
|
||||
if (name_len < cmd->uc_namelen)
|
||||
cmp = -1;
|
||||
else if (name_len > len)
|
||||
else if (name_len > cmd->uc_namelen)
|
||||
cmp = 1;
|
||||
}
|
||||
|
||||
@ -1078,6 +1145,7 @@ uc_add_command(
|
||||
++gap->ga_len;
|
||||
|
||||
cmd->uc_name = p;
|
||||
cmd->uc_namelen = name_len;
|
||||
}
|
||||
|
||||
cmd->uc_rep = rep_buf;
|
||||
@ -1199,7 +1267,7 @@ ex_command(exarg_T *eap)
|
||||
p = skipwhite(end);
|
||||
if (!has_attr && ends_excmd2(eap->arg, p))
|
||||
{
|
||||
uc_list(name, end - name);
|
||||
uc_list(name, name_len);
|
||||
}
|
||||
else if (!ASCII_ISUPPER(*name))
|
||||
{
|
||||
@ -1282,6 +1350,7 @@ uc_clear(garray_T *gap)
|
||||
{
|
||||
cmd = USER_CMD_GA(gap, i);
|
||||
vim_free(cmd->uc_name);
|
||||
cmd->uc_namelen = 0;
|
||||
vim_free(cmd->uc_rep);
|
||||
# if defined(FEAT_EVAL)
|
||||
vim_free(cmd->uc_compl_arg);
|
||||
@ -1439,30 +1508,31 @@ uc_split_args(char_u *arg, size_t *lenp)
|
||||
}
|
||||
}
|
||||
*q++ = '"';
|
||||
*q = 0;
|
||||
*q = NUL;
|
||||
|
||||
*lenp = len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static size_t
|
||||
add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods)
|
||||
add_cmd_modifier(char_u *buf, size_t buflen, char *mod_str, size_t mod_strlen, int *multi_mods)
|
||||
{
|
||||
size_t result;
|
||||
|
||||
result = STRLEN(mod_str);
|
||||
if (*multi_mods)
|
||||
result += 1;
|
||||
if (buf != NULL)
|
||||
{
|
||||
if (*multi_mods)
|
||||
STRCAT(buf, " ");
|
||||
STRCAT(buf, mod_str);
|
||||
{
|
||||
STRCPY(buf + buflen, " "); // the separating space
|
||||
++buflen;
|
||||
}
|
||||
STRCPY(buf + buflen, mod_str);
|
||||
}
|
||||
|
||||
*multi_mods = 1;
|
||||
if (*multi_mods)
|
||||
++mod_strlen; // +1 for the separating space
|
||||
else
|
||||
*multi_mods = 1;
|
||||
|
||||
return result;
|
||||
return mod_strlen;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1472,17 +1542,17 @@ add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods)
|
||||
size_t
|
||||
add_win_cmd_modifiers(char_u *buf, cmdmod_T *cmod, int *multi_mods)
|
||||
{
|
||||
size_t result = 0;
|
||||
size_t buflen = 0;
|
||||
|
||||
// :aboveleft and :leftabove
|
||||
if (cmod->cmod_split & WSP_ABOVE)
|
||||
result += add_cmd_modifier(buf, "aboveleft", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "aboveleft", STRLEN_LITERAL("aboveleft"), multi_mods);
|
||||
// :belowright and :rightbelow
|
||||
if (cmod->cmod_split & WSP_BELOW)
|
||||
result += add_cmd_modifier(buf, "belowright", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "belowright", STRLEN_LITERAL("belowright"), multi_mods);
|
||||
// :botright
|
||||
if (cmod->cmod_split & WSP_BOT)
|
||||
result += add_cmd_modifier(buf, "botright", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "botright", STRLEN_LITERAL("botright"), multi_mods);
|
||||
|
||||
// :tab
|
||||
if (cmod->cmod_tab > 0)
|
||||
@ -1493,27 +1563,29 @@ add_win_cmd_modifiers(char_u *buf, cmdmod_T *cmod, int *multi_mods)
|
||||
{
|
||||
// For compatibility, don't add a tabpage number if it is the same
|
||||
// as the default number for :tab.
|
||||
result += add_cmd_modifier(buf, "tab", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "tab", STRLEN_LITERAL("tab"), multi_mods);
|
||||
}
|
||||
else
|
||||
{
|
||||
char tab_buf[NUMBUFLEN + 3];
|
||||
size_t tab_buflen;
|
||||
|
||||
sprintf(tab_buf, "%dtab", tabnr);
|
||||
result += add_cmd_modifier(buf, tab_buf, multi_mods);
|
||||
tab_buflen = vim_snprintf(tab_buf, sizeof(tab_buf), "%dtab", tabnr);
|
||||
buflen += add_cmd_modifier(buf, buflen, tab_buf, tab_buflen, multi_mods);
|
||||
}
|
||||
}
|
||||
|
||||
// :topleft
|
||||
if (cmod->cmod_split & WSP_TOP)
|
||||
result += add_cmd_modifier(buf, "topleft", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "topleft", STRLEN_LITERAL("topleft"), multi_mods);
|
||||
// :vertical
|
||||
if (cmod->cmod_split & WSP_VERT)
|
||||
result += add_cmd_modifier(buf, "vertical", multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "vertical", STRLEN_LITERAL("vertical"), multi_mods);
|
||||
// :horizontal
|
||||
if (cmod->cmod_split & WSP_HOR)
|
||||
result += add_cmd_modifier(buf, "horizontal", multi_mods);
|
||||
return result;
|
||||
buflen += add_cmd_modifier(buf, buflen, "horizontal", STRLEN_LITERAL("horizontal"), multi_mods);
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1523,78 +1595,92 @@ add_win_cmd_modifiers(char_u *buf, cmdmod_T *cmod, int *multi_mods)
|
||||
size_t
|
||||
produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote)
|
||||
{
|
||||
size_t result = 0;
|
||||
size_t buflen = 0;
|
||||
int multi_mods = 0;
|
||||
int i;
|
||||
typedef struct {
|
||||
int flag;
|
||||
char *name;
|
||||
} mod_entry_T;
|
||||
static mod_entry_T mod_entries[] = {
|
||||
static keyvalue_T mod_entry_tab[] =
|
||||
{
|
||||
#ifdef FEAT_BROWSE_CMD
|
||||
{CMOD_BROWSE, "browse"},
|
||||
KEYVALUE_ENTRY(CMOD_BROWSE, "browse"),
|
||||
#endif
|
||||
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
|
||||
{CMOD_CONFIRM, "confirm"},
|
||||
KEYVALUE_ENTRY(CMOD_CONFIRM, "confirm"),
|
||||
#endif
|
||||
{CMOD_HIDE, "hide"},
|
||||
{CMOD_KEEPALT, "keepalt"},
|
||||
{CMOD_KEEPJUMPS, "keepjumps"},
|
||||
{CMOD_KEEPMARKS, "keepmarks"},
|
||||
{CMOD_KEEPPATTERNS, "keeppatterns"},
|
||||
{CMOD_LOCKMARKS, "lockmarks"},
|
||||
{CMOD_NOSWAPFILE, "noswapfile"},
|
||||
{CMOD_UNSILENT, "unsilent"},
|
||||
{CMOD_NOAUTOCMD, "noautocmd"},
|
||||
KEYVALUE_ENTRY(CMOD_HIDE, "hide"),
|
||||
KEYVALUE_ENTRY(CMOD_KEEPALT, "keepalt"),
|
||||
KEYVALUE_ENTRY(CMOD_KEEPJUMPS, "keepjumps"),
|
||||
KEYVALUE_ENTRY(CMOD_KEEPMARKS, "keepmarks"),
|
||||
KEYVALUE_ENTRY(CMOD_KEEPPATTERNS, "keeppatterns"),
|
||||
KEYVALUE_ENTRY(CMOD_LOCKMARKS, "lockmarks"),
|
||||
KEYVALUE_ENTRY(CMOD_NOSWAPFILE, "noswapfile"),
|
||||
KEYVALUE_ENTRY(CMOD_UNSILENT, "unsilent"),
|
||||
KEYVALUE_ENTRY(CMOD_NOAUTOCMD, "noautocmd"),
|
||||
#ifdef HAVE_SANDBOX
|
||||
{CMOD_SANDBOX, "sandbox"},
|
||||
KEYVALUE_ENTRY(CMOD_SANDBOX, "sandbox"),
|
||||
#endif
|
||||
{CMOD_LEGACY, "legacy"},
|
||||
{0, NULL}
|
||||
KEYVALUE_ENTRY(CMOD_LEGACY, "legacy")
|
||||
};
|
||||
|
||||
result = quote ? 2 : 0;
|
||||
if (buf != NULL)
|
||||
if (quote)
|
||||
{
|
||||
if (quote)
|
||||
*buf++ = '"';
|
||||
*buf = '\0';
|
||||
++buflen;
|
||||
if (buf != NULL)
|
||||
{
|
||||
*buf = '"';
|
||||
*(buf + buflen) = NUL;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (buf != NULL)
|
||||
*buf = NUL;
|
||||
|
||||
// the modifiers that are simple flags
|
||||
for (i = 0; mod_entries[i].name != NULL; ++i)
|
||||
if (cmod->cmod_flags & mod_entries[i].flag)
|
||||
result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods);
|
||||
for (i = 0; i < (int)ARRAY_LENGTH(mod_entry_tab); ++i)
|
||||
if (cmod->cmod_flags & mod_entry_tab[i].key)
|
||||
buflen += add_cmd_modifier(buf, buflen, mod_entry_tab[i].value, mod_entry_tab[i].length, &multi_mods);
|
||||
|
||||
// :silent
|
||||
if (cmod->cmod_flags & CMOD_SILENT)
|
||||
result += add_cmd_modifier(buf,
|
||||
(cmod->cmod_flags & CMOD_ERRSILENT) ? "silent!"
|
||||
: "silent", &multi_mods);
|
||||
{
|
||||
if (cmod->cmod_flags & CMOD_ERRSILENT)
|
||||
buflen += add_cmd_modifier(buf, buflen, "silent!", STRLEN_LITERAL("silent!"), &multi_mods);
|
||||
else
|
||||
buflen += add_cmd_modifier(buf, buflen, "silent", STRLEN_LITERAL("silent"), &multi_mods);
|
||||
}
|
||||
|
||||
// :verbose
|
||||
if (cmod->cmod_verbose > 0)
|
||||
{
|
||||
int verbose_value = cmod->cmod_verbose - 1;
|
||||
|
||||
if (verbose_value == 1)
|
||||
result += add_cmd_modifier(buf, "verbose", &multi_mods);
|
||||
buflen += add_cmd_modifier(buf, buflen, "verbose", STRLEN_LITERAL("verbose"), &multi_mods);
|
||||
else
|
||||
{
|
||||
char verbose_buf[NUMBUFLEN];
|
||||
size_t verbose_buflen;
|
||||
|
||||
sprintf(verbose_buf, "%dverbose", verbose_value);
|
||||
result += add_cmd_modifier(buf, verbose_buf, &multi_mods);
|
||||
verbose_buflen = vim_snprintf(verbose_buf, sizeof(verbose_buf), "%dverbose", verbose_value);
|
||||
buflen += add_cmd_modifier(buf, buflen, verbose_buf, verbose_buflen, &multi_mods);
|
||||
}
|
||||
}
|
||||
// flags from cmod->cmod_split
|
||||
result += add_win_cmd_modifiers(buf, cmod, &multi_mods);
|
||||
|
||||
if (quote && buf != NULL)
|
||||
// flags from cmod->cmod_split
|
||||
buflen += add_win_cmd_modifiers((buf == NULL) ? NULL : buf + buflen, cmod, &multi_mods);
|
||||
|
||||
if (quote)
|
||||
{
|
||||
buf += result - 2;
|
||||
*buf = '"';
|
||||
if (buf == NULL)
|
||||
++buflen;
|
||||
else
|
||||
{
|
||||
*(buf + buflen) = '"';
|
||||
++buflen;
|
||||
*(buf + buflen) = NUL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1755,15 +1841,14 @@ uc_check_code(
|
||||
case ct_RANGE:
|
||||
case ct_COUNT:
|
||||
{
|
||||
char num_buf[20];
|
||||
char num_buf[NUMBUFLEN];
|
||||
long num = (type == ct_LINE1) ? eap->line1 :
|
||||
(type == ct_LINE2) ? eap->line2 :
|
||||
(type == ct_RANGE) ? eap->addr_count :
|
||||
(eap->addr_count > 0) ? eap->line2 : cmd->uc_def;
|
||||
size_t num_len;
|
||||
|
||||
sprintf(num_buf, "%ld", num);
|
||||
num_len = STRLEN(num_buf);
|
||||
num_len = vim_snprintf(num_buf, sizeof(num_buf), "%ld", num);
|
||||
result = num_len;
|
||||
|
||||
if (quote)
|
||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
685,
|
||||
/**/
|
||||
684,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user