Merge #8866 from janlazo/vim-8.0.0878

This commit is contained in:
Justin M. Keyes 2018-08-20 23:09:10 +02:00 committed by GitHub
commit 0839c44257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 365 additions and 164 deletions

View File

@ -163,12 +163,14 @@ CTRL-R CTRL-F *c_CTRL-R_CTRL-F* *c_<C-R>_<C-F>*
CTRL-R CTRL-P *c_CTRL-R_CTRL-P* *c_<C-R>_<C-P>* CTRL-R CTRL-P *c_CTRL-R_CTRL-P* *c_<C-R>_<C-P>*
CTRL-R CTRL-W *c_CTRL-R_CTRL-W* *c_<C-R>_<C-W>* CTRL-R CTRL-W *c_CTRL-R_CTRL-W* *c_<C-R>_<C-W>*
CTRL-R CTRL-A *c_CTRL-R_CTRL-A* *c_<C-R>_<C-A>* CTRL-R CTRL-A *c_CTRL-R_CTRL-A* *c_<C-R>_<C-A>*
CTRL-R CTRL-L *c_CTRL-R_CTRL-L* *c_<C-R>_<C-L>*
Insert the object under the cursor: Insert the object under the cursor:
CTRL-F the Filename under the cursor CTRL-F the Filename under the cursor
CTRL-P the Filename under the cursor, expanded with CTRL-P the Filename under the cursor, expanded with
'path' as in |gf| 'path' as in |gf|
CTRL-W the Word under the cursor CTRL-W the Word under the cursor
CTRL-A the WORD under the cursor; see |WORD| CTRL-A the WORD under the cursor; see |WORD|
CTRL-L the line under the cursor
When 'incsearch' is set the cursor position at the end of the When 'incsearch' is set the cursor position at the end of the
currently displayed match is used. With CTRL-W the part of currently displayed match is used. With CTRL-W the part of
@ -176,8 +178,8 @@ CTRL-R CTRL-A *c_CTRL-R_CTRL-A* *c_<C-R>_<C-A>*
*c_CTRL-R_CTRL-R* *c_<C-R>_<C-R>* *c_CTRL-R_CTRL-R* *c_<C-R>_<C-R>*
*c_CTRL-R_CTRL-O* *c_<C-R>_<C-O>* *c_CTRL-R_CTRL-O* *c_<C-R>_<C-O>*
CTRL-R CTRL-R {0-9a-z"%#:-=. CTRL-F CTRL-P CTRL-W CTRL-A} CTRL-R CTRL-R {0-9a-z"%#:-=. CTRL-F CTRL-P CTRL-W CTRL-A CTRL-L}
CTRL-R CTRL-O {0-9a-z"%#:-=. CTRL-F CTRL-P CTRL-W CTRL-A} CTRL-R CTRL-O {0-9a-z"%#:-=. CTRL-F CTRL-P CTRL-W CTRL-A CTRL-L}
Insert register or object under the cursor. Works like Insert register or object under the cursor. Works like
|c_CTRL-R| but inserts the text literally. For example, if |c_CTRL-R| but inserts the text literally. For example, if
register a contains "xy^Hz" (where ^H is a backspace), register a contains "xy^Hz" (where ^H is a backspace),
@ -786,6 +788,11 @@ Also see |`=|.
Note: these are typed literally, they are not special keys! Note: these are typed literally, they are not special keys!
<cword> is replaced with the word under the cursor (like |star|) <cword> is replaced with the word under the cursor (like |star|)
<cWORD> is replaced with the WORD under the cursor (see |WORD|) <cWORD> is replaced with the WORD under the cursor (see |WORD|)
<cexpr> is replaced with the word under the cursor, including more
to form a C expression. E.g., when the cursor is on "arg"
of "ptr->arg" then the result is "ptr->arg"; when the
cursor is on "]" of "list[idx]" then the result is
"list[idx]". This is used for |v:beval_text|.
<cfile> is replaced with the path name under the cursor (like what <cfile> is replaced with the path name under the cursor (like what
|gf| uses) |gf| uses)
<afile> When executing autocommands, is replaced with the file name <afile> When executing autocommands, is replaced with the file name

View File

@ -4079,6 +4079,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
specifies what for. The following completion types are specifies what for. The following completion types are
supported: supported:
arglist file names in argument list
augroup autocmd groups augroup autocmd groups
buffer buffer names buffer buffer names
behave :behave suboptions behave :behave suboptions
@ -4099,6 +4100,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
highlight highlight groups highlight highlight groups
history :history suboptions history :history suboptions
locale locale names (as output of locale -a) locale locale names (as output of locale -a)
mapclear buffer argument
mapping mapping name mapping mapping name
menu menus menu menus
messages |:messages| suboptions messages |:messages| suboptions

View File

@ -1208,6 +1208,7 @@ By default, the arguments of user defined commands do not undergo completion.
However, by specifying one or the other of the following attributes, argument However, by specifying one or the other of the following attributes, argument
completion can be enabled: completion can be enabled:
-complete=arglist file names in argument list
-complete=augroup autocmd groups -complete=augroup autocmd groups
-complete=buffer buffer names -complete=buffer buffer names
-complete=behave :behave suboptions -complete=behave :behave suboptions
@ -1227,6 +1228,7 @@ completion can be enabled:
-complete=highlight highlight groups -complete=highlight highlight groups
-complete=history :history suboptions -complete=history :history suboptions
-complete=locale locale names (as output of locale -a) -complete=locale locale names (as output of locale -a)
-complete=mapclear buffer argument
-complete=mapping mapping name -complete=mapping mapping name
-complete=menu menus -complete=menu menus
-complete=messages |:messages| suboptions -complete=messages |:messages| suboptions

View File

@ -2659,9 +2659,8 @@ buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum)
* Get alternate file name for current window. * Get alternate file name for current window.
* Return NULL if there isn't any, and give error message if requested. * Return NULL if there isn't any, and give error message if requested.
*/ */
char_u * char_u * getaltfname(
getaltfname ( bool errmsg // give error message
int errmsg /* give error message */
) )
{ {
char_u *fname; char_u *fname;

View File

@ -2254,6 +2254,15 @@ static int alist_add_list(int count, char_u **files, int after)
} }
} }
// Function given to ExpandGeneric() to obtain the possible arguments of the
// argedit and argdelete commands.
char_u *get_arglist_name(expand_T *xp FUNC_ATTR_UNUSED, int idx)
{
if (idx >= ARGCOUNT) {
return NULL;
}
return alist_name(&ARGLIST[idx]);
}
/// ":compiler[!] {name}" /// ":compiler[!] {name}"
void ex_compiler(exarg_T *eap) void ex_compiler(exarg_T *eap)

View File

@ -2665,8 +2665,8 @@ const char * set_one_cmd_context(
size_t len = 0; size_t len = 0;
exarg_T ea; exarg_T ea;
int context = EXPAND_NOTHING; int context = EXPAND_NOTHING;
int forceit = false; bool forceit = false;
int usefilter = false; // Filter instead of file name. bool usefilter = false; // Filter instead of file name.
ExpandInit(xp); ExpandInit(xp);
xp->xp_pattern = (char_u *)buff; xp->xp_pattern = (char_u *)buff;
@ -2786,9 +2786,9 @@ const char * set_one_cmd_context(
xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */ xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */
if (*p == '!') { /* forced commands */ if (*p == '!') { // forced commands
forceit = TRUE; forceit = true;
++p; p++;
} }
/* /*
@ -2813,10 +2813,10 @@ const char * set_one_cmd_context(
} }
if (ea.cmdidx == CMD_read) { if (ea.cmdidx == CMD_read) {
usefilter = forceit; /* :r! filter if forced */ usefilter = forceit; // :r! filter if forced
if (*arg == '!') { /* :r !filter */ if (*arg == '!') { // :r !filter
++arg; arg++;
usefilter = TRUE; usefilter = true;
} }
} }
@ -2978,7 +2978,7 @@ const char * set_one_cmd_context(
// A full match ~user<Tab> will be replaced by user's home // A full match ~user<Tab> will be replaced by user's home
// directory i.e. something like ~user<Tab> -> /home/user/ // directory i.e. something like ~user<Tab> -> /home/user/
if (*p == NUL && p > (const char *)xp->xp_pattern + 1 if (*p == NUL && p > (const char *)xp->xp_pattern + 1
&& match_user(xp->xp_pattern + 1) == 1) { && match_user(xp->xp_pattern + 1) >= 1) {
xp->xp_context = EXPAND_USER; xp->xp_context = EXPAND_USER;
++xp->xp_pattern; ++xp->xp_pattern;
} }
@ -3350,6 +3350,19 @@ const char * set_one_cmd_context(
case CMD_xunmap: case CMD_xunmap:
return (const char *)set_context_in_map_cmd( return (const char *)set_context_in_map_cmd(
xp, (char_u *)cmd, (char_u *)arg, forceit, false, true, ea.cmdidx); xp, (char_u *)cmd, (char_u *)arg, forceit, false, true, ea.cmdidx);
case CMD_mapclear:
case CMD_nmapclear:
case CMD_vmapclear:
case CMD_omapclear:
case CMD_imapclear:
case CMD_cmapclear:
case CMD_lmapclear:
case CMD_smapclear:
case CMD_xmapclear:
xp->xp_context = EXPAND_MAPCLEAR;
xp->xp_pattern = (char_u *)arg;
break;
case CMD_abbreviate: case CMD_noreabbrev: case CMD_abbreviate: case CMD_noreabbrev:
case CMD_cabbrev: case CMD_cnoreabbrev: case CMD_cabbrev: case CMD_cnoreabbrev:
case CMD_iabbrev: case CMD_inoreabbrev: case CMD_iabbrev: case CMD_inoreabbrev:
@ -3441,6 +3454,13 @@ const char * set_one_cmd_context(
xp->xp_pattern = (char_u *)arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_argdelete:
while ((xp->xp_pattern = vim_strchr((const char_u *)arg, ' ')) != NULL) {
arg = (const char *)(xp->xp_pattern + 1);
}
xp->xp_context = EXPAND_ARGLIST;
xp->xp_pattern = (char_u *)arg;
break;
default: default:
break; break;
@ -4846,6 +4866,7 @@ static struct {
*/ */
static const char *command_complete[] = static const char *command_complete[] =
{ {
[EXPAND_ARGLIST] = "arglist",
[EXPAND_AUGROUP] = "augroup", [EXPAND_AUGROUP] = "augroup",
[EXPAND_BEHAVE] = "behave", [EXPAND_BEHAVE] = "behave",
[EXPAND_BUFFERS] = "buffer", [EXPAND_BUFFERS] = "buffer",
@ -4870,6 +4891,7 @@ static const char *command_complete[] =
#ifdef HAVE_WORKING_LIBINTL #ifdef HAVE_WORKING_LIBINTL
[EXPAND_LOCALES] = "locale", [EXPAND_LOCALES] = "locale",
#endif #endif
[EXPAND_MAPCLEAR] = "mapclear",
[EXPAND_MAPPINGS] = "mapping", [EXPAND_MAPPINGS] = "mapping",
[EXPAND_MENUS] = "menu", [EXPAND_MENUS] = "menu",
[EXPAND_MESSAGES] = "messages", [EXPAND_MESSAGES] = "messages",
@ -8370,23 +8392,25 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
"%", "%",
#define SPEC_PERC 0 #define SPEC_PERC 0
"#", "#",
#define SPEC_HASH 1 #define SPEC_HASH (SPEC_PERC + 1)
"<cword>", /* cursor word */ "<cword>", // cursor word
#define SPEC_CWORD 2 #define SPEC_CWORD (SPEC_HASH + 1)
"<cWORD>", /* cursor WORD */ "<cWORD>", // cursor WORD
#define SPEC_CCWORD 3 #define SPEC_CCWORD (SPEC_CWORD + 1)
"<cfile>", /* cursor path name */ "<cexpr>", // expr under cursor
#define SPEC_CFILE 4 #define SPEC_CEXPR (SPEC_CCWORD + 1)
"<sfile>", /* ":so" file name */ "<cfile>", // cursor path name
#define SPEC_SFILE 5 #define SPEC_CFILE (SPEC_CEXPR + 1)
"<slnum>", /* ":so" file line number */ "<sfile>", // ":so" file name
#define SPEC_SLNUM 6 #define SPEC_SFILE (SPEC_CFILE + 1)
"<afile>", /* autocommand file name */ "<slnum>", // ":so" file line number
# define SPEC_AFILE 7 #define SPEC_SLNUM (SPEC_SFILE + 1)
"<abuf>", /* autocommand buffer number */ "<afile>", // autocommand file name
# define SPEC_ABUF 8 #define SPEC_AFILE (SPEC_SLNUM + 1)
"<amatch>", /* autocommand match name */ "<abuf>", // autocommand buffer number
# define SPEC_AMATCH 9 #define SPEC_ABUF (SPEC_AFILE + 1)
"<amatch>", // autocommand match name
#define SPEC_AMATCH (SPEC_ABUF + 1)
}; };
for (size_t i = 0; i < ARRAY_SIZE(spec_str); ++i) { for (size_t i = 0; i < ARRAY_SIZE(spec_str); ++i) {
@ -8467,9 +8491,15 @@ eval_vars (
/* /*
* word or WORD under cursor * word or WORD under cursor
*/ */
if (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD) { if (spec_idx == SPEC_CWORD
resultlen = find_ident_under_cursor(&result, (spec_idx == SPEC_CWORD || spec_idx == SPEC_CCWORD
|| spec_idx == SPEC_CEXPR) {
resultlen = find_ident_under_cursor(
&result,
spec_idx == SPEC_CWORD
? (FIND_IDENT | FIND_STRING) ? (FIND_IDENT | FIND_STRING)
: (spec_idx == SPEC_CEXPR
? (FIND_IDENT | FIND_STRING | FIND_EVAL)
: FIND_STRING)); : FIND_STRING));
if (resultlen == 0) { if (resultlen == 0) {
*errormsg = (char_u *)""; *errormsg = (char_u *)"";
@ -8507,9 +8537,13 @@ eval_vars (
if (*s == '<') /* "#<99" uses v:oldfiles */ if (*s == '<') /* "#<99" uses v:oldfiles */
++s; ++s;
i = getdigits_int(&s); i = getdigits_int(&s);
*usedlen = (size_t)(s - src); /* length of what we expand */ if (s == src + 2 && src[1] == '-') {
// just a minus sign, don't skip over it
s--;
}
*usedlen = (size_t)(s - src); // length of what we expand
if (src[1] == '<') { if (src[1] == '<' && i != 0) {
if (*usedlen < 2) { if (*usedlen < 2) {
/* Should we give an error message for #<text? */ /* Should we give an error message for #<text? */
*usedlen = 1; *usedlen = 1;
@ -8522,6 +8556,9 @@ eval_vars (
return NULL; return NULL;
} }
} else { } else {
if (i == 0 && src[1] == '<' && *usedlen > 1) {
*usedlen = 1;
}
buf = buflist_findnr(i); buf = buflist_findnr(i);
if (buf == NULL) { if (buf == NULL) {
*errormsg = (char_u *)_( *errormsg = (char_u *)_(
@ -9655,6 +9692,14 @@ char_u *get_messages_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
return NULL; return NULL;
} }
char_u *get_mapclear_arg(expand_T *xp FUNC_ATTR_UNUSED, int idx)
{
if (idx == 0) {
return (char_u *)"<buffer>";
}
return NULL;
}
static TriState filetype_detect = kNone; static TriState filetype_detect = kNone;
static TriState filetype_plugin = kNone; static TriState filetype_plugin = kNone;
static TriState filetype_indent = kNone; static TriState filetype_indent = kNone;

View File

@ -3290,17 +3290,18 @@ void restore_cmdline_alloc(char_u *p)
/// @returns FAIL for failure, OK otherwise /// @returns FAIL for failure, OK otherwise
static bool cmdline_paste(int regname, bool literally, bool remcr) static bool cmdline_paste(int regname, bool literally, bool remcr)
{ {
long i;
char_u *arg; char_u *arg;
char_u *p; char_u *p;
int allocated; bool allocated;
struct cmdline_info save_ccline; struct cmdline_info save_ccline;
/* check for valid regname; also accept special characters for CTRL-R in /* check for valid regname; also accept special characters for CTRL-R in
* the command line */ * the command line */
if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W if (regname != Ctrl_F && regname != Ctrl_P && regname != Ctrl_W
&& regname != Ctrl_A && !valid_yank_reg(regname, false)) && regname != Ctrl_A && regname != Ctrl_L
&& !valid_yank_reg(regname, false)) {
return FAIL; return FAIL;
}
/* A register containing CTRL-R can cause an endless loop. Allow using /* A register containing CTRL-R can cause an endless loop. Allow using
* CTRL-C to break the loop. */ * CTRL-C to break the loop. */
@ -3312,9 +3313,9 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
/* Need to save and restore ccline. And set "textlock" to avoid nasty /* Need to save and restore ccline. And set "textlock" to avoid nasty
* things like going to another buffer when evaluating an expression. */ * things like going to another buffer when evaluating an expression. */
save_cmdline(&save_ccline); save_cmdline(&save_ccline);
++textlock; textlock++;
i = get_spec_reg(regname, &arg, &allocated, TRUE); const bool i = get_spec_reg(regname, &arg, &allocated, true);
--textlock; textlock--;
restore_cmdline(&save_ccline); restore_cmdline(&save_ccline);
if (i) { if (i) {
@ -4760,6 +4761,7 @@ ExpandFromContext (
} tab[] = { } tab[] = {
{ EXPAND_COMMANDS, get_command_name, false, true }, { EXPAND_COMMANDS, get_command_name, false, true },
{ EXPAND_BEHAVE, get_behave_arg, true, true }, { EXPAND_BEHAVE, get_behave_arg, true, true },
{ EXPAND_MAPCLEAR, get_mapclear_arg, true, true },
{ EXPAND_MESSAGES, get_messages_arg, true, true }, { EXPAND_MESSAGES, get_messages_arg, true, true },
{ EXPAND_HISTORY, get_history_arg, true, true }, { EXPAND_HISTORY, get_history_arg, true, true },
{ EXPAND_USER_COMMANDS, get_user_commands, false, true }, { EXPAND_USER_COMMANDS, get_user_commands, false, true },
@ -4787,6 +4789,7 @@ ExpandFromContext (
#endif #endif
{ EXPAND_ENV_VARS, get_env_name, true, true }, { EXPAND_ENV_VARS, get_env_name, true, true },
{ EXPAND_USER, get_users, true, false }, { EXPAND_USER, get_users, true, false },
{ EXPAND_ARGLIST, get_arglist_name, true, false },
}; };
int i; int i;

View File

@ -2990,6 +2990,43 @@ void reset_VIsual(void)
} }
} }
// Check for a balloon-eval special item to include when searching for an
// identifier. When "dir" is BACKWARD "ptr[-1]" must be valid!
// Returns true if the character at "*ptr" should be included.
// "dir" is FORWARD or BACKWARD, the direction of searching.
// "*colp" is in/decremented if "ptr[-dir]" should also be included.
// "bnp" points to a counter for square brackets.
static bool find_is_eval_item(
const char_u *const ptr,
int *const colp,
int *const bnp,
const int dir)
{
// Accept everything inside [].
if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) {
*bnp += 1;
}
if (*bnp > 0) {
if ((*ptr == '[' && dir == BACKWARD) || (*ptr == ']' && dir == FORWARD)) {
*bnp -= 1;
}
return true;
}
// skip over "s.var"
if (*ptr == '.') {
return true;
}
// two-character item: s->var
if (ptr[dir == BACKWARD ? 0 : 1] == '>'
&& ptr[dir == BACKWARD ? -1 : 0] == '-') {
*colp += dir;
return true;
}
return false;
}
/* /*
* Find the identifier under or to the right of the cursor. * Find the identifier under or to the right of the cursor.
* "find_type" can have one of three values: * "find_type" can have one of three values:
@ -3030,6 +3067,7 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
int this_class = 0; int this_class = 0;
int prev_class; int prev_class;
int prevcol; int prevcol;
int bn = 0; // bracket nesting
/* /*
* if i == 0: try to find an identifier * if i == 0: try to find an identifier
@ -3041,71 +3079,62 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
* 1. skip to start of identifier/string * 1. skip to start of identifier/string
*/ */
col = startcol; col = startcol;
if (has_mbyte) {
while (ptr[col] != NUL) { while (ptr[col] != NUL) {
this_class = mb_get_class(ptr + col); // Stop at a ']' to evaluate "a[x]".
if (this_class != 0 && (i == 1 || this_class != 1)) if ((find_type & FIND_EVAL) && ptr[col] == ']') {
break; break;
col += (*mb_ptr2len)(ptr + col);
} }
} else this_class = mb_get_class(ptr + col);
while (ptr[col] != NUL if (this_class != 0 && (i == 1 || this_class != 1)) {
&& (i == 0 ? !vim_iswordc(ptr[col]) : ascii_iswhite(ptr[col])) break;
) }
++col; col += utfc_ptr2len(ptr + col);
}
// When starting on a ']' count it, so that we include the '['.
bn = ptr[col] == ']';
/* /*
* 2. Back up to start of identifier/string. * 2. Back up to start of identifier/string.
*/ */
if (has_mbyte) { // Remember class of character under cursor.
/* Remember class of character under cursor. */ if ((find_type & FIND_EVAL) && ptr[col] == ']') {
this_class = mb_get_class((char_u *)"a");
} else {
this_class = mb_get_class(ptr + col); this_class = mb_get_class(ptr + col);
}
while (col > 0 && this_class != 0) { while (col > 0 && this_class != 0) {
prevcol = col - 1 - (*mb_head_off)(ptr, ptr + col - 1); prevcol = col - 1 - utf_head_off(ptr, ptr + col - 1);
prev_class = mb_get_class(ptr + prevcol); prev_class = mb_get_class(ptr + prevcol);
if (this_class != prev_class if (this_class != prev_class
&& (i == 0 && (i == 0
|| prev_class == 0 || prev_class == 0
|| (find_type & FIND_IDENT)) || (find_type & FIND_IDENT))
) && (!(find_type & FIND_EVAL)
|| prevcol == 0
|| !find_is_eval_item(ptr + prevcol, &prevcol, &bn, BACKWARD))) {
break; break;
}
col = prevcol; col = prevcol;
} }
/* If we don't want just any old string, or we've found an // If we don't want just any old string, or we've found an
* identifier, stop searching. */ // identifier, stop searching.
if (this_class > 2) if (this_class > 2) {
this_class = 2; this_class = 2;
if (!(find_type & FIND_STRING) || this_class == 2) }
break; if (!(find_type & FIND_STRING) || this_class == 2) {
} else {
while (col > 0
&& ((i == 0
? vim_iswordc(ptr[col - 1])
: (!ascii_iswhite(ptr[col - 1])
&& (!(find_type & FIND_IDENT)
|| !vim_iswordc(ptr[col - 1]))))
))
--col;
/* If we don't want just any old string, or we've found an
* identifier, stop searching. */
if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
break; break;
} }
} }
if (ptr[col] == NUL || (i == 0 && ( if (ptr[col] == NUL || (i == 0 && this_class != 2)) {
has_mbyte ? this_class != 2 : // didn't find an identifier or string
!vim_iswordc(ptr[col])))) { if (find_type & FIND_STRING) {
/*
* didn't find an identifier or string
*/
if (find_type & FIND_STRING)
EMSG(_("E348: No string under cursor")); EMSG(_("E348: No string under cursor"));
else } else {
EMSG(_(e_noident)); EMSG(_(e_noident));
}
return 0; return 0;
} }
ptr += col; ptr += col;
@ -3114,20 +3143,19 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol,
/* /*
* 3. Find the end if the identifier/string. * 3. Find the end if the identifier/string.
*/ */
bn = 0;
startcol -= col;
col = 0; col = 0;
if (has_mbyte) { // Search for point of changing multibyte character class.
/* Search for point of changing multibyte character class. */
this_class = mb_get_class(ptr); this_class = mb_get_class(ptr);
while (ptr[col] != NUL while (ptr[col] != NUL
&& ((i == 0 ? mb_get_class(ptr + col) == this_class && ((i == 0
? mb_get_class(ptr + col) == this_class
: mb_get_class(ptr + col) != 0) : mb_get_class(ptr + col) != 0)
)) || ((find_type & FIND_EVAL)
col += (*mb_ptr2len)(ptr + col); && col <= (int)startcol
} else && find_is_eval_item(ptr + col, &col, &bn, FORWARD)))) {
while ((i == 0 ? vim_iswordc(ptr[col]) col += utfc_ptr2len(ptr + col);
: (ptr[col] != NUL && !ascii_iswhite(ptr[col])))
) {
++col;
} }
assert(col >= 0); assert(col >= 0);

View File

@ -1110,7 +1110,7 @@ int insert_reg(
) )
{ {
int retval = OK; int retval = OK;
int allocated; bool allocated;
/* /*
* It is possible to get into an endless loop by having CTRL-R a in * It is possible to get into an endless loop by having CTRL-R a in
@ -1187,82 +1187,92 @@ static void stuffescaped(const char *arg, int literally)
} }
} }
/* // If "regname" is a special register, return true and store a pointer to its
* If "regname" is a special register, return TRUE and store a pointer to its // value in "argp".
* value in "argp". bool get_spec_reg(
*/
int get_spec_reg(
int regname, int regname,
char_u **argp, char_u **argp,
int *allocated, /* return: TRUE when value was allocated */ bool *allocated, // return: true when value was allocated
int errmsg /* give error message when failing */ bool errmsg // give error message when failing
) )
{ {
size_t cnt; size_t cnt;
*argp = NULL; *argp = NULL;
*allocated = FALSE; *allocated = false;
switch (regname) { switch (regname) {
case '%': /* file name */ case '%': /* file name */
if (errmsg) if (errmsg)
check_fname(); /* will give emsg if not set */ check_fname(); /* will give emsg if not set */
*argp = curbuf->b_fname; *argp = curbuf->b_fname;
return TRUE; return true;
case '#': /* alternate file name */ case '#': // alternate file name
*argp = getaltfname(errmsg); /* may give emsg if not set */ *argp = getaltfname(errmsg); // may give emsg if not set
return TRUE; return true;
case '=': /* result of expression */ case '=': /* result of expression */
*argp = get_expr_line(); *argp = get_expr_line();
*allocated = TRUE; *allocated = true;
return TRUE; return true;
case ':': /* last command line */ case ':': /* last command line */
if (last_cmdline == NULL && errmsg) if (last_cmdline == NULL && errmsg)
EMSG(_(e_nolastcmd)); EMSG(_(e_nolastcmd));
*argp = last_cmdline; *argp = last_cmdline;
return TRUE; return true;
case '/': /* last search-pattern */ case '/': /* last search-pattern */
if (last_search_pat() == NULL && errmsg) if (last_search_pat() == NULL && errmsg)
EMSG(_(e_noprevre)); EMSG(_(e_noprevre));
*argp = last_search_pat(); *argp = last_search_pat();
return TRUE; return true;
case '.': /* last inserted text */ case '.': /* last inserted text */
*argp = get_last_insert_save(); *argp = get_last_insert_save();
*allocated = TRUE; *allocated = true;
if (*argp == NULL && errmsg) if (*argp == NULL && errmsg) {
EMSG(_(e_noinstext)); EMSG(_(e_noinstext));
return TRUE; }
return true;
case Ctrl_F: /* Filename under cursor */ case Ctrl_F: // Filename under cursor
case Ctrl_P: /* Path under cursor, expand via "path" */ case Ctrl_P: // Path under cursor, expand via "path"
if (!errmsg) if (!errmsg) {
return FALSE; return false;
*argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP }
| (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL); *argp = file_name_at_cursor(
*allocated = TRUE; FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0),
return TRUE; 1L, NULL);
*allocated = true;
return true;
case Ctrl_W: /* word under cursor */ case Ctrl_W: // word under cursor
case Ctrl_A: /* WORD (mnemonic All) under cursor */ case Ctrl_A: // WORD (mnemonic All) under cursor
if (!errmsg) if (!errmsg) {
return FALSE; return false;
}
cnt = find_ident_under_cursor(argp, (regname == Ctrl_W cnt = find_ident_under_cursor(argp, (regname == Ctrl_W
? (FIND_IDENT|FIND_STRING) ? (FIND_IDENT|FIND_STRING)
: FIND_STRING)); : FIND_STRING));
*argp = cnt ? vim_strnsave(*argp, cnt) : NULL; *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
*allocated = TRUE; *allocated = true;
return TRUE; return true;
case Ctrl_L: // Line under cursor
if (!errmsg) {
return false;
}
*argp = ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false);
return true;
case '_': /* black hole: always empty */ case '_': /* black hole: always empty */
*argp = (char_u *)""; *argp = (char_u *)"";
return TRUE; return true;
} }
return FALSE; return false;
} }
/// Paste a yank register into the command line. /// Paste a yank register into the command line.
@ -2652,7 +2662,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
int lendiff = 0; int lendiff = 0;
pos_T old_pos; pos_T old_pos;
char_u *insert_string = NULL; char_u *insert_string = NULL;
int allocated = FALSE; bool allocated = false;
long cnt; long cnt;
if (flags & PUT_FIXINDENT) if (flags & PUT_FIXINDENT)
@ -2748,10 +2758,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
* For special registers '%' (file name), '#' (alternate file name) and * For special registers '%' (file name), '#' (alternate file name) and
* ':' (last command line), etc. we have to create a fake yank register. * ':' (last command line), etc. we have to create a fake yank register.
*/ */
if (get_spec_reg(regname, &insert_string, &allocated, TRUE)) { if (get_spec_reg(regname, &insert_string, &allocated, true)) {
if (insert_string == NULL) if (insert_string == NULL) {
return; return;
} }
}
if (!curbuf->terminal) { if (!curbuf->terminal) {
// Autocommands may be executed when saving lines for undo, which may make // Autocommands may be executed when saving lines for undo, which may make
@ -4907,10 +4918,11 @@ void *get_reg_contents(int regname, int flags)
return NULL; return NULL;
char_u *retval; char_u *retval;
int allocated; bool allocated;
if (get_spec_reg(regname, &retval, &allocated, FALSE)) { if (get_spec_reg(regname, &retval, &allocated, false)) {
if (retval == NULL) if (retval == NULL) {
return NULL; return NULL;
}
if (allocated) { if (allocated) {
return get_reg_wrap_one_line(retval, flags); return get_reg_wrap_one_line(retval, flags);
} }

View File

@ -137,6 +137,11 @@ func Test_getcompletion()
let l = getcompletion('v:notexists', 'var') let l = getcompletion('v:notexists', 'var')
call assert_equal([], l) call assert_equal([], l)
args a.c b.c
let l = getcompletion('', 'arglist')
call assert_equal(['a.c', 'b.c'], l)
%argdelete
let l = getcompletion('', 'augroup') let l = getcompletion('', 'augroup')
call assert_true(index(l, 'END') >= 0) call assert_true(index(l, 'END') >= 0)
let l = getcompletion('blahblah', 'augroup') let l = getcompletion('blahblah', 'augroup')
@ -222,6 +227,11 @@ func Test_getcompletion()
let l = getcompletion('not', 'messages') let l = getcompletion('not', 'messages')
call assert_equal([], l) call assert_equal([], l)
let l = getcompletion('', 'mapclear')
call assert_true(index(l, '<buffer>') >= 0)
let l = getcompletion('not', 'mapclear')
call assert_equal([], l)
if has('cscope') if has('cscope')
let l = getcompletion('', 'cscope') let l = getcompletion('', 'cscope')
let cmds = ['add', 'find', 'help', 'kill', 'reset', 'show'] let cmds = ['add', 'find', 'help', 'kill', 'reset', 'show']
@ -311,6 +321,9 @@ func Test_paste_in_cmdline()
call feedkeys("ft:aaa \<C-R>\<C-F> bbb\<C-B>\"\<CR>", 'tx') call feedkeys("ft:aaa \<C-R>\<C-F> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa /tmp/some bbb', @:) call assert_equal('"aaa /tmp/some bbb', @:)
call feedkeys(":aaa \<C-R>\<C-L> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa '.getline(1).' bbb', @:)
set incsearch set incsearch
call feedkeys("fy:aaa veryl\<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx') call feedkeys("fy:aaa veryl\<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa verylongword bbb', @:) call assert_equal('"aaa verylongword bbb', @:)
@ -375,6 +388,27 @@ func Test_cmdline_complete_user_cmd()
delcommand Foo delcommand Foo
endfunc endfunc
func Test_cmdline_write_alternatefile()
new
call setline('.', ['one', 'two'])
f foo.txt
new
f #-A
call assert_equal('foo.txt-A', expand('%'))
f #<-B.txt
call assert_equal('foo-B.txt', expand('%'))
f %<
call assert_equal('foo-B', expand('%'))
new
call assert_fails('f #<', 'E95')
bw!
f foo-B.txt
f %<-A
call assert_equal('foo-B-A', expand('%'))
bw!
bw!
endfunc
" using a leading backslash here " using a leading backslash here
set cpo+=C set cpo+=C
@ -430,6 +464,22 @@ func Test_getcmdtype()
cunmap <F6> cunmap <F6>
endfunc endfunc
func Test_getcmdwintype()
call feedkeys("q/:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
call assert_equal('/', a)
call feedkeys("q?:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
call assert_equal('?', a)
call feedkeys("q::let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
call assert_equal(':', a)
call feedkeys(":\<C-F>:let a = getcmdwintype()\<CR>:q\<CR>", 'x!')
call assert_equal(':', a)
call assert_equal('', getcmdwintype())
endfunc
func Test_verbosefile() func Test_verbosefile()
set verbosefile=Xlog set verbosefile=Xlog
echomsg 'foo' echomsg 'foo'
@ -440,4 +490,25 @@ func Test_verbosefile()
call delete('Xlog') call delete('Xlog')
endfunc endfunc
func Test_setcmdpos()
func InsertTextAtPos(text, pos)
call assert_equal(0, setcmdpos(a:pos))
return a:text
endfunc
" setcmdpos() with position in the middle of the command line.
call feedkeys(":\"12\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
call assert_equal('"1ab2', @:)
call feedkeys(":\"12\<C-R>\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
call assert_equal('"1b2a', @:)
" setcmdpos() with position beyond the end of the command line.
call feedkeys(":\"12\<C-B>\<C-R>=InsertTextAtPos('a', 10)\<CR>b\<CR>", 'xt')
call assert_equal('"12ab', @:)
" setcmdpos() returns 1 when not editing the command line.
call assert_equal(1, setcmdpos(3))
endfunc
set cpo& set cpo&

View File

@ -392,10 +392,31 @@ func! Test_normal10_expand()
call setline(1, ['1', 'ifooar,,cbar']) call setline(1, ['1', 'ifooar,,cbar'])
2 2
norm! $ norm! $
let a=expand('<cword>') call assert_equal('cbar', expand('<cword>'))
let b=expand('<cWORD>') call assert_equal('ifooar,,cbar', expand('<cWORD>'))
call assert_equal('cbar', a)
call assert_equal('ifooar,,cbar', b) call setline(1, ['prx = list[idx];'])
1
let expected = ['', 'prx', 'prx', 'prx',
\ 'list', 'list', 'list', 'list', 'list', 'list', 'list',
\ 'idx', 'idx', 'idx', 'idx',
\ 'list[idx]',
\ '];',
\ ]
for i in range(1, 16)
exe 'norm ' . i . '|'
call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i)
endfor
if executable('echo')
" Test expand(`...`) i.e. backticks command expansion.
" MS-Windows has a trailing space.
call assert_match('^abcde *$', expand('`echo abcde`'))
endif
" Test expand(`=...`) i.e. backticks expression expansion
call assert_equal('5', expand('`=2+3`'))
" clean up " clean up
bw! bw!
endfunc endfunc
@ -1536,12 +1557,12 @@ fun! Test_normal29_brace()
\ 'the ''{'' flag is in ''cpoptions'' then ''{'' in the first column is used as a', \ 'the ''{'' flag is in ''cpoptions'' then ''{'' in the first column is used as a',
\ 'paragraph boundary |posix|.', \ 'paragraph boundary |posix|.',
\ '{', \ '{',
\ 'This is no paragaraph', \ 'This is no paragraph',
\ 'unless the ''{'' is set', \ 'unless the ''{'' is set',
\ 'in ''cpoptions''', \ 'in ''cpoptions''',
\ '}', \ '}',
\ '.IP', \ '.IP',
\ 'The nroff macros IP seperates a paragraph', \ 'The nroff macros IP separates a paragraph',
\ 'That means, it must be a ''.''', \ 'That means, it must be a ''.''',
\ 'followed by IP', \ 'followed by IP',
\ '.LPIt does not matter, if afterwards some', \ '.LPIt does not matter, if afterwards some',
@ -1556,7 +1577,7 @@ fun! Test_normal29_brace()
1 1
norm! 0d2} norm! 0d2}
call assert_equal(['.IP', call assert_equal(['.IP',
\ 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', 'followed by IP', \ 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''', 'followed by IP',
\ '.LPIt does not matter, if afterwards some', 'more characters follow.', '.SHAlso section boundaries from the nroff', \ '.LPIt does not matter, if afterwards some', 'more characters follow.', '.SHAlso section boundaries from the nroff',
\ 'macros terminate a paragraph. That means', 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) \ 'macros terminate a paragraph. That means', 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
norm! 0d} norm! 0d}
@ -1576,21 +1597,21 @@ fun! Test_normal29_brace()
" set cpo+={ " set cpo+={
" 1 " 1
" norm! 0d2} " norm! 0d2}
" call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', " call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
" \ '.IP', 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', " \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
" \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.', " \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
" \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means', " \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
" \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) " \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
" $ " $
" norm! d} " norm! d}
" call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', " call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}',
" \ '.IP', 'The nroff macros IP seperates a paragraph', 'That means, it must be a ''.''', " \ '.IP', 'The nroff macros IP separates a paragraph', 'That means, it must be a ''.''',
" \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.', " \ 'followed by IP', '.LPIt does not matter, if afterwards some', 'more characters follow.',
" \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means', " \ '.SHAlso section boundaries from the nroff', 'macros terminate a paragraph. That means',
" \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$')) " \ 'a character like this:', '.NH', 'End of text here', ''], getline(1,'$'))
" norm! gg} " norm! gg}
" norm! d5} " norm! d5}
" call assert_equal(['{', 'This is no paragaraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', ''], getline(1,'$')) " call assert_equal(['{', 'This is no paragraph', 'unless the ''{'' is set', 'in ''cpoptions''', '}', ''], getline(1,'$'))
" clean up " clean up
set cpo-={ set cpo-={

View File

@ -155,6 +155,8 @@ enum {
EXPAND_USER_ADDR_TYPE, EXPAND_USER_ADDR_TYPE,
EXPAND_PACKADD, EXPAND_PACKADD,
EXPAND_MESSAGES, EXPAND_MESSAGES,
EXPAND_MAPCLEAR,
EXPAND_ARGLIST,
EXPAND_CHECKHEALTH, EXPAND_CHECKHEALTH,
}; };