1
0
forked from aniani/vim

patch 9.1.0831: 'findexpr' can't be used as lambad or Funcref

Problem:  'findexpr' can't be used for lambads
          (Justin Keyes)
Solution: Replace the findexpr option with the findfunc option
          (Yegappan Lakshmanan)

related: #15905
closes: #15976

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2024-11-02 18:40:10 +01:00
committed by Christian Brabandt
parent 0b8176dff2
commit a13f3a4f5d
25 changed files with 629 additions and 256 deletions

View File

@@ -2412,7 +2412,6 @@ free_buf_options(
clear_string_option(&buf->b_p_fp);
#if defined(FEAT_EVAL)
clear_string_option(&buf->b_p_fex);
clear_string_option(&buf->b_p_fexpr);
#endif
#ifdef FEAT_CRYPT
# ifdef FEAT_SODIUM
@@ -2485,6 +2484,8 @@ free_buf_options(
#ifdef FEAT_EVAL
clear_string_option(&buf->b_p_tfu);
free_callback(&buf->b_tfu_cb);
clear_string_option(&buf->b_p_ffu);
free_callback(&buf->b_ffu_cb);
#endif
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);

View File

@@ -50,7 +50,7 @@ cmdline_fuzzy_completion_supported(expand_T *xp)
&& xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
&& xp->xp_context != EXPAND_FINDEXPR
&& xp->xp_context != EXPAND_FINDFUNC
&& xp->xp_context != EXPAND_HELP
&& xp->xp_context != EXPAND_KEYMAP
&& xp->xp_context != EXPAND_OLD_SETTING
@@ -1419,7 +1419,7 @@ addstar(
// For help tags the translation is done in find_help_tags().
// For a tag pattern starting with "/" no translation is needed.
if (context == EXPAND_FINDEXPR
if (context == EXPAND_FINDFUNC
|| context == EXPAND_HELP
|| context == EXPAND_COLORS
|| context == EXPAND_COMPILER
@@ -2140,7 +2140,7 @@ set_context_by_cmdname(
case CMD_sfind:
case CMD_tabfind:
if (xp->xp_context == EXPAND_FILES)
xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR
xp->xp_context = *get_findfunc() != NUL ? EXPAND_FINDFUNC
: EXPAND_FILES_IN_PATH;
break;
case CMD_cd:
@@ -2853,10 +2853,10 @@ expand_files_and_dirs(
}
}
if (xp->xp_context == EXPAND_FINDEXPR)
if (xp->xp_context == EXPAND_FINDFUNC)
{
#ifdef FEAT_EVAL
ret = expand_findexpr(pat, matches, numMatches);
ret = expand_findfunc(pat, matches, numMatches);
#endif
}
else
@@ -3122,7 +3122,7 @@ ExpandFromContext(
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
|| xp->xp_context == EXPAND_FILES_IN_PATH
|| xp->xp_context == EXPAND_FINDEXPR
|| xp->xp_context == EXPAND_FINDFUNC
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH)
return expand_files_and_dirs(xp, pat, matches, numMatches, flags,
options);

View File

@@ -3652,5 +3652,5 @@ EXTERN char e_wrong_character_width_for_field_str[]
INIT(= N_("E1512: Wrong character width for field \"%s\""));
EXTERN char e_winfixbuf_cannot_go_to_buffer[]
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
EXTERN char e_invalid_return_type_from_findexpr[]
INIT(= N_("E1514: 'findexpr' did not return a List type"));
EXTERN char e_invalid_return_type_from_findfunc[]
INIT(= N_("E1514: 'findfunc' did not return a List type"));

View File

@@ -45,6 +45,8 @@ set_ref_in_buffers(int copyID)
#endif
if (!abort)
abort = abort || set_ref_in_callback(&bp->b_tfu_cb, copyID);
if (!abort)
abort = abort || set_ref_in_callback(&bp->b_ffu_cb, copyID);
if (abort)
break;
}

View File

@@ -160,8 +160,7 @@ static struct vimvar
{VV_NAME("python3_version", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_typealias", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_enum", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO},
{VV_NAME("cmdcomplete", VAR_BOOL), NULL, VV_RO},
{VV_NAME("t_enumvalue", VAR_NUMBER), NULL, VV_RO}
};
// shorthand
@@ -235,7 +234,6 @@ evalvars_init(void)
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
set_vim_var_nr(VV_EXITING, VVAL_NULL);
set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
set_vim_var_list(VV_ERRORS, list_alloc());
set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));

View File

@@ -6924,58 +6924,71 @@ ex_wrongmodifier(exarg_T *eap)
}
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* Evaluate the 'findexpr' expression and return the result. When evaluating
* the expression, v:fname is set to the ":find" command argument.
*/
static list_T *
eval_findexpr(char_u *pat, int cmdcomplete)
// callback function for 'findfunc'
static callback_T ffu_cb;
static callback_T *
get_findfunc_callback(void)
{
return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb;
}
static list_T *
call_findfunc(char_u *pat, int cmdcomplete)
{
typval_T args[3];
callback_T *cb;
typval_T rettv;
int retval;
sctx_T saved_sctx = current_sctx;
char_u *findexpr;
char_u *arg;
typval_T tv;
list_T *retlist = NULL;
sctx_T *ctx;
findexpr = get_findexpr();
set_vim_var_string(VV_FNAME, pat, -1);
set_vim_var_nr(VV_CMDCOMPLETE, cmdcomplete ? VVAL_TRUE : VVAL_FALSE);
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
arg = skipwhite(findexpr);
// Call 'findfunc' to obtain the list of file names.
args[0].v_type = VAR_STRING;
args[0].vval.v_string = pat;
args[1].v_type = VAR_BOOL;
args[1].vval.v_number = cmdcomplete;
args[2].v_type = VAR_UNKNOWN;
// Lock the text to prevent weird things from happening. Also disallow
// switching to another window, it should not be needed and may end up in
// Insert mode in another buffer.
++textlock;
// Evaluate the expression. If the expression is "FuncName()" call the
// function directly.
if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL)
retlist = NULL;
else
{
if (tv.v_type == VAR_LIST)
retlist = list_copy(tv.vval.v_list, TRUE, TRUE, get_copyID());
else
emsg(_(e_invalid_return_type_from_findexpr));
clear_tv(&tv);
}
--textlock;
clear_evalarg(&EVALARG_EVALUATE, NULL);
ctx = get_option_sctx("findfunc");
if (ctx != NULL)
current_sctx = *ctx;
cb = get_findfunc_callback();
retval = call_callback(cb, -1, &rettv, 2, args);
set_vim_var_string(VV_FNAME, NULL, 0);
set_vim_var_nr(VV_CMDCOMPLETE, VVAL_FALSE);
current_sctx = saved_sctx;
--textlock;
list_T *retlist = NULL;
if (retval == OK)
{
if (rettv.v_type == VAR_LIST)
retlist = list_copy(rettv.vval.v_list, FALSE, FALSE, get_copyID());
else
emsg(_(e_invalid_return_type_from_findfunc));
clear_tv(&rettv);
}
return retlist;
}
/*
* Find file names matching "pat" using 'findexpr' and return it in "files".
* Find file names matching "pat" using 'findfunc' and return it in "files".
* Used for expanding the :find, :sfind and :tabfind command argument.
* Returns OK on success and FAIL otherwise.
*/
int
expand_findexpr(char_u *pat, char_u ***files, int *numMatches)
expand_findfunc(char_u *pat, char_u ***files, int *numMatches)
{
list_T *l;
int len;
@@ -6983,7 +6996,7 @@ expand_findexpr(char_u *pat, char_u ***files, int *numMatches)
*numMatches = 0;
*files = NULL;
l = eval_findexpr(pat, TRUE);
l = call_findfunc(pat, VVAL_TRUE);
if (l == NULL)
return FAIL;
@@ -7015,11 +7028,11 @@ expand_findexpr(char_u *pat, char_u ***files, int *numMatches)
}
/*
* Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
* Use 'findfunc' to find file 'findarg'. The 'count' argument is used to find
* the n'th matching file.
*/
static char_u *
findexpr_find_file(char_u *findarg, int findarg_len, int count)
findfunc_find_file(char_u *findarg, int findarg_len, int count)
{
list_T *fname_list;
char_u *ret_fname = NULL;
@@ -7029,7 +7042,7 @@ findexpr_find_file(char_u *findarg, int findarg_len, int count)
cc = findarg[findarg_len];
findarg[findarg_len] = NUL;
fname_list = eval_findexpr(findarg, FALSE);
fname_list = call_findfunc(findarg, VVAL_FALSE);
fname_count = list_len(fname_list);
if (fname_count == 0)
@@ -7053,6 +7066,62 @@ findexpr_find_file(char_u *findarg, int findarg_len, int count)
return ret_fname;
}
/*
* Process the 'findfunc' option value.
* Returns NULL on success and an error message on failure.
*/
char *
did_set_findfunc(optset_T *args UNUSED)
{
int retval;
if (*curbuf->b_p_ffu != NUL)
{
// buffer-local option set
retval = option_set_callback_func(curbuf->b_p_ffu, &curbuf->b_ffu_cb);
}
else
{
// global option set
retval = option_set_callback_func(p_ffu, &ffu_cb);
}
if (retval == FAIL)
return e_invalid_argument;
// If the option value starts with <SID> or s:, then replace that with
// the script identifier.
char_u **varp = (char_u **)args->os_varp;
char_u *name = get_scriptlocal_funcname(*varp);
if (name != NULL)
{
free_string_option(*varp);
*varp = name;
}
return NULL;
}
# if defined(EXITFREE) || defined(PROTO)
void
free_findfunc_option(void)
{
free_callback(&ffu_cb);
}
# endif
/*
* Mark the global 'findfunc' callback with "copyID" so that it is not
* garbage collected.
*/
int
set_ref_in_findfunc(int copyID UNUSED)
{
int abort = FALSE;
abort = set_ref_in_callback(&ffu_cb, copyID);
return abort;
}
#endif
/*
@@ -7105,10 +7174,10 @@ ex_splitview(exarg_T *eap)
char_u *file_to_find = NULL;
char *search_ctx = NULL;
if (*get_findexpr() != NUL)
if (*get_findfunc() != NUL)
{
#ifdef FEAT_EVAL
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
fname = findfunc_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}
@@ -7389,10 +7458,10 @@ ex_find(exarg_T *eap)
char_u *file_to_find = NULL;
char *search_ctx = NULL;
if (*get_findexpr() != NUL)
if (*get_findfunc() != NUL)
{
#ifdef FEAT_EVAL
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
fname = findfunc_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}

View File

@@ -183,6 +183,9 @@ garbage_collect(int testing)
// 'imactivatefunc' and 'imstatusfunc' callbacks
abort = abort || set_ref_in_im_funcs(copyID);
// 'findfunc' callback
abort = abort || set_ref_in_findfunc(copyID);
#ifdef FEAT_LUA
abort = abort || set_ref_in_lua(copyID);
#endif

View File

@@ -1014,6 +1014,9 @@ free_all_options(void)
}
free_operatorfunc_option();
free_tagfunc_option();
# if defined(FEAT_EVAL)
free_findfunc_option();
# endif
}
#endif
@@ -6372,8 +6375,8 @@ unset_global_local_option(char_u *name, void *from)
clear_string_option(&buf->b_p_fp);
break;
# ifdef FEAT_EVAL
case PV_FEXPR:
clear_string_option(&buf->b_p_fexpr);
case PV_FFU:
clear_string_option(&buf->b_p_ffu);
break;
# endif
# ifdef FEAT_QUICKFIX
@@ -6455,7 +6458,7 @@ get_varp_scope(struct vimoption *p, int scope)
{
case PV_FP: return (char_u *)&(curbuf->b_p_fp);
#ifdef FEAT_EVAL
case PV_FEXPR: return (char_u *)&(curbuf->b_p_fexpr);
case PV_FFU: return (char_u *)&(curbuf->b_p_ffu);
#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
@@ -6568,8 +6571,8 @@ get_varp(struct vimoption *p)
case PV_FP: return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var;
#ifdef FEAT_EVAL
case PV_FEXPR: return *curbuf->b_p_fexpr != NUL
? (char_u *)&curbuf->b_p_fexpr : p->var;
case PV_FFU: return *curbuf->b_p_ffu != NUL
? (char_u *)&(curbuf->b_p_ffu) : p->var;
#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return *curbuf->b_p_efm != NUL
@@ -6818,15 +6821,15 @@ get_equalprg(void)
}
/*
* Get the value of 'findexpr', either the buffer-local one or the global one.
* Get the value of 'findfunc', either the buffer-local one or the global one.
*/
char_u *
get_findexpr(void)
get_findfunc(void)
{
#ifdef FEAT_EVAL
if (*curbuf->b_p_fexpr == NUL)
return p_fexpr;
return curbuf->b_p_fexpr;
if (*curbuf->b_p_ffu == NUL)
return p_ffu;
return curbuf->b_p_ffu;
#else
return (char_u *)"";
#endif
@@ -7361,8 +7364,7 @@ buf_copy_options(buf_T *buf, int flags)
#endif
buf->b_p_ep = empty_option;
#if defined(FEAT_EVAL)
buf->b_p_fexpr = vim_strsave(p_fexpr);
COPY_OPT_SCTX(buf, BV_FEXPR);
buf->b_p_ffu = empty_option;
#endif
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
@@ -8749,6 +8751,7 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
#ifdef FEAT_EVAL
typval_T *tv;
callback_T cb;
int funcname = FALSE;
if (optval == NULL || *optval == NUL)
{
@@ -8762,8 +8765,11 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
// Lambda expression or a funcref
tv = eval_expr(optval, NULL);
else
{
// treat everything else as a function name string
tv = alloc_string_tv(vim_strsave(optval));
funcname = TRUE;
}
if (tv == NULL)
return FAIL;
@@ -8780,6 +8786,16 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
vim_free(cb.cb_name);
free_tv(tv);
if (in_vim9script() && funcname && (vim_strchr(optval, '.') != NULL))
{
// When a Vim9 imported function name is used, it is expanded by the
// call to get_callback() above to <SNR>_funcname. Revert the name to
// back to "import.funcname".
if (optcb->cb_free_name)
vim_free(optcb->cb_name);
optcb->cb_name = vim_strsave(optval);
optcb->cb_free_name = TRUE;
}
// when using Vim9 style "import.funcname" it needs to be expanded to
// "import#funcname".
expand_autload_callback(optcb);

View File

@@ -597,7 +597,7 @@ EXTERN int p_fic; // 'fileignorecase'
EXTERN char_u *p_ft; // 'filetype'
EXTERN char_u *p_fcs; // 'fillchar'
#ifdef FEAT_EVAL
EXTERN char_u *p_fexpr; // 'findexpr'
EXTERN char_u *p_ffu; // 'findfunc'
#endif
EXTERN int p_fixeol; // 'fixendofline'
#ifdef FEAT_FOLDING
@@ -1171,11 +1171,11 @@ enum
, BV_EP
, BV_ET
, BV_FENC
, BV_FEXPR
, BV_FP
#ifdef FEAT_EVAL
, BV_BEXPR
, BV_FEX
, BV_FFU
#endif
, BV_FF
, BV_FLP

View File

@@ -54,6 +54,7 @@
#define PV_CPT OPT_BUF(BV_CPT)
#define PV_DICT OPT_BOTH(OPT_BUF(BV_DICT))
#define PV_TSR OPT_BOTH(OPT_BUF(BV_TSR))
#define PV_FFU OPT_BOTH(OPT_BUF(BV_FFU))
#define PV_CSL OPT_BUF(BV_CSL)
#ifdef FEAT_COMPL_FUNC
# define PV_CFU OPT_BUF(BV_CFU)
@@ -74,7 +75,6 @@
#define PV_FP OPT_BOTH(OPT_BUF(BV_FP))
#ifdef FEAT_EVAL
# define PV_FEX OPT_BUF(BV_FEX)
# define PV_FEXPR OPT_BOTH(OPT_BUF(BV_FEXPR))
#endif
#define PV_FF OPT_BUF(BV_FF)
#define PV_FLP OPT_BUF(BV_FLP)
@@ -959,9 +959,10 @@ static struct vimoption options[] =
{(char_u *)"vert:|,fold:-,eob:~,lastline:@",
(char_u *)0L}
SCTX_INIT},
{"findexpr", "fexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE,
#if defined(FEAT_EVAL)
(char_u *)&p_fexpr, PV_FEXPR, did_set_optexpr, NULL,
{"findfunc", "ffu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC,
#ifdef FEAT_EVAL
(char_u *)&p_ffu, PV_FFU,
did_set_findfunc, NULL,
{(char_u *)"", (char_u *)0L}
#else
(char_u *)NULL, PV_NONE, NULL, NULL,

View File

@@ -313,6 +313,7 @@ check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_tsrfu);
#endif
#ifdef FEAT_EVAL
check_string_option(&buf->b_p_ffu);
check_string_option(&buf->b_p_tfu);
#endif
#ifdef FEAT_KEYMAP
@@ -324,9 +325,6 @@ check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_efm);
#endif
check_string_option(&buf->b_p_ep);
#ifdef FEAT_EVAL
check_string_option(&buf->b_p_fexpr);
#endif
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
check_string_option(&buf->b_p_tc);
@@ -3135,9 +3133,8 @@ expand_set_nrformats(optexpand_T *args, int *numMatches, char_u ***matches)
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* One of the '*expr' options is changed: 'balloonexpr', 'diffexpr',
* 'findexpr', 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr',
* 'indentexpr', 'patchexpr', 'printexpr' and 'charconvert'.
*
* 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
* 'patchexpr', 'printexpr' and 'charconvert'.
*/
char *
did_set_optexpr(optset_T *args)

View File

@@ -46,7 +46,10 @@ void tabpage_close_other(tabpage_T *tp, int forceit);
void ex_stop(exarg_T *eap);
void handle_drop(int filec, char_u **filev, int split, void (*callback)(void *), void *cookie);
void handle_any_postponed_drop(void);
int expand_findexpr(char_u *pat, char_u ***files, int *numMatches);
int expand_findfunc(char_u *pat, char_u ***files, int *numMatches);
char *did_set_findfunc(optset_T *args);
void free_findfunc_option(void);
int set_ref_in_findfunc(int copyID);
void ex_splitview(exarg_T *eap);
void tabpage_new(void);
void do_exedit(exarg_T *eap, win_T *old_curwin);

View File

@@ -120,7 +120,7 @@ char_u *get_option_var(int opt_idx);
char_u *get_option_fullname(int opt_idx);
opt_did_set_cb_T get_option_did_set_cb(int opt_idx);
char_u *get_equalprg(void);
char_u *get_findexpr(void);
char_u *get_findfunc(void);
void win_copy_options(win_T *wp_from, win_T *wp_to);
void after_copy_winopt(win_T *wp);
void copy_winopt(winopt_T *from, winopt_T *to);

View File

@@ -3248,6 +3248,8 @@ struct file_buffer
#ifdef FEAT_EVAL
char_u *b_p_tfu; // 'tagfunc' option value
callback_T b_tfu_cb; // 'tagfunc' callback
char_u *b_p_ffu; // 'findfunc' option value
callback_T b_ffu_cb; // 'findfunc' callback
#endif
int b_p_eof; // 'endoffile'
int b_p_eol; // 'endofline'
@@ -3334,9 +3336,6 @@ struct file_buffer
char_u *b_p_efm; // 'errorformat' local value
#endif
char_u *b_p_ep; // 'equalprg' local value
#ifdef FEAT_EVAL
char_u *b_p_fexpr; // 'findexpr' local value
#endif
char_u *b_p_path; // 'path' local value
int b_p_ar; // 'autoread' local value
char_u *b_p_tags; // 'tags' local value

View File

@@ -1,6 +1,7 @@
" Test findfile() and finddir()
source check.vim
import './vim9.vim' as v9
let s:files = [ 'Xfinddir1/foo',
\ 'Xfinddir1/bar',
@@ -283,223 +284,491 @@ func Test_find_non_existing_path()
let &path = save_path
endfunc
" Test for 'findexpr'
func Test_findexpr()
" Test for 'findfunc'
func Test_findfunc()
CheckUnix
call assert_equal('', &findexpr)
call writefile(['aFile'], 'Xfindexpr1.c', 'D')
call writefile(['bFile'], 'Xfindexpr2.c', 'D')
call writefile(['cFile'], 'Xfindexpr3.c', 'D')
call assert_equal('', &findfunc)
call writefile(['aFile'], 'Xfindfunc1.c', 'D')
call writefile(['bFile'], 'Xfindfunc2.c', 'D')
call writefile(['cFile'], 'Xfindfunc3.c', 'D')
" basic tests
func FindExpr1()
let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
return fnames->copy()->filter('v:val =~? v:fname')
func FindFuncBasic(pat, cmdcomplete)
let fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
return fnames->copy()->filter('v:val =~? a:pat')
endfunc
set findexpr=FindExpr1()
find Xfindexpr3
call assert_match('Xfindexpr3.c', @%)
set findfunc=FindFuncBasic
find Xfindfunc3
call assert_match('Xfindfunc3.c', @%)
bw!
2find Xfind
call assert_match('Xfindexpr2.c', @%)
call assert_match('Xfindfunc2.c', @%)
bw!
call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path')
call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path')
sfind Xfindexpr2.c
call assert_match('Xfindexpr2.c', @%)
sfind Xfindfunc2.c
call assert_match('Xfindfunc2.c', @%)
call assert_equal(2, winnr('$'))
%bw!
call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path')
tabfind Xfindexpr3.c
call assert_match('Xfindexpr3.c', @%)
tabfind Xfindfunc3.c
call assert_match('Xfindfunc3.c', @%)
call assert_equal(2, tabpagenr())
%bw!
call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path')
" Test garbage collection
call test_garbagecollect_now()
find Xfindfunc2
call assert_match('Xfindfunc2.c', @%)
bw!
delfunc FindFuncBasic
call test_garbagecollect_now()
call assert_fails('find Xfindfunc2', 'E117: Unknown function: FindFuncBasic')
" Buffer-local option
set findexpr=['abc']
func GlobalFindFunc(pat, cmdcomplete)
return ['global']
endfunc
func LocalFindFunc(pat, cmdcomplete)
return ['local']
endfunc
set findfunc=GlobalFindFunc
new
setlocal findexpr=['def']
setlocal findfunc=LocalFindFunc
find xxxx
call assert_equal('def', @%)
call assert_equal('local', @%)
wincmd w
find xxxx
call assert_equal('abc', @%)
call assert_equal('global', @%)
aboveleft new
call assert_equal("['abc']", &findexpr)
call assert_equal("GlobalFindFunc", &findfunc)
wincmd k
aboveleft new
call assert_equal("['abc']", &findexpr)
call assert_equal("GlobalFindFunc", &findfunc)
%bw!
delfunc GlobalFindFunc
delfunc LocalFindFunc
" Empty list
set findexpr=[]
call assert_fails('find xxxx', 'E345: Can''t find file "xxxx" in path')
" Assign an expression
set findfunc=[]
call assert_fails('find xxxx', 'E117: Unknown function: []')
" Error cases
" Syntax error in the expression
set findexpr=FindExpr1{}
call assert_fails('find Xfindexpr1.c', 'E15: Invalid expression')
" Function that doesn't any argument
func FindFuncNoArg()
endfunc
set findfunc=FindFuncNoArg
call assert_fails('find Xfindfunc1.c', 'E118: Too many arguments for function: FindFuncNoArg')
delfunc FindFuncNoArg
" Find expression throws an error
func FindExpr2()
" Syntax error in the function
func FindFuncSyntaxError(pat, cmdcomplete)
return l
endfunc
set findfunc=FindFuncSyntaxError
call assert_fails('find Xfindfunc1.c', 'E121: Undefined variable: l')
delfunc FindFuncSyntaxError
" Find function throws an error
func FindFuncWithThrow(pat, cmdcomplete)
throw 'find error'
endfunc
set findexpr=FindExpr2()
call assert_fails('find Xfindexpr1.c', 'find error')
set findfunc=FindFuncWithThrow
call assert_fails('find Xfindfunc1.c', 'find error')
delfunc FindFuncWithThrow
" Try using a null List as the expression
set findexpr=test_null_list()
call assert_fails('find Xfindexpr1.c', 'E345: Can''t find file "Xfindexpr1.c" in path')
" Try using a null function
call assert_fails('let &findfunc = test_null_function()', 'E129: Function name required')
" Try to create a new window from the find expression
func FindExpr3()
" Try to create a new window from the find function
func FindFuncNewWindow(pat, cmdexpand)
new
return ["foo"]
endfunc
set findexpr=FindExpr3()
call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
set findfunc=FindFuncNewWindow
call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window')
delfunc FindFuncNewWindow
" Try to modify the current buffer from the find expression
func FindExpr4()
" Try to modify the current buffer from the find function
func FindFuncModifyBuf(pat, cmdexpand)
call setline(1, ['abc'])
return ["foo"]
endfunc
set findexpr=FindExpr4()
call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
set findfunc=FindFuncModifyBuf
call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window')
delfunc FindFuncModifyBuf
" Expression returning a string
set findexpr='abc'
call assert_fails('find Xfindexpr1.c', "E1514: 'findexpr' did not return a List type")
" Return the wrong type from the function
func FindFuncWrongRet(pat, cmdexpand)
return 'foo'
endfunc
set findfunc=FindFuncWrongRet
call assert_fails('find Xfindfunc1.c', "E1514: 'findfunc' did not return a List type")
delfunc FindFuncWrongRet
set findexpr&
delfunc! FindExpr1
delfunc! FindExpr2
delfunc! FindExpr3
delfunc! FindExpr4
set findfunc&
endfunc
" Test for using a script-local function for 'findexpr'
func Test_findexpr_scriptlocal_func()
func! s:FindExprScript()
let g:FindExprArg = v:fname
" Test for using a script-local function for 'findfunc'
func Test_findfunc_scriptlocal_func()
func! s:FindFuncScript(pat, cmdexpand)
let g:FindFuncArg = a:pat
return ['xxx']
endfunc
set findexpr=s:FindExprScript()
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
set findfunc=s:FindFuncScript
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
new | only
let g:FindExprArg = ''
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
set findexpr=<SID>FindExprScript()
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
set findfunc=<SID>FindFuncScript
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
new | only
let g:FindExprArg = ''
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
let &findexpr = 's:FindExprScript()'
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
let &findfunc = 's:FindFuncScript'
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
new | only
let g:FindExprArg = ''
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
let &findexpr = '<SID>FindExprScript()'
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
let &findfunc = '<SID>FindFuncScript'
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
new | only
let g:FindExprArg = ''
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
set findexpr=
setglobal findexpr=s:FindExprScript()
setlocal findexpr=
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
call assert_equal('', &l:findexpr)
set findfunc=
setglobal findfunc=s:FindFuncScript
setlocal findfunc=
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
call assert_equal('', &l:findfunc)
new | only
let g:FindExprArg = ''
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
new | only
set findexpr=
setglobal findexpr=
setlocal findexpr=s:FindExprScript()
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &l:findexpr)
call assert_equal('', &g:findexpr)
let g:FindExprArg = ''
set findfunc=
setglobal findfunc=
setlocal findfunc=s:FindFuncScript
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
call assert_equal(expand('<SID>') .. 'FindFuncScript', &l:findfunc)
call assert_equal('', &g:findfunc)
let g:FindFuncArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
call assert_equal('abc', g:FindFuncArg)
bw!
set findexpr=
delfunc s:FindExprScript
set findfunc=
delfunc s:FindFuncScript
endfunc
" Test for expanding the argument to the :find command using 'findexpr'
func Test_findexpr_expand_arg()
let s:fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
" Test for expanding the argument to the :find command using 'findfunc'
func Test_findfunc_expand_arg()
let s:fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
" 'findexpr' that accepts a regular expression
func FindExprRegexp()
return s:fnames->copy()->filter('v:val =~? v:fname')
" 'findfunc' that accepts a regular expression
func FindFuncRegexp(pat, cmdcomplete)
return s:fnames->copy()->filter('v:val =~? a:pat')
endfunc
" 'findexpr' that accepts a glob
func FindExprGlob()
let pat = glob2regpat(v:cmdcomplete ? $'*{v:fname}*' : v:fname)
" 'findfunc' that accepts a glob
func FindFuncGlob(pat_arg, cmdcomplete)
let pat = glob2regpat(a:cmdcomplete ? $'*{a:pat_arg}*' : a:pat_arg)
return s:fnames->copy()->filter('v:val =~? pat')
endfunc
for regexp in [v:true, v:false]
let &findexpr = regexp ? 'FindExprRegexp()' : 'FindExprGlob()'
let &findfunc = regexp ? 'FindFuncRegexp' : 'FindFuncGlob'
call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr1.c', @:)
call assert_equal('"find Xfindfunc1.c', @:)
call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr2.c', @:)
call assert_equal('"find Xfindfunc2.c', @:)
call assert_equal(s:fnames, getcompletion('find ', 'cmdline'))
call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline'))
let pat = regexp ? 'X.*1\.c' : 'X*1.c'
call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr1.c', @:)
call assert_equal(['Xfindexpr1.c'], getcompletion($'find {pat}', 'cmdline'))
call assert_equal('"find Xfindfunc1.c', @:)
call assert_equal(['Xfindfunc1.c'], getcompletion($'find {pat}', 'cmdline'))
call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr3.c', @:)
call assert_equal(['Xfindexpr3.c'], getcompletion($'find 3', 'cmdline'))
call assert_equal('"find Xfindfunc3.c', @:)
call assert_equal(['Xfindfunc3.c'], getcompletion($'find 3', 'cmdline'))
call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr1.c Xfindexpr2.c Xfindexpr3.c', @:)
call assert_equal('"find Xfindfunc1.c Xfindfunc2.c Xfindfunc3.c', @:)
call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find abc', @:)
call assert_equal([], getcompletion('find abc', 'cmdline'))
endfor
set findexpr&
delfunc! FindExprRegexp
delfunc! FindExprGlob
set findfunc&
delfunc! FindFuncRegexp
delfunc! FindFuncGlob
unlet s:fnames
endfunc
" Test for different ways of setting the 'findfunc' option
func Test_findfunc_callback()
new
func FindFunc1(pat, cmdexpand)
let g:FindFunc1Args = [a:pat, a:cmdexpand]
return ['findfunc1']
endfunc
let lines =<< trim END
#" Test for using a function name
LET &findfunc = 'g:FindFunc1'
LET g:FindFunc1Args = []
find abc1
call assert_equal(['abc1', v:false], g:FindFunc1Args)
#" Test for using a function()
set findfunc=function('g:FindFunc1')
LET g:FindFunc1Args = []
find abc2
call assert_equal(['abc2', v:false], g:FindFunc1Args)
#" Using a funcref variable to set 'findfunc'
VAR Fn = function('g:FindFunc1')
LET &findfunc = Fn
LET g:FindFunc1Args = []
find abc3
call assert_equal(['abc3', v:false], g:FindFunc1Args)
#" Using a string(funcref_variable) to set 'findfunc'
LET Fn = function('g:FindFunc1')
LET &findfunc = string(Fn)
LET g:FindFunc1Args = []
find abc4
call assert_equal(['abc4', v:false], g:FindFunc1Args)
#" Test for using a funcref()
set findfunc=funcref('g:FindFunc1')
LET g:FindFunc1Args = []
find abc5
call assert_equal(['abc5', v:false], g:FindFunc1Args)
#" Using a funcref variable to set 'findfunc'
LET Fn = funcref('g:FindFunc1')
LET &findfunc = Fn
LET g:FindFunc1Args = []
find abc6
call assert_equal(['abc6', v:false], g:FindFunc1Args)
#" Using a string(funcref_variable) to set 'findfunc'
LET Fn = funcref('g:FindFunc1')
LET &findfunc = string(Fn)
LET g:FindFunc1Args = []
find abc7
call assert_equal(['abc7', v:false], g:FindFunc1Args)
#" Test for using a lambda function using set
VAR optval = "LSTART pat, cmdexpand LMIDDLE FindFunc1(pat, cmdexpand) LEND"
LET optval = substitute(optval, ' ', '\\ ', 'g')
exe "set findfunc=" .. optval
LET g:FindFunc1Args = []
find abc8
call assert_equal(['abc8', v:false], g:FindFunc1Args)
#" Test for using a lambda function using LET
LET &findfunc = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
LET g:FindFunc1Args = []
find abc9
call assert_equal(['abc9', v:false], g:FindFunc1Args)
#" Set 'findfunc' to a string(lambda expression)
LET &findfunc = 'LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND'
LET g:FindFunc1Args = []
find abc10
call assert_equal(['abc10', v:false], g:FindFunc1Args)
#" Set 'findfunc' to a variable with a lambda expression
VAR Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
LET &findfunc = Lambda
LET g:FindFunc1Args = []
find abc11
call assert_equal(['abc11', v:false], g:FindFunc1Args)
#" Set 'findfunc' to a string(variable with a lambda expression)
LET Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND
LET &findfunc = string(Lambda)
LET g:FindFunc1Args = []
find abc12
call assert_equal(['abc12', v:false], g:FindFunc1Args)
#" Try to use 'findfunc' after the function is deleted
func g:TmpFindFunc(pat, cmdexpand)
let g:TmpFindFunc1Args = [a:pat, a:cmdexpand]
endfunc
LET &findfunc = function('g:TmpFindFunc')
delfunc g:TmpFindFunc
call test_garbagecollect_now()
LET g:TmpFindFunc1Args = []
call assert_fails('find abc13', 'E117:')
call assert_equal([], g:TmpFindFunc1Args)
#" Try to use a function with three arguments for 'findfunc'
func g:TmpFindFunc2(x, y, z)
let g:TmpFindFunc2Args = [a:x, a:y, a:z]
endfunc
set findfunc=TmpFindFunc2
LET g:TmpFindFunc2Args = []
call assert_fails('find abc14', 'E119:')
call assert_equal([], g:TmpFindFunc2Args)
delfunc TmpFindFunc2
#" Try to use a function with zero arguments for 'findfunc'
func g:TmpFindFunc3()
let g:TmpFindFunc3Called = v:true
endfunc
set findfunc=TmpFindFunc3
LET g:TmpFindFunc3Called = v:false
call assert_fails('find abc15', 'E118:')
call assert_equal(v:false, g:TmpFindFunc3Called)
delfunc TmpFindFunc3
#" Try to use a lambda function with three arguments for 'findfunc'
LET &findfunc = LSTART a, b, c LMIDDLE FindFunc1(a, v:false) LEND
LET g:FindFunc1Args = []
call assert_fails('find abc16', 'E119:')
call assert_equal([], g:FindFunc1Args)
#" Test for clearing the 'findfunc' option
set findfunc=''
set findfunc&
call assert_fails("set findfunc=function('abc')", "E700:")
call assert_fails("set findfunc=funcref('abc')", "E700:")
#" set 'findfunc' to a non-existing function
LET &findfunc = function('g:FindFunc1')
call assert_fails("set findfunc=function('NonExistingFunc')", 'E700:')
call assert_fails("LET &findfunc = function('NonExistingFunc')", 'E700:')
LET g:FindFunc1Args = []
find abc17
call assert_equal(['abc17', v:false], g:FindFunc1Args)
END
call v9.CheckTransLegacySuccess(lines)
" Test for using a script-local function name
func s:FindFunc2(pat, cmdexpand)
let g:FindFunc2Args = [a:pat, a:cmdexpand]
return ['findfunc2']
endfunc
set findfunc=s:FindFunc2
let g:FindFunc2Args = []
find abc18
call assert_equal(['abc18', v:false], g:FindFunc2Args)
let &findfunc = 's:FindFunc2'
let g:FindFunc2Args = []
find abc19
call assert_equal(['abc19', v:false], g:FindFunc2Args)
delfunc s:FindFunc2
" Using Vim9 lambda expression in legacy context should fail
set findfunc=(pat,\ cmdexpand)\ =>\ FindFunc1(pat,\ v:false)
let g:FindFunc1Args = []
call assert_fails('find abc20', 'E117:')
call assert_equal([], g:FindFunc1Args)
" set 'findfunc' to a partial with dict.
func SetFindFunc()
let operator = {'execute': function('FindFuncExecute')}
let &findfunc = operator.execute
endfunc
func FindFuncExecute(pat, cmdexpand) dict
return ['findfuncexecute']
endfunc
call SetFindFunc()
call test_garbagecollect_now()
set findfunc=
delfunc SetFindFunc
delfunc FindFuncExecute
func FindFunc2(pat, cmdexpand)
let g:FindFunc2Args = [a:pat, a:cmdexpand]
return ['findfunc2']
endfunc
" Vim9 tests
let lines =<< trim END
vim9script
def g:Vim9findFunc(pat: string, cmdexpand: bool): list<string>
g:FindFunc1Args = [pat, cmdexpand]
return ['vim9findfunc']
enddef
# Test for using a def function with findfunc
set findfunc=function('g:Vim9findFunc')
g:FindFunc1Args = []
find abc21
assert_equal(['abc21', false], g:FindFunc1Args)
# Test for using a global function name
&findfunc = g:FindFunc2
g:FindFunc2Args = []
find abc22
assert_equal(['abc22', false], g:FindFunc2Args)
bw!
# Test for using a script-local function name
def LocalFindFunc(pat: string, cmdexpand: bool): list<string>
g:LocalFindFuncArgs = [pat, cmdexpand]
return ['localfindfunc']
enddef
&findfunc = LocalFindFunc
g:LocalFindFuncArgs = []
find abc23
assert_equal(['abc23', false], g:LocalFindFuncArgs)
bw!
END
call v9.CheckScriptSuccess(lines)
" setting 'findfunc' to a script local function outside of a script context
" should fail
let cleanup =<< trim END
call writefile([execute('messages')], 'Xtest.out')
qall
END
call writefile(cleanup, 'Xverify.vim', 'D')
call RunVim([], [], "-c \"set findfunc=s:abc\" -S Xverify.vim")
call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
call delete('Xtest.out')
" cleanup
set findfunc&
delfunc FindFunc1
delfunc FindFunc2
unlet g:FindFunc1Args g:FindFunc2Args
%bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -208,7 +208,7 @@ func Test_modeline_fails_always()
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
call s:modeline_fails('exrc', 'exrc=Something()', 'E520:')
call s:modeline_fails('findexpr', 'findexpr=Something()', 'E520:')
call s:modeline_fails('findfunc', 'findfunc=Something', 'E520:')
call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:')
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')

View File

@@ -1570,7 +1570,7 @@ endfunc
" Test for changing options in a sandbox
func Test_opt_sandbox()
for opt in ['backupdir', 'cdpath', 'exrc', 'findexpr']
for opt in ['backupdir', 'cdpath', 'exrc', 'findfunc']
call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor

View File

@@ -1560,27 +1560,47 @@ def Run_Test_import_in_printexpr()
set printexpr=
enddef
" Test for using an imported function as 'findexpr'
func Test_import_in_findexpr()
call Run_Test_import_in_findexpr()
" Test for using an imported function as 'findfunc'
func Test_import_in_findfunc()
call Run_Test_import_in_findfunc()
endfunc
def Run_Test_import_in_findexpr()
def Run_Test_import_in_findfunc()
var lines =<< trim END
vim9script
vim9script
export def FindExpr(): list<string>
var fnames = ['Xfile1.c', 'Xfile2.c', 'Xfile3.c']
return fnames->copy()->filter('v:val =~? v:fname')
enddef
export def FindFunc(pat: string, cmdexpand: bool): list<string>
var fnames = ['Xfile1.c', 'Xfile2.c', 'Xfile3.c']
return fnames->filter((_, v) => v =~? pat)
enddef
END
writefile(lines, 'Xfindexpr', 'D')
writefile(lines, 'Xfindfunc', 'D')
# Test using the "set" command
lines =<< trim END
vim9script
import './Xfindexpr' as find
vim9script
import './Xfindfunc' as find1
set findexpr=find.FindExpr()
set findfunc=find1.FindFunc
END
v9.CheckScriptSuccess(lines)
enew!
find Xfile2
assert_equal('Xfile2.c', @%)
bwipe!
botright vert new
find Xfile1
assert_equal('Xfile1.c', @%)
bw!
# Test using the option variable
lines =<< trim END
vim9script
import './Xfindfunc' as find2
&findfunc = find2.FindFunc
END
v9.CheckScriptSuccess(lines)
@@ -1593,7 +1613,7 @@ def Run_Test_import_in_findexpr()
find Xfile1
assert_equal('Xfile1.c', @%)
set findexpr=
set findfunc=
bwipe!
enddef

View File

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

View File

@@ -845,7 +845,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define EXPAND_KEYMAP 58
#define EXPAND_DIRS_IN_CDPATH 59
#define EXPAND_SHELLCMDLINE 60
#define EXPAND_FINDEXPR 61
#define EXPAND_FINDFUNC 61
// Values for exmode_active (0 is no exmode)
@@ -2189,8 +2189,7 @@ typedef int sock_T;
#define VV_TYPE_TYPEALIAS 107
#define VV_TYPE_ENUM 108
#define VV_TYPE_ENUMVALUE 109
#define VV_CMDCOMPLETE 110
#define VV_LEN 111 // number of v: vars
#define VV_LEN 110 // number of v: vars
// used for v_number in VAR_BOOL and VAR_SPECIAL
#define VVAL_FALSE 0L // VAR_BOOL