Compare commits

...

19 Commits

Author SHA1 Message Date
Bram Moolenaar
1fc34225ac patch 8.2.4498: using <Plug> with "noremap" does not work
Problem:    Using <Plug> with "noremap" does not work.
Solution:   Always remap <Plug>. (closes #9879, closes #9789)
2022-03-03 13:56:24 +00:00
Bram Moolenaar
35d8c2010e patch 8.2.4497: wrong color for half of wide character next to pum scrollbar
Problem:    Wrong color for half of wide character next to pum scrollbar.
Solution:   Redraw the screen cell with the right color. (closes #9874)
2022-03-03 11:46:00 +00:00
Bram Moolenaar
fe9112e630 patch 8.2.4496: Coverity gives warnings after tags code refactoring
Problem:    Coverity gives warnings after tags code refactoring.
Solution:   Avoid the warnings. (Yegappan Lakshmanan, closes #9882)
2022-03-03 10:44:17 +00:00
Bram Moolenaar
e4e1a1e1c8 patch 8.2.4495: help test fails in 24 line terminal
Problem:    Help test fails in 24 line terminal.
Solution:   Use up to 23 lines for text.
2022-03-02 20:49:50 +00:00
Yegappan Lakshmanan
2f87a99b6e patch 8.2.4494: the find_tags() function is much too long
Problem:    The find_tags() function is much too long.
Solution:   Refactor the function. (Yegappan Lakshmanan, closes #9869)
2022-03-02 20:29:35 +00:00
Bram Moolenaar
b9c5108593 patch 8.2.4493: options test fails in the GUI
Problem:    Options test fails in the GUI.
Solution:   Do not save and restore 'term'.
2022-03-02 20:12:03 +00:00
Bram Moolenaar
8ccbbeb620 patch 8.2.4492: no error if an option is given a value with ":let &opt = val"
Problem:    No error if an option is given an invalid value with
            ":let &opt = val".
Solution:   Give the error. (closes #9864)
2022-03-02 19:49:38 +00:00
K.Takata
7f687aaca9 patch 8.2.4491: MS-Windows makefile dependencies are outdated
Problem:    MS-Windows makefile dependencies are outdated.
Solution:   Update dependencies. (Ken Takata, closes #9876)
2022-03-02 17:34:56 +00:00
Bram Moolenaar
8d5daf267e patch 8.2.4490: terminal focus reporting only works for xterm-like terminals
Problem:    Terminal focus reporting only works for xterm-like terminals.
            (Jonathan Rascher)
Solution:   Remove the "focus_mode" flag. (closes #9859)
2022-03-02 17:16:39 +00:00
Bram Moolenaar
c6e9d7063d patch 8.2.4489: failing test for comparing v:null with number
Problem:    Failing test for comparing v:null with number.
Solution:   Allow comparing v:null with number in legacy script.
            (Ken Takata, closes #9873)  Also do this for float.
2022-03-02 13:13:30 +00:00
Bram Moolenaar
f6b0c79742 patch 8.2.4488: build error with +eval but without +channel or +job
Problem:    Build error with +eval but without +channel or +job.
Solution:   Add #ifdef. (John Marriott)
2022-03-01 19:52:48 +00:00
Bram Moolenaar
7a22224875 patch 8.2.4487: Vim9: cannot compare with v:null
Problem:    Vim9: cannot compare with v:null.
Solution:   Allow comparing anything with v:null. (closes #9866)
2022-03-01 19:23:24 +00:00
Bram Moolenaar
f01af9c4e6 patch 8.2.4486: MS-Windows GUI: slow scrolling with maximized window
Problem:    MS-Windows GUI: slow scrolling with maximized window.
Solution:   Use a better way to check the window is on screen. (Ken Takata,
            closes #9865)
2022-03-01 16:02:26 +00:00
Bram Moolenaar
3e7637bd26 patch 8.2.4485: compiler warning for uninitialized variable
Problem:    Compiler warning for uninitialized variable.
Solution:   Initialize the variable. (John Marriott)
2022-02-28 21:02:19 +00:00
Bram Moolenaar
1983f1aa31 patch 8.2.4484: Vim9: some error messages are not tested
Problem:    Vim9: some error messages are not tested.
Solution:   Add a few more test cases.  Delete dead code.
2022-02-28 20:55:02 +00:00
Yegappan Lakshmanan
5de4c4372d patch 8.2.4483: command completion makes two rounds to collect matches
Problem:    Command completion makes two rounds to collect matches.
Solution:   Use a growarray to collect matches. (Yegappan Lakshmanan,
            closes #9860)
2022-02-28 13:28:38 +00:00
Yegappan Lakshmanan
afd4ae35d6 patch 8.2.4482: no fuzzy cmdline completion for user defined completion
Problem:    No fuzzy cmdline completion for user defined completion.
Solution:   Add fuzzy completion for user defined completion. (Yegappan
            Lakshmanan, closes #9858)
2022-02-27 21:03:21 +00:00
Bram Moolenaar
5c52be40fb patch 8.2.4481: cmdline popup menu not removed when 'lazyredraw' is set
Problem:    Cmdline popup menu not removed when 'lazyredraw' is set.
Solution:   Temporarily reset 'lazyredraw' when removing the popup menu.
            (closes #9857)
2022-02-27 14:28:31 +00:00
xtkoba
cbef12e60b patch 8.2.4480: suspending with CTRL-Z does not work on Android
Problem:    Suspending with CTRL-Z does not work on Android.
Solution:   Do not handle SIGTSTP. (closes #9854)
2022-02-27 12:31:52 +00:00
34 changed files with 2255 additions and 1523 deletions

View File

@@ -80,6 +80,8 @@ modes.
where the map command applies. Disallow mapping of
{rhs}, to avoid nested and recursive mappings. Often
used to redefine a command.
Note: When <Plug> appears in the {rhs} this part is
always applied even if remapping is disallowed.
:unm[ap] {lhs} |mapmode-nvo| *:unm* *:unmap*

View File

@@ -1229,19 +1229,19 @@ $(OUTDIR)/netbeans.o: netbeans.c $(INCL) version.h
$(OUTDIR)/version.o: version.c $(INCL) version.h
$(OUTDIR)/vim9cmds.o: vim9cmds.c $(INCL) version.h
$(OUTDIR)/vim9cmds.o: vim9cmds.c $(INCL) vim9.h
$(OUTDIR)/vim9compile.o: vim9compile.c $(INCL) version.h
$(OUTDIR)/vim9compile.o: vim9compile.c $(INCL) vim9.h
$(OUTDIR)/vim9execute.o: vim9execute.c $(INCL) version.h
$(OUTDIR)/vim9execute.o: vim9execute.c $(INCL) vim9.h
$(OUTDIR)/vim9expr.o: vim9expr.c $(INCL) version.h
$(OUTDIR)/vim9expr.o: vim9expr.c $(INCL) vim9.h
$(OUTDIR)/vim9instr.o: vim9instr.c $(INCL) version.h
$(OUTDIR)/vim9instr.o: vim9instr.c $(INCL) vim9.h
$(OUTDIR)/vim9script.o: vim9script.c $(INCL) version.h
$(OUTDIR)/vim9script.o: vim9script.c $(INCL) vim9.h
$(OUTDIR)/vim9type.o: vim9type.c $(INCL) version.h
$(OUTDIR)/vim9type.o: vim9type.c $(INCL) vim9.h
$(OUTDIR)/viminfo.o: viminfo.c $(INCL) version.h

View File

@@ -1812,19 +1812,19 @@ $(OUTDIR)/userfunc.obj: $(OUTDIR) userfunc.c $(INCL)
$(OUTDIR)/version.obj: $(OUTDIR) version.c $(INCL) version.h
$(OUTDIR)/vim9cmds.obj: $(OUTDIR) vim9cmds.c $(INCL)
$(OUTDIR)/vim9cmds.obj: $(OUTDIR) vim9cmds.c $(INCL) vim9.h
$(OUTDIR)/vim9compile.obj: $(OUTDIR) vim9compile.c $(INCL)
$(OUTDIR)/vim9compile.obj: $(OUTDIR) vim9compile.c $(INCL) vim9.h
$(OUTDIR)/vim9execute.obj: $(OUTDIR) vim9execute.c $(INCL)
$(OUTDIR)/vim9execute.obj: $(OUTDIR) vim9execute.c $(INCL) vim9.h
$(OUTDIR)/vim9expr.obj: $(OUTDIR) vim9expr.c $(INCL)
$(OUTDIR)/vim9expr.obj: $(OUTDIR) vim9expr.c $(INCL) vim9.h
$(OUTDIR)/vim9instr.obj: $(OUTDIR) vim9instr.c $(INCL)
$(OUTDIR)/vim9instr.obj: $(OUTDIR) vim9instr.c $(INCL) vim9.h
$(OUTDIR)/vim9script.obj: $(OUTDIR) vim9script.c $(INCL)
$(OUTDIR)/vim9script.obj: $(OUTDIR) vim9script.c $(INCL) vim9.h
$(OUTDIR)/vim9type.obj: $(OUTDIR) vim9type.c $(INCL)
$(OUTDIR)/vim9type.obj: $(OUTDIR) vim9type.c $(INCL) vim9.h
$(OUTDIR)/viminfo.obj: $(OUTDIR) viminfo.c $(INCL) version.h

View File

@@ -2814,38 +2814,39 @@ ExpandBufnames(
}
}
if (p != NULL)
{
if (round == 1)
++count;
else
{
if (options & WILD_HOME_REPLACE)
p = home_replace_save(buf, p);
else
p = vim_strsave(p);
if (p == NULL)
continue;
if (!fuzzy)
{
if (round == 1)
{
++count;
continue;
}
if (options & WILD_HOME_REPLACE)
p = home_replace_save(buf, p);
else
p = vim_strsave(p);
if (!fuzzy)
{
#ifdef FEAT_VIMINFO
if (matches != NULL)
{
matches[count].buf = buf;
matches[count].match = p;
count++;
}
else
#endif
(*file)[count++] = p;
}
else
{
fuzmatch[count].idx = count;
fuzmatch[count].str = p;
fuzmatch[count].score = score;
count++;
}
if (matches != NULL)
{
matches[count].buf = buf;
matches[count].match = p;
count++;
}
else
#endif
(*file)[count++] = p;
}
else
{
fuzmatch[count].idx = count;
fuzmatch[count].str = p;
fuzmatch[count].score = score;
count++;
}
}
if (count == 0) // no match found, break here

View File

@@ -16,15 +16,14 @@
static int cmd_showtail; // Only show path tail in lists ?
static void set_expand_context(expand_T *xp);
static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch,
static int ExpandGeneric(char_u *pat, expand_T *xp, regmatch_T *regmatch,
char_u ***matches, int *numMatches,
char_u *((*func)(expand_T *, int)), int escaped,
char_u *fuzzystr);
char_u *((*func)(expand_T *, int)), int escaped);
static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int);
static int expand_showtail(expand_T *xp);
static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg);
#if defined(FEAT_EVAL)
static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches);
static int ExpandUserDefined(char_u *pat, expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches);
static int ExpandUserList(expand_T *xp, char_u ***matches, int *numMatches);
#endif
@@ -62,13 +61,13 @@ cmdline_fuzzy_completion_supported(expand_T *xp)
&& xp->xp_context != EXPAND_SHELLCMD
&& xp->xp_context != EXPAND_TAGS
&& xp->xp_context != EXPAND_TAGS_LISTFILES
&& xp->xp_context != EXPAND_USER_DEFINED
&& xp->xp_context != EXPAND_USER_LIST);
}
/*
* Returns TRUE if fuzzy completion for cmdline completion is enabled and
* 'fuzzystr' is not empty.
* 'fuzzystr' is not empty. If search pattern is empty, then don't use fuzzy
* matching.
*/
int
cmdline_fuzzy_complete(char_u *fuzzystr)
@@ -377,9 +376,13 @@ int cmdline_pum_active(void)
*/
void cmdline_pum_remove(void)
{
int save_p_lz = p_lz;
pum_undisplay();
VIM_CLEAR(compl_match_array);
p_lz = FALSE; // avoid the popup menu hanging around
update_screen(0);
p_lz = save_p_lz;
redrawcmd();
}
@@ -2440,16 +2443,10 @@ ExpandOther(
{
if (xp->xp_context == tab[i].context)
{
// Use fuzzy matching if 'wildoptions' has 'fuzzy'.
// If no search pattern is supplied, then don't use fuzzy
// matching and return all the found items.
int fuzzy = cmdline_fuzzy_complete(pat);
if (tab[i].ic)
rmp->rm_ic = TRUE;
ret = ExpandGeneric(xp, rmp, matches, numMatches,
tab[i].func, tab[i].escaped,
fuzzy ? pat : NULL);
ret = ExpandGeneric(pat, xp, rmp, matches, numMatches,
tab[i].func, tab[i].escaped);
break;
}
}
@@ -2600,7 +2597,7 @@ ExpandFromContext(
ret = ExpandMappings(pat, &regmatch, numMatches, matches);
# if defined(FEAT_EVAL)
else if (xp->xp_context == EXPAND_USER_DEFINED)
ret = ExpandUserDefined(xp, &regmatch, matches, numMatches);
ret = ExpandUserDefined(pat, xp, &regmatch, matches, numMatches);
# endif
else
ret = ExpandOther(pat, xp, &regmatch, matches, numMatches);
@@ -2626,124 +2623,144 @@ ExpandFromContext(
*/
static int
ExpandGeneric(
char_u *pat,
expand_T *xp,
regmatch_T *regmatch,
char_u ***matches,
int *numMatches,
char_u *((*func)(expand_T *, int)),
// returns a string from the list
int escaped,
char_u *fuzzystr)
int escaped)
{
int i;
int count = 0;
int round;
garray_T ga;
char_u *str;
fuzmatch_str_T *fuzmatch = NULL;
int score = 0;
int fuzzy = (fuzzystr != NULL);
int funcsort = FALSE;
int score = 0;
int fuzzy;
int match;
// do this loop twice:
// round == 0: count the number of matching names
// round == 1: copy the matching names into allocated memory
for (round = 0; round <= 1; ++round)
{
for (i = 0; ; ++i)
{
str = (*func)(xp, i);
if (str == NULL) // end of list
break;
if (*str == NUL) // skip empty strings
continue;
fuzzy = cmdline_fuzzy_complete(pat);
*matches = NULL;
*numMatches = 0;
if (!fuzzy)
ga_init2(&ga, sizeof(char *), 30);
else
ga_init2(&ga, sizeof(fuzmatch_str_T), 30);
for (i = 0; ; ++i)
{
str = (*func)(xp, i);
if (str == NULL) // end of list
break;
if (*str == NUL) // skip empty strings
continue;
if (xp->xp_pattern[0] != NUL)
{
if (!fuzzy)
match = vim_regexec(regmatch, str, (colnr_T)0);
match = vim_regexec(regmatch, str, (colnr_T)0);
else
{
score = fuzzy_match_str(str, fuzzystr);
score = fuzzy_match_str(str, pat);
match = (score != 0);
}
if (!match)
continue;
if (round)
{
if (escaped)
str = vim_strsave_escaped(str, (char_u *)" \t\\.");
else
str = vim_strsave(str);
if (str == NULL)
{
if (fuzzy)
fuzmatch_str_free(fuzmatch, count);
else if (count > 0)
FreeWild(count, *matches);
*numMatches = 0;
*matches = NULL;
return FAIL;
}
if (fuzzy)
{
fuzmatch[count].idx = count;
fuzmatch[count].str = str;
fuzmatch[count].score = score;
}
else
(*matches)[count] = str;
# ifdef FEAT_MENU
if (func == get_menu_names && str != NULL)
{
// test for separator added by get_menu_names()
str += STRLEN(str) - 1;
if (*str == '\001')
*str = '.';
}
# endif
}
++count;
}
if (round == 0)
else
match = TRUE;
if (!match)
continue;
if (escaped)
str = vim_strsave_escaped(str, (char_u *)" \t\\.");
else
str = vim_strsave(str);
if (str == NULL)
{
if (count == 0)
return OK;
if (fuzzy)
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
else
*matches = ALLOC_MULT(char_u *, count);
if ((!fuzzy && (*matches == NULL))
|| (fuzzy && (fuzmatch == NULL)))
if (!fuzzy)
{
*numMatches = 0;
*matches = NULL;
ga_clear_strings(&ga);
return FAIL;
}
*numMatches = count;
count = 0;
for (i = 0; i < ga.ga_len; ++i)
{
fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[i];
vim_free(fuzmatch->str);
}
ga_clear(&ga);
return FAIL;
}
if (ga_grow(&ga, 1) == FAIL)
{
vim_free(str);
break;
}
if (fuzzy)
{
fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch->idx = ga.ga_len;
fuzmatch->str = str;
fuzmatch->score = score;
}
else
((char_u **)ga.ga_data)[ga.ga_len] = str;
# ifdef FEAT_MENU
if (func == get_menu_names)
{
// test for separator added by get_menu_names()
str += STRLEN(str) - 1;
if (*str == '\001')
*str = '.';
}
# endif
++ga.ga_len;
}
if (ga.ga_len == 0)
return OK;
// Sort the results. Keep menu's in the specified order.
if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS)
if (!fuzzy && xp->xp_context != EXPAND_MENUNAMES
&& xp->xp_context != EXPAND_MENUS)
{
if (xp->xp_context == EXPAND_EXPRESSION
|| xp->xp_context == EXPAND_FUNCTIONS
|| xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE)
{
// <SNR> functions should be sorted to the end.
qsort((void *)ga.ga_data, (size_t)ga.ga_len, sizeof(char_u *),
sort_func_compare);
else
sort_strings((char_u **)ga.ga_data, ga.ga_len);
}
if (!fuzzy)
{
*matches = ga.ga_data;
*numMatches = ga.ga_len;
}
else
{
int funcsort = FALSE;
if (xp->xp_context == EXPAND_EXPRESSION
|| xp->xp_context == EXPAND_FUNCTIONS
|| xp->xp_context == EXPAND_USER_FUNC
|| xp->xp_context == EXPAND_DISASSEMBLE)
// <SNR> functions should be sorted to the end.
funcsort = TRUE;
if (!fuzzy)
qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *),
sort_func_compare);
}
else
{
if (!fuzzy)
sort_strings(*matches, *numMatches);
}
if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
funcsort) == FAIL)
return FAIL;
*numMatches = ga.ga_len;
}
#if defined(FEAT_SYN_HL)
@@ -2752,10 +2769,6 @@ ExpandGeneric(
reset_expand_highlight();
#endif
if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
funcsort) == FAIL)
return FAIL;
return OK;
}
@@ -2972,10 +2985,12 @@ call_user_expand_func(
}
/*
* Expand names with a function defined by the user.
* Expand names with a function defined by the user (EXPAND_USER_DEFINED and
* EXPAND_USER_LIST).
*/
static int
ExpandUserDefined(
char_u *pat,
expand_T *xp,
regmatch_T *regmatch,
char_u ***matches,
@@ -2986,15 +3001,23 @@ ExpandUserDefined(
char_u *e;
int keep;
garray_T ga;
int skip;
int fuzzy;
int match;
int score = 0;
fuzzy = cmdline_fuzzy_complete(pat);
*matches = NULL;
*numMatches = 0;
retstr = call_user_expand_func(call_func_retstr, xp);
if (retstr == NULL)
return FAIL;
ga_init2(&ga, sizeof(char *), 3);
if (!fuzzy)
ga_init2(&ga, sizeof(char *), 3);
else
ga_init2(&ga, sizeof(fuzmatch_str_T), 3);
for (s = retstr; *s != NUL; s = e)
{
e = vim_strchr(s, '\n');
@@ -3003,14 +3026,35 @@ ExpandUserDefined(
keep = *e;
*e = NUL;
skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0;
if (xp->xp_pattern[0] != NUL)
{
if (!fuzzy)
match = vim_regexec(regmatch, s, (colnr_T)0);
else
{
score = fuzzy_match_str(s, pat);
match = (score != 0);
}
}
else
match = TRUE; // match everything
*e = keep;
if (!skip)
if (match)
{
if (ga_grow(&ga, 1) == FAIL)
break;
((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, e - s);
if (!fuzzy)
((char_u **)ga.ga_data)[ga.ga_len] = vim_strnsave(s, e - s);
else
{
fuzmatch_str_T *fuzmatch =
&((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch->idx = ga.ga_len;
fuzmatch->str = vim_strnsave(s, e - s);
fuzmatch->score = score;
}
++ga.ga_len;
}
@@ -3018,8 +3062,22 @@ ExpandUserDefined(
++e;
}
vim_free(retstr);
*matches = ga.ga_data;
*numMatches = ga.ga_len;
if (ga.ga_len == 0)
return OK;
if (!fuzzy)
{
*matches = ga.ga_data;
*numMatches = ga.ga_len;
}
else
{
if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
FALSE) == FAIL)
return FAIL;
*numMatches = ga.ga_len;
}
return OK;
}

View File

@@ -1518,8 +1518,11 @@ ex_let_option(
{
if (opt_type != gov_string || s != NULL)
{
set_option_value(arg, n, s, scope);
char *err = set_option_value(arg, n, s, scope);
arg_end = p;
if (err != NULL)
emsg(_(err));
}
else
emsg(_(e_string_required));
@@ -2816,29 +2819,33 @@ eval_variable(
}
// If a list or dict variable wasn't initialized, do it now.
if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL)
// Not for global variables, they are not declared.
if (ht != &globvarht)
{
tv->vval.v_dict = dict_alloc();
if (tv->vval.v_dict != NULL)
if (tv->v_type == VAR_DICT && tv->vval.v_dict == NULL)
{
++tv->vval.v_dict->dv_refcount;
tv->vval.v_dict->dv_type = alloc_type(type);
tv->vval.v_dict = dict_alloc();
if (tv->vval.v_dict != NULL)
{
++tv->vval.v_dict->dv_refcount;
tv->vval.v_dict->dv_type = alloc_type(type);
}
}
}
else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL)
{
tv->vval.v_list = list_alloc();
if (tv->vval.v_list != NULL)
else if (tv->v_type == VAR_LIST && tv->vval.v_list == NULL)
{
++tv->vval.v_list->lv_refcount;
tv->vval.v_list->lv_type = alloc_type(type);
tv->vval.v_list = list_alloc();
if (tv->vval.v_list != NULL)
{
++tv->vval.v_list->lv_refcount;
tv->vval.v_list->lv_type = alloc_type(type);
}
}
else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL)
{
tv->vval.v_blob = blob_alloc();
if (tv->vval.v_blob != NULL)
++tv->vval.v_blob->bv_refcount;
}
}
else if (tv->v_type == VAR_BLOB && tv->vval.v_blob == NULL)
{
tv->vval.v_blob = blob_alloc();
if (tv->vval.v_blob != NULL)
++tv->vval.v_blob->bv_refcount;
}
copy_tv(tv, rettv);
}

View File

@@ -2424,6 +2424,13 @@ handle_mapping(
int keylen = *keylenp;
int i;
int local_State = get_real_state();
int is_plug_map = FALSE;
// If typehead starts with <Plug> then remap, even for a "noremap" mapping.
if (typebuf.tb_buf[typebuf.tb_off] == K_SPECIAL
&& typebuf.tb_buf[typebuf.tb_off + 1] == KS_EXTRA
&& typebuf.tb_buf[typebuf.tb_off + 2] == KE_PLUG)
is_plug_map = TRUE;
/*
* Check for a mappable key sequence.
@@ -2441,7 +2448,7 @@ handle_mapping(
tb_c1 = typebuf.tb_buf[typebuf.tb_off];
if (no_mapping == 0 && is_maphash_valid()
&& (no_zero_mapping == 0 || tb_c1 != '0')
&& (typebuf.tb_maplen == 0
&& (typebuf.tb_maplen == 0 || is_plug_map
|| (p_remap
&& (typebuf.tb_noremap[typebuf.tb_off]
& (RM_NONE|RM_ABBR)) == 0))
@@ -2562,7 +2569,7 @@ handle_mapping(
for (n = mlen; --n >= 0; )
if (*s++ & (RM_NONE|RM_ABBR))
break;
if (n >= 0)
if (!is_plug_map && n >= 0)
continue;
if (keylen > typebuf.tb_len)

View File

@@ -3016,7 +3016,7 @@ is_point_onscreen(int x, int y)
}
/*
* Check if the whole area of the specified window is on-screen.
* Check if the whole client area of the specified window is on-screen.
*
* Note about DirectX: Windows 10 1809 or above no longer maintains image of
* the window portion that is off-screen. Scrolling by DWriteContext_Scroll()
@@ -3026,16 +3026,23 @@ is_point_onscreen(int x, int y)
is_window_onscreen(HWND hwnd)
{
RECT rc;
POINT p1, p2;
GetWindowRect(hwnd, &rc);
GetClientRect(hwnd, &rc);
p1.x = rc.left;
p1.y = rc.top;
p2.x = rc.right - 1;
p2.y = rc.bottom - 1;
ClientToScreen(hwnd, &p1);
ClientToScreen(hwnd, &p2);
if (!is_point_onscreen(rc.left, rc.top))
if (!is_point_onscreen(p1.x, p1.y))
return FALSE;
if (!is_point_onscreen(rc.left, rc.bottom))
if (!is_point_onscreen(p1.x, p2.y))
return FALSE;
if (!is_point_onscreen(rc.right, rc.top))
if (!is_point_onscreen(p2.x, p1.y))
return FALSE;
if (!is_point_onscreen(rc.right, rc.bottom))
if (!is_point_onscreen(p2.x, p2.y))
return FALSE;
return TRUE;
}

201
src/map.c
View File

@@ -1263,15 +1263,15 @@ ExpandMappings(
char_u ***matches)
{
mapblock_T *mp;
garray_T ga;
int hash;
int count;
int round;
char_u *p;
int i;
int fuzzy;
int match;
int score;
fuzmatch_str_T *fuzmatch = NULL;
fuzmatch_str_T *fuzmatch;
fuzzy = cmdline_fuzzy_complete(pat);
@@ -1280,32 +1280,78 @@ ExpandMappings(
*numMatches = 0; // return values in case of FAIL
*matches = NULL;
// round == 1: Count the matches.
// round == 2: Build the array to keep the matches.
for (round = 1; round <= 2; ++round)
{
count = 0;
if (!fuzzy)
ga_init2(&ga, sizeof(char *), 3);
else
ga_init2(&ga, sizeof(fuzmatch_str_T), 3);
// First search in map modifier arguments
for (i = 0; i < 7; ++i)
{
if (i == 0)
p = (char_u *)"<silent>";
else if (i == 1)
p = (char_u *)"<unique>";
// First search in map modifier arguments
for (i = 0; i < 7; ++i)
{
if (i == 0)
p = (char_u *)"<silent>";
else if (i == 1)
p = (char_u *)"<unique>";
#ifdef FEAT_EVAL
else if (i == 2)
p = (char_u *)"<script>";
else if (i == 3)
p = (char_u *)"<expr>";
else if (i == 2)
p = (char_u *)"<script>";
else if (i == 3)
p = (char_u *)"<expr>";
#endif
else if (i == 4 && !expand_buffer)
p = (char_u *)"<buffer>";
else if (i == 5)
p = (char_u *)"<nowait>";
else if (i == 6)
p = (char_u *)"<special>";
else
else if (i == 4 && !expand_buffer)
p = (char_u *)"<buffer>";
else if (i == 5)
p = (char_u *)"<nowait>";
else if (i == 6)
p = (char_u *)"<special>";
else
continue;
if (!fuzzy)
match = vim_regexec(regmatch, p, (colnr_T)0);
else
{
score = fuzzy_match_str(p, pat);
match = (score != 0);
}
if (!match)
continue;
if (ga_grow(&ga, 1) == FAIL)
break;
if (fuzzy)
{
fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch->idx = ga.ga_len;
fuzmatch->str = vim_strsave(p);
fuzmatch->score = score;
}
else
((char_u **)ga.ga_data)[ga.ga_len] = vim_strsave(p);
++ga.ga_len;
}
for (hash = 0; hash < 256; ++hash)
{
if (expand_isabbrev)
{
if (hash > 0) // only one abbrev list
break; // for (hash)
mp = first_abbr;
}
else if (expand_buffer)
mp = curbuf->b_maphash[hash];
else
mp = maphash[hash];
for (; mp; mp = mp->m_next)
{
if (!(mp->m_mode & expand_mapmodes))
continue;
p = translate_mapping(mp->m_keys);
if (p == NULL)
continue;
if (!fuzzy)
@@ -1317,95 +1363,48 @@ ExpandMappings(
}
if (!match)
{
vim_free(p);
continue;
if (round == 2)
{
if (fuzzy)
{
fuzmatch[count].idx = count;
fuzmatch[count].str = vim_strsave(p);
fuzmatch[count].score = score;
}
else
(*matches)[count] = vim_strsave(p);
}
++count;
}
for (hash = 0; hash < 256; ++hash)
{
if (expand_isabbrev)
if (ga_grow(&ga, 1) == FAIL)
{
if (hash > 0) // only one abbrev list
break; // for (hash)
mp = first_abbr;
vim_free(p);
break;
}
else if (expand_buffer)
mp = curbuf->b_maphash[hash];
else
mp = maphash[hash];
for (; mp; mp = mp->m_next)
{
if (mp->m_mode & expand_mapmodes)
{
p = translate_mapping(mp->m_keys);
if (p != NULL)
{
if (!fuzzy)
match = vim_regexec(regmatch, p, (colnr_T)0);
else
{
score = fuzzy_match_str(p, pat);
match = (score != 0);
}
if (match)
{
if (round == 2)
{
if (fuzzy)
{
fuzmatch[count].idx = count;
fuzmatch[count].str = p;
fuzmatch[count].score = score;
}
else
(*matches)[count] = p;
p = NULL;
}
++count;
}
}
vim_free(p);
}
} // for (mp)
} // for (hash)
if (count == 0) // no match found
break; // for (round)
if (round == 1)
{
if (fuzzy)
{
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
if (fuzmatch == NULL)
return FAIL;
fuzmatch = &((fuzmatch_str_T *)ga.ga_data)[ga.ga_len];
fuzmatch->idx = ga.ga_len;
fuzmatch->str = p;
fuzmatch->score = score;
}
else
{
*matches = ALLOC_MULT(char_u *, count);
if (*matches == NULL)
return FAIL;
}
}
} // for (round)
((char_u **)ga.ga_data)[ga.ga_len] = p;
if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
FALSE) == FAIL)
++ga.ga_len;
} // for (mp)
} // for (hash)
if (ga.ga_len == 0)
return FAIL;
if (!fuzzy)
{
*matches = ga.ga_data;
*numMatches = ga.ga_len;
}
else
{
if (fuzzymatches_to_strmatches(ga.ga_data, matches, ga.ga_len,
FALSE) == FAIL)
return FAIL;
*numMatches = ga.ga_len;
}
count = *numMatches;
if (count > 1)
{
char_u **ptr1;

View File

@@ -887,8 +887,10 @@ sig_tstp SIGDEFARG(sigarg)
else
got_tstp = TRUE;
// this is not required on all systems, but it doesn't hurt anybody
#ifndef __ANDROID__
// this is not required on all systems
signal(SIGTSTP, (RETSIGTYPE (*)())sig_tstp);
#endif
SIGRETURN;
}
#endif

View File

@@ -57,6 +57,7 @@ int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
void copy_tv(typval_T *from, typval_T *to);
int typval_compare(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic);
int typval_compare_list(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res);
int typval_compare_null(typval_T *tv1, typval_T *tv2);
int typval_compare_blob(typval_T *tv1, typval_T *tv2, exprtype_T type, int *res);
int typval_compare_dict(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res);
int typval_compare_func(typval_T *tv1, typval_T *tv2, exprtype_T type, int ic, int *res);

View File

@@ -5013,6 +5013,8 @@ ex_make(exarg_T *eap)
int res;
char_u *au_name = NULL;
int_u save_qfid;
char_u *errorformat = p_efm;
int newlist = TRUE;
// Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal".
if (grep_internal(eap->cmdidx))
@@ -5059,11 +5061,13 @@ ex_make(exarg_T *eap)
incr_quickfix_busy();
res = qf_init(wp, fname, (eap->cmdidx != CMD_make
&& eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
(eap->cmdidx != CMD_grepadd
&& eap->cmdidx != CMD_lgrepadd),
qf_cmdtitle(*eap->cmdlinep), enc);
if (eap->cmdidx != CMD_make && eap->cmdidx != CMD_lmake)
errorformat = p_gefm;
if (eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd)
newlist = FALSE;
res = qf_init(wp, fname, errorformat, newlist, qf_cmdtitle(*eap->cmdlinep),
enc);
if (wp != NULL)
{
qi = GET_LOC_LIST(wp);

View File

@@ -1495,8 +1495,9 @@ screen_puts_len(
int textlen,
int row,
int col,
int attr)
int attr_arg)
{
int attr = attr_arg;
unsigned off;
char_u *ptr = text;
int len = textlen;
@@ -1722,8 +1723,10 @@ screen_puts_len(
if (clear_next_cell)
{
// This only happens at the end, display one space next.
// Keep the attribute from before.
ptr = (char_u *)" ";
len = -1;
attr = ScreenAttrs[off];
}
}
else

2316
src/tag.c

File diff suppressed because it is too large Load Diff

View File

@@ -197,8 +197,7 @@ static char_u *vim_tgetstr(char *s, char_u **pp);
static int detected_8bit = FALSE; // detected 8-bit terminal
#if (defined(UNIX) || defined(VMS))
static int focus_mode = FALSE; // xterm's "focus reporting" availability
static int focus_state = FALSE; // TRUE if the terminal window gains focus
static int focus_state = MAYBE; // TRUE if the Vim window has focus
#endif
#ifdef FEAT_TERMRESPONSE
@@ -2047,7 +2046,7 @@ set_termname(char_u *term)
#endif
#ifdef FEAT_MOUSE_XTERM
// focus reporting is supported by xterm compatible terminals and tmux.
// Focus reporting is supported by xterm compatible terminals and tmux.
if (use_xterm_like_mouse(term))
{
char_u name[3];
@@ -2062,11 +2061,13 @@ set_termname(char_u *term)
name[1] = KE_FOCUSLOST;
add_termcode(name, (char_u *)"\033[O", FALSE);
focus_mode = TRUE;
focus_state = TRUE;
need_gather = TRUE;
}
#endif
#if (defined(UNIX) || defined(VMS))
// First time after setting 'term' a focus event is always reported.
focus_state = MAYBE;
#endif
#ifdef USE_TERM_CONSOLE
// DEFAULT_TERM indicates that it is the machine console.
@@ -3633,7 +3634,7 @@ starttermcap(void)
#if defined(UNIX) || defined(VMS)
// Enable xterm's focus reporting mode when 'esckeys' is set.
if (focus_mode && p_ek && *T_FE != NUL)
if (p_ek && *T_FE != NUL)
out_str(T_FE);
#endif
@@ -3691,7 +3692,7 @@ stoptermcap(void)
#if defined(UNIX) || defined(VMS)
// Disable xterm's focus reporting mode if 'esckeys' is set.
if (focus_mode && p_ek && *T_FD != NUL)
if (p_ek && *T_FD != NUL)
out_str(T_FD);
#endif
@@ -5812,11 +5813,10 @@ check_termcode(
* Handle FocusIn/FocusOut event sequences reported by XTerm.
* (CSI I/CSI O)
*/
if (focus_mode
if (key_name[0] == KS_EXTRA
# ifdef FEAT_GUI
&& !gui.in_use
# endif
&& key_name[0] == KS_EXTRA
)
{
if (key_name[1] == KE_FOCUSGAINED)

View File

@@ -0,0 +1,10 @@
|a+0&#ffffff0@1|0|b@1> @69
|a+0#0000001#e0e0e08@1|0|b@1| @9| +0#0000000#0000001|啊*0&#ffffff0| +&@56
|a+0#0000001#ffd7ff255@1|1|b@1| @9| +0#0000000#0000001| +0&#ffffff0|哦*&| +&@55
|a+0#0000001#ffd7ff255@1|2|b@1| @9| +0#0000000#0000001|呃*0&#ffffff0@1| +&@54
|a+0#0000001#ffd7ff255@1|3|b@1| @9| +0#0000000#0000001| +0&#ffffff0@58
|a+0#0000001#ffd7ff255@1|4|b@1| @9| +0#0000000#0000001| +0&#ffffff0@58
|a+0#0000001#ffd7ff255@1|5|b@1| @9| +0#0000000#0000001| +0&#ffffff0@58
|a+0#0000001#ffd7ff255@1|6|b@1| @9| +0#0000000#a8a8a8255| +0&#ffffff0@58
|a+0#0000001#ffd7ff255@1|7|b@1| @9| +0#0000000#a8a8a8255| +0&#ffffff0@58
|-+2&&@1| |K|e|y|w|o|r|d| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |1|0| +0#0000000&@32

View File

@@ -0,0 +1,10 @@
| +0&#ffffff0@74
|~+0#4040ff13&| @73
|~| @73
|~| @73
|~| @73
| +0#0000001#e0e0e08|a|b@1|r|e|v|i|a|t|e| @4| +0#4040ff13#ffffff0@58
| +0#0000001#ffd7ff255|a|b|c|l|e|a|r| @7| +0#4040ff13#ffffff0@58
| +0#0000001#ffd7ff255|a|b|o|v|e|l|e|f|t| @5| +0#4040ff13#ffffff0@58
| +0#0000001#ffd7ff255|a|b|s|t|r|a|c|t| @6| +0#4040ff13#ffffff0@58
|:+0#0000000&|a|b@1|r|e|v|i|a|t|e> @63

View File

@@ -15,7 +15,6 @@ let script = [
\ '',
\ 'let save_columns = &columns',
\ 'let save_lines = &lines',
\ 'let save_term = &term',
\ 'set t_WS=',
\ ]
@@ -224,7 +223,6 @@ while 1
endif
endwhile
call add(script, 'let &term = save_term')
call add(script, 'let &columns = save_columns')
call add(script, 'let &lines = save_lines')

View File

@@ -2181,6 +2181,11 @@ func Test_wildmenu_pum()
set tabline=%!MyTabLine()
set showtabline=2
endfunc
func DoFeedKeys()
let &wildcharm = char2nr("\t")
call feedkeys(":edit $VIMRUNTIME/\<Tab>\<Left>\<C-U>ab\<Tab>")
endfunc
[CODE]
call writefile(commands, 'Xtest')
@@ -2378,6 +2383,12 @@ func Test_wildmenu_pum()
call term_sendkeys(buf, "\<Esc>")
call VerifyScreenDump(buf, 'Test_wildmenu_pum_40', {})
" popup is cleared also when 'lazyredraw' is set
call term_sendkeys(buf, ":set showtabline=1 laststatus=1 lazyredraw\<CR>")
call term_sendkeys(buf, ":call DoFeedKeys()\<CR>")
call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {})
call term_sendkeys(buf, "\<Esc>")
call term_sendkeys(buf, "\<C-U>\<CR>")
call StopVimInTerminal(buf)
call delete('Xtest')
@@ -2444,9 +2455,8 @@ func Test_cmdline_complete_dlist()
call assert_equal("\"dlist 10 /pat/ | chistory", @:)
endfunc
" Test for 'fuzzy' in 'wildoptions' (fuzzy completion)
func Test_wildoptions_fuzzy()
" argument list (only for :argdel)
" argument list (only for :argdel) fuzzy completion
func Test_fuzzy_completion_arglist()
argadd change.py count.py charge.py
set wildoptions&
call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
@@ -2455,8 +2465,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"argdel change.py charge.py', @:)
%argdelete
set wildoptions&
endfunc
" autocmd group name fuzzy completion
" autocmd group name fuzzy completion
func Test_fuzzy_completion_autocmd()
set wildoptions&
augroup MyFuzzyGroup
augroup END
@@ -2470,8 +2483,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"augroup My*p', @:)
augroup! MyFuzzyGroup
set wildoptions&
endfunc
" buffer name fuzzy completion
" buffer name fuzzy completion
func Test_fuzzy_completion_bufname()
set wildoptions&
edit SomeFile.txt
enew
@@ -2485,24 +2501,29 @@ func Test_wildoptions_fuzzy()
call feedkeys(":b S*File.txt\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"b S*File.txt', @:)
%bw!
set wildoptions&
endfunc
" buffer name (full path) fuzzy completion
if has('unix')
set wildoptions&
call mkdir('Xcmd/Xstate/Xfile.js', 'p')
edit Xcmd/Xstate/Xfile.js
cd Xcmd/Xstate
enew
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"b CmdStateFile', @:)
set wildoptions=fuzzy
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_match('Xcmd/Xstate/Xfile.js$', @:)
cd -
call delete('Xcmd', 'rf')
endif
" buffer name (full path) fuzzy completion
func Test_fuzzy_completion_bufname_fullpath()
CheckUnix
set wildoptions&
call mkdir('Xcmd/Xstate/Xfile.js', 'p')
edit Xcmd/Xstate/Xfile.js
cd Xcmd/Xstate
enew
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"b CmdStateFile', @:)
set wildoptions=fuzzy
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_match('Xcmd/Xstate/Xfile.js$', @:)
cd -
call delete('Xcmd', 'rf')
set wildoptions&
endfunc
" :behave suboptions fuzzy completion
" :behave suboptions fuzzy completion
func Test_fuzzy_completion_behave()
set wildoptions&
call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"behave xm', @:)
@@ -2517,10 +2538,15 @@ func Test_wildoptions_fuzzy()
call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx')
call assert_equal('mswin', g:Sline)
call assert_equal('"behave win', @:)
set wildoptions&
endfunc
" colorscheme name fuzzy completion - NOT supported
" " colorscheme name fuzzy completion - NOT supported
" func Test_fuzzy_completion_colorscheme()
" endfunc
" built-in command name fuzzy completion
" built-in command name fuzzy completion
func Test_fuzzy_completion_cmdname()
set wildoptions&
call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sbwin', @:)
@@ -2531,24 +2557,31 @@ func Test_wildoptions_fuzzy()
call assert_equal('"sbrewind', @:)
call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sbr*d', @:)
set wildoptions&
endfunc
" compiler name fuzzy completion - NOT supported
" " compiler name fuzzy completion - NOT supported
" func Test_fuzzy_completion_compiler()
" endfunc
" :cscope suboptions fuzzy completion
if has('cscope')
set wildoptions&
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope ret', @:)
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope reset', @:)
set wildoptions=fuzzy
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope reset', @:)
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope re*t', @:)
endif
" :cscope suboptions fuzzy completion
func Test_fuzzy_completion_cscope()
CheckFeature cscope
set wildoptions&
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope ret', @:)
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope reset', @:)
set wildoptions=fuzzy
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope reset', @:)
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"cscope re*t', @:)
set wildoptions&
endfunc
" :diffget/:diffput buffer name fuzzy completion
" :diffget/:diffput buffer name fuzzy completion
func Test_fuzzy_completion_diff()
new SomeBuffer
diffthis
new OtherBuffer
@@ -2564,26 +2597,37 @@ func Test_wildoptions_fuzzy()
call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"diffput SomeBuffer', @:)
%bw!
set wildoptions&
endfunc
" directory name fuzzy completion - NOT supported
" " directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_dirname()
" endfunc
" environment variable name fuzzy completion
" environment variable name fuzzy completion
func Test_fuzzy_completion_env()
set wildoptions&
call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"echo $VUT', @:)
set wildoptions=fuzzy
call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"echo $VIMRUNTIME', @:)
set wildoptions&
endfunc
" autocmd event fuzzy completion
" autocmd event fuzzy completion
func Test_fuzzy_completion_autocmd_event()
set wildoptions&
call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"autocmd BWout', @:)
set wildoptions=fuzzy
call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"autocmd BufWipeout', @:)
set wildoptions&
endfunc
" vim expression fuzzy completion
" vim expression fuzzy completion
func Test_fuzzy_completion_expr()
let g:PerPlaceCount = 10
set wildoptions&
call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
@@ -2591,32 +2635,67 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy
call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"let c = PerPlaceCount', @:)
" file name fuzzy completion - NOT supported
" files in path fuzzy completion - NOT supported
" filetype name fuzzy completion - NOT supported
" user defined function name completion
set wildoptions&
call feedkeys(":call Test_w_fuz\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_w_fuz', @:)
set wildoptions=fuzzy
call feedkeys(":call Test_w_fuz\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_wildoptions_fuzzy()', @:)
endfunc
" user defined command name completion
" " file name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filename()
" endfunc
" " files in path fuzzy completion - NOT supported
" func Test_fuzzy_completion_filesinpath()
" endfunc
" " filetype name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filetype()
" endfunc
" user defined function name completion
func Test_fuzzy_completion_userdefined_func()
set wildoptions&
call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_f_u_f', @:)
set wildoptions=fuzzy
call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_fuzzy_completion_userdefined_func()', @:)
set wildoptions&
endfunc
" <SNR> functions should be sorted to the end
func Test_fuzzy_completion_userdefined_snr_func()
func s:Sendmail()
endfunc
func SendSomemail()
endfunc
func S1e2n3dmail()
endfunc
set wildoptions=fuzzy
call feedkeys(":call sendmail\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call SendSomemail() S1e2n3dmail() '
\ .. expand("<SID>") .. 'Sendmail()', @:)
set wildoptions&
delfunc s:Sendmail
delfunc SendSomemail
delfunc S1e2n3dmail
endfunc
" user defined command name completion
func Test_fuzzy_completion_userdefined_cmd()
set wildoptions&
call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"MsFeat', @:)
set wildoptions=fuzzy
call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"MissingFeature', @:)
set wildoptions&
endfunc
" :help tag fuzzy completion - NOT supported
" " :help tag fuzzy completion - NOT supported
" func Test_fuzzy_completion_helptag()
" endfunc
" highlight group name fuzzy completion
" highlight group name fuzzy completion
func Test_fuzzy_completion_hlgroup()
set wildoptions&
call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"highlight SKey', @:)
@@ -2627,8 +2706,11 @@ func Test_wildoptions_fuzzy()
call assert_equal('"highlight SpecialKey', @:)
call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"highlight Sp*Key', @:)
set wildoptions&
endfunc
" :history suboptions fuzzy completion
" :history suboptions fuzzy completion
func Test_fuzzy_completion_history()
set wildoptions&
call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history dg', @:)
@@ -2639,26 +2721,34 @@ func Test_wildoptions_fuzzy()
call assert_equal('"history debug', @:)
call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history se*h', @:)
set wildoptions&
endfunc
" :language locale name fuzzy completion
if has('unix')
set wildoptions&
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"lang psx', @:)
set wildoptions=fuzzy
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"lang POSIX', @:)
endif
" :language locale name fuzzy completion
func Test_fuzzy_completion_lang()
CheckUnix
set wildoptions&
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"lang psx', @:)
set wildoptions=fuzzy
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"lang POSIX', @:)
set wildoptions&
endfunc
" :mapclear buffer argument fuzzy completion
" :mapclear buffer argument fuzzy completion
func Test_fuzzy_completion_mapclear()
set wildoptions&
call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"mapclear buf', @:)
set wildoptions=fuzzy
call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"mapclear <buffer>', @:)
set wildoptions&
endfunc
" map name fuzzy completion
" map name fuzzy completion
func Test_fuzzy_completion_mapname()
" test regex completion works
set wildoptions=fuzzy
call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx')
@@ -2693,8 +2783,11 @@ func Test_wildoptions_fuzzy()
nunmap <Plug>fendoff
nunmap <Plug>state
nunmap <Plug>FendingOff
set wildoptions&
endfunc
" abbreviation fuzzy completion
" abbreviation fuzzy completion
func Test_fuzzy_completion_abbr()
set wildoptions=fuzzy
call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr <nowait>", @:)
@@ -2704,26 +2797,34 @@ func Test_wildoptions_fuzzy()
call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr a1z\t", @:)
iunabbrev WaitForCompletion
set wildoptions&
endfunc
" menu name fuzzy completion
if has('gui_running')
set wildoptions&
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"menu pup', @:)
set wildoptions=fuzzy
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"menu PopUp.', @:)
endif
" menu name fuzzy completion
func Test_fuzzy_completion_menu()
CheckGui
set wildoptions&
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"menu pup', @:)
set wildoptions=fuzzy
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"menu PopUp.', @:)
set wildoptions&
endfunc
" :messages suboptions fuzzy completion
" :messages suboptions fuzzy completion
func Test_fuzzy_completion_messages()
set wildoptions&
call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"messages clr', @:)
set wildoptions=fuzzy
call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"messages clear', @:)
set wildoptions&
endfunc
" :set option name fuzzy completion
" :set option name fuzzy completion
func Test_fuzzy_completion_option()
set wildoptions&
call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set brkopt', @:)
@@ -2736,8 +2837,11 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy
call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set fixendofline', @:)
set wildoptions&
endfunc
" :set <term_option>
" :set <term_option>
func Test_fuzzy_completion_term_option()
set wildoptions&
call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set t_EC', @:)
@@ -2748,52 +2852,76 @@ func Test_wildoptions_fuzzy()
call assert_equal('"set t_EC', @:)
call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set <t_EC>', @:)
set wildoptions&
endfunc
" :packadd directory name fuzzy completion - NOT supported
" " :packadd directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_packadd()
" endfunc
" shell command name fuzzy completion - NOT supported
" " shell command name fuzzy completion - NOT supported
" func Test_fuzzy_completion_shellcmd()
" endfunc
" :sign suboptions fuzzy completion
" :sign suboptions fuzzy completion
func Test_fuzzy_completion_sign()
set wildoptions&
call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign ufe', @:)
set wildoptions=fuzzy
call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign undefine', @:)
set wildoptions&
endfunc
" :syntax suboptions fuzzy completion
" :syntax suboptions fuzzy completion
func Test_fuzzy_completion_syntax_cmd()
set wildoptions&
call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax kwd', @:)
set wildoptions=fuzzy
call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax keyword', @:)
set wildoptions&
endfunc
" syntax group name fuzzy completion
" syntax group name fuzzy completion
func Test_fuzzy_completion_syntax_group()
set wildoptions&
call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax list mpar', @:)
set wildoptions=fuzzy
call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax list MatchParen', @:)
set wildoptions&
endfunc
" :syntime suboptions fuzzy completion
if has('profile')
set wildoptions&
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntime clr', @:)
set wildoptions=fuzzy
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntime clear', @:)
endif
" :syntime suboptions fuzzy completion
func Test_fuzzy_completion_syntime()
CheckFeature profile
set wildoptions&
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntime clr', @:)
set wildoptions=fuzzy
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntime clear', @:)
set wildoptions&
endfunc
" tag name fuzzy completion - NOT supported
" " tag name fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagname()
" endfunc
" tag name and file fuzzy completion - NOT supported
" " tag name and file fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagfile()
" endfunc
" user names fuzzy completion - how to test this functionality?
" " user names fuzzy completion - how to test this functionality?
" func Test_fuzzy_completion_username()
" endfunc
" user defined variable name fuzzy completion
" user defined variable name fuzzy completion
func Test_fuzzy_completion_userdefined_var()
let g:SomeVariable=10
set wildoptions&
call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
@@ -2801,8 +2929,11 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy
call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"let SomeVariable', @:)
set wildoptions&
endfunc
" Test for sorting the results by the best match
" Test for sorting the results by the best match
func Test_fuzzy_completion_cmd_sort_results()
%bw!
command T123format :
command T123goformat :
@@ -2820,9 +2951,11 @@ func Test_wildoptions_fuzzy()
delcommand T123state
delcommand T123FendingOff
%bw
set wildoptions&
endfunc
" Test for fuzzy completion of a command with lower case letters and a
" number
" Test for fuzzy completion of a command with lower case letters and a number
func Test_fuzzy_completion_cmd_alnum()
command Foo2Bar :
set wildoptions=fuzzy
call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx')
@@ -2832,8 +2965,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"Foo2Bar', @:)
delcommand Foo2Bar
set wildoptions&
endfunc
" Test for command completion for a command starting with 'k'
" Test for command completion for a command starting with 'k'
func Test_fuzzy_completion_cmd_k()
command KillKillKill :
set wildoptions&
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
@@ -2842,9 +2978,33 @@ func Test_wildoptions_fuzzy()
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"KillKillKill', @:)
delcom KillKillKill
set wildoptions&
%bw!
endfunc
" Test for fuzzy completion for user defined custom completion function
func Test_fuzzy_completion_custom_func()
func Tcompl(a, c, p)
return "format\ngoformat\nTestFOrmat\nfendoff\nstate"
endfunc
command -nargs=* -complete=custom,Tcompl Fuzzy :
set wildoptions&
call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format", @:)
call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy xy", @:)
call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy ttt", @:)
set wildoptions=fuzzy
call feedkeys(":Fuzzy \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format goformat TestFOrmat fendoff state", @:)
call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format TestFOrmat goformat fendoff", @:)
call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy xy", @:)
call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy TestFOrmat", @:)
delcom Fuzzy
set wildoptions&
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -152,7 +152,7 @@ endfunc
" Test for setting the 'helpheight' option in the help window
func Test_help_window_height()
let &cmdheight = &lines - 24
let &cmdheight = &lines - 23
set helpheight=10
help
set helpheight=14

View File

@@ -606,6 +606,24 @@ func Test_pum_with_preview_win()
call delete('Xpreviewscript')
endfunc
func Test_scrollbar_on_wide_char()
CheckScreendump
let lines =<< trim END
call setline(1, ['a', ' 啊啊啊',
\ ' 哦哦哦',
\ ' 呃呃呃'])
call setline(5, range(10)->map({i, v -> 'aa' .. v .. 'bb'}))
END
call writefile(lines, 'Xwidescript')
let buf = RunVimInTerminal('-S Xwidescript', #{rows: 10})
call term_sendkeys(buf, "A\<C-N>")
call VerifyScreenDump(buf, 'Test_scrollbar_on_wide_char', {})
call StopVimInTerminal(buf)
call delete('Xwidescript')
endfunc
" Test for inserting the tag search pattern in insert mode
func Test_ins_compl_tag_sft()
call writefile([

View File

@@ -1536,4 +1536,34 @@ func Test_abbreviate_latin1_encoding()
set encoding=utf-8
endfunc
" Test for <Plug> always being mapped, even when used with "noremap".
func Test_plug_remap()
let g:foo = 0
nnoremap <Plug>(Increase_x) <Cmd>let g:foo += 1<CR>
nmap <F2> <Plug>(Increase_x)
nnoremap <F3> <Plug>(Increase_x)
call feedkeys("\<F2>", 'xt')
call assert_equal(1, g:foo)
call feedkeys("\<F3>", 'xt')
call assert_equal(2, g:foo)
nnoremap x <Nop>
nmap <F4> x<Plug>(Increase_x)x
nnoremap <F5> x<Plug>(Increase_x)x
call setline(1, 'Some text')
normal! gg$
call feedkeys("\<F4>", 'xt')
call assert_equal(3, g:foo)
call assert_equal('Some text', getline(1))
call feedkeys("\<F5>", 'xt')
call assert_equal(4, g:foo)
call assert_equal('Some te', getline(1))
nunmap <Plug>(Increase_x)
nunmap <F2>
nunmap <F3>
nunmap <F4>
nunmap <F5>
unlet g:foo
%bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -369,6 +369,7 @@ func Test_set_errors()
call assert_fails('set sidescroll=-1', 'E487:')
call assert_fails('set tabstop=-1', 'E487:')
call assert_fails('set tabstop=10000', 'E474:')
call assert_fails('let &tabstop = 10000', 'E474:')
call assert_fails('set tabstop=5500000000', 'E474:')
call assert_fails('set textwidth=-1', 'E487:')
call assert_fails('set timeoutlen=-1', 'E487:')
@@ -384,6 +385,7 @@ func Test_set_errors()
call assert_fails('set comments=a', 'E525:')
call assert_fails('set foldmarker=x', 'E536:')
call assert_fails('set commentstring=x', 'E537:')
call assert_fails('let &commentstring = "x"', 'E537:')
call assert_fails('set complete=x', 'E539:')
call assert_fails('set rulerformat=%-', 'E539:')
call assert_fails('set rulerformat=%(', 'E542:')

View File

@@ -1427,6 +1427,11 @@ func Test_tagfile_errors()
endtry
call assert_equal(v:true, caught_431)
" tag name and file name are not separated by a tab
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "foo Xfile 1"], 'Xtags')
call assert_fails('tag foo', 'E431:')
call delete('Xtags')
call delete('Xfile')
set tags&

View File

@@ -550,6 +550,13 @@ def Test_assign_index()
bl[-2] = 0x66
assert_equal(0z77226644, bl)
lines =<< trim END
g:val = '22'
var bl = 0z11
bl[1] = g:val
END
v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "22"')
# should not read the next line when generating "a.b"
var a = {}
a.b = {}
@@ -1233,12 +1240,18 @@ def Test_script_var_default()
var lines =<< trim END
vim9script
var l: list<number>
var li = [1, 2]
var bl: blob
var bli = 0z12
var d: dict<number>
var di = {'a': 1, 'b': 2}
def Echo()
assert_equal([], l)
assert_equal([1, 2], li)
assert_equal(0z, bl)
assert_equal(0z12, bli)
assert_equal({}, d)
assert_equal({'a': 1, 'b': 2}, di)
enddef
Echo()
END
@@ -1502,6 +1515,30 @@ def Test_assign_list()
END
v9.CheckDefAndScriptSuccess(lines)
lines =<< trim END
var l = [1, 2]
g:idx = 'x'
l[g:idx : 1] = [0]
echo l
END
v9.CheckDefExecAndScriptFailure(lines, 'E1030: Using a String as a Number: "x"')
lines =<< trim END
var l = [1, 2]
g:idx = 3
l[g:idx : 1] = [0]
echo l
END
v9.CheckDefExecAndScriptFailure(lines, 'E684: list index out of range: 3')
lines =<< trim END
var l = [1, 2]
g:idx = 'y'
l[1 : g:idx] = [0]
echo l
END
v9.CheckDefExecAndScriptFailure(lines, ['E1012: Type mismatch; expected number but got string', 'E1030: Using a String as a Number: "y"'])
v9.CheckDefFailure(["var l: list<number> = ['', true]"], 'E1012: Type mismatch; expected list<number> but got list<any>', 1)
v9.CheckDefFailure(["var l: list<list<number>> = [['', true]]"], 'E1012: Type mismatch; expected list<list<number>> but got list<list<any>>', 1)
enddef

View File

@@ -1846,6 +1846,8 @@ def Test_disassemble_compare()
['true != isFalse', 'COMPAREBOOL !='],
['v:none == isNull', 'COMPARESPECIAL =='],
['v:none != isNull', 'COMPARESPECIAL !='],
['"text" == isNull', 'COMPARENULL =='],
['"text" != isNull', 'COMPARENULL !='],
['111 == aNumber', 'COMPARENR =='],
['111 != aNumber', 'COMPARENR !='],

View File

@@ -712,6 +712,81 @@ def Test_expr4_equal()
unlet g:notReached
enddef
def Test_expr4_compare_null()
g:null_dict = test_null_dict()
g:not_null_list = []
var lines =<< trim END
assert_true(test_null_blob() == v:null)
assert_true(v:null == test_null_blob())
assert_false(test_null_blob() != v:null)
assert_false(v:null != test_null_blob())
if has('channel')
assert_true(test_null_channel() == v:null)
assert_true(v:null == test_null_channel())
assert_false(test_null_channel() != v:null)
assert_false(v:null != test_null_channel())
endif
assert_true(test_null_dict() == v:null)
assert_true(v:null == test_null_dict())
assert_false(test_null_dict() != v:null)
assert_false(v:null != test_null_dict())
assert_true(g:null_dict == v:null)
assert_true(v:null == g:null_dict)
assert_false(g:null_dict != v:null)
assert_false(v:null != g:null_dict)
assert_true(test_null_function() == v:null)
assert_true(v:null == test_null_function())
assert_false(test_null_function() != v:null)
assert_false(v:null != test_null_function())
if has('job')
assert_true(test_null_job() == v:null)
assert_true(v:null == test_null_job())
assert_false(test_null_job() != v:null)
assert_false(v:null != test_null_job())
endif
assert_true(test_null_list() == v:null)
assert_true(v:null == test_null_list())
assert_false(test_null_list() != v:null)
assert_false(v:null != test_null_list())
assert_false(g:not_null_list == v:null)
assert_false(v:null == g:not_null_list)
assert_true(g:not_null_list != v:null)
assert_true(v:null != g:not_null_list)
assert_true(test_null_partial() == v:null)
assert_true(v:null == test_null_partial())
assert_false(test_null_partial() != v:null)
assert_false(v:null != test_null_partial())
assert_true(test_null_string() == v:null)
assert_true(v:null == test_null_string())
assert_false(test_null_string() != v:null)
assert_false(v:null != test_null_string())
END
v9.CheckDefAndScriptSuccess(lines)
unlet g:null_dict
unlet g:not_null_list
v9.CheckDefAndScriptFailure(['echo 123 == v:null'], 'E1072: Cannot compare number with special')
v9.CheckDefAndScriptFailure(['echo v:null == 123'], 'E1072: Cannot compare special with number')
v9.CheckDefAndScriptFailure(['echo 123 != v:null'], 'E1072: Cannot compare number with special')
v9.CheckDefAndScriptFailure(['echo v:null != 123'], 'E1072: Cannot compare special with number')
v9.CheckDefAndScriptFailure(['echo true == v:null'], 'E1072: Cannot compare bool with special')
v9.CheckDefAndScriptFailure(['echo v:null == true'], 'E1072: Cannot compare special with bool')
v9.CheckDefAndScriptFailure(['echo true != v:null'], 'E1072: Cannot compare bool with special')
v9.CheckDefAndScriptFailure(['echo v:null != true'], 'E1072: Cannot compare special with bool')
v9.CheckDefAndScriptFailure(['echo false == v:null'], 'E1072: Cannot compare bool with special')
v9.CheckDefExecAndScriptFailure(['echo [] == v:none'], ['E1072: Cannot compare list with special', 'E691: Can only compare List with List'])
enddef
def Test_expr4_wrong_type()
for op in ['>', '>=', '<', '<=', '=~', '!~']
v9.CheckDefExecAndScriptFailure([
@@ -2782,6 +2857,23 @@ def Test_expr8_any_index_slice()
v9.CheckDefAndScriptSuccess(lines)
lines =<< trim END
vim9script
def PosIdx(s: string): string
return s[1]
enddef
def NegIdx(s: string): string
return s[-1]
enddef
set enc=latin1
assert_equal("\xe4", PosIdx("a\xe4\xe5"))
assert_equal("\xe5", NegIdx("a\xe4\xe5"))
set enc=utf-8
END
v9.CheckScriptSuccess(lines)
v9.CheckDefExecAndScriptFailure(['echo g:testblob[2]'], 'E979:', 1)
v9.CheckDefExecAndScriptFailure(['echo g:testblob[-3]'], 'E979:', 1)

View File

@@ -550,6 +550,44 @@ def Test_call_ufunc_count()
unlet g:counter
enddef
def Test_call_ufunc_failure()
var lines =<< trim END
vim9script
def Tryit()
g:Global(1, 2, 3)
enddef
func g:Global(a, b, c)
echo a:a a:b a:c
endfunc
defcompile
func! g:Global(a, b)
echo a:a a:b
endfunc
Tryit()
END
v9.CheckScriptFailure(lines, 'E118: Too many arguments for function: Global')
delfunc g:Global
lines =<< trim END
vim9script
g:Ref = function('len')
def Tryit()
g:Ref('x')
enddef
defcompile
g:Ref = function('add')
Tryit()
END
v9.CheckScriptFailure(lines, 'E119: Not enough arguments for function: add')
unlet g:Ref
enddef
def s:MyVarargs(arg: string, ...rest: list<string>): string
var res = arg
for s in rest

View File

@@ -6546,9 +6546,16 @@ func Test_type()
call assert_true(v:true != v:false)
call assert_true(v:null == 0)
call assert_false(v:null == 1)
call assert_false(v:null != 0)
call assert_true(v:none == 0)
call assert_false(v:none == 1)
call assert_false(v:none != 0)
if has('float')
call assert_true(v:null == 0.0)
call assert_false(v:null == 0.1)
call assert_false(v:null != 0.0)
endif
call assert_true(v:false is v:false)
call assert_true(v:true is v:true)

View File

@@ -1169,6 +1169,21 @@ typval_compare(
// it means TRUE.
n1 = (type == EXPR_ISNOT);
}
else if (((tv1->v_type == VAR_SPECIAL && tv1->vval.v_number == VVAL_NULL)
|| (tv2->v_type == VAR_SPECIAL
&& tv2->vval.v_number == VVAL_NULL))
&& tv1->v_type != tv2->v_type
&& (type == EXPR_EQUAL || type == EXPR_NEQUAL))
{
n1 = typval_compare_null(tv1, tv2);
if (n1 == MAYBE)
{
clear_tv(tv1);
return FAIL;
}
if (type == EXPR_NEQUAL)
n1 = !n1;
}
else if (tv1->v_type == VAR_BLOB || tv2->v_type == VAR_BLOB)
{
if (typval_compare_blob(tv1, tv2, type, &res) == FAIL)
@@ -1365,6 +1380,48 @@ typval_compare_list(
return OK;
}
/*
* Compare v:null/v:none with another type. Return TRUE if the value is NULL.
*/
int
typval_compare_null(typval_T *tv1, typval_T *tv2)
{
if ((tv1->v_type == VAR_SPECIAL && tv1->vval.v_number == VVAL_NULL)
|| (tv2->v_type == VAR_SPECIAL && tv2->vval.v_number == VVAL_NULL))
{
typval_T *tv = tv1->v_type == VAR_SPECIAL ? tv2 : tv1;
switch (tv->v_type)
{
case VAR_BLOB: return tv->vval.v_blob == NULL;
#ifdef FEAT_JOB_CHANNEL
case VAR_CHANNEL: return tv->vval.v_channel == NULL;
#endif
case VAR_DICT: return tv->vval.v_dict == NULL;
case VAR_FUNC: return tv->vval.v_string == NULL;
#ifdef FEAT_JOB_CHANNEL
case VAR_JOB: return tv->vval.v_job == NULL;
#endif
case VAR_LIST: return tv->vval.v_list == NULL;
case VAR_PARTIAL: return tv->vval.v_partial == NULL;
case VAR_STRING: return tv->vval.v_string == NULL;
case VAR_NUMBER: if (!in_vim9script())
return tv->vval.v_number == 0;
break;
#ifdef FEAT_FLOAT
case VAR_FLOAT: if (!in_vim9script())
return tv->vval.v_float == 0.0;
break;
#endif
default: break;
}
}
semsg(_(e_cannot_compare_str_with_str),
vartype_name(tv1->v_type), vartype_name(tv2->v_type));
return MAYBE;
}
/*
* Compare "tv1" to "tv2" as blobs acording to "type".
* Put the result, false or true, in "res".

View File

@@ -754,6 +754,44 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
4498,
/**/
4497,
/**/
4496,
/**/
4495,
/**/
4494,
/**/
4493,
/**/
4492,
/**/
4491,
/**/
4490,
/**/
4489,
/**/
4488,
/**/
4487,
/**/
4486,
/**/
4485,
/**/
4484,
/**/
4483,
/**/
4482,
/**/
4481,
/**/
4480,
/**/
4479,
/**/

View File

@@ -134,6 +134,7 @@ typedef enum {
// comparative operations; isn_arg.op.op_type is exprtype_T, op_ic used
ISN_COMPAREBOOL,
ISN_COMPARESPECIAL,
ISN_COMPARENULL,
ISN_COMPARENR,
ISN_COMPAREFLOAT,
ISN_COMPARESTRING,

View File

@@ -1027,7 +1027,7 @@ call_by_name(
{
int func_idx = find_internal_func(name);
if (func_idx < 0)
if (func_idx < 0) // Impossible?
return FAIL;
if (check_internal_func(func_idx, argcount) < 0)
return FAIL;
@@ -1452,8 +1452,6 @@ get_split_sourceline(
char_u *p;
char_u *line;
if (*sp->nextline == NUL)
return NULL;
p = vim_strchr(sp->nextline, '\n');
if (p == NULL)
{
@@ -1911,11 +1909,11 @@ execute_storerange(isn_T *iptr, ectx_T *ectx)
else
n2 = (long)tv_get_number_chk(tv_idx2, &error);
if (error)
status = FAIL;
status = FAIL; // cannot happen?
else
{
listitem_T *li1 = check_range_index_one(
tv_dest->vval.v_list, &n1, FALSE);
tv_dest->vval.v_list, &n1, FALSE);
if (li1 == NULL)
status = FAIL;
@@ -3882,6 +3880,25 @@ exec_instructions(ectx_T *ectx)
}
break;
case ISN_COMPARENULL:
{
typval_T *tv1 = STACK_TV_BOT(-2);
typval_T *tv2 = STACK_TV_BOT(-1);
int res;
res = typval_compare_null(tv1, tv2);
if (res == MAYBE)
goto on_error;
if (iptr->isn_arg.op.op_type == EXPR_NEQUAL)
res = !res;
clear_tv(tv1);
clear_tv(tv2);
--ectx->ec_stack.ga_len;
tv1->v_type = VAR_BOOL;
tv1->vval.v_number = res ? VVAL_TRUE : VVAL_FALSE;
}
break;
// Operation with two number arguments
case ISN_OPNR:
case ISN_COMPARENR:
@@ -5903,6 +5920,7 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_COMPAREBOOL:
case ISN_COMPARESPECIAL:
case ISN_COMPARENULL:
case ISN_COMPARENR:
case ISN_COMPAREFLOAT:
case ISN_COMPARESTRING:
@@ -5938,6 +5956,7 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc)
case ISN_COMPAREBOOL: type = "COMPAREBOOL"; break;
case ISN_COMPARESPECIAL:
type = "COMPARESPECIAL"; break;
case ISN_COMPARENULL: type = "COMPARENULL"; break;
case ISN_COMPARENR: type = "COMPARENR"; break;
case ISN_COMPAREFLOAT: type = "COMPAREFLOAT"; break;
case ISN_COMPARESTRING:

View File

@@ -372,6 +372,24 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
|| ((type1 == VAR_NUMBER || type1 == VAR_FLOAT)
&& (type2 == VAR_NUMBER || type2 == VAR_FLOAT)))
isntype = ISN_COMPAREANY;
else if (type1 == VAR_SPECIAL || type2 == VAR_SPECIAL)
{
switch (type1 == VAR_SPECIAL ? type2 : type1)
{
case VAR_BLOB: break;
case VAR_CHANNEL: break;
case VAR_DICT: break;
case VAR_FUNC: break;
case VAR_JOB: break;
case VAR_LIST: break;
case VAR_PARTIAL: break;
case VAR_STRING: break;
default: semsg(_(e_cannot_compare_str_with_str),
vartype_name(type1), vartype_name(type2));
return ISN_DROP;
}
isntype = ISN_COMPARENULL;
}
if ((exprtype == EXPR_IS || exprtype == EXPR_ISNOT)
&& (isntype == ISN_COMPAREBOOL
@@ -388,7 +406,7 @@ get_compare_isn(exprtype_T exprtype, vartype_T type1, vartype_T type2)
&& (type1 == VAR_BOOL || type1 == VAR_SPECIAL
|| type2 == VAR_BOOL || type2 == VAR_SPECIAL)))
|| ((exprtype != EXPR_EQUAL && exprtype != EXPR_NEQUAL
&& exprtype != EXPR_IS && exprtype != EXPR_ISNOT
&& exprtype != EXPR_IS && exprtype != EXPR_ISNOT
&& (type1 == VAR_BLOB || type2 == VAR_BLOB
|| type1 == VAR_LIST || type2 == VAR_LIST))))
{
@@ -2131,6 +2149,7 @@ delete_instr(isn_T *isn)
case ISN_COMPAREFUNC:
case ISN_COMPARELIST:
case ISN_COMPARENR:
case ISN_COMPARENULL:
case ISN_COMPARESPECIAL:
case ISN_COMPARESTRING:
case ISN_CONCAT: