Compare commits

...

7 Commits

Author SHA1 Message Date
zeertzjq
fdf135a052 patch 9.1.0814: mapset() may remove unrelated mapping
Problem:  mapset() may remove unrelated mapping whose {rhs} matches the
          restored mapping's {lhs}.
Solution: only match by {lhs} when unmapping for mapset() (zeertzjq).

closes: #15935

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-24 21:43:43 +02:00
Milly
118072862b patch 9.1.0813: no error handling with setglobal and number types
Problem:  no error handling with setglobal and number types
Solution: validate values when using :setglobal with number option types
          (Milly)

closes: #15928

Signed-off-by: Milly <milly.ca@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-23 21:42:41 +02:00
Christian Brabandt
d0809869d6 patch 9.1.0812: Coverity warns about dereferencing NULL ptr
Problem:  Coverity warns about dereferencing NULL ptr
          in check_colorcolumn()
Solution: verify that wp is not null before accessing it

related: #15914

Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-23 21:32:31 +02:00
Yegappan Lakshmanan
2f6efaccfd patch 9.1.0811: :find expansion does not consider 'findexpr'
Problem:  :find expansion does not consider 'findexpr'
Solution: Support expanding :find command argument using 'findexpr'
          (Yegappan Lakshmanan)

closes: #15929

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-23 21:06:10 +02:00
Yegappan Lakshmanan
aeb1c97db5 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: #15901
closes: #15905

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-22 23:42:20 +02:00
Wu, Zhenyu
626b6ab486 patch 9.1.0809: filetype: petalinux config files not recognized
Problem:  filetype: petalinux config files not recognized
Solution: detect 'project-spec/*.conf' files as bitbake filetype
          (Wu, Zhenyu)

References:
https://www.amd.com/en/products/software/adaptive-socs-and-fpgas/embedded-software/petalinux-sdk.html

closes: #15926

Signed-off-by: Wu, Zhenyu <wuzhenyu@ustc.edu>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-22 23:23:56 +02:00
Milly
6d5f4a0bed patch 9.1.0808: Terminal scrollback doesn't shrink when decreasing 'termwinscroll'
Problem:  Terminal scrollback doesn't shrink when reducing
          'termwinscroll'
Solution: Check if option value was decreased (Milly).

closes: #15904

Signed-off-by: Milly <milly.ca@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
2024-10-22 23:17:45 +02:00
29 changed files with 690 additions and 77 deletions

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 9.1. Last change: 2024 Jul 28
*eval.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2223,7 +2223,8 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
*v:fname* *fname-variable*
v:fname When evaluating 'includeexpr': the file name that was
detected. Empty otherwise.
detected. When evaluating 'findexpr': the argument passed to
the |:find| command. Empty otherwise.
*v:fname_in* *fname_in-variable*
v:fname_in The name of the input file. Valid while evaluating:

View File

@@ -3552,6 +3552,51 @@ A jump table for the options with a short description can be found at |Q_op|.
eob EndOfBuffer |hl-EndOfBuffer|
lastline NonText |hl-NonText|
*'findexpr'* *'fexpr'* *E1514*
'findexpr' 'fexpr' string (default "")
global or local to buffer |global-local|
{not available when compiled without the |+eval|
feature}
Expression that is evaluated to obtain the filename(s) for the |:find|
command. When this option is empty, the internal |file-searching|
mechanism is used.
While evaluating the expression, the |v:fname| variable is set to the
argument of the |:find| command.
The expression is evaluated only once per |:find| command invocation.
The expression can process all the directories specified in 'path'.
If a match is found, the expression should return a |List| containing
one or more file names. If a match is not found, the expression
should return an empty List.
If any errors are encountered during the expression evaluation, an
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
evaluating 'findexpr' |textlock|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
Examples:
>
" Use glob()
func FindExprGlob()
return glob(v:fname, v:false, v:true)
endfunc
set findexpr=FindExprGlob()
" Use the 'git ls-files' output
func FindGitFiles()
let fnames = systemlist('git ls-files')
return fnames->filter('v:val =~? v:fname')
endfunc
set findexpr=FindGitFiles()
<
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on)
local to buffer

View File

@@ -1,4 +1,4 @@
*quickref.txt* For Vim version 9.1. Last change: 2024 Mar 03
*quickref.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -707,6 +707,7 @@ Short explanation of each option: *option-list*
'fileignorecase' 'fic' ignore case when using file names
'filetype' 'ft' type of file, used for autocommands
'fillchars' 'fcs' characters to use for displaying special items
'findexpr' 'fexpr' expression to evaluate for |:find|
'fixendofline' 'fixeol' make sure last line in file has <EOL>
'fkmap' 'fk' obsolete option for Farsi
'foldclose' 'fcl' close a fold when the cursor leaves it

