mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
Merge #10294 from janlazo/vim-8.0.1239
vim-patch:8.0.1239,8.1.{112,125,165,166,167,169,181,242,270,272,747,850,853,1519}
This commit is contained in:
commit
7d604a1e61
@ -1257,7 +1257,7 @@ to the file.
|
||||
Changing directory
|
||||
|
||||
The following uppercase conversion characters specify the type of special
|
||||
format strings. At most one of them may be given as a prefix at the begin
|
||||
format strings. At most one of them may be given as a prefix at the beginning
|
||||
of a single comma-separated format pattern.
|
||||
Some compilers produce messages that consist of directory names that have to
|
||||
be prepended to each file name read by %f (example: GNU make). The following
|
||||
|
@ -3838,11 +3838,14 @@ static int ins_compl_get_exp(pos_T *ini)
|
||||
e_cpt = (compl_cont_status & CONT_LOCAL)
|
||||
? (char_u *)"." : curbuf->b_p_cpt;
|
||||
last_match_pos = first_match_pos = *ini;
|
||||
} else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
|
||||
ins_buf = curbuf; // In case the buffer was wiped out.
|
||||
}
|
||||
|
||||
compl_old_match = compl_curr_match; // remember the last current match
|
||||
pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
|
||||
/* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
|
||||
|
||||
// For ^N/^P loop over all the flags/windows/buffers in 'complete'
|
||||
for (;; ) {
|
||||
found_new_match = FAIL;
|
||||
set_match_pos = FALSE;
|
||||
|
171
src/nvim/eval.c
171
src/nvim/eval.c
@ -955,6 +955,88 @@ eval_to_bool(
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Call eval1() and give an error message if not done at a lower level.
|
||||
static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
const int did_emsg_before = did_emsg;
|
||||
const int called_emsg_before = called_emsg;
|
||||
|
||||
const int ret = eval1(arg, rettv, evaluate);
|
||||
if (ret == FAIL) {
|
||||
// Report the invalid expression unless the expression evaluation has
|
||||
// been cancelled due to an aborting error, an interrupt, or an
|
||||
// exception, or we already gave a more specific error.
|
||||
// Also check called_emsg for when using assert_fails().
|
||||
if (!aborting()
|
||||
&& did_emsg == did_emsg_before
|
||||
&& called_emsg == called_emsg_before) {
|
||||
emsgf(_(e_invexpr2), arg);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eval_expr_typval(const typval_T *expr, typval_T *argv,
|
||||
int argc, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
if (expr->v_type == VAR_FUNC) {
|
||||
const char_u *const s = expr->vval.v_string;
|
||||
if (s == NULL || *s == NUL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
|
||||
0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
} else if (expr->v_type == VAR_PARTIAL) {
|
||||
partial_T *const partial = expr->vval.v_partial;
|
||||
const char_u *const s = partial_name(partial);
|
||||
if (s == NULL || *s == NUL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
|
||||
0L, 0L, &dummy, true, partial, NULL) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
} else {
|
||||
char buf[NUMBUFLEN];
|
||||
char_u *s = (char_u *)tv_get_string_buf_chk(expr, buf);
|
||||
if (s == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
s = skipwhite(s);
|
||||
if (eval1_emsg(&s, rettv, true) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (*s != NUL) { // check for trailing chars after expr
|
||||
tv_clear(rettv);
|
||||
emsgf(_(e_invexpr2), s);
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Like eval_to_bool() but using a typval_T instead of a string.
|
||||
/// Works for string, funcref and partial.
|
||||
static bool eval_expr_to_bool(const typval_T *expr, bool *error)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
typval_T argv, rettv;
|
||||
|
||||
if (eval_expr_typval(expr, &argv, 0, &rettv) == FAIL) {
|
||||
*error = true;
|
||||
return false;
|
||||
}
|
||||
const bool res = (tv_get_number_chk(&rettv, error) != 0);
|
||||
tv_clear(&rettv);
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Top level evaluation function, returning a string
|
||||
///
|
||||
/// @param[in] arg String to evaluate.
|
||||
@ -6308,6 +6390,7 @@ call_func(
|
||||
partial_T *partial, // optional, can be NULL
|
||||
dict_T *selfdict_in // Dictionary for "self"
|
||||
)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
|
||||
{
|
||||
int ret = FAIL;
|
||||
int error = ERROR_NONE;
|
||||
@ -8830,6 +8913,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
|
||||
}
|
||||
hash_unlock(ht);
|
||||
} else {
|
||||
assert(argvars[0].v_type == VAR_LIST);
|
||||
vimvars[VV_KEY].vv_type = VAR_NUMBER;
|
||||
|
||||
for (listitem_T *li = tv_list_first(l); li != NULL;) {
|
||||
@ -8860,44 +8944,17 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
|
||||
}
|
||||
|
||||
static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
typval_T rettv;
|
||||
typval_T argv[3];
|
||||
int retval = FAIL;
|
||||
int dummy;
|
||||
|
||||
tv_copy(tv, &vimvars[VV_VAL].vv_tv);
|
||||
argv[0] = vimvars[VV_KEY].vv_tv;
|
||||
argv[1] = vimvars[VV_VAL].vv_tv;
|
||||
if (expr->v_type == VAR_FUNC) {
|
||||
const char_u *const s = expr->vval.v_string;
|
||||
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
||||
0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
|
||||
goto theend;
|
||||
}
|
||||
} else if (expr->v_type == VAR_PARTIAL) {
|
||||
partial_T *partial = expr->vval.v_partial;
|
||||
|
||||
const char_u *const s = partial_name(partial);
|
||||
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
|
||||
0L, 0L, &dummy, true, partial, NULL) == FAIL) {
|
||||
goto theend;
|
||||
}
|
||||
} else {
|
||||
char buf[NUMBUFLEN];
|
||||
const char *s = tv_get_string_buf_chk(expr, buf);
|
||||
if (s == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
s = (const char *)skipwhite((const char_u *)s);
|
||||
if (eval1((char_u **)&s, &rettv, true) == FAIL) {
|
||||
goto theend;
|
||||
}
|
||||
|
||||
if (*s != NUL) { // check for trailing chars after expr
|
||||
emsgf(_(e_invexpr2), s);
|
||||
goto theend;
|
||||
}
|
||||
if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) {
|
||||
goto theend;
|
||||
}
|
||||
if (map) {
|
||||
// map(): replace the list item value.
|
||||
@ -14498,10 +14555,10 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
||||
long lnum_stop = 0;
|
||||
long time_limit = 0;
|
||||
|
||||
// Get the three pattern arguments: start, middle, end.
|
||||
// Get the three pattern arguments: start, middle, end. Will result in an
|
||||
// error if not a valid argument.
|
||||
char nbuf1[NUMBUFLEN];
|
||||
char nbuf2[NUMBUFLEN];
|
||||
char nbuf3[NUMBUFLEN];
|
||||
const char *spat = tv_get_string_chk(&argvars[0]);
|
||||
const char *mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
|
||||
const char *epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
|
||||
@ -14529,23 +14586,28 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
||||
}
|
||||
|
||||
// Optional fifth argument: skip expression.
|
||||
const char *skip;
|
||||
const typval_T *skip;
|
||||
if (argvars[3].v_type == VAR_UNKNOWN
|
||||
|| argvars[4].v_type == VAR_UNKNOWN) {
|
||||
skip = "";
|
||||
skip = NULL;
|
||||
} else {
|
||||
skip = tv_get_string_buf_chk(&argvars[4], nbuf3);
|
||||
if (skip == NULL) {
|
||||
skip = &argvars[4];
|
||||
if (skip->v_type != VAR_FUNC
|
||||
&& skip->v_type != VAR_PARTIAL
|
||||
&& skip->v_type != VAR_STRING) {
|
||||
emsgf(_(e_invarg2), tv_get_string(&argvars[4]));
|
||||
goto theend; // Type error.
|
||||
}
|
||||
if (argvars[5].v_type != VAR_UNKNOWN) {
|
||||
lnum_stop = tv_get_number_chk(&argvars[5], NULL);
|
||||
if (lnum_stop < 0) {
|
||||
emsgf(_(e_invarg2), tv_get_string(&argvars[5]));
|
||||
goto theend;
|
||||
}
|
||||
if (argvars[6].v_type != VAR_UNKNOWN) {
|
||||
time_limit = tv_get_number_chk(&argvars[6], NULL);
|
||||
if (time_limit < 0) {
|
||||
emsgf(_(e_invarg2), tv_get_string(&argvars[6]));
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@ -14553,7 +14615,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
|
||||
}
|
||||
|
||||
retval = do_searchpair(
|
||||
(char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, (char_u *)skip,
|
||||
(char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip,
|
||||
flags, match_pos, lnum_stop, time_limit);
|
||||
|
||||
theend:
|
||||
@ -14601,7 +14663,7 @@ do_searchpair(
|
||||
char_u *mpat, // middle pattern
|
||||
char_u *epat, // end pattern
|
||||
int dir, // BACKWARD or FORWARD
|
||||
char_u *skip, // skip expression
|
||||
const typval_T *skip, // skip expression
|
||||
int flags, // SP_SETPCMARK and other SP_ values
|
||||
pos_T *match_pos,
|
||||
linenr_T lnum_stop, // stop at this line if not zero
|
||||
@ -14617,8 +14679,8 @@ do_searchpair(
|
||||
pos_T save_cursor;
|
||||
pos_T save_pos;
|
||||
int n;
|
||||
int r;
|
||||
int nest = 1;
|
||||
bool use_skip = false;
|
||||
int options = SEARCH_KEEP;
|
||||
proftime_T tm;
|
||||
size_t pat2_len;
|
||||
@ -14648,6 +14710,13 @@ do_searchpair(
|
||||
options |= SEARCH_START;
|
||||
}
|
||||
|
||||
if (skip != NULL) {
|
||||
// Empty string means to not use the skip expression.
|
||||
if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) {
|
||||
use_skip = skip->vval.v_string != NULL && *skip->vval.v_string != NUL;
|
||||
}
|
||||
}
|
||||
|
||||
save_cursor = curwin->w_cursor;
|
||||
pos = curwin->w_cursor;
|
||||
clearpos(&firstpos);
|
||||
@ -14677,12 +14746,12 @@ do_searchpair(
|
||||
/* clear the start flag to avoid getting stuck here */
|
||||
options &= ~SEARCH_START;
|
||||
|
||||
/* If the skip pattern matches, ignore this match. */
|
||||
if (*skip != NUL) {
|
||||
// If the skip pattern matches, ignore this match.
|
||||
if (use_skip) {
|
||||
save_pos = curwin->w_cursor;
|
||||
curwin->w_cursor = pos;
|
||||
bool err;
|
||||
r = eval_to_bool(skip, &err, NULL, false);
|
||||
bool err = false;
|
||||
const bool r = eval_expr_to_bool(skip, &err);
|
||||
curwin->w_cursor = save_pos;
|
||||
if (err) {
|
||||
/* Evaluating {skip} caused an error, break here. */
|
||||
@ -17773,7 +17842,6 @@ static void add_timer_info(typval_T *rettv, timer_T *timer)
|
||||
di->di_tv.v_type = VAR_FUNC;
|
||||
di->di_tv.vval.v_string = vim_strsave(timer->callback.data.funcref);
|
||||
}
|
||||
di->di_tv.v_lock = 0;
|
||||
}
|
||||
|
||||
static void add_timer_info_all(typval_T *rettv)
|
||||
@ -20480,7 +20548,6 @@ void ex_execute(exarg_T *eap)
|
||||
char_u *arg = eap->arg;
|
||||
typval_T rettv;
|
||||
int ret = OK;
|
||||
char_u *p;
|
||||
garray_T ga;
|
||||
int save_did_emsg = did_emsg;
|
||||
|
||||
@ -20489,17 +20556,8 @@ void ex_execute(exarg_T *eap)
|
||||
if (eap->skip)
|
||||
++emsg_skip;
|
||||
while (*arg != NUL && *arg != '|' && *arg != '\n') {
|
||||
p = arg;
|
||||
if (eval1(&arg, &rettv, !eap->skip) == FAIL) {
|
||||
/*
|
||||
* Report the invalid expression unless the expression evaluation
|
||||
* has been cancelled due to an aborting error, an interrupt, or an
|
||||
* exception.
|
||||
*/
|
||||
if (!aborting() && did_emsg == save_did_emsg) {
|
||||
EMSG2(_(e_invexpr2), p);
|
||||
}
|
||||
ret = FAIL;
|
||||
ret = eval1_emsg(&arg, &rettv, !eap->skip);
|
||||
if (ret == FAIL) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -21134,7 +21192,6 @@ void ex_function(exarg_T *eap)
|
||||
tv_clear(&fudi.fd_di->di_tv);
|
||||
}
|
||||
fudi.fd_di->di_tv.v_type = VAR_FUNC;
|
||||
fudi.fd_di->di_tv.v_lock = 0;
|
||||
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
|
||||
|
||||
/* behave like "dict" was used */
|
||||
|
@ -1221,7 +1221,8 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
|
||||
|
||||
/// Allocate a dictionary item
|
||||
///
|
||||
/// @note that the value of the item (->di_tv) still needs to be initialized.
|
||||
/// @note that the type and value of the item (->di_tv) still needs to
|
||||
/// be initialized.
|
||||
///
|
||||
/// @param[in] key Key, is copied to the new item.
|
||||
/// @param[in] key_len Key length.
|
||||
@ -1235,12 +1236,14 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
|
||||
memcpy(di->di_key, key, key_len);
|
||||
di->di_key[key_len] = NUL;
|
||||
di->di_flags = DI_FLAGS_ALLOC;
|
||||
di->di_tv.v_lock = VAR_UNLOCKED;
|
||||
return di;
|
||||
}
|
||||
|
||||
/// Allocate a dictionary item
|
||||
///
|
||||
/// @note that the value of the item (->di_tv) still needs to be initialized.
|
||||
/// @note that the type and value of the item (->di_tv) still needs to
|
||||
/// be initialized.
|
||||
///
|
||||
/// @param[in] key Key, is copied to the new item.
|
||||
///
|
||||
@ -1572,7 +1575,6 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_LIST;
|
||||
item->di_tv.vval.v_list = list;
|
||||
tv_list_ref(list);
|
||||
@ -1597,7 +1599,6 @@ int tv_dict_add_dict(dict_T *const d, const char *const key,
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_DICT;
|
||||
item->di_tv.vval.v_dict = dict;
|
||||
dict->dv_refcount++;
|
||||
@ -1621,7 +1622,6 @@ int tv_dict_add_nr(dict_T *const d, const char *const key,
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_NUMBER;
|
||||
item->di_tv.vval.v_number = nr;
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
@ -1644,7 +1644,6 @@ int tv_dict_add_special(dict_T *const d, const char *const key,
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_SPECIAL;
|
||||
item->di_tv.vval.v_special = val;
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
@ -1706,7 +1705,6 @@ int tv_dict_add_allocated_str(dict_T *const d,
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
item->di_tv.v_lock = VAR_UNLOCKED;
|
||||
item->di_tv.v_type = VAR_STRING;
|
||||
item->di_tv.vval.v_string = (char_u *)val;
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
|
@ -335,7 +335,7 @@ static int linelen(int *has_tab)
|
||||
len = linetabsize(line);
|
||||
// Check for embedded TAB.
|
||||
if (has_tab != NULL) {
|
||||
*has_tab = STRRCHR(first, TAB) != NULL;
|
||||
*has_tab = vim_strchr(first, TAB) != NULL;
|
||||
}
|
||||
*last = save;
|
||||
|
||||
|
@ -611,7 +611,7 @@ static int dbg_parsearg(char_u *arg, garray_T *gap)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// ":breakadd".
|
||||
/// ":breakadd". Also used for ":profile".
|
||||
void ex_breakadd(exarg_T *eap)
|
||||
{
|
||||
struct debuggy *bp;
|
||||
|
@ -1765,6 +1765,7 @@ del_lines (
|
||||
}
|
||||
|
||||
int gchar_pos(pos_T *pos)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
// When searching columns is sometimes put at the end of a line.
|
||||
if (pos->col == MAXCOL) {
|
||||
|
@ -1638,12 +1638,25 @@ static void mb_adjust_opend(oparg_T *oap)
|
||||
/*
|
||||
* Put character 'c' at position 'lp'
|
||||
*/
|
||||
static inline void pchar(pos_T lp, int c)
|
||||
static inline void pbyte(pos_T lp, int c)
|
||||
{
|
||||
assert(c <= UCHAR_MAX);
|
||||
*(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c;
|
||||
}
|
||||
|
||||
// Replace the character under the cursor with "c".
|
||||
// This takes care of multi-byte characters.
|
||||
static void replace_character(int c)
|
||||
{
|
||||
const int n = State;
|
||||
|
||||
State = REPLACE;
|
||||
ins_char(c);
|
||||
State = n;
|
||||
// Backup to the replaced character.
|
||||
dec_cursor();
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace a whole area with one character.
|
||||
*/
|
||||
@ -1795,12 +1808,7 @@ int op_replace(oparg_T *oap, int c)
|
||||
* with a multi-byte and the other way around. */
|
||||
if (curwin->w_cursor.lnum == oap->end.lnum)
|
||||
oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n);
|
||||
n = State;
|
||||
State = REPLACE;
|
||||
ins_char(c);
|
||||
State = n;
|
||||
/* Backup to the replaced character. */
|
||||
dec_cursor();
|
||||
replace_character(c);
|
||||
} else {
|
||||
if (n == TAB) {
|
||||
int end_vcol = 0;
|
||||
@ -1815,7 +1823,7 @@ int op_replace(oparg_T *oap, int c)
|
||||
if (curwin->w_cursor.lnum == oap->end.lnum)
|
||||
getvpos(&oap->end, end_vcol);
|
||||
}
|
||||
pchar(curwin->w_cursor, c);
|
||||
pbyte(curwin->w_cursor, c);
|
||||
}
|
||||
} else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum) {
|
||||
int virtcols = oap->end.coladd;
|
||||
@ -1830,9 +1838,14 @@ int op_replace(oparg_T *oap, int c)
|
||||
coladvance_force(getviscol2(oap->end.col, oap->end.coladd) + 1);
|
||||
curwin->w_cursor.col -= (virtcols + 1);
|
||||
for (; virtcols >= 0; virtcols--) {
|
||||
pchar(curwin->w_cursor, c);
|
||||
if (inc(&curwin->w_cursor) == -1)
|
||||
if (utf_char2len(c) > 1) {
|
||||
replace_character(c);
|
||||
} else {
|
||||
pbyte(curwin->w_cursor, c);
|
||||
}
|
||||
if (inc(&curwin->w_cursor) == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1953,23 +1966,20 @@ static int swapchars(int op_type, pos_T *pos, int length)
|
||||
return did_change;
|
||||
}
|
||||
|
||||
/*
|
||||
* If op_type == OP_UPPER: make uppercase,
|
||||
* if op_type == OP_LOWER: make lowercase,
|
||||
* if op_type == OP_ROT13: do rot13 encoding,
|
||||
* else swap case of character at 'pos'
|
||||
* returns TRUE when something actually changed.
|
||||
*/
|
||||
int swapchar(int op_type, pos_T *pos)
|
||||
// If op_type == OP_UPPER: make uppercase,
|
||||
// if op_type == OP_LOWER: make lowercase,
|
||||
// if op_type == OP_ROT13: do rot13 encoding,
|
||||
// else swap case of character at 'pos'
|
||||
// returns true when something actually changed.
|
||||
bool swapchar(int op_type, pos_T *pos)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
int c;
|
||||
int nc;
|
||||
const int c = gchar_pos(pos);
|
||||
|
||||
c = gchar_pos(pos);
|
||||
|
||||
/* Only do rot13 encoding for ASCII characters. */
|
||||
if (c >= 0x80 && op_type == OP_ROT13)
|
||||
return FALSE;
|
||||
// Only do rot13 encoding for ASCII characters.
|
||||
if (c >= 0x80 && op_type == OP_ROT13) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op_type == OP_UPPER && c == 0xdf) {
|
||||
pos_T sp = curwin->w_cursor;
|
||||
@ -1983,7 +1993,7 @@ int swapchar(int op_type, pos_T *pos)
|
||||
inc(pos);
|
||||
}
|
||||
|
||||
nc = c;
|
||||
int nc = c;
|
||||
if (mb_islower(c)) {
|
||||
if (op_type == OP_ROT13) {
|
||||
nc = ROT13(c, 'a');
|
||||
@ -1998,7 +2008,7 @@ int swapchar(int op_type, pos_T *pos)
|
||||
}
|
||||
}
|
||||
if (nc != c) {
|
||||
if (enc_utf8 && (c >= 0x80 || nc >= 0x80)) {
|
||||
if (c >= 0x80 || nc >= 0x80) {
|
||||
pos_T sp = curwin->w_cursor;
|
||||
|
||||
curwin->w_cursor = *pos;
|
||||
@ -2006,11 +2016,12 @@ int swapchar(int op_type, pos_T *pos)
|
||||
del_bytes(utf_ptr2len(get_cursor_pos_ptr()), FALSE, FALSE);
|
||||
ins_char(nc);
|
||||
curwin->w_cursor = sp;
|
||||
} else
|
||||
pchar(*pos, nc);
|
||||
return TRUE;
|
||||
} else {
|
||||
pbyte(*pos, nc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2528,9 +2528,9 @@ void qf_list(exarg_T *eap)
|
||||
qfp = qi->qf_lists[qi->qf_curlist].qf_start;
|
||||
for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) {
|
||||
if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) {
|
||||
msg_putchar('\n');
|
||||
if (got_int)
|
||||
if (got_int) {
|
||||
break;
|
||||
}
|
||||
|
||||
fname = NULL;
|
||||
if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
|
||||
@ -2549,6 +2549,27 @@ void qf_list(exarg_T *eap)
|
||||
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)fname);
|
||||
}
|
||||
}
|
||||
|
||||
// Support for filtering entries using :filter /pat/ clist
|
||||
// Match against the module name, file name, search pattern and
|
||||
// text of the entry.
|
||||
bool filter_entry = true;
|
||||
if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
|
||||
filter_entry &= message_filtered(qfp->qf_module);
|
||||
}
|
||||
if (filter_entry && fname != NULL) {
|
||||
filter_entry &= message_filtered(fname);
|
||||
}
|
||||
if (filter_entry && qfp->qf_pattern != NULL) {
|
||||
filter_entry &= message_filtered(qfp->qf_pattern);
|
||||
}
|
||||
if (filter_entry) {
|
||||
filter_entry &= message_filtered(qfp->qf_text);
|
||||
}
|
||||
if (filter_entry) {
|
||||
goto next_entry;
|
||||
}
|
||||
msg_putchar('\n');
|
||||
msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
|
||||
? HL_ATTR(HLF_QFL) : HL_ATTR(HLF_D));
|
||||
if (qfp->qf_lnum == 0) {
|
||||
@ -2579,6 +2600,7 @@ void qf_list(exarg_T *eap)
|
||||
ui_flush(); /* show one line at a time */
|
||||
}
|
||||
|
||||
next_entry:
|
||||
qfp = qfp->qf_next;
|
||||
if (qfp == NULL) {
|
||||
break;
|
||||
@ -4721,11 +4743,8 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict)
|
||||
/// Return the quickfix list title as 'title' in retdict
|
||||
static int qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict)
|
||||
{
|
||||
char_u *t = qi->qf_lists[qf_idx].qf_title;
|
||||
if (t == NULL) {
|
||||
t = (char_u *)"";
|
||||
}
|
||||
return tv_dict_add_str(retdict, S_LEN("title"), (const char *)t);
|
||||
return tv_dict_add_str(retdict, S_LEN("title"),
|
||||
(const char *)qi->qf_lists[qf_idx].qf_title);
|
||||
}
|
||||
|
||||
/// Return the quickfix list items/entries as 'items' in retdict
|
||||
|
@ -3370,7 +3370,6 @@ current_tagblock(
|
||||
)
|
||||
{
|
||||
long count = count_arg;
|
||||
long n;
|
||||
pos_T old_pos;
|
||||
pos_T start_pos;
|
||||
pos_T end_pos;
|
||||
@ -3379,7 +3378,6 @@ current_tagblock(
|
||||
char_u *p;
|
||||
char_u *cp;
|
||||
int len;
|
||||
int r;
|
||||
bool do_include = include;
|
||||
bool save_p_ws = p_ws;
|
||||
int retval = FAIL;
|
||||
@ -3428,12 +3426,12 @@ again:
|
||||
* Search backwards for unclosed "<aaa>".
|
||||
* Put this position in start_pos.
|
||||
*/
|
||||
for (n = 0; n < count; ++n) {
|
||||
if (do_searchpair((char_u *)
|
||||
"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
|
||||
(char_u *)"",
|
||||
(char_u *)"</[^>]*>", BACKWARD, (char_u *)"", 0,
|
||||
NULL, (linenr_T)0, 0L) <= 0) {
|
||||
for (long n = 0; n < count; n++) {
|
||||
if (do_searchpair(
|
||||
(char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
|
||||
(char_u *)"",
|
||||
(char_u *)"</[^>]*>", BACKWARD, NULL, 0,
|
||||
NULL, (linenr_T)0, 0L) <= 0) {
|
||||
curwin->w_cursor = old_pos;
|
||||
goto theend;
|
||||
}
|
||||
@ -3459,8 +3457,8 @@ again:
|
||||
sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
|
||||
sprintf((char *)epat, "</%.*s>\\c", len, p);
|
||||
|
||||
r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"",
|
||||
0, NULL, (linenr_T)0, 0L);
|
||||
const int r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
|
||||
0, NULL, (linenr_T)0, 0L);
|
||||
|
||||
xfree(spat);
|
||||
xfree(epat);
|
||||
|
@ -79,3 +79,8 @@ func Test_filter_map_dict_expr_funcref()
|
||||
endfunc
|
||||
call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4')))
|
||||
endfunc
|
||||
|
||||
func Test_map_fails()
|
||||
call assert_fails('call map([1], "42 +")', 'E15:')
|
||||
call assert_fails('call filter([1], "42 +")', 'E15:')
|
||||
endfunc
|
||||
|
@ -92,9 +92,6 @@ function! Test_path_keep_commas()
|
||||
endfunction
|
||||
|
||||
func Test_filetype_valid()
|
||||
if !has('autocmd')
|
||||
return
|
||||
endif
|
||||
set ft=valid_name
|
||||
call assert_equal("valid_name", &filetype)
|
||||
set ft=valid-name
|
||||
@ -347,19 +344,62 @@ func Test_set_indentexpr()
|
||||
endfunc
|
||||
|
||||
func Test_backupskip()
|
||||
" Option 'backupskip' may contain several comma-separated path
|
||||
" specifications if one or more of the environment variables TMPDIR, TMP,
|
||||
" or TEMP is defined. To simplify testing, convert the string value into a
|
||||
" list.
|
||||
let bsklist = split(&bsk, ',')
|
||||
|
||||
if has("mac")
|
||||
call assert_match('/private/tmp/\*', &bsk)
|
||||
let found = (index(bsklist, '/private/tmp/*') >= 0)
|
||||
call assert_true(found, '/private/tmp not in option bsk: ' . &bsk)
|
||||
elseif has("unix")
|
||||
call assert_match('/tmp/\*', &bsk)
|
||||
let found = (index(bsklist, '/tmp/*') >= 0)
|
||||
call assert_true(found, '/tmp not in option bsk: ' . &bsk)
|
||||
endif
|
||||
|
||||
let bskvalue = substitute(&bsk, '\\', '/', 'g')
|
||||
for var in ['$TEMPDIR', '$TMP', '$TEMP']
|
||||
" If our test platform is Windows, the path(s) in option bsk will use
|
||||
" backslash for the path separator and the components could be in short
|
||||
" (8.3) format. As such, we need to replace the backslashes with forward
|
||||
" slashes and convert the path components to long format. The expand()
|
||||
" function will do this but it cannot handle comma-separated paths. This is
|
||||
" why bsk was converted from a string into a list of strings above.
|
||||
"
|
||||
" One final complication is that the wildcard "/*" is at the end of each
|
||||
" path and so expand() might return a list of matching files. To prevent
|
||||
" this, we need to remove the wildcard before calling expand() and then
|
||||
" append it afterwards.
|
||||
if has('win32')
|
||||
let item_nbr = 0
|
||||
while item_nbr < len(bsklist)
|
||||
let path_spec = bsklist[item_nbr]
|
||||
let path_spec = strcharpart(path_spec, 0, strlen(path_spec)-2)
|
||||
let path_spec = substitute(expand(path_spec), '\\', '/', 'g')
|
||||
let bsklist[item_nbr] = path_spec . '/*'
|
||||
let item_nbr += 1
|
||||
endwhile
|
||||
endif
|
||||
|
||||
" Option bsk will also include these environment variables if defined.
|
||||
" If they're defined, verify they appear in the option value.
|
||||
for var in ['$TMPDIR', '$TMP', '$TEMP']
|
||||
if exists(var)
|
||||
let varvalue = substitute(expand(var), '\\', '/', 'g')
|
||||
call assert_match(varvalue . '.\*', bskvalue)
|
||||
let varvalue = substitute(varvalue, '/$', '', '')
|
||||
let varvalue .= '/*'
|
||||
let found = (index(bsklist, varvalue) >= 0)
|
||||
call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk)
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Duplicates should be filtered out (option has P_NODUP)
|
||||
let backupskip = &backupskip
|
||||
set backupskip=
|
||||
set backupskip+=/test/dir
|
||||
set backupskip+=/other/dir
|
||||
set backupskip+=/test/dir
|
||||
call assert_equal('/test/dir,/other/dir', &backupskip)
|
||||
let &backupskip = backupskip
|
||||
endfunc
|
||||
|
||||
func Test_copy_winopt()
|
||||
|
@ -3373,6 +3373,23 @@ func Test_lbuffer_with_bwipe()
|
||||
augroup END
|
||||
endfunc
|
||||
|
||||
" Tests for the ':filter /pat/ clist' command
|
||||
func Test_filter_clist()
|
||||
cexpr ['Xfile1:10:10:Line 10', 'Xfile2:15:15:Line 15']
|
||||
call assert_equal([' 2 Xfile2:15 col 15: Line 15'],
|
||||
\ split(execute('filter /Line 15/ clist'), "\n"))
|
||||
call assert_equal([' 1 Xfile1:10 col 10: Line 10'],
|
||||
\ split(execute('filter /Xfile1/ clist'), "\n"))
|
||||
call assert_equal([], split(execute('filter /abc/ clist'), "\n"))
|
||||
|
||||
call setqflist([{'module' : 'abc', 'pattern' : 'pat1'},
|
||||
\ {'module' : 'pqr', 'pattern' : 'pat2'}], ' ')
|
||||
call assert_equal([' 2 pqr:pat2: '],
|
||||
\ split(execute('filter /pqr/ clist'), "\n"))
|
||||
call assert_equal([' 1 abc:pat1: '],
|
||||
\ split(execute('filter /pat1/ clist'), "\n"))
|
||||
endfunc
|
||||
|
||||
func Test_setloclist_in_aucmd()
|
||||
" This was using freed memory.
|
||||
augroup nasty
|
||||
|
@ -288,16 +288,53 @@ func Test_searchpair()
|
||||
new
|
||||
call setline(1, ['other code here', '', '[', '" cursor here', ']'])
|
||||
4
|
||||
let a=searchpair('\[','',']','bW')
|
||||
let a = searchpair('\[','',']','bW')
|
||||
call assert_equal(3, a)
|
||||
set nomagic
|
||||
4
|
||||
let a=searchpair('\[','',']','bW')
|
||||
let a = searchpair('\[','',']','bW')
|
||||
call assert_equal(3, a)
|
||||
set magic
|
||||
q!
|
||||
endfunc
|
||||
|
||||
func Test_searchpair_errors()
|
||||
call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
|
||||
call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
|
||||
call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
|
||||
call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
|
||||
call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
|
||||
call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
|
||||
call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
|
||||
endfunc
|
||||
|
||||
func Test_searchpair_skip()
|
||||
func Zero()
|
||||
return 0
|
||||
endfunc
|
||||
func Partial(x)
|
||||
return a:x
|
||||
endfunc
|
||||
new
|
||||
call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
|
||||
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
|
||||
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
|
||||
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
|
||||
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
|
||||
3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_searchpair_leak()
|
||||
new
|
||||
call setline(1, 'if one else another endif')
|
||||
|
||||
" The error in the skip expression caused memory to leak.
|
||||
call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
|
||||
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
func Test_searchc()
|
||||
" These commands used to cause memory overflow in searchc().
|
||||
new
|
||||
|
@ -42,6 +42,22 @@ func Test_paste_end_of_line()
|
||||
set virtualedit=
|
||||
endfunc
|
||||
|
||||
func Test_replace_end_of_line()
|
||||
new
|
||||
set virtualedit=all
|
||||
call setline(1, range(20))
|
||||
exe "normal! gg2jv10lr-"
|
||||
call assert_equal(["1", "-----------", "3"], getline(2,4))
|
||||
if has('multi_byte')
|
||||
call setline(1, range(20))
|
||||
exe "normal! gg2jv10lr\<c-k>hh"
|
||||
call assert_equal(["1", "───────────", "3"], getline(2,4))
|
||||
endif
|
||||
|
||||
bwipe!
|
||||
set virtualedit=
|
||||
endfunc
|
||||
|
||||
func Test_edit_CTRL_G()
|
||||
new
|
||||
set virtualedit=insert
|
||||
|
Loading…
Reference in New Issue
Block a user