mirror of
https://github.com/neovim/neovim.git
synced 2025-09-12 22:38:16 +00:00
vim-patch:9.1.0831: 'findexpr' can't be used as lambad or Funcref (#31058)
Problem: 'findexpr' can't be used for lambads
(Justin Keyes)
Solution: Replace the findexpr option with the findfunc option
(Yegappan Lakshmanan)
related: vim/vim#15905
closes: vim/vim#15976
a13f3a4f5d
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -370,10 +370,11 @@ Note: In the future more global options can be made |global-local|. Using
|
|||||||
":setlocal" on a global option might work differently then.
|
":setlocal" on a global option might work differently then.
|
||||||
|
|
||||||
*option-value-function*
|
*option-value-function*
|
||||||
Some options ('completefunc', 'omnifunc', 'operatorfunc', 'quickfixtextfunc',
|
Some options ('completefunc', 'findfunc', 'omnifunc', 'operatorfunc',
|
||||||
'tagfunc' and 'thesaurusfunc') are set to a function name or a function
|
'quickfixtextfunc', 'tagfunc' and 'thesaurusfunc') are set to a function name
|
||||||
reference or a lambda function. When using a lambda it will be converted to
|
or a function reference or a lambda function. When using a lambda it will be
|
||||||
the name, e.g. "<lambda>123". Examples:
|
converted to the name, e.g. "<lambda>123".
|
||||||
|
Examples:
|
||||||
>
|
>
|
||||||
set opfunc=MyOpFunc
|
set opfunc=MyOpFunc
|
||||||
set opfunc=function('MyOpFunc')
|
set opfunc=function('MyOpFunc')
|
||||||
@@ -2598,34 +2599,34 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
eob EndOfBuffer |hl-EndOfBuffer|
|
eob EndOfBuffer |hl-EndOfBuffer|
|
||||||
lastline NonText |hl-NonText|
|
lastline NonText |hl-NonText|
|
||||||
|
|
||||||
*'findexpr'* *'fexpr'* *E1514*
|
*'findfunc'* *'ffu'* *E1514*
|
||||||
'findexpr' 'fexpr' string (default "")
|
'findfunc' 'ffu' string (default "")
|
||||||
global or local to buffer |global-local|
|
global or local to buffer |global-local|
|
||||||
Expression that is evaluated to obtain the filename(s) for the |:find|
|
Function that is called to obtain the filename(s) for the |:find|
|
||||||
command. When this option is empty, the internal |file-searching|
|
command. When this option is empty, the internal |file-searching|
|
||||||
mechanism is used.
|
mechanism is used.
|
||||||
|
|
||||||
While evaluating the expression, the |v:fname| variable is set to the
|
The value can be the name of a function, a |lambda| or a |Funcref|.
|
||||||
argument of the |:find| command.
|
See |option-value-function| for more information.
|
||||||
|
|
||||||
The expression is evaluated only once per |:find| command invocation.
|
The function is called with two arguments. The first argument is a
|
||||||
The expression can process all the directories specified in 'path'.
|
|String| and is the |:find| command argument. The second argument is
|
||||||
|
a |Boolean| and is set to |v:true| when the function is called to get
|
||||||
|
a List of command-line completion matches for the |:find| command.
|
||||||
|
The function should return a List of strings.
|
||||||
|
|
||||||
The expression may be evaluated for command-line completion as well,
|
The function is called only once per |:find| command invocation.
|
||||||
in which case the |v:cmdcomplete| variable will be set to |v:true|,
|
The function can process all the directories specified in 'path'.
|
||||||
otherwise it will be set to |v:false|.
|
|
||||||
|
|
||||||
If a match is found, the expression should return a |List| containing
|
If a match is found, the function should return a |List| containing
|
||||||
one or more file names. If a match is not found, the expression
|
one or more file names. If a match is not found, the function
|
||||||
should return an empty List.
|
should return an empty List.
|
||||||
|
|
||||||
If any errors are encountered during the expression evaluation, an
|
If any errors are encountered during the function invocation, an
|
||||||
empty List is used as the return value.
|
empty List is used as the return value.
|
||||||
|
|
||||||
Using a function call without arguments is faster |expr-option-function|
|
|
||||||
|
|
||||||
It is not allowed to change text or jump to another window while
|
It is not allowed to change text or jump to another window while
|
||||||
evaluating 'findexpr' |textlock|.
|
executing the 'findfunc' |textlock|.
|
||||||
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
@@ -2633,18 +2634,18 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
Examples:
|
Examples:
|
||||||
>vim
|
>vim
|
||||||
" Use glob()
|
" Use glob()
|
||||||
func FindExprGlob()
|
func FindFuncGlob(cmdarg, cmdcomplete)
|
||||||
let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname
|
let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
|
||||||
return glob(pat, v:false, v:true)
|
return glob(pat, v:false, v:true)
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindExprGlob()
|
set findfunc=FindFuncGlob
|
||||||
|
|
||||||
" Use the 'git ls-files' output
|
" Use the 'git ls-files' output
|
||||||
func FindGitFiles()
|
func FindGitFiles(cmdarg, cmdcomplete)
|
||||||
let fnames = systemlist('git ls-files')
|
let fnames = systemlist('git ls-files')
|
||||||
return fnames->filter('v:val =~? v:fname')
|
return fnames->filter('v:val =~? a:cmdarg')
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindGitFiles()
|
set findfunc=FindGitFiles
|
||||||
<
|
<
|
||||||
|
|
||||||
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
|
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
|
||||||
|
@@ -705,7 +705,7 @@ Short explanation of each option: *option-list*
|
|||||||
'fileignorecase' 'fic' ignore case when using file names
|
'fileignorecase' 'fic' ignore case when using file names
|
||||||
'filetype' 'ft' type of file, used for autocommands
|
'filetype' 'ft' type of file, used for autocommands
|
||||||
'fillchars' 'fcs' characters to use for displaying special items
|
'fillchars' 'fcs' characters to use for displaying special items
|
||||||
'findexpr' 'fexpr' expression to evaluate for |:find|
|
'findfunc' 'ffu' function to be called for the |:find| command
|
||||||
'fixendofline' 'fixeol' make sure last line in file has <EOL>
|
'fixendofline' 'fixeol' make sure last line in file has <EOL>
|
||||||
'foldclose' 'fcl' close a fold when the cursor leaves it
|
'foldclose' 'fcl' close a fold when the cursor leaves it
|
||||||
'foldcolumn' 'fdc' width of the column used to indicate folds
|
'foldcolumn' 'fdc' width of the column used to indicate folds
|
||||||
|
@@ -48,11 +48,6 @@ v:cmdbang
|
|||||||
can only be used in autocommands. For user commands |<bang>|
|
can only be used in autocommands. For user commands |<bang>|
|
||||||
can be used.
|
can be used.
|
||||||
|
|
||||||
*v:cmdcomplete* *cmdcomplete-variable*
|
|
||||||
v:cmdcomplete
|
|
||||||
When evaluating 'findexpr': if 'findexpr' is used for cmdline
|
|
||||||
completion the value is |v:true|, otherwise it is |v:false|.
|
|
||||||
|
|
||||||
*v:collate* *collate-variable*
|
*v:collate* *collate-variable*
|
||||||
v:collate
|
v:collate
|
||||||
The current locale setting for collation order of the runtime
|
The current locale setting for collation order of the runtime
|
||||||
@@ -259,8 +254,7 @@ v:fcs_reason
|
|||||||
*v:fname* *fname-variable*
|
*v:fname* *fname-variable*
|
||||||
v:fname
|
v:fname
|
||||||
When evaluating 'includeexpr': the file name that was
|
When evaluating 'includeexpr': the file name that was
|
||||||
detected. When evaluating 'findexpr': the argument passed to
|
detected. Empty otherwise.
|
||||||
the |:find| command. Empty otherwise.
|
|
||||||
|
|
||||||
*v:fname_diff* *fname_diff-variable*
|
*v:fname_diff* *fname_diff-variable*
|
||||||
v:fname_diff
|
v:fname_diff
|
||||||
|
52
runtime/lua/vim/_meta/options.lua
generated
52
runtime/lua/vim/_meta/options.lua
generated
@@ -2294,31 +2294,31 @@ vim.wo.fcs = vim.wo.fillchars
|
|||||||
vim.go.fillchars = vim.o.fillchars
|
vim.go.fillchars = vim.o.fillchars
|
||||||
vim.go.fcs = vim.go.fillchars
|
vim.go.fcs = vim.go.fillchars
|
||||||
|
|
||||||
--- Expression that is evaluated to obtain the filename(s) for the `:find`
|
--- Function that is called to obtain the filename(s) for the `:find`
|
||||||
--- command. When this option is empty, the internal `file-searching`
|
--- command. When this option is empty, the internal `file-searching`
|
||||||
--- mechanism is used.
|
--- mechanism is used.
|
||||||
---
|
---
|
||||||
--- While evaluating the expression, the `v:fname` variable is set to the
|
--- The value can be the name of a function, a `lambda` or a `Funcref`.
|
||||||
--- argument of the `:find` command.
|
--- See `option-value-function` for more information.
|
||||||
---
|
---
|
||||||
--- The expression is evaluated only once per `:find` command invocation.
|
--- The function is called with two arguments. The first argument is a
|
||||||
--- The expression can process all the directories specified in 'path'.
|
--- `String` and is the `:find` command argument. The second argument is
|
||||||
|
--- a `Boolean` and is set to `v:true` when the function is called to get
|
||||||
|
--- a List of command-line completion matches for the `:find` command.
|
||||||
|
--- The function should return a List of strings.
|
||||||
---
|
---
|
||||||
--- The expression may be evaluated for command-line completion as well,
|
--- The function is called only once per `:find` command invocation.
|
||||||
--- in which case the `v:cmdcomplete` variable will be set to `v:true`,
|
--- The function can process all the directories specified in 'path'.
|
||||||
--- otherwise it will be set to `v:false`.
|
|
||||||
---
|
---
|
||||||
--- If a match is found, the expression should return a `List` containing
|
--- If a match is found, the function should return a `List` containing
|
||||||
--- one or more file names. If a match is not found, the expression
|
--- one or more file names. If a match is not found, the function
|
||||||
--- should return an empty List.
|
--- should return an empty List.
|
||||||
---
|
---
|
||||||
--- If any errors are encountered during the expression evaluation, an
|
--- If any errors are encountered during the function invocation, an
|
||||||
--- empty List is used as the return value.
|
--- empty List is used as the return value.
|
||||||
---
|
---
|
||||||
--- Using a function call without arguments is faster `expr-option-function`
|
|
||||||
---
|
|
||||||
--- It is not allowed to change text or jump to another window while
|
--- It is not allowed to change text or jump to another window while
|
||||||
--- evaluating 'findexpr' `textlock`.
|
--- executing the 'findfunc' `textlock`.
|
||||||
---
|
---
|
||||||
--- This option cannot be set from a `modeline` or in the `sandbox`, for
|
--- This option cannot be set from a `modeline` or in the `sandbox`, for
|
||||||
--- security reasons.
|
--- security reasons.
|
||||||
@@ -2327,28 +2327,28 @@ vim.go.fcs = vim.go.fillchars
|
|||||||
---
|
---
|
||||||
--- ```vim
|
--- ```vim
|
||||||
--- " Use glob()
|
--- " Use glob()
|
||||||
--- func FindExprGlob()
|
--- func FindFuncGlob(cmdarg, cmdcomplete)
|
||||||
--- let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname
|
--- let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
|
||||||
--- return glob(pat, v:false, v:true)
|
--- return glob(pat, v:false, v:true)
|
||||||
--- endfunc
|
--- endfunc
|
||||||
--- set findexpr=FindExprGlob()
|
--- set findfunc=FindFuncGlob
|
||||||
---
|
---
|
||||||
--- " Use the 'git ls-files' output
|
--- " Use the 'git ls-files' output
|
||||||
--- func FindGitFiles()
|
--- func FindGitFiles(cmdarg, cmdcomplete)
|
||||||
--- let fnames = systemlist('git ls-files')
|
--- let fnames = systemlist('git ls-files')
|
||||||
--- return fnames->filter('v:val =~? v:fname')
|
--- return fnames->filter('v:val =~? a:cmdarg')
|
||||||
--- endfunc
|
--- endfunc
|
||||||
--- set findexpr=FindGitFiles()
|
--- set findfunc=FindGitFiles
|
||||||
--- ```
|
--- ```
|
||||||
---
|
---
|
||||||
---
|
---
|
||||||
--- @type string
|
--- @type string
|
||||||
vim.o.findexpr = ""
|
vim.o.findfunc = ""
|
||||||
vim.o.fexpr = vim.o.findexpr
|
vim.o.ffu = vim.o.findfunc
|
||||||
vim.bo.findexpr = vim.o.findexpr
|
vim.bo.findfunc = vim.o.findfunc
|
||||||
vim.bo.fexpr = vim.bo.findexpr
|
vim.bo.ffu = vim.bo.findfunc
|
||||||
vim.go.findexpr = vim.o.findexpr
|
vim.go.findfunc = vim.o.findfunc
|
||||||
vim.go.fexpr = vim.go.findexpr
|
vim.go.ffu = vim.go.findfunc
|
||||||
|
|
||||||
--- When writing a file and this option is on, <EOL> at the end of file
|
--- When writing a file and this option is on, <EOL> at the end of file
|
||||||
--- will be restored if missing. Turn this option off if you want to
|
--- will be restored if missing. Turn this option off if you want to
|
||||||
|
8
runtime/lua/vim/_meta/vvars.lua
generated
8
runtime/lua/vim/_meta/vvars.lua
generated
@@ -44,11 +44,6 @@ vim.v.cmdarg = ...
|
|||||||
--- @type integer
|
--- @type integer
|
||||||
vim.v.cmdbang = ...
|
vim.v.cmdbang = ...
|
||||||
|
|
||||||
--- When evaluating 'findexpr': if 'findexpr' is used for cmdline
|
|
||||||
--- completion the value is `v:true`, otherwise it is `v:false`.
|
|
||||||
--- @type boolean
|
|
||||||
vim.v.cmdcomplete = ...
|
|
||||||
|
|
||||||
--- The current locale setting for collation order of the runtime
|
--- The current locale setting for collation order of the runtime
|
||||||
--- environment. This allows Vim scripts to be aware of the
|
--- environment. This allows Vim scripts to be aware of the
|
||||||
--- current locale encoding. Technical: it's the value of
|
--- current locale encoding. Technical: it's the value of
|
||||||
@@ -272,8 +267,7 @@ vim.v.fcs_choice = ...
|
|||||||
vim.v.fcs_reason = ...
|
vim.v.fcs_reason = ...
|
||||||
|
|
||||||
--- When evaluating 'includeexpr': the file name that was
|
--- When evaluating 'includeexpr': the file name that was
|
||||||
--- detected. When evaluating 'findexpr': the argument passed to
|
--- detected. Empty otherwise.
|
||||||
--- the `:find` command. Empty otherwise.
|
|
||||||
--- @type string
|
--- @type string
|
||||||
vim.v.fname = ...
|
vim.v.fname = ...
|
||||||
|
|
||||||
|
@@ -2049,7 +2049,6 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
|
|||||||
clear_string_option(&buf->b_p_indk);
|
clear_string_option(&buf->b_p_indk);
|
||||||
clear_string_option(&buf->b_p_fp);
|
clear_string_option(&buf->b_p_fp);
|
||||||
clear_string_option(&buf->b_p_fex);
|
clear_string_option(&buf->b_p_fex);
|
||||||
clear_string_option(&buf->b_p_fexpr);
|
|
||||||
clear_string_option(&buf->b_p_kp);
|
clear_string_option(&buf->b_p_kp);
|
||||||
clear_string_option(&buf->b_p_mps);
|
clear_string_option(&buf->b_p_mps);
|
||||||
clear_string_option(&buf->b_p_fo);
|
clear_string_option(&buf->b_p_fo);
|
||||||
@@ -2098,6 +2097,8 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
|
|||||||
clear_string_option(&buf->b_p_tc);
|
clear_string_option(&buf->b_p_tc);
|
||||||
clear_string_option(&buf->b_p_tfu);
|
clear_string_option(&buf->b_p_tfu);
|
||||||
callback_free(&buf->b_tfu_cb);
|
callback_free(&buf->b_tfu_cb);
|
||||||
|
clear_string_option(&buf->b_p_ffu);
|
||||||
|
callback_free(&buf->b_ffu_cb);
|
||||||
clear_string_option(&buf->b_p_dict);
|
clear_string_option(&buf->b_p_dict);
|
||||||
clear_string_option(&buf->b_p_tsr);
|
clear_string_option(&buf->b_p_tsr);
|
||||||
clear_string_option(&buf->b_p_qe);
|
clear_string_option(&buf->b_p_qe);
|
||||||
|
@@ -543,8 +543,10 @@ struct file_buffer {
|
|||||||
Callback b_cfu_cb; ///< 'completefunc' callback
|
Callback b_cfu_cb; ///< 'completefunc' callback
|
||||||
char *b_p_ofu; ///< 'omnifunc'
|
char *b_p_ofu; ///< 'omnifunc'
|
||||||
Callback b_ofu_cb; ///< 'omnifunc' callback
|
Callback b_ofu_cb; ///< 'omnifunc' callback
|
||||||
char *b_p_tfu; ///< 'tagfunc'
|
char *b_p_tfu; ///< 'tagfunc' option value
|
||||||
Callback b_tfu_cb; ///< 'tagfunc' callback
|
Callback b_tfu_cb; ///< 'tagfunc' callback
|
||||||
|
char *b_p_ffu; ///< 'findfunc' option value
|
||||||
|
Callback b_ffu_cb; ///< 'findfunc' callback
|
||||||
int b_p_eof; ///< 'endoffile'
|
int b_p_eof; ///< 'endoffile'
|
||||||
int b_p_eol; ///< 'endofline'
|
int b_p_eol; ///< 'endofline'
|
||||||
int b_p_fixeol; ///< 'fixendofline'
|
int b_p_fixeol; ///< 'fixendofline'
|
||||||
@@ -608,7 +610,6 @@ struct file_buffer {
|
|||||||
char *b_p_mp; ///< 'makeprg' local value
|
char *b_p_mp; ///< 'makeprg' local value
|
||||||
char *b_p_efm; ///< 'errorformat' local value
|
char *b_p_efm; ///< 'errorformat' local value
|
||||||
char *b_p_ep; ///< 'equalprg' local value
|
char *b_p_ep; ///< 'equalprg' local value
|
||||||
char *b_p_fexpr; ///< 'findexpr' local value
|
|
||||||
char *b_p_path; ///< 'path' local value
|
char *b_p_path; ///< 'path' local value
|
||||||
int b_p_ar; ///< 'autoread' local value
|
int b_p_ar; ///< 'autoread' local value
|
||||||
char *b_p_tags; ///< 'tags' local value
|
char *b_p_tags; ///< 'tags' local value
|
||||||
|
@@ -109,7 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
|
|||||||
&& xp->xp_context != EXPAND_FILES
|
&& xp->xp_context != EXPAND_FILES
|
||||||
&& xp->xp_context != EXPAND_FILES_IN_PATH
|
&& xp->xp_context != EXPAND_FILES_IN_PATH
|
||||||
&& xp->xp_context != EXPAND_FILETYPE
|
&& xp->xp_context != EXPAND_FILETYPE
|
||||||
&& xp->xp_context != EXPAND_FINDEXPR
|
&& xp->xp_context != EXPAND_FINDFUNC
|
||||||
&& xp->xp_context != EXPAND_HELP
|
&& xp->xp_context != EXPAND_HELP
|
||||||
&& xp->xp_context != EXPAND_KEYMAP
|
&& xp->xp_context != EXPAND_KEYMAP
|
||||||
&& xp->xp_context != EXPAND_LUA
|
&& xp->xp_context != EXPAND_LUA
|
||||||
@@ -1229,7 +1229,7 @@ char *addstar(char *fname, size_t len, int context)
|
|||||||
|
|
||||||
// For help tags the translation is done in find_help_tags().
|
// For help tags the translation is done in find_help_tags().
|
||||||
// For a tag pattern starting with "/" no translation is needed.
|
// For a tag pattern starting with "/" no translation is needed.
|
||||||
if (context == EXPAND_FINDEXPR
|
if (context == EXPAND_FINDFUNC
|
||||||
|| context == EXPAND_HELP
|
|| context == EXPAND_HELP
|
||||||
|| context == EXPAND_COLORS
|
|| context == EXPAND_COLORS
|
||||||
|| context == EXPAND_COMPILER
|
|| context == EXPAND_COMPILER
|
||||||
@@ -1829,7 +1829,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
|
|||||||
case CMD_sfind:
|
case CMD_sfind:
|
||||||
case CMD_tabfind:
|
case CMD_tabfind:
|
||||||
if (xp->xp_context == EXPAND_FILES) {
|
if (xp->xp_context == EXPAND_FILES) {
|
||||||
xp->xp_context = *get_findexpr() != NUL ? EXPAND_FINDEXPR : EXPAND_FILES_IN_PATH;
|
xp->xp_context = *get_findfunc() != NUL ? EXPAND_FINDFUNC : EXPAND_FILES_IN_PATH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CMD_cd:
|
case CMD_cd:
|
||||||
@@ -2500,8 +2500,8 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ret = FAIL;
|
int ret = FAIL;
|
||||||
if (xp->xp_context == EXPAND_FINDEXPR) {
|
if (xp->xp_context == EXPAND_FINDFUNC) {
|
||||||
ret = expand_findexpr(pat, matches, numMatches);
|
ret = expand_findfunc(pat, matches, numMatches);
|
||||||
} else {
|
} else {
|
||||||
if (xp->xp_context == EXPAND_FILES) {
|
if (xp->xp_context == EXPAND_FILES) {
|
||||||
flags |= EW_FILE;
|
flags |= EW_FILE;
|
||||||
@@ -2722,7 +2722,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
|
|||||||
if (xp->xp_context == EXPAND_FILES
|
if (xp->xp_context == EXPAND_FILES
|
||||||
|| xp->xp_context == EXPAND_DIRECTORIES
|
|| xp->xp_context == EXPAND_DIRECTORIES
|
||||||
|| xp->xp_context == EXPAND_FILES_IN_PATH
|
|| xp->xp_context == EXPAND_FILES_IN_PATH
|
||||||
|| xp->xp_context == EXPAND_FINDEXPR
|
|| xp->xp_context == EXPAND_FINDFUNC
|
||||||
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
|
|| xp->xp_context == EXPAND_DIRS_IN_CDPATH) {
|
||||||
return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options);
|
return expand_files_and_dirs(xp, pat, matches, numMatches, flags, options);
|
||||||
}
|
}
|
||||||
|
@@ -107,7 +107,7 @@ enum {
|
|||||||
EXPAND_KEYMAP,
|
EXPAND_KEYMAP,
|
||||||
EXPAND_DIRS_IN_CDPATH,
|
EXPAND_DIRS_IN_CDPATH,
|
||||||
EXPAND_SHELLCMDLINE,
|
EXPAND_SHELLCMDLINE,
|
||||||
EXPAND_FINDEXPR,
|
EXPAND_FINDFUNC,
|
||||||
EXPAND_CHECKHEALTH,
|
EXPAND_CHECKHEALTH,
|
||||||
EXPAND_LUA,
|
EXPAND_LUA,
|
||||||
};
|
};
|
||||||
|
@@ -186,7 +186,7 @@ INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")
|
|||||||
|
|
||||||
EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
|
EXTERN const char e_winfixbuf_cannot_go_to_buffer[]
|
||||||
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
|
INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled"));
|
||||||
EXTERN const char e_invalid_return_type_from_findexpr[] INIT( = N_("E1514: 'findexpr' did not return a List type"));
|
EXTERN const char e_invalid_return_type_from_findfunc[] INIT( = N_("E1514: 'findfunc' did not return a List type"));
|
||||||
|
|
||||||
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
|
EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
|
||||||
|
|
||||||
|
@@ -270,7 +270,6 @@ static struct vimvar {
|
|||||||
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
|
VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
|
||||||
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
|
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
|
||||||
VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO),
|
VV(VV_MAXCOL, "maxcol", VAR_NUMBER, VV_RO),
|
||||||
VV(VV_CMDCOMPLETE, "cmdcomplete", VAR_BOOL, VV_RO),
|
|
||||||
// Neovim
|
// Neovim
|
||||||
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
|
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
|
||||||
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
|
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
|
||||||
@@ -462,7 +461,6 @@ void eval_init(void)
|
|||||||
set_vim_var_nr(VV_HLSEARCH, 1);
|
set_vim_var_nr(VV_HLSEARCH, 1);
|
||||||
set_vim_var_nr(VV_COUNT1, 1);
|
set_vim_var_nr(VV_COUNT1, 1);
|
||||||
set_vim_var_special(VV_EXITING, kSpecialVarNull);
|
set_vim_var_special(VV_EXITING, kSpecialVarNull);
|
||||||
set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse);
|
|
||||||
|
|
||||||
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
|
set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER);
|
||||||
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
|
set_vim_var_nr(VV_TYPE_STRING, VAR_TYPE_STRING);
|
||||||
@@ -4793,6 +4791,7 @@ bool garbage_collect(bool testing)
|
|||||||
ABORTING(set_ref_in_callback)(&buf->b_ofu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_ofu_cb, copyID, NULL, NULL);
|
||||||
ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL);
|
||||||
ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL);
|
||||||
|
ABORTING(set_ref_in_callback)(&buf->b_ffu_cb, copyID, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks
|
// 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks
|
||||||
@@ -4804,6 +4803,9 @@ bool garbage_collect(bool testing)
|
|||||||
// 'tagfunc' callback
|
// 'tagfunc' callback
|
||||||
ABORTING(set_ref_in_tagfunc)(copyID);
|
ABORTING(set_ref_in_tagfunc)(copyID);
|
||||||
|
|
||||||
|
// 'findfunc' callback
|
||||||
|
ABORTING(set_ref_in_findfunc)(copyID);
|
||||||
|
|
||||||
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
FOR_ALL_TAB_WINDOWS(tp, wp) {
|
||||||
// window-local variables
|
// window-local variables
|
||||||
ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL);
|
ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL);
|
||||||
|
@@ -167,7 +167,6 @@ typedef enum {
|
|||||||
VV_COLLATE,
|
VV_COLLATE,
|
||||||
VV_EXITING,
|
VV_EXITING,
|
||||||
VV_MAXCOL,
|
VV_MAXCOL,
|
||||||
VV_CMDCOMPLETE,
|
|
||||||
// Nvim
|
// Nvim
|
||||||
VV_STDERR,
|
VV_STDERR,
|
||||||
VV_MSGPACK_TYPES,
|
VV_MSGPACK_TYPES,
|
||||||
|
@@ -5165,55 +5165,68 @@ static void ex_wrongmodifier(exarg_T *eap)
|
|||||||
eap->errmsg = _(e_invcmd);
|
eap->errmsg = _(e_invcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate the 'findexpr' expression and return the result. When evaluating
|
/// callback function for 'findfunc'
|
||||||
/// the expression, v:fname is set to the ":find" command argument.
|
static Callback ffu_cb;
|
||||||
static list_T *eval_findexpr(const char *pat, bool cmdcomplete)
|
|
||||||
|
static Callback *get_findfunc_callback(void)
|
||||||
|
{
|
||||||
|
return *curbuf->b_p_ffu != NUL ? &curbuf->b_ffu_cb : &ffu_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call 'findfunc' to obtain the list of file names.
|
||||||
|
static list_T *call_findfunc(char *pat, BoolVarValue cmdcomplete)
|
||||||
{
|
{
|
||||||
const sctx_T saved_sctx = current_sctx;
|
const sctx_T saved_sctx = current_sctx;
|
||||||
|
|
||||||
char *findexpr = get_findexpr();
|
typval_T args[3];
|
||||||
|
args[0].v_type = VAR_STRING;
|
||||||
set_vim_var_string(VV_FNAME, pat, -1);
|
args[0].vval.v_string = pat;
|
||||||
set_vim_var_bool(VV_CMDCOMPLETE, cmdcomplete ? kBoolVarTrue : kBoolVarFalse);
|
args[1].v_type = VAR_BOOL;
|
||||||
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx;
|
args[1].vval.v_bool = cmdcomplete;
|
||||||
|
args[2].v_type = VAR_UNKNOWN;
|
||||||
char *arg = skipwhite(findexpr);
|
|
||||||
|
|
||||||
|
// 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++;
|
textlock++;
|
||||||
|
|
||||||
// Evaluate the expression. If the expression is "FuncName()" call the
|
sctx_T *ctx = get_option_sctx(kOptFindfunc);
|
||||||
// function directly.
|
if (ctx != NULL) {
|
||||||
typval_T tv;
|
current_sctx = *ctx;
|
||||||
list_T *retlist = NULL;
|
|
||||||
if (eval0_simple_funccal(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) {
|
|
||||||
retlist = NULL;
|
|
||||||
} else {
|
|
||||||
if (tv.v_type == VAR_LIST) {
|
|
||||||
retlist = tv_list_copy(NULL, tv.vval.v_list, true, get_copyID());
|
|
||||||
} else {
|
|
||||||
emsg(_(e_invalid_return_type_from_findexpr));
|
|
||||||
}
|
}
|
||||||
tv_clear(&tv);
|
|
||||||
}
|
|
||||||
textlock--;
|
|
||||||
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
|
||||||
|
|
||||||
set_vim_var_string(VV_FNAME, NULL, 0);
|
Callback *cb = get_findfunc_callback();
|
||||||
set_vim_var_bool(VV_CMDCOMPLETE, kBoolVarFalse);
|
typval_T rettv;
|
||||||
|
int retval = callback_call(cb, 2, args, &rettv);
|
||||||
|
|
||||||
current_sctx = saved_sctx;
|
current_sctx = saved_sctx;
|
||||||
|
|
||||||
|
textlock--;
|
||||||
|
|
||||||
|
list_T *retlist = NULL;
|
||||||
|
|
||||||
|
if (retval == OK) {
|
||||||
|
if (rettv.v_type == VAR_LIST) {
|
||||||
|
retlist = tv_list_copy(NULL, rettv.vval.v_list, false, get_copyID());
|
||||||
|
} else {
|
||||||
|
emsg(_(e_invalid_return_type_from_findfunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
tv_clear(&rettv);
|
||||||
|
}
|
||||||
|
|
||||||
return retlist;
|
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.
|
/// Used for expanding the :find, :sfind and :tabfind command argument.
|
||||||
/// Returns OK on success and FAIL otherwise.
|
/// Returns OK on success and FAIL otherwise.
|
||||||
int expand_findexpr(const char *pat, char ***files, int *numMatches)
|
int expand_findfunc(char *pat, char ***files, int *numMatches)
|
||||||
{
|
{
|
||||||
*numMatches = 0;
|
*numMatches = 0;
|
||||||
*files = NULL;
|
*files = NULL;
|
||||||
|
|
||||||
list_T *l = eval_findexpr(pat, true);
|
list_T *l = call_findfunc(pat, kBoolVarTrue);
|
||||||
if (l == NULL) {
|
if (l == NULL) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@@ -5240,16 +5253,16 @@ int expand_findexpr(const char *pat, char ***files, int *numMatches)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
/// the n'th matching file.
|
||||||
static char *findexpr_find_file(char *findarg, size_t findarg_len, int count)
|
static char *findfunc_find_file(char *findarg, size_t findarg_len, int count)
|
||||||
{
|
{
|
||||||
char *ret_fname = NULL;
|
char *ret_fname = NULL;
|
||||||
|
|
||||||
const char cc = findarg[findarg_len];
|
const char cc = findarg[findarg_len];
|
||||||
findarg[findarg_len] = NUL;
|
findarg[findarg_len] = NUL;
|
||||||
|
|
||||||
list_T *fname_list = eval_findexpr(findarg, false);
|
list_T *fname_list = call_findfunc(findarg, kBoolVarFalse);
|
||||||
int fname_count = tv_list_len(fname_list);
|
int fname_count = tv_list_len(fname_list);
|
||||||
|
|
||||||
if (fname_count == 0) {
|
if (fname_count == 0) {
|
||||||
@@ -5274,6 +5287,51 @@ static char *findexpr_find_file(char *findarg, size_t findarg_len, int count)
|
|||||||
return ret_fname;
|
return ret_fname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process the 'findfunc' option value.
|
||||||
|
/// Returns NULL on success and an error message on failure.
|
||||||
|
const char *did_set_findfunc(optset_T *args)
|
||||||
|
{
|
||||||
|
buf_T *buf = (buf_T *)args->os_buf;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
if (*buf->b_p_ffu != NUL) {
|
||||||
|
// buffer-local option set
|
||||||
|
retval = option_set_callback_func(buf->b_p_ffu, &buf->b_ffu_cb);
|
||||||
|
} else {
|
||||||
|
// global option set
|
||||||
|
retval = option_set_callback_func(p_ffu, &ffu_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval == FAIL) {
|
||||||
|
return e_invarg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the option value starts with <SID> or s:, then replace that with
|
||||||
|
// the script identifier.
|
||||||
|
char **varp = (char **)args->os_varp;
|
||||||
|
char *name = get_scriptlocal_funcname(*varp);
|
||||||
|
if (name != NULL) {
|
||||||
|
free_string_option(*varp);
|
||||||
|
*varp = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_findfunc_option(void)
|
||||||
|
{
|
||||||
|
callback_free(&ffu_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the global 'findfunc' callback with "copyID" so that it is not
|
||||||
|
/// garbage collected.
|
||||||
|
bool set_ref_in_findfunc(int copyID)
|
||||||
|
{
|
||||||
|
bool abort = false;
|
||||||
|
abort = set_ref_in_callback(&ffu_cb, copyID, NULL, NULL);
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
|
||||||
/// :sview [+command] file split window with new file, read-only
|
/// :sview [+command] file split window with new file, read-only
|
||||||
/// :split [[+command] file] split window with current or new file
|
/// :split [[+command] file] split window with current or new file
|
||||||
/// :vsplit [[+command] file] split window vertically with current or new file
|
/// :vsplit [[+command] file] split window vertically with current or new file
|
||||||
@@ -5305,8 +5363,8 @@ void ex_splitview(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
|
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
|
||||||
if (*get_findexpr() != NUL) {
|
if (*get_findfunc() != NUL) {
|
||||||
fname = findexpr_find_file(eap->arg, strlen(eap->arg),
|
fname = findfunc_find_file(eap->arg, strlen(eap->arg),
|
||||||
eap->addr_count > 0 ? eap->line2 : 1);
|
eap->addr_count > 0 ? eap->line2 : 1);
|
||||||
} else {
|
} else {
|
||||||
char *file_to_find = NULL;
|
char *file_to_find = NULL;
|
||||||
@@ -5512,8 +5570,8 @@ static void ex_find(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *fname = NULL;
|
char *fname = NULL;
|
||||||
if (*get_findexpr() != NUL) {
|
if (*get_findfunc() != NUL) {
|
||||||
fname = findexpr_find_file(eap->arg, strlen(eap->arg),
|
fname = findfunc_find_file(eap->arg, strlen(eap->arg),
|
||||||
eap->addr_count > 0 ? eap->line2 : 1);
|
eap->addr_count > 0 ? eap->line2 : 1);
|
||||||
} else {
|
} else {
|
||||||
char *file_to_find = NULL;
|
char *file_to_find = NULL;
|
||||||
|
@@ -260,6 +260,7 @@ local function dump_option(i, o)
|
|||||||
end
|
end
|
||||||
|
|
||||||
w([[
|
w([[
|
||||||
|
#include "nvim/ex_docmd.h"
|
||||||
#include "nvim/ex_getln.h"
|
#include "nvim/ex_getln.h"
|
||||||
#include "nvim/insexpand.h"
|
#include "nvim/insexpand.h"
|
||||||
#include "nvim/mapping.h"
|
#include "nvim/mapping.h"
|
||||||
|
@@ -578,6 +578,7 @@ void free_all_options(void)
|
|||||||
}
|
}
|
||||||
free_operatorfunc_option();
|
free_operatorfunc_option();
|
||||||
free_tagfunc_option();
|
free_tagfunc_option();
|
||||||
|
free_findfunc_option();
|
||||||
XFREE_CLEAR(fenc_default);
|
XFREE_CLEAR(fenc_default);
|
||||||
XFREE_CLEAR(p_term);
|
XFREE_CLEAR(p_term);
|
||||||
XFREE_CLEAR(p_ttytype);
|
XFREE_CLEAR(p_ttytype);
|
||||||
@@ -4472,8 +4473,8 @@ void *get_varp_scope_from(vimoption_T *p, int scope, buf_T *buf, win_T *win)
|
|||||||
switch ((int)p->indir) {
|
switch ((int)p->indir) {
|
||||||
case PV_FP:
|
case PV_FP:
|
||||||
return &(buf->b_p_fp);
|
return &(buf->b_p_fp);
|
||||||
case PV_FEXPR:
|
case PV_FFU:
|
||||||
return &(buf->b_p_fexpr);
|
return &(buf->b_p_ffu);
|
||||||
case PV_EFM:
|
case PV_EFM:
|
||||||
return &(buf->b_p_efm);
|
return &(buf->b_p_efm);
|
||||||
case PV_GP:
|
case PV_GP:
|
||||||
@@ -4595,8 +4596,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win)
|
|||||||
return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var;
|
return *buf->b_p_tsrfu != NUL ? &(buf->b_p_tsrfu) : p->var;
|
||||||
case PV_FP:
|
case PV_FP:
|
||||||
return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var;
|
return *buf->b_p_fp != NUL ? &(buf->b_p_fp) : p->var;
|
||||||
case PV_FEXPR:
|
case PV_FFU:
|
||||||
return *buf->b_p_fexpr != NUL ? &(buf->b_p_fexpr) : p->var;
|
return *buf->b_p_ffu != NUL ? &(buf->b_p_ffu) : p->var;
|
||||||
case PV_EFM:
|
case PV_EFM:
|
||||||
return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var;
|
return *buf->b_p_efm != NUL ? &(buf->b_p_efm) : p->var;
|
||||||
case PV_GP:
|
case PV_GP:
|
||||||
@@ -4868,13 +4869,13 @@ char *get_equalprg(void)
|
|||||||
return curbuf->b_p_ep;
|
return curbuf->b_p_ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 *get_findexpr(void)
|
char *get_findfunc(void)
|
||||||
{
|
{
|
||||||
if (*curbuf->b_p_fexpr == NUL) {
|
if (*curbuf->b_p_ffu == NUL) {
|
||||||
return p_fexpr;
|
return p_ffu;
|
||||||
}
|
}
|
||||||
return curbuf->b_p_fexpr;
|
return curbuf->b_p_ffu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy options from one window to another.
|
/// Copy options from one window to another.
|
||||||
@@ -5275,8 +5276,7 @@ void buf_copy_options(buf_T *buf, int flags)
|
|||||||
buf->b_p_mp = empty_string_option;
|
buf->b_p_mp = empty_string_option;
|
||||||
buf->b_p_efm = empty_string_option;
|
buf->b_p_efm = empty_string_option;
|
||||||
buf->b_p_ep = empty_string_option;
|
buf->b_p_ep = empty_string_option;
|
||||||
buf->b_p_fexpr = xstrdup(p_fexpr);
|
buf->b_p_ffu = empty_string_option;
|
||||||
COPY_OPT_SCTX(buf, BV_FEXPR);
|
|
||||||
buf->b_p_kp = empty_string_option;
|
buf->b_p_kp = empty_string_option;
|
||||||
buf->b_p_path = empty_string_option;
|
buf->b_p_path = empty_string_option;
|
||||||
buf->b_p_tags = empty_string_option;
|
buf->b_p_tags = empty_string_option;
|
||||||
|
@@ -451,7 +451,7 @@ EXTERN char *p_ffs; ///< 'fileformats'
|
|||||||
EXTERN int p_fic; ///< 'fileignorecase'
|
EXTERN int p_fic; ///< 'fileignorecase'
|
||||||
EXTERN char *p_ft; ///< 'filetype'
|
EXTERN char *p_ft; ///< 'filetype'
|
||||||
EXTERN char *p_fcs; ///< 'fillchar'
|
EXTERN char *p_fcs; ///< 'fillchar'
|
||||||
EXTERN char *p_fexpr; ///< 'findexpr'
|
EXTERN char *p_ffu; ///< 'findfunc'
|
||||||
EXTERN int p_fixeol; ///< 'fixendofline'
|
EXTERN int p_fixeol; ///< 'fixendofline'
|
||||||
EXTERN char *p_fcl; ///< 'foldclose'
|
EXTERN char *p_fcl; ///< 'foldclose'
|
||||||
EXTERN OptInt p_fdls; ///< 'foldlevelstart'
|
EXTERN OptInt p_fdls; ///< 'foldlevelstart'
|
||||||
|
@@ -2906,35 +2906,35 @@ return {
|
|||||||
varname = 'p_fcs',
|
varname = 'p_fcs',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
abbreviation = 'fexpr',
|
abbreviation = 'ffu',
|
||||||
cb = 'did_set_optexpr',
|
cb = 'did_set_findfunc',
|
||||||
defaults = { if_true = '' },
|
defaults = { if_true = '' },
|
||||||
desc = [=[
|
desc = [=[
|
||||||
Expression that is evaluated to obtain the filename(s) for the |:find|
|
Function that is called to obtain the filename(s) for the |:find|
|
||||||
command. When this option is empty, the internal |file-searching|
|
command. When this option is empty, the internal |file-searching|
|
||||||
mechanism is used.
|
mechanism is used.
|
||||||
|
|
||||||
While evaluating the expression, the |v:fname| variable is set to the
|
The value can be the name of a function, a |lambda| or a |Funcref|.
|
||||||
argument of the |:find| command.
|
See |option-value-function| for more information.
|
||||||
|
|
||||||
The expression is evaluated only once per |:find| command invocation.
|
The function is called with two arguments. The first argument is a
|
||||||
The expression can process all the directories specified in 'path'.
|
|String| and is the |:find| command argument. The second argument is
|
||||||
|
a |Boolean| and is set to |v:true| when the function is called to get
|
||||||
|
a List of command-line completion matches for the |:find| command.
|
||||||
|
The function should return a List of strings.
|
||||||
|
|
||||||
The expression may be evaluated for command-line completion as well,
|
The function is called only once per |:find| command invocation.
|
||||||
in which case the |v:cmdcomplete| variable will be set to |v:true|,
|
The function can process all the directories specified in 'path'.
|
||||||
otherwise it will be set to |v:false|.
|
|
||||||
|
|
||||||
If a match is found, the expression should return a |List| containing
|
If a match is found, the function should return a |List| containing
|
||||||
one or more file names. If a match is not found, the expression
|
one or more file names. If a match is not found, the function
|
||||||
should return an empty List.
|
should return an empty List.
|
||||||
|
|
||||||
If any errors are encountered during the expression evaluation, an
|
If any errors are encountered during the function invocation, an
|
||||||
empty List is used as the return value.
|
empty List is used as the return value.
|
||||||
|
|
||||||
Using a function call without arguments is faster |expr-option-function|
|
|
||||||
|
|
||||||
It is not allowed to change text or jump to another window while
|
It is not allowed to change text or jump to another window while
|
||||||
evaluating 'findexpr' |textlock|.
|
executing the 'findfunc' |textlock|.
|
||||||
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
@@ -2942,27 +2942,28 @@ return {
|
|||||||
Examples:
|
Examples:
|
||||||
>vim
|
>vim
|
||||||
" Use glob()
|
" Use glob()
|
||||||
func FindExprGlob()
|
func FindFuncGlob(cmdarg, cmdcomplete)
|
||||||
let pat = v:cmdcomplete ? $'{v:fname}*' : v:fname
|
let pat = a:cmdcomplete ? $'{a:cmdarg}*' : a:cmdarg
|
||||||
return glob(pat, v:false, v:true)
|
return glob(pat, v:false, v:true)
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindExprGlob()
|
set findfunc=FindFuncGlob
|
||||||
|
|
||||||
" Use the 'git ls-files' output
|
" Use the 'git ls-files' output
|
||||||
func FindGitFiles()
|
func FindGitFiles(cmdarg, cmdcomplete)
|
||||||
let fnames = systemlist('git ls-files')
|
let fnames = systemlist('git ls-files')
|
||||||
return fnames->filter('v:val =~? v:fname')
|
return fnames->filter('v:val =~? a:cmdarg')
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindGitFiles()
|
set findfunc=FindGitFiles
|
||||||
<
|
<
|
||||||
]=],
|
]=],
|
||||||
full_name = 'findexpr',
|
full_name = 'findfunc',
|
||||||
|
func = true,
|
||||||
scope = { 'global', 'buffer' },
|
scope = { 'global', 'buffer' },
|
||||||
secure = true,
|
secure = true,
|
||||||
short_desc = N_('expression used for :find'),
|
short_desc = N_('function called for :find'),
|
||||||
tags = { 'E1514' },
|
tags = { 'E1514' },
|
||||||
type = 'string',
|
type = 'string',
|
||||||
varname = 'p_fexpr',
|
varname = 'p_ffu',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
abbreviation = 'fixeol',
|
abbreviation = 'fixeol',
|
||||||
|
@@ -233,9 +233,9 @@ void check_buf_options(buf_T *buf)
|
|||||||
check_string_option(&buf->b_p_mp);
|
check_string_option(&buf->b_p_mp);
|
||||||
check_string_option(&buf->b_p_efm);
|
check_string_option(&buf->b_p_efm);
|
||||||
check_string_option(&buf->b_p_ep);
|
check_string_option(&buf->b_p_ep);
|
||||||
check_string_option(&buf->b_p_fexpr);
|
|
||||||
check_string_option(&buf->b_p_path);
|
check_string_option(&buf->b_p_path);
|
||||||
check_string_option(&buf->b_p_tags);
|
check_string_option(&buf->b_p_tags);
|
||||||
|
check_string_option(&buf->b_p_ffu);
|
||||||
check_string_option(&buf->b_p_tfu);
|
check_string_option(&buf->b_p_tfu);
|
||||||
check_string_option(&buf->b_p_tc);
|
check_string_option(&buf->b_p_tc);
|
||||||
check_string_option(&buf->b_p_dict);
|
check_string_option(&buf->b_p_dict);
|
||||||
@@ -1886,9 +1886,8 @@ int expand_set_nrformats(optexpand_T *args, int *numMatches, char ***matches)
|
|||||||
matches);
|
matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One of the '*expr' options is changed:, 'diffexpr', 'findexpr',
|
/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext',
|
||||||
/// 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
|
/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'.
|
||||||
/// 'patchexpr' and 'charconvert'.
|
|
||||||
const char *did_set_optexpr(optset_T *args)
|
const char *did_set_optexpr(optset_T *args)
|
||||||
{
|
{
|
||||||
char **varp = (char **)args->os_varp;
|
char **varp = (char **)args->os_varp;
|
||||||
|
@@ -50,13 +50,6 @@ M.vars = {
|
|||||||
can be used.
|
can be used.
|
||||||
]=],
|
]=],
|
||||||
},
|
},
|
||||||
cmdcomplete = {
|
|
||||||
type = 'boolean',
|
|
||||||
desc = [=[
|
|
||||||
When evaluating 'findexpr': if 'findexpr' is used for cmdline
|
|
||||||
completion the value is |v:true|, otherwise it is |v:false|.
|
|
||||||
]=],
|
|
||||||
},
|
|
||||||
collate = {
|
collate = {
|
||||||
type = 'string',
|
type = 'string',
|
||||||
desc = [=[
|
desc = [=[
|
||||||
@@ -291,8 +284,7 @@ M.vars = {
|
|||||||
type = 'string',
|
type = 'string',
|
||||||
desc = [=[
|
desc = [=[
|
||||||
When evaluating 'includeexpr': the file name that was
|
When evaluating 'includeexpr': the file name that was
|
||||||
detected. When evaluating 'findexpr': the argument passed to
|
detected. Empty otherwise.
|
||||||
the |:find| command. Empty otherwise.
|
|
||||||
]=],
|
]=],
|
||||||
},
|
},
|
||||||
fname_diff = {
|
fname_diff = {
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
" Test findfile() and finddir()
|
" Test findfile() and finddir()
|
||||||
|
|
||||||
source check.vim
|
source check.vim
|
||||||
|
source vim9.vim
|
||||||
|
|
||||||
let s:files = [ 'Xfinddir1/foo',
|
let s:files = [ 'Xfinddir1/foo',
|
||||||
\ 'Xfinddir1/bar',
|
\ 'Xfinddir1/bar',
|
||||||
@@ -288,223 +289,491 @@ func Test_find_non_existing_path()
|
|||||||
let &path = save_path
|
let &path = save_path
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for 'findexpr'
|
" Test for 'findfunc'
|
||||||
func Test_findexpr()
|
func Test_findfunc()
|
||||||
CheckUnix
|
CheckUnix
|
||||||
call assert_equal('', &findexpr)
|
call assert_equal('', &findfunc)
|
||||||
call writefile(['aFile'], 'Xfindexpr1.c', 'D')
|
call writefile(['aFile'], 'Xfindfunc1.c', 'D')
|
||||||
call writefile(['bFile'], 'Xfindexpr2.c', 'D')
|
call writefile(['bFile'], 'Xfindfunc2.c', 'D')
|
||||||
call writefile(['cFile'], 'Xfindexpr3.c', 'D')
|
call writefile(['cFile'], 'Xfindfunc3.c', 'D')
|
||||||
|
|
||||||
" basic tests
|
" basic tests
|
||||||
func FindExpr1()
|
func FindFuncBasic(pat, cmdcomplete)
|
||||||
let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
|
let fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
|
||||||
return fnames->copy()->filter('v:val =~? v:fname')
|
return fnames->copy()->filter('v:val =~? a:pat')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
set findexpr=FindExpr1()
|
set findfunc=FindFuncBasic
|
||||||
find Xfindexpr3
|
find Xfindfunc3
|
||||||
call assert_match('Xfindexpr3.c', @%)
|
call assert_match('Xfindfunc3.c', @%)
|
||||||
bw!
|
bw!
|
||||||
2find Xfind
|
2find Xfind
|
||||||
call assert_match('Xfindexpr2.c', @%)
|
call assert_match('Xfindfunc2.c', @%)
|
||||||
bw!
|
bw!
|
||||||
call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path')
|
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')
|
call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path')
|
||||||
|
|
||||||
sfind Xfindexpr2.c
|
sfind Xfindfunc2.c
|
||||||
call assert_match('Xfindexpr2.c', @%)
|
call assert_match('Xfindfunc2.c', @%)
|
||||||
call assert_equal(2, winnr('$'))
|
call assert_equal(2, winnr('$'))
|
||||||
%bw!
|
%bw!
|
||||||
call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path')
|
call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path')
|
||||||
|
|
||||||
tabfind Xfindexpr3.c
|
tabfind Xfindfunc3.c
|
||||||
call assert_match('Xfindexpr3.c', @%)
|
call assert_match('Xfindfunc3.c', @%)
|
||||||
call assert_equal(2, tabpagenr())
|
call assert_equal(2, tabpagenr())
|
||||||
%bw!
|
%bw!
|
||||||
call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path')
|
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
|
" Buffer-local option
|
||||||
set findexpr=['abc']
|
func GlobalFindFunc(pat, cmdcomplete)
|
||||||
|
return ['global']
|
||||||
|
endfunc
|
||||||
|
func LocalFindFunc(pat, cmdcomplete)
|
||||||
|
return ['local']
|
||||||
|
endfunc
|
||||||
|
set findfunc=GlobalFindFunc
|
||||||
new
|
new
|
||||||
setlocal findexpr=['def']
|
setlocal findfunc=LocalFindFunc
|
||||||
find xxxx
|
find xxxx
|
||||||
call assert_equal('def', @%)
|
call assert_equal('local', @%)
|
||||||
wincmd w
|
wincmd w
|
||||||
find xxxx
|
find xxxx
|
||||||
call assert_equal('abc', @%)
|
call assert_equal('global', @%)
|
||||||
aboveleft new
|
aboveleft new
|
||||||
call assert_equal("['abc']", &findexpr)
|
call assert_equal("GlobalFindFunc", &findfunc)
|
||||||
wincmd k
|
wincmd k
|
||||||
aboveleft new
|
aboveleft new
|
||||||
call assert_equal("['abc']", &findexpr)
|
call assert_equal("GlobalFindFunc", &findfunc)
|
||||||
%bw!
|
%bw!
|
||||||
|
delfunc GlobalFindFunc
|
||||||
|
delfunc LocalFindFunc
|
||||||
|
|
||||||
" Empty list
|
" Assign an expression
|
||||||
set findexpr=[]
|
set findfunc=[]
|
||||||
call assert_fails('find xxxx', 'E345: Can''t find file "xxxx" in path')
|
call assert_fails('find xxxx', 'E117: Unknown function: []')
|
||||||
|
|
||||||
" Error cases
|
" Error cases
|
||||||
|
|
||||||
" Syntax error in the expression
|
" Function that doesn't any argument
|
||||||
set findexpr=FindExpr1{}
|
func FindFuncNoArg()
|
||||||
call assert_fails('find Xfindexpr1.c', 'E15: Invalid expression')
|
endfunc
|
||||||
|
set findfunc=FindFuncNoArg
|
||||||
|
call assert_fails('find Xfindfunc1.c', 'E118: Too many arguments for function: FindFuncNoArg')
|
||||||
|
delfunc FindFuncNoArg
|
||||||
|
|
||||||
" Find expression throws an error
|
" Syntax error in the function
|
||||||
func FindExpr2()
|
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'
|
throw 'find error'
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindExpr2()
|
set findfunc=FindFuncWithThrow
|
||||||
call assert_fails('find Xfindexpr1.c', 'find error')
|
call assert_fails('find Xfindfunc1.c', 'find error')
|
||||||
|
delfunc FindFuncWithThrow
|
||||||
|
|
||||||
" Try using a null List as the expression
|
" Try using a null function
|
||||||
set findexpr=v:_null_list
|
"call assert_fails('let &findfunc = test_null_function()', 'E129: Function name required')
|
||||||
call assert_fails('find Xfindexpr1.c', 'E345: Can''t find file "Xfindexpr1.c" in path')
|
|
||||||
|
|
||||||
" Try to create a new window from the find expression
|
" Try to create a new window from the find function
|
||||||
func FindExpr3()
|
func FindFuncNewWindow(pat, cmdexpand)
|
||||||
new
|
new
|
||||||
return ["foo"]
|
return ["foo"]
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindExpr3()
|
set findfunc=FindFuncNewWindow
|
||||||
call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
|
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
|
" Try to modify the current buffer from the find function
|
||||||
func FindExpr4()
|
func FindFuncModifyBuf(pat, cmdexpand)
|
||||||
call setline(1, ['abc'])
|
call setline(1, ['abc'])
|
||||||
return ["foo"]
|
return ["foo"]
|
||||||
endfunc
|
endfunc
|
||||||
set findexpr=FindExpr4()
|
set findfunc=FindFuncModifyBuf
|
||||||
call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
|
call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window')
|
||||||
|
delfunc FindFuncModifyBuf
|
||||||
|
|
||||||
" Expression returning a string
|
" Return the wrong type from the function
|
||||||
set findexpr='abc'
|
func FindFuncWrongRet(pat, cmdexpand)
|
||||||
call assert_fails('find Xfindexpr1.c', "E1514: 'findexpr' did not return a List type")
|
return 'foo'
|
||||||
|
endfunc
|
||||||
|
set findfunc=FindFuncWrongRet
|
||||||
|
call assert_fails('find Xfindfunc1.c', "E1514: 'findfunc' did not return a List type")
|
||||||
|
delfunc FindFuncWrongRet
|
||||||
|
|
||||||
set findexpr&
|
set findfunc&
|
||||||
delfunc! FindExpr1
|
|
||||||
delfunc! FindExpr2
|
|
||||||
delfunc! FindExpr3
|
|
||||||
delfunc! FindExpr4
|
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for using a script-local function for 'findexpr'
|
" Test for using a script-local function for 'findfunc'
|
||||||
func Test_findexpr_scriptlocal_func()
|
func Test_findfunc_scriptlocal_func()
|
||||||
func! s:FindExprScript()
|
func! s:FindFuncScript(pat, cmdexpand)
|
||||||
let g:FindExprArg = v:fname
|
let g:FindFuncArg = a:pat
|
||||||
return ['xxx']
|
return ['xxx']
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
set findexpr=s:FindExprScript()
|
set findfunc=s:FindFuncScript
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
|
||||||
new | only
|
new | only
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
set findexpr=<SID>FindExprScript()
|
set findfunc=<SID>FindFuncScript
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
|
||||||
new | only
|
new | only
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
let &findexpr = 's:FindExprScript()'
|
let &findfunc = 's:FindFuncScript'
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
|
||||||
new | only
|
new | only
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
let &findexpr = '<SID>FindExprScript()'
|
let &findfunc = '<SID>FindFuncScript'
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
|
||||||
new | only
|
new | only
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
set findexpr=
|
set findfunc=
|
||||||
setglobal findexpr=s:FindExprScript()
|
setglobal findfunc=s:FindFuncScript
|
||||||
setlocal findexpr=
|
setlocal findfunc=
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc)
|
||||||
call assert_equal('', &l:findexpr)
|
call assert_equal('', &l:findfunc)
|
||||||
new | only
|
new | only
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
new | only
|
new | only
|
||||||
set findexpr=
|
set findfunc=
|
||||||
setglobal findexpr=
|
setglobal findfunc=
|
||||||
setlocal findexpr=s:FindExprScript()
|
setlocal findfunc=s:FindFuncScript
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc)
|
||||||
call assert_equal(expand('<SID>') .. 'FindExprScript()', &l:findexpr)
|
call assert_equal(expand('<SID>') .. 'FindFuncScript', &l:findfunc)
|
||||||
call assert_equal('', &g:findexpr)
|
call assert_equal('', &g:findfunc)
|
||||||
let g:FindExprArg = ''
|
let g:FindFuncArg = ''
|
||||||
find abc
|
find abc
|
||||||
call assert_equal('abc', g:FindExprArg)
|
call assert_equal('abc', g:FindFuncArg)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
set findexpr=
|
set findfunc=
|
||||||
delfunc s:FindExprScript
|
delfunc s:FindFuncScript
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for expanding the argument to the :find command using 'findexpr'
|
" Test for expanding the argument to the :find command using 'findfunc'
|
||||||
func Test_findexpr_expand_arg()
|
func Test_findfunc_expand_arg()
|
||||||
let s:fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
|
let s:fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c']
|
||||||
|
|
||||||
" 'findexpr' that accepts a regular expression
|
" 'findfunc' that accepts a regular expression
|
||||||
func FindExprRegexp()
|
func FindFuncRegexp(pat, cmdcomplete)
|
||||||
return s:fnames->copy()->filter('v:val =~? v:fname')
|
return s:fnames->copy()->filter('v:val =~? a:pat')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" 'findexpr' that accepts a glob
|
" 'findfunc' that accepts a glob
|
||||||
func FindExprGlob()
|
func FindFuncGlob(pat_arg, cmdcomplete)
|
||||||
let pat = glob2regpat(v:cmdcomplete ? $'*{v:fname}*' : v:fname)
|
let pat = glob2regpat(a:cmdcomplete ? $'*{a:pat_arg}*' : a:pat_arg)
|
||||||
return s:fnames->copy()->filter('v:val =~? pat')
|
return s:fnames->copy()->filter('v:val =~? pat')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
for regexp in [v:true, v:false]
|
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 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 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 ', 'cmdline'))
|
||||||
call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline'))
|
call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline'))
|
||||||
|
|
||||||
let pat = regexp ? 'X.*1\.c' : 'X*1.c'
|
let pat = regexp ? 'X.*1\.c' : 'X*1.c'
|
||||||
call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt")
|
call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt")
|
||||||
call assert_equal('"find Xfindexpr1.c', @:)
|
call assert_equal('"find Xfindfunc1.c', @:)
|
||||||
call assert_equal(['Xfindexpr1.c'], getcompletion($'find {pat}', 'cmdline'))
|
call assert_equal(['Xfindfunc1.c'], getcompletion($'find {pat}', 'cmdline'))
|
||||||
|
|
||||||
call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt")
|
call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt")
|
||||||
call assert_equal('"find Xfindexpr3.c', @:)
|
call assert_equal('"find Xfindfunc3.c', @:)
|
||||||
call assert_equal(['Xfindexpr3.c'], getcompletion($'find 3', 'cmdline'))
|
call assert_equal(['Xfindfunc3.c'], getcompletion($'find 3', 'cmdline'))
|
||||||
|
|
||||||
call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
|
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 feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
|
||||||
call assert_equal('"find abc', @:)
|
call assert_equal('"find abc', @:)
|
||||||
call assert_equal([], getcompletion('find abc', 'cmdline'))
|
call assert_equal([], getcompletion('find abc', 'cmdline'))
|
||||||
endfor
|
endfor
|
||||||
|
|
||||||
set findexpr&
|
set findfunc&
|
||||||
delfunc! FindExprRegexp
|
delfunc! FindFuncRegexp
|
||||||
delfunc! FindExprGlob
|
delfunc! FindFuncGlob
|
||||||
unlet s:fnames
|
unlet s:fnames
|
||||||
endfunc
|
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 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 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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -1713,10 +1713,10 @@ func Test_completefunc_callback()
|
|||||||
call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
|
call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
|
||||||
|
|
||||||
" Using Vim9 lambda expression in legacy context should fail
|
" Using Vim9 lambda expression in legacy context should fail
|
||||||
" set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b)
|
set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b)
|
||||||
new | only
|
new | only
|
||||||
let g:CompleteFunc1Args = []
|
let g:CompleteFunc1Args = []
|
||||||
" call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:')
|
call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:')
|
||||||
call assert_equal([], g:CompleteFunc1Args)
|
call assert_equal([], g:CompleteFunc1Args)
|
||||||
|
|
||||||
" set 'completefunc' to a partial with dict. This used to cause a crash.
|
" set 'completefunc' to a partial with dict. This used to cause a crash.
|
||||||
@@ -1970,10 +1970,10 @@ func Test_omnifunc_callback()
|
|||||||
call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
|
call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
|
||||||
|
|
||||||
" Using Vim9 lambda expression in legacy context should fail
|
" Using Vim9 lambda expression in legacy context should fail
|
||||||
" set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b)
|
set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b)
|
||||||
new | only
|
new | only
|
||||||
let g:OmniFunc1Args = []
|
let g:OmniFunc1Args = []
|
||||||
" call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:')
|
call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:')
|
||||||
call assert_equal([], g:OmniFunc1Args)
|
call assert_equal([], g:OmniFunc1Args)
|
||||||
|
|
||||||
" set 'omnifunc' to a partial with dict. This used to cause a crash.
|
" set 'omnifunc' to a partial with dict. This used to cause a crash.
|
||||||
@@ -2250,10 +2250,10 @@ func Test_thesaurusfunc_callback()
|
|||||||
call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
|
call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
|
||||||
|
|
||||||
" Using Vim9 lambda expression in legacy context should fail
|
" Using Vim9 lambda expression in legacy context should fail
|
||||||
" set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b)
|
set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b)
|
||||||
new | only
|
new | only
|
||||||
let g:TsrFunc1Args = []
|
let g:TsrFunc1Args = []
|
||||||
" call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:')
|
call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:')
|
||||||
call assert_equal([], g:TsrFunc1Args)
|
call assert_equal([], g:TsrFunc1Args)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
|
@@ -217,7 +217,7 @@ func Test_modeline_fails_always()
|
|||||||
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
|
call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
|
||||||
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
|
call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
|
||||||
call s:modeline_fails('exrc', 'exrc=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('formatprg', 'formatprg=Something()', 'E520:')
|
||||||
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
|
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
|
||||||
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')
|
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')
|
||||||
|
@@ -692,9 +692,9 @@ func Test_opfunc_callback()
|
|||||||
delfunc s:OpFunc3
|
delfunc s:OpFunc3
|
||||||
|
|
||||||
" Using Vim9 lambda expression in legacy context should fail
|
" Using Vim9 lambda expression in legacy context should fail
|
||||||
" set opfunc=(a)\ =>\ OpFunc1(24,\ a)
|
set opfunc=(a)\ =>\ OpFunc1(24,\ a)
|
||||||
let g:OpFunc1Args = []
|
let g:OpFunc1Args = []
|
||||||
" call assert_fails('normal! g@l', 'E117:')
|
call assert_fails('normal! g@l', 'E117:')
|
||||||
call assert_equal([], g:OpFunc1Args)
|
call assert_equal([], g:OpFunc1Args)
|
||||||
|
|
||||||
" set 'operatorfunc' to a partial with dict. This used to cause a crash.
|
" set 'operatorfunc' to a partial with dict. This used to cause a crash.
|
||||||
|
@@ -1559,7 +1559,7 @@ endfunc
|
|||||||
|
|
||||||
" Test for changing options in a sandbox
|
" Test for changing options in a sandbox
|
||||||
func Test_opt_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 set ' .. opt .. '?', 'E48:')
|
||||||
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
|
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
|
||||||
endfor
|
endfor
|
||||||
|
@@ -291,10 +291,10 @@ func Test_tagfunc_callback()
|
|||||||
call assert_fails("echo taglist('a')", "E987:")
|
call assert_fails("echo taglist('a')", "E987:")
|
||||||
|
|
||||||
" Using Vim9 lambda expression in legacy context should fail
|
" Using Vim9 lambda expression in legacy context should fail
|
||||||
" set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c)
|
set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c)
|
||||||
new
|
new
|
||||||
let g:TagFunc1Args = []
|
let g:TagFunc1Args = []
|
||||||
" call assert_fails("tag a17", "E117:")
|
call assert_fails("tag a17", "E117:")
|
||||||
call assert_equal([], g:TagFunc1Args)
|
call assert_equal([], g:TagFunc1Args)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user