mirror of
https://github.com/neovim/neovim.git
synced 2025-10-20 16:51:48 +00:00
vim-patch:9.1.0810: cannot easily adjust the |:find| command
Problem: cannot easily adjust the |:find| command
Solution: Add support for the 'findexpr' option (Yegappan Lakshmanan)
closes: vim/vim#15901
closes: vim/vim#15905
aeb1c97db5
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -5165,6 +5165,90 @@ static void ex_wrongmodifier(exarg_T *eap)
|
||||
eap->errmsg = _(e_invcmd);
|
||||
}
|
||||
|
||||
/// 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(const char *ptr, size_t len)
|
||||
{
|
||||
const sctx_T saved_sctx = current_sctx;
|
||||
bool use_sandbox = false;
|
||||
|
||||
char *findexpr;
|
||||
if (*curbuf->b_p_fexpr == NUL) {
|
||||
use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_GLOBAL);
|
||||
findexpr = p_fexpr;
|
||||
} else {
|
||||
use_sandbox = was_set_insecurely(curwin, kOptFindexpr, OPT_LOCAL);
|
||||
findexpr = curbuf->b_p_fexpr;
|
||||
}
|
||||
|
||||
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
|
||||
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR].script_ctx;
|
||||
|
||||
char *arg = skipwhite(findexpr);
|
||||
|
||||
if (use_sandbox) {
|
||||
sandbox++;
|
||||
}
|
||||
textlock++;
|
||||
|
||||
// Evaluate the expression. If the expression is "FuncName()" call the
|
||||
// function directly.
|
||||
typval_T tv;
|
||||
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());
|
||||
}
|
||||
tv_clear(&tv);
|
||||
}
|
||||
if (use_sandbox) {
|
||||
sandbox--;
|
||||
}
|
||||
textlock--;
|
||||
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
||||
|
||||
set_vim_var_string(VV_FNAME, NULL, 0);
|
||||
current_sctx = saved_sctx;
|
||||
|
||||
return retlist;
|
||||
}
|
||||
|
||||
/// Use 'findexpr' to find file 'findarg'. The 'count' argument is used to find
|
||||
/// the n'th matching file.
|
||||
static char *findexpr_find_file(char *findarg, size_t findarg_len, int count)
|
||||
{
|
||||
char *ret_fname = NULL;
|
||||
|
||||
const char cc = findarg[findarg_len];
|
||||
findarg[findarg_len] = NUL;
|
||||
|
||||
list_T *fname_list = eval_findexpr(findarg, findarg_len);
|
||||
int fname_count = tv_list_len(fname_list);
|
||||
|
||||
if (fname_count == 0) {
|
||||
semsg(_(e_cant_find_file_str_in_path), findarg);
|
||||
} else {
|
||||
if (count > fname_count) {
|
||||
semsg(_(e_no_more_file_str_found_in_path), findarg);
|
||||
} else {
|
||||
listitem_T *li = tv_list_find(fname_list, count - 1);
|
||||
if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING) {
|
||||
ret_fname = xstrdup(TV_LIST_ITEM_TV(li)->vval.v_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fname_list != NULL) {
|
||||
tv_list_free(fname_list);
|
||||
}
|
||||
|
||||
findarg[findarg_len] = cc;
|
||||
|
||||
return ret_fname;
|
||||
}
|
||||
|
||||
/// :sview [+command] file split window with new file, read-only
|
||||
/// :split [[+command] file] split window with current or new file
|
||||
/// :vsplit [[+command] file] split window vertically with current or new file
|
||||
@@ -5196,13 +5280,17 @@ void ex_splitview(exarg_T *eap)
|
||||
}
|
||||
|
||||
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
|
||||
char *file_to_find = NULL;
|
||||
char *search_ctx = NULL;
|
||||
fname = find_file_in_path(eap->arg, strlen(eap->arg),
|
||||
FNAME_MESS, true, curbuf->b_ffname,
|
||||
&file_to_find, &search_ctx);
|
||||
xfree(file_to_find);
|
||||
vim_findfile_cleanup(search_ctx);
|
||||
if (*get_findexpr() != NUL) {
|
||||
fname = findexpr_find_file(eap->arg, strlen(eap->arg),
|
||||
eap->addr_count > 0 ? eap->line2 : 1);
|
||||
} else {
|
||||
char *file_to_find = NULL;
|
||||
char *search_ctx = NULL;
|
||||
fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true,
|
||||
curbuf->b_ffname, &file_to_find, &search_ctx);
|
||||
xfree(file_to_find);
|
||||
vim_findfile_cleanup(search_ctx);
|
||||
}
|
||||
if (fname == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
@@ -5398,23 +5486,28 @@ static void ex_find(exarg_T *eap)
|
||||
return;
|
||||
}
|
||||
|
||||
char *file_to_find = NULL;
|
||||
char *search_ctx = NULL;
|
||||
char *fname = find_file_in_path(eap->arg, strlen(eap->arg),
|
||||
FNAME_MESS, true, curbuf->b_ffname,
|
||||
&file_to_find, &search_ctx);
|
||||
if (eap->addr_count > 0) {
|
||||
// Repeat finding the file "count" times. This matters when it appears
|
||||
// several times in the path.
|
||||
linenr_T count = eap->line2;
|
||||
while (fname != NULL && --count > 0) {
|
||||
xfree(fname);
|
||||
fname = find_file_in_path(NULL, 0, FNAME_MESS, false, curbuf->b_ffname,
|
||||
&file_to_find, &search_ctx);
|
||||
char *fname = NULL;
|
||||
if (*get_findexpr() != NUL) {
|
||||
fname = findexpr_find_file(eap->arg, strlen(eap->arg),
|
||||
eap->addr_count > 0 ? eap->line2 : 1);
|
||||
} else {
|
||||
char *file_to_find = NULL;
|
||||
char *search_ctx = NULL;
|
||||
fname = find_file_in_path(eap->arg, strlen(eap->arg), FNAME_MESS, true,
|
||||
curbuf->b_ffname, &file_to_find, &search_ctx);
|
||||
if (eap->addr_count > 0) {
|
||||
// Repeat finding the file "count" times. This matters when it appears
|
||||
// several times in the path.
|
||||
linenr_T count = eap->line2;
|
||||
while (fname != NULL && --count > 0) {
|
||||
xfree(fname);
|
||||
fname = find_file_in_path(NULL, 0, FNAME_MESS, false,
|
||||
curbuf->b_ffname, &file_to_find, &search_ctx);
|
||||
}
|
||||
}
|
||||
xfree(file_to_find);
|
||||
vim_findfile_cleanup(search_ctx);
|
||||
}
|
||||
xfree(file_to_find);
|
||||
vim_findfile_cleanup(search_ctx);
|
||||
|
||||
if (fname == NULL) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user