View File

@@ -267,6 +267,7 @@ $quote eval.txt /*$quote*
'fenc' options.txt /*'fenc'*
'fencs' options.txt /*'fencs'*
'fex' options.txt /*'fex'*
'fexpr' options.txt /*'fexpr'*
'ff' options.txt /*'ff'*
'ffs' options.txt /*'ffs'*
'fic' options.txt /*'fic'*
@@ -277,6 +278,7 @@ $quote eval.txt /*$quote*
'fileignorecase' options.txt /*'fileignorecase'*
'filetype' options.txt /*'filetype'*
'fillchars' options.txt /*'fillchars'*
'findexpr' options.txt /*'findexpr'*
'fixendofline' options.txt /*'fixendofline'*
'fixeol' options.txt /*'fixeol'*
'fk' options.txt /*'fk'*
@@ -4572,6 +4574,7 @@ E1510 change.txt /*E1510*
E1511 options.txt /*E1511*
E1512 options.txt /*E1512*
E1513 message.txt /*E1513*
E1514 options.txt /*E1514*
E152 helphelp.txt /*E152*
E153 helphelp.txt /*E153*
E154 helphelp.txt /*E154*

View File

@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2024 Oct 14
*version9.txt* For Vim version 9.1. Last change: 2024 Oct 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41649,6 +41649,8 @@ Options: ~
'completeitemalign' Order of |complete-items| in Insert mode completion
popup
'findexpr' Vim expression to obtain the results for a |:find|
command
'winfixbuf' Keep buffer focused in a window
'tabclose' Which tab page to focus after closing a tab page
't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420)

View File

@@ -283,7 +283,7 @@ au BufNewFile,BufRead *.blade.php setf blade
au BufNewFile,BufRead *.bl setf blank
" Bitbake
au BufNewFile,BufRead *.bb,*.bbappend,*.bbclass,*/build/conf/*.conf,*/meta{-*,}/conf/*.conf setf bitbake
au BufNewFile,BufRead *.bb,*.bbappend,*.bbclass,*/build/conf/*.conf,*/meta{-*,}/conf/*.conf,*/project-spec/configs/*.conf setf bitbake
" Blkid cache file
au BufNewFile,BufRead */etc/blkid.tab,*/etc/blkid.tab.old setf xml

View File

@@ -2412,6 +2412,7 @@ 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

View File

@@ -2819,7 +2819,7 @@ expand_files_and_dirs(
{
int free_pat = FALSE;
int i;
int ret;
int ret = FAIL;
// for ":set path=" and ":set tags=" halve backslashes for escaped
// space
@@ -2850,19 +2850,28 @@ expand_files_and_dirs(
}
}
if (xp->xp_context == EXPAND_FILES)
flags |= EW_FILE;
else if (xp->xp_context == EXPAND_FILES_IN_PATH)
flags |= (EW_FILE | EW_PATH);
else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH)
flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
if (xp->xp_context == EXPAND_FILES_IN_PATH && *get_findexpr() != NUL)
{
#ifdef FEAT_EVAL
ret = expand_findexpr(pat, matches, numMatches);
#endif
}
else
flags = (flags | EW_DIR) & ~EW_FILE;
if (options & WILD_ICASE)
flags |= EW_ICASE;
{
if (xp->xp_context == EXPAND_FILES)
flags |= EW_FILE;
else if (xp->xp_context == EXPAND_FILES_IN_PATH)
flags |= (EW_FILE | EW_PATH);
else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH)
flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
else
flags = (flags | EW_DIR) & ~EW_FILE;
if (options & WILD_ICASE)
flags |= EW_ICASE;
// Expand wildcards, supporting %:h and the like.
ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
// Expand wildcards, supporting %:h and the like.
ret = expand_wildcards_eval(&pat, numMatches, matches, flags);
}
if (free_pat)
vim_free(pat);
#ifdef BACKSLASH_IN_FILENAME

View File

@@ -3652,3 +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"));

View File

@@ -6923,6 +6923,146 @@ ex_wrongmodifier(exarg_T *eap)
eap->errmsg = ex_errmsg(e_invalid_command_str, eap->cmd);
}
#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 *ptr)
{
sctx_T saved_sctx = current_sctx;
char_u *findexpr;
char_u *arg;
typval_T tv;
list_T *retlist = NULL;
findexpr = get_findexpr();
set_vim_var_string(VV_FNAME, ptr, -1);
current_sctx = curbuf->b_p_script_ctx[BV_FEXPR];
arg = skipwhite(findexpr);
++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);
set_vim_var_string(VV_FNAME, NULL, 0);
current_sctx = saved_sctx;
return retlist;
}
/*
* Find file names matching "pat" using 'findexpr' 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)
{
list_T *l;
int len;
char_u *regpat;
*numMatches = 0;
*files = NULL;
// File name expansion uses wildchars. But the 'findexpr' expression
// expects a regular expression argument. So convert wildchars in the
// argument to regular expression patterns.
regpat = file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
if (regpat == NULL)
return FAIL;
l = eval_findexpr(regpat);
vim_free(regpat);
if (l == NULL)
return FAIL;
len = list_len(l);
if (len == 0) // empty List
return FAIL;
*files = ALLOC_MULT(char_u *, len);
if (*files == NULL)
return FAIL;
// Copy all the List items
listitem_T *li;
int idx = 0;
FOR_ALL_LIST_ITEMS(l, li)
{
if (li->li_tv.v_type == VAR_STRING)
{
(*files)[idx] = vim_strsave(li->li_tv.vval.v_string);
idx++;
}
}
*numMatches = idx;
list_free(l);
return OK;
}
/*
* Use 'findexpr' 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)
{
list_T *fname_list;
char_u *ret_fname = NULL;
char_u cc;
int fname_count;
cc = findarg[findarg_len];
findarg[findarg_len] = NUL;
fname_list = eval_findexpr(findarg);
fname_count = 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 = list_find(fname_list, count - 1);
if (li != NULL && li->li_tv.v_type == VAR_STRING)
ret_fname = vim_strsave(li->li_tv.vval.v_string);
}
}
if (fname_list != NULL)
list_free(fname_list);
findarg[findarg_len] = cc;
return ret_fname;
}
#endif
/*
* :sview [+command] file split window with new file, read-only
* :split [[+command] file] split window with current or new file
@@ -6972,11 +7112,22 @@ ex_splitview(exarg_T *eap)
{
char_u *file_to_find = NULL;
char *search_ctx = NULL;
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
FNAME_MESS, TRUE, curbuf->b_ffname,
&file_to_find, &search_ctx);
vim_free(file_to_find);
vim_findfile_cleanup(search_ctx);
if (*get_findexpr() != NUL)
{
#ifdef FEAT_EVAL
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}
else
{
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg),
FNAME_MESS, TRUE, curbuf->b_ffname,
&file_to_find, &search_ctx);
vim_free(file_to_find);
vim_findfile_cleanup(search_ctx);
}
if (fname == NULL)
goto theend;
eap->arg = fname;
@@ -7241,27 +7392,37 @@ ex_find(exarg_T *eap)
if (!check_can_set_curbuf_forceit(eap->forceit))
return;
char_u *fname;
char_u *fname = NULL;
int count;
char_u *file_to_find = NULL;
char *search_ctx = NULL;
fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), FNAME_MESS,
TRUE, curbuf->b_ffname, &file_to_find, &search_ctx);
if (eap->addr_count > 0)
if (*get_findexpr() != NUL)
{
// Repeat finding the file "count" times. This matters when it appears
// several times in the path.
count = eap->line2;
while (fname != NULL && --count > 0)
{
vim_free(fname);
fname = find_file_in_path(NULL, 0, FNAME_MESS,
FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
}
#ifdef FEAT_EVAL
fname = findexpr_find_file(eap->arg, (int)STRLEN(eap->arg),
eap->addr_count > 0 ? eap->line2 : 1);
#endif
}
else
{
fname = find_file_in_path(eap->arg, (int)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.
count = eap->line2;
while (fname != NULL && --count > 0)
{
vim_free(fname);
fname = find_file_in_path(NULL, 0, FNAME_MESS,
FALSE, curbuf->b_ffname, &file_to_find, &search_ctx);
}
}
VIM_CLEAR(file_to_find);
vim_findfile_cleanup(search_ctx);
}
VIM_CLEAR(file_to_find);
vim_findfile_cleanup(search_ctx);
if (fname == NULL)
return;

View File

@@ -408,9 +408,11 @@ list_mappings(
* noreabbr {lhs} {rhs} : same, but no remapping for {rhs}
* unabbr {lhs} : remove abbreviation for {lhs}
*
* maptype: MAPTYPE_MAP for :map
* MAPTYPE_UNMAP for :unmap
* MAPTYPE_NOREMAP for noremap
* maptype: MAPTYPE_MAP for :map or :abbr
* MAPTYPE_UNMAP for :unmap or :unabbr
* MAPTYPE_NOREMAP for :noremap or :noreabbr
* MAPTYPE_UNMAP_LHS is like MAPTYPE_UNMAP, but doesn't try to match
* with {rhs} if there is no match with {lhs}.
*
* arg is pointer to any arguments. Note: arg cannot be a read-only string,
* it will be modified.
@@ -470,6 +472,7 @@ do_map(
int expr = FALSE;
#endif
int did_simplify = FALSE;
int unmap_lhs_only = FALSE;
int noremap;
char_u *orig_rhs;
@@ -477,6 +480,12 @@ do_map(
map_table = maphash;
abbr_table = &first_abbr;
if (maptype == MAPTYPE_UNMAP_LHS)
{
unmap_lhs_only = TRUE;
maptype = MAPTYPE_UNMAP;
}
// For ":noremap" don't remap, otherwise do remap.
if (maptype == MAPTYPE_NOREMAP)
noremap = REMAP_NONE;
@@ -619,6 +628,7 @@ do_map(
int did_local = FALSE;
int keyround1_simplified = keyround == 1 && did_simplify;
int round;
int num_rounds;
if (keyround == 2)
{
@@ -742,8 +752,8 @@ do_map(
// an entry with a matching 'to' part. This was done to allow
// ":ab foo bar" to be unmapped by typing ":unab foo", where "foo" will
// be replaced by "bar" because of the abbreviation.
for (round = 0; (round == 0 || maptype == MAPTYPE_UNMAP) && round <= 1
&& !did_it && !got_int; ++round)
num_rounds = maptype == MAPTYPE_UNMAP && !unmap_lhs_only ? 2 : 1;
for (round = 0; round < num_rounds && !did_it && !got_int; ++round)
{
// need to loop over all hash lists
for (int hash = 0; hash < 256 && !got_int; ++hash)
@@ -2817,7 +2827,7 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED)
if (arg == NULL)
return;
}
do_map(MAPTYPE_UNMAP, arg, mode, is_abbr);
do_map(MAPTYPE_UNMAP_LHS, arg, mode, is_abbr);
vim_free(arg);
mp_result[0] = map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs,

View File

@@ -3465,6 +3465,16 @@ did_set_conceallevel(optset_T *args UNUSED)
errmsg = e_invalid_argument;
curwin->w_p_cole = 3;
}
if (curwin->w_allbuf_opt.wo_cole < 0)
{
errmsg = e_argument_must_be_positive;
curwin->w_allbuf_opt.wo_cole = 0;
}
else if (curwin->w_allbuf_opt.wo_cole > 3)
{
errmsg = e_invalid_argument;
curwin->w_allbuf_opt.wo_cole = 3;
}
return errmsg;
}
@@ -3530,6 +3540,16 @@ did_set_foldcolumn(optset_T *args UNUSED)
errmsg = e_invalid_argument;
curwin->w_p_fdc = 12;
}
if (curwin->w_allbuf_opt.wo_fdc < 0)
{
errmsg = e_argument_must_be_positive;
curwin->w_allbuf_opt.wo_fdc = 0;
}
else if (curwin->w_allbuf_opt.wo_fdc > 12)
{
errmsg = e_invalid_argument;
curwin->w_allbuf_opt.wo_fdc = 12;
}
return errmsg;
}
@@ -3856,11 +3876,21 @@ did_set_numberwidth(optset_T *args UNUSED)
errmsg = e_argument_must_be_positive;
curwin->w_p_nuw = 1;
}
if (curwin->w_p_nuw > 20)
else if (curwin->w_p_nuw > 20)
{
errmsg = e_invalid_argument;
curwin->w_p_nuw = 20;
}
if (curwin->w_allbuf_opt.wo_nuw < 1)
{
errmsg = e_argument_must_be_positive;
curwin->w_allbuf_opt.wo_nuw = 1;
}
else if (curwin->w_allbuf_opt.wo_nuw > 20)
{
errmsg = e_invalid_argument;
curwin->w_allbuf_opt.wo_nuw = 20;
}
curwin->w_nrwidth_line_count = 0; // trigger a redraw
return errmsg;
@@ -4141,6 +4171,27 @@ did_set_shiftwidth_tabstop(optset_T *args)
long *pp = (long *)args->os_varp;
char *errmsg = NULL;
if (curbuf->b_p_ts <= 0)
{
errmsg = e_argument_must_be_positive;
curbuf->b_p_ts = 8;
}
else if (curbuf->b_p_ts > TABSTOP_MAX)
{
errmsg = e_invalid_argument;
curbuf->b_p_ts = 8;
}
if (p_ts <= 0)
{
errmsg = e_argument_must_be_positive;
p_ts = 8;
}
else if (p_ts > TABSTOP_MAX)
{
errmsg = e_invalid_argument;
p_ts = 8;
}
if (curbuf->b_p_sw < 0)
{
errmsg = e_argument_must_be_positive;
@@ -4151,6 +4202,18 @@ did_set_shiftwidth_tabstop(optset_T *args)
: curbuf->b_p_ts;
#else
curbuf->b_p_sw = curbuf->b_p_ts;
#endif
}
if (p_sw < 0)
{
errmsg = e_argument_must_be_positive;
#ifdef FEAT_VARTABS
// Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
? tabstop_first(curbuf->b_p_vts_array)
: curbuf->b_p_ts;
#else
p_sw = curbuf->b_p_ts;
#endif
}
@@ -4259,6 +4322,26 @@ did_set_termguicolors(optset_T *args UNUSED)
}
#endif
#if defined(FEAT_TERMINAL) || defined(PROTO)
/*
* Process the updated 'termwinscroll' option value.
*/
char *
did_set_termwinscroll(optset_T *args)
{
long *pp = (long *)args->os_varp;
char *errmsg = NULL;
if (*pp < 1)
{
errmsg = e_argument_must_be_positive;
*pp = 1;
}
return errmsg;
}
#endif
/*
* Process the updated 'terse' option value.
*/
@@ -4322,6 +4405,11 @@ did_set_textwidth(optset_T *args UNUSED)
errmsg = e_argument_must_be_positive;
curbuf->b_p_tw = 0;
}
if (p_tw < 0)
{
errmsg = e_argument_must_be_positive;
p_tw = 0;
}
#ifdef FEAT_SYN_HL
{
win_T *wp;
@@ -4790,16 +4878,6 @@ check_num_option_bounds(
p_window = Rows - 1;
}
if (curbuf->b_p_ts <= 0)
{
errmsg = e_argument_must_be_positive;
curbuf->b_p_ts = 8;
}
else if (curbuf->b_p_ts > TABSTOP_MAX)
{
errmsg = e_invalid_argument;
curbuf->b_p_ts = 8;
}
if (p_tm < 0)
{
errmsg = e_argument_must_be_positive;
@@ -4932,6 +5010,10 @@ set_num_option(
need_mouse_correct = TRUE;
#endif
// May set global value for local option.
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = value;
// Invoke the option specific callback function to validate and apply the
// new value.
if (options[opt_idx].opt_did_set_cb != NULL)
@@ -4951,10 +5033,6 @@ set_num_option(
errmsg = check_num_option_bounds(pp, old_value, old_Rows, old_Columns,
errbuf, errbuflen, errmsg);
// May set global value for local option.
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
options[opt_idx].flags |= P_WAS_SET;
#if defined(FEAT_EVAL)
@@ -6293,6 +6371,11 @@ unset_global_local_option(char_u *name, void *from)
case PV_FP:
clear_string_option(&buf->b_p_fp);
break;
# ifdef FEAT_EVAL
case PV_FEXPR:
clear_string_option(&buf->b_p_fexpr);
break;
# endif
# ifdef FEAT_QUICKFIX
case PV_EFM:
clear_string_option(&buf->b_p_efm);
@@ -6371,6 +6454,9 @@ get_varp_scope(struct vimoption *p, int scope)
switch ((int)p->indir)
{
case PV_FP: return (char_u *)&(curbuf->b_p_fp);
#ifdef FEAT_EVAL
case PV_FEXPR: return (char_u *)&(curbuf->b_p_fexpr);
#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
case PV_GP: return (char_u *)&(curbuf->b_p_gp);
@@ -6481,6 +6567,10 @@ get_varp(struct vimoption *p)
#endif
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;
#endif
#ifdef FEAT_QUICKFIX
case PV_EFM: return *curbuf->b_p_efm != NUL
? (char_u *)&(curbuf->b_p_efm) : p->var;
@@ -6727,6 +6817,21 @@ get_equalprg(void)
return curbuf->b_p_ep;
}
/*
* Get the value of 'findexpr', either the buffer-local one or the global one.
*/
char_u *
get_findexpr(void)
{
#ifdef FEAT_EVAL
if (*curbuf->b_p_fexpr == NUL)
return p_fexpr;
return curbuf->b_p_fexpr;
#else
return (char_u *)"";
#endif
}
/*
* Copy options from one window to another.
* Used when splitting a window.
@@ -7255,6 +7360,10 @@ buf_copy_options(buf_T *buf, int flags)
buf->b_p_efm = empty_option;
#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);
#endif
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
buf->b_p_tags = empty_option;

View File

@@ -596,6 +596,9 @@ EXTERN char_u *p_ffs; // 'fileformats'
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'
#endif
EXTERN int p_fixeol; // 'fixendofline'
#ifdef FEAT_FOLDING
EXTERN char_u *p_fcl; // 'foldclose'
@@ -1168,6 +1171,7 @@ enum
, BV_EP
, BV_ET
, BV_FENC
, BV_FEXPR
, BV_FP
#ifdef FEAT_EVAL
, BV_BEXPR

View File

@@ -74,6 +74,7 @@
#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)
@@ -958,6 +959,15 @@ 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,
{(char_u *)"", (char_u *)0L}
#else
(char_u *)NULL, PV_NONE, NULL, NULL,
{(char_u *)0L, (char_u *)0L}
#endif
SCTX_INIT},
{"fixendofline", "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
(char_u *)&p_fixeol, PV_FIXEOL,
did_set_eof_eol_fixeol_bomb, NULL,
@@ -2563,7 +2573,7 @@ static struct vimoption options[] =
SCTX_INIT},
{"termwinscroll", "twsl", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
#ifdef FEAT_TERMINAL
(char_u *)&p_twsl, PV_TWSL, NULL, NULL,
(char_u *)&p_twsl, PV_TWSL, did_set_termwinscroll, NULL,
{(char_u *)10000L, (char_u *)10000L}
#else
(char_u *)NULL, PV_NONE, NULL, NULL,

View File

@@ -324,6 +324,9 @@ 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);
@@ -3132,8 +3135,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',
* 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr', 'indentexpr',
* 'patchexpr', 'printexpr' and 'charconvert'.
* 'findexpr', 'foldexpr', 'foldtext', 'formatexpr', 'includeexpr',
* 'indentexpr', 'patchexpr', 'printexpr' and 'charconvert'.
*
*/
char *

View File

@@ -46,6 +46,7 @@ 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);
void ex_splitview(exarg_T *eap);
void tabpage_new(void);
void do_exedit(exarg_T *eap, win_T *old_curwin);

View File

@@ -71,6 +71,7 @@ char *did_set_spell(optset_T *args);
char *did_set_swapfile(optset_T *args);
char *did_set_tabclose(optset_T *args);
char *did_set_termguicolors(optset_T *args);
char *did_set_termwinscroll(optset_T *args);
char *did_set_terse(optset_T *args);
char *did_set_textauto(optset_T *args);
char *did_set_textmode(optset_T *args);
@@ -119,6 +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);
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

@@ -3327,6 +3327,9 @@ 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

@@ -3436,7 +3436,8 @@ limit_scrollback(term_T *term, garray_T *gap, int update_buffer)
if (gap->ga_len < term->tl_buffer->b_p_twsl)
return;
int todo = term->tl_buffer->b_p_twsl / 10;
int todo = MAX(term->tl_buffer->b_p_twsl / 10,
gap->ga_len - term->tl_buffer->b_p_twsl);
int i;
curbuf = term->tl_buffer;

View File

@@ -45,14 +45,6 @@ endwhile
let skip_setglobal_reasons = #{
\ iminsert: 'The global value is always overwritten by the local value',
\ imsearch: 'The global value is always overwritten by the local value',
\ conceallevel: 'TODO: fix missing error handling for setglobal',
\ foldcolumn: 'TODO: fix missing error handling for setglobal',
\ numberwidth: 'TODO: fix missing error handling for setglobal',
\ scrolloff: 'TODO: fix missing error handling for setglobal',
\ shiftwidth: 'TODO: fix missing error handling for setglobal',
\ sidescrolloff: 'TODO: fix missing error handling for setglobal',
\ tabstop: 'TODO: fix missing error handling for setglobal',
\ textwidth: 'TODO: fix missing error handling for setglobal',
\}
" Script header.
@@ -103,6 +95,7 @@ let test_values = {
\ 'sidescroll': [[0, 1, 8, 999], [-1]],
\ 'sidescrolloff': [[0, 1, 8, 999], [-1]],
\ 'tabstop': [[1, 4, 8, 12, 9999], [-1, 0, 10000]],
\ 'termwinscroll': [[1, 100, 99999], [-1, 0]],
\ 'textwidth': [[0, 1, 8, 99], [-1]],
\ 'timeoutlen': [[0, 8, 99999], [-1]],
\ 'titlelen': [[0, 1, 8, 9999], [-1]],

View File

@@ -133,7 +133,8 @@ def s:GetFilenameChecks(): dict<list<string>>
bib: ['file.bib'],
bicep: ['file.bicep', 'file.bicepparam'],
bindzone: ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'],
bitbake: ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'],
bitbake: ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf',
'project-spec/configs/zynqmp-generic-xczu7ev.conf'],
blade: ['file.blade.php'],
blank: ['file.bl'],
blueprint: ['file.blp'],

View File

@@ -1,5 +1,7 @@
" Test findfile() and finddir()
source check.vim
let s:files = [ 'Xfinddir1/foo',
\ 'Xfinddir1/bar',
\ 'Xfinddir1/Xdir2/foo',
@@ -281,4 +283,200 @@ func Test_find_non_existing_path()
let &path = save_path
endfunc
" Test for 'findexpr'
func Test_findexpr()
CheckUnix
call assert_equal('', &findexpr)
call writefile(['aFile'], 'Xfindexpr1.c', 'D')
call writefile(['bFile'], 'Xfindexpr2.c', 'D')
call writefile(['cFile'], 'Xfindexpr3.c', 'D')
" basic tests
func FindExpr1()
let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
return fnames->copy()->filter('v:val =~? v:fname')
endfunc
set findexpr=FindExpr1()
find Xfindexpr3
call assert_match('Xfindexpr3.c', @%)
bw!
2find Xfind
call assert_match('Xfindexpr2.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', @%)
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', @%)
call assert_equal(2, tabpagenr())
%bw!
call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path')
" Buffer-local option
set findexpr=['abc']
new
setlocal findexpr=['def']
find xxxx
call assert_equal('def', @%)
wincmd w
find xxxx
call assert_equal('abc', @%)
aboveleft new
call assert_equal("['abc']", &findexpr)
wincmd k
aboveleft new
call assert_equal("['abc']", &findexpr)
%bw!
" Empty list
set findexpr=[]
call assert_fails('find xxxx', 'E345: Can''t find file "xxxx" in path')
" Error cases
" Syntax error in the expression
set findexpr=FindExpr1{}
call assert_fails('find Xfindexpr1.c', 'E15: Invalid expression')
" Find expression throws an error
func FindExpr2()
throw 'find error'
endfunc
set findexpr=FindExpr2()
call assert_fails('find Xfindexpr1.c', 'find error')
" 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 to create a new window from the find expression
func FindExpr3()
new
return ["foo"]
endfunc
set findexpr=FindExpr3()
call assert_fails('find Xfindexpr1.c', 'E565: Not allowed to change text or change window')
" Try to modify the current buffer from the find expression
func FindExpr4()
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')
" Expression returning a string
set findexpr='abc'
call assert_fails('find Xfindexpr1.c', 'E1514: findexpr did not return a List type')
set findexpr&
delfunc! FindExpr1
delfunc! FindExpr2
delfunc! FindExpr3
delfunc! FindExpr4
endfunc
" Test for using a script-local function for 'findexpr'
func Test_findexpr_scriptlocal_func()
func! s:FindExprScript()
let g:FindExprArg = v:fname
return ['xxx']
endfunc
set findexpr=s:FindExprScript()
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
new | only
let g:FindExprArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
bw!
set findexpr=<SID>FindExprScript()
call assert_equal(expand('<SID>') .. 'FindExprScript()', &findexpr)
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
new | only
let g:FindExprArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
bw!
let &findexpr = 's:FindExprScript()'
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
new | only
let g:FindExprArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
bw!
let &findexpr = '<SID>FindExprScript()'
call assert_equal(expand('<SID>') .. 'FindExprScript()', &g:findexpr)
new | only
let g:FindExprArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
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)
new | only
let g:FindExprArg = ''
find abc
call assert_equal('abc', g:FindExprArg)
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 = ''
find abc
call assert_equal('abc', g:FindExprArg)
bw!
set findexpr=
delfunc s:FindExprScript
endfunc
" Test for expanding the argument to the :find command using 'findexpr'
func Test_findexpr_expand_arg()
func FindExpr1()
let fnames = ['Xfindexpr1.c', 'Xfindexpr2.c', 'Xfindexpr3.c']
return fnames->copy()->filter('v:val =~? v:fname')
endfunc
set findexpr=FindExpr1()
call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr1.c', @:)
call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr2.c', @:)
call feedkeys(":find *3*\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr3.c', @:)
call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt")
call assert_equal('"find Xfindexpr1.c Xfindexpr2.c Xfindexpr3.c', @:)
call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt")
call assert_equal('"find abc', @:)
set findexpr&
delfunc! FindExpr1
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -540,6 +540,25 @@ func Test_map_restore_negative_sid()
call delete('Xresult')
endfunc
" Check that restoring a mapping doesn't remove a mapping whose {rhs} matches
" the restored mapping's {lhs}.
func Test_map_restore_with_rhs_match_lhs()
nnoremap <F2> <F3>
nnoremap <F3> <F4>
call assert_equal('<F3>', maparg('<F2>', 'n'))
call assert_equal('<F4>', maparg('<F3>', 'n'))
let d = maparg('<F3>', 'n', v:false, v:true)
nunmap <F3>
call assert_equal('<F3>', maparg('<F2>', 'n'))
call assert_equal('', maparg('<F3>', 'n'))
call mapset(d)
call assert_equal('<F3>', maparg('<F2>', 'n'))
call assert_equal('<F4>', maparg('<F3>', 'n'))
nunmap <F2>
nunmap <F3>
endfunc
def Test_maplist()
new
def ClearMappingsAbbreviations()

View File

@@ -208,6 +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('formatprg', 'formatprg=Something()', 'E520:')
call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')

View File

@@ -752,6 +752,9 @@ func Test_set_option_errors()
call assert_fails('set tabstop=10000', 'E474:')
call assert_fails('let &tabstop = 10000', 'E474:')
call assert_fails('set tabstop=5500000000', 'E474:')
if has('terminal')
call assert_fails('set termwinscroll=-1', 'E487:')
endif
call assert_fails('set textwidth=-1', 'E487:')
call assert_fails('set timeoutlen=-1', 'E487:')
call assert_fails('set updatecount=-1', 'E487:')
@@ -1567,7 +1570,7 @@ endfunc
" Test for changing options in a sandbox
func Test_opt_sandbox()
for opt in ['backupdir', 'cdpath', 'exrc']
for opt in ['backupdir', 'cdpath', 'exrc', 'findexpr']
call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor

View File

@@ -501,6 +501,21 @@ func Test_terminal_scrollback()
let lines = line('$')
call assert_inrange(91, 100, lines)
" When 'termwinscroll' becomes small, the scrollback should become small.
set termwinscroll=20
call term_sendkeys(buf, "echo set20\<CR>")
call WaitForAssert({-> assert_true([term_getline(buf, rows - 1), term_getline(buf, rows - 2)]->index('set20') >= 0)})
let lines = line('$')
call assert_inrange(19, 20, lines)
" When 'termwinscroll' under 10 which means 10% of it will be 0,
" the scrollback should become small.
set termwinscroll=1
call term_sendkeys(buf, "echo set1\<CR>")
call WaitForAssert({-> assert_true([term_getline(buf, rows - 1), term_getline(buf, rows - 2)]->index('set1') >= 0)})
let lines = line('$')
call assert_inrange(1, 2, lines)
call StopShellInTerminal(buf)
exe buf . 'bwipe'
set termwinscroll&

View File

@@ -704,6 +704,20 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
814,
/**/
813,
/**/
812,
/**/
811,
/**/
810,
/**/
809,
/**/
808,
/**/
807,
/**/

View File

@@ -1013,9 +1013,10 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define KEY_COMPLETE 0x103 // end of completion
// Used for the first argument of do_map()
#define MAPTYPE_MAP 0
#define MAPTYPE_UNMAP 1
#define MAPTYPE_NOREMAP 2
#define MAPTYPE_MAP 0
#define MAPTYPE_UNMAP 1
#define MAPTYPE_NOREMAP 2
#define MAPTYPE_UNMAP_LHS 3
// Values for "noremap" argument of ins_typebuf(). Also used for
// map->m_noremap and menu->noremap[].

View File

@@ -7934,7 +7934,7 @@ check_colorcolumn(
char_u *cc, // when NULL: use "wp->w_p_cc"
win_T *wp) // when NULL: only parse "cc"
{
char_u *s;
char_u *s = empty_option;
int tw;
int col;
int count = 0;
@@ -7947,7 +7947,7 @@ check_colorcolumn(
if (cc != NULL)
s = cc;
else
else if (wp != NULL)
s = wp->w_p_cc;
if (wp != NULL)