aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/README.md26
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/diff.c95
-rw-r--r--src/nvim/eval.c290
-rw-r--r--src/nvim/ex_cmds.c22
-rw-r--r--src/nvim/ex_docmd.c19
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/fileio.c15
-rw-r--r--src/nvim/fold.c6
-rw-r--r--src/nvim/main.c42
-rw-r--r--src/nvim/normal.c25
-rw-r--r--src/nvim/syntax.c29
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test45.in80
-rw-r--r--src/nvim/testdir/test45.ok18
-rw-r--r--src/nvim/testdir/test47.in45
-rw-r--r--src/nvim/testdir/test47.ok40
-rw-r--r--src/nvim/testdir/test55.in11
-rw-r--r--src/nvim/testdir/test55.ok3
-rw-r--r--src/nvim/testdir/test_listlbr.in6
-rw-r--r--src/nvim/testdir/test_listlbr.ok5
-rw-r--r--src/nvim/version.c44
22 files changed, 456 insertions, 374 deletions
diff --git a/src/nvim/README.md b/src/nvim/README.md
index e4939d94fd..f16c6de12f 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -11,7 +11,7 @@ that are constantly changing. As the code becomes more organized and stable,
this document will be updated to reflect the changes.
If you are looking for module-specific details, it is best to read the source
-code. Some files are extensively commented at the top(eg: terminal.c,
+code. Some files are extensively commented at the top (e.g. terminal.c,
screen.c).
### Top-level program loops
@@ -43,13 +43,13 @@ a typical editing session:
Note that we have split user actions into sequences of inputs that change the
state of the editor. While there's no documentation about a "g command
-mode"(step 16), internally it is implemented similarly to "operator-pending
+mode" (step 16), internally it is implemented similarly to "operator-pending
mode".
From this we can see that Vim has the behavior of a input-driven state
-machine(more specifically, a pushdown automaton since it requires a stack for
+machine (more specifically, a pushdown automaton since it requires a stack for
transitioning back from states). Assuming each state has a callback responsible
-for handling keys, this pseudocode(a python-like language) shows a good
+for handling keys, this pseudocode (a python-like language) shows a good
representation of the main program loop:
```py
@@ -129,20 +129,20 @@ def insert_state(data, key):
While the actual code is much more complicated, the above gives an idea of how
Neovim is organized internally. Some states like the `g_command_state` or
`get_operator_count_state` do not have a dedicated `state_enter` callback, but
-are implicitly embedded into other states(this will change later as we continue
+are implicitly embedded into other states (this will change later as we continue
the refactoring effort). To start reading the actual code, here's the
recommended order:
-1. `state_enter()` function(state.c). This is the actual program loop,
+1. `state_enter()` function (state.c). This is the actual program loop,
note that a `VimState` structure is used, which contains function pointers
for the callback and state data.
-2. `main()` function(main.c). After all startup, `normal_enter` is called
+2. `main()` function (main.c). After all startup, `normal_enter` is called
at the end of function to enter normal mode.
-3. `normal_enter()` function(normal.c) is a small wrapper for setting
+3. `normal_enter()` function (normal.c) is a small wrapper for setting
up the NormalState structure and calling `state_enter`.
-4. `normal_check()` function(normal.c) is called before each iteration of
+4. `normal_check()` function (normal.c) is called before each iteration of
normal mode.
-5. `normal_execute()` function(normal.c) is called when a key is read in normal
+5. `normal_execute()` function (normal.c) is called when a key is read in normal
mode.
The basic structure described for normal mode in 3, 4 and 5 is used for other
@@ -159,7 +159,7 @@ asynchronous events, which can include:
- msgpack-rpc requests
- job control callbacks
-- timers(not implemented yet but the support code is already there)
+- timers (not implemented yet but the support code is already there)
Neovim implements this functionality by entering another event loop while
waiting for characters, so instead of:
@@ -180,11 +180,11 @@ def state_enter(state_callback, data):
while state_callback(data, event) # invoke the callback for the current state
```
-where `event` is something the operating system delivers to us, including(but
+where `event` is something the operating system delivers to us, including (but
not limited to) user input. The `read_next_event()` part is internally
implemented by libuv, the platform layer used by Neovim.
Since Neovim inherited its code from Vim, the states are not prepared to receive
-"arbitrary events", so we use a special key to represent those(When a state
+"arbitrary events", so we use a special key to represent those (When a state
receives an "arbitrary event", it normally doesn't do anything other update the
screen).
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 34e24712cd..f56c64f109 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3895,6 +3895,11 @@ void get_rel_pos(win_T *wp, char_u *buf, int buflen)
above = wp->w_topline - 1;
above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
+ if (wp->w_topline == 1 && wp->w_topfill >= 1) {
+ // All buffer lines are displayed and there is an indication
+ // of filler lines, that can be considered seeing all lines.
+ above = 0;
+ }
below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
if (below <= 0)
STRLCPY(buf, (above == 0 ? _("All") : _("Bot")), buflen);
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index ce79158050..e06ffd0bbc 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -763,8 +763,8 @@ void ex_diffupdate(exarg_T *eap)
// Make a difference between the first buffer and every other.
for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new) {
buf_T *buf = curtab->tp_diffbuf[idx_new];
- if (buf == NULL) {
- continue;
+ if (buf == NULL || buf->b_ml.ml_mfp == NULL) {
+ continue; // skip buffer that isn't loaded
}
if (diff_write(buf, tmp_new) == FAIL) {
@@ -1057,27 +1057,28 @@ void diff_win_options(win_T *wp, int addbuf)
newFoldLevel();
curwin = old_curwin;
- wp->w_p_diff = TRUE;
-
// Use 'scrollbind' and 'cursorbind' when available
- if (!wp->w_p_diff_saved) {
+ if (!wp->w_p_diff) {
wp->w_p_scb_save = wp->w_p_scb;
}
wp->w_p_scb = TRUE;
- if (!wp->w_p_diff_saved) {
+ if (!wp->w_p_diff) {
wp->w_p_crb_save = wp->w_p_crb;
}
wp->w_p_crb = TRUE;
- if (!wp->w_p_diff_saved) {
+ if (!wp->w_p_diff) {
wp->w_p_wrap_save = wp->w_p_wrap;
}
wp->w_p_wrap = FALSE;
curwin = wp;
curbuf = curwin->w_buffer;
- if (!wp->w_p_diff_saved) {
+ if (!wp->w_p_diff) {
+ if (wp->w_p_diff_saved) {
+ free_string_option(wp->w_p_fdm_save);
+ }
wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm);
}
set_string_option_direct((char_u *)"fdm", -1, (char_u *)"diff",
@@ -1085,7 +1086,7 @@ void diff_win_options(win_T *wp, int addbuf)
curwin = old_curwin;
curbuf = curwin->w_buffer;
- if (!wp->w_p_diff_saved) {
+ if (!wp->w_p_diff) {
wp->w_p_fdc_save = wp->w_p_fdc;
wp->w_p_fen_save = wp->w_p_fen;
wp->w_p_fdl_save = wp->w_p_fdl;
@@ -1104,6 +1105,8 @@ void diff_win_options(win_T *wp, int addbuf)
// Saved the current values, to be restored in ex_diffoff().
wp->w_p_diff_saved = TRUE;
+ wp->w_p_diff = true;
+
if (addbuf) {
diff_buf_add(wp->w_buffer);
}
@@ -1116,68 +1119,50 @@ void diff_win_options(win_T *wp, int addbuf)
/// @param eap
void ex_diffoff(exarg_T *eap)
{
- win_T *old_curwin = curwin;
- int diffwin = FALSE;
+ int diffwin = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (eap->forceit ? wp->w_p_diff : (wp == curwin)) {
- // Set 'diff', 'scrollbind' off and 'wrap' on. If option values
- // were saved in diff_win_options() restore them.
- wp->w_p_diff = FALSE;
-
- if (wp->w_p_scb) {
- wp->w_p_scb = wp->w_p_diff_saved ? wp->w_p_scb_save : FALSE;
- }
-
- if (wp->w_p_crb) {
- wp->w_p_crb = wp->w_p_diff_saved ? wp->w_p_crb_save : FALSE;
- }
-
- if (!wp->w_p_wrap) {
- wp->w_p_wrap = wp->w_p_diff_saved ? wp->w_p_wrap_save : TRUE;
- }
- curwin = wp;
- curbuf = curwin->w_buffer;
+ // Set 'diff' off. If option values were saved in
+ // diff_win_options(), restore the ones whose settings seem to have
+ // been left over from diff mode.
+ wp->w_p_diff = false;
if (wp->w_p_diff_saved) {
- free_string_option(wp->w_p_fdm);
- wp->w_p_fdm = wp->w_p_fdm_save;
- wp->w_p_fdm_save = empty_option;
- } else {
- set_string_option_direct((char_u *)"fdm", -1,
- (char_u *)"manual", OPT_LOCAL | OPT_FREE, 0);
- }
- curwin = old_curwin;
- curbuf = curwin->w_buffer;
+ if (wp->w_p_scb) {
+ wp->w_p_scb = wp->w_p_scb_save;
+ }
- if (wp->w_p_fdc == diff_foldcolumn) {
- wp->w_p_fdc = wp->w_p_diff_saved ? wp->w_p_fdc_save : 0;
- }
+ if (wp->w_p_crb) {
+ wp->w_p_crb = wp->w_p_crb_save;
+ }
- if ((wp->w_p_fdl == 0)
- && wp->w_p_diff_saved) {
- wp->w_p_fdl = wp->w_p_fdl_save;
- }
+ if (!wp->w_p_wrap) {
+ wp->w_p_wrap = wp->w_p_wrap_save;
+ }
- if (wp->w_p_fen) {
+ free_string_option(wp->w_p_fdm);
+ wp->w_p_fdm = vim_strsave(wp->w_p_fdm_save);
+ if (wp->w_p_fdc == diff_foldcolumn) {
+ wp->w_p_fdc = wp->w_p_fdc_save;
+ }
+ if (wp->w_p_fdl == 0) {
+ wp->w_p_fdl = wp->w_p_fdl_save;
+ }
// Only restore 'foldenable' when 'foldmethod' is not
// "manual", otherwise we continue to show the diff folds.
- if (foldmethodIsManual(wp) || !wp->w_p_diff_saved) {
- wp->w_p_fen = FALSE;
- } else {
- wp->w_p_fen = wp->w_p_fen_save;
+ if (wp->w_p_fen) {
+ wp->w_p_fen = foldmethodIsManual(wp) ? false : wp->w_p_fen_save;
}
- }
- foldUpdateAll(wp);
+ foldUpdateAll(wp);
- // make sure topline is not halfway through a fold
- changed_window_setting_win(wp);
+ // make sure topline is not halfway through a fold
+ changed_window_setting_win(wp);
+ }
// Note: 'sbo' is not restored, it's a global option.
diff_buf_adjust(wp);
-
- wp->w_p_diff_saved = FALSE;
}
diffwin |= wp->w_p_diff;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a9af7d94c1..7ca1f1512e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1700,12 +1700,13 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first)
}
error = TRUE;
} else {
- if (tofree != NULL)
+ if (tofree != NULL) {
name = tofree;
- if (get_var_tv(name, len, &tv, TRUE, FALSE) == FAIL)
- error = TRUE;
- else {
- /* handle d.key, l[idx], f(expr) */
+ }
+ if (get_var_tv(name, len, &tv, NULL, true, false) == FAIL) {
+ error = true;
+ } else {
+ // handle d.key, l[idx], f(expr)
arg_subsc = arg;
if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL)
error = TRUE;
@@ -2176,10 +2177,10 @@ get_lval (
if (len == -1)
clear_tv(&var1);
break;
- }
- /* existing variable, need to check if it can be changed */
- else if (var_check_ro(lp->ll_di->di_flags, name))
+ } else if (var_check_ro(lp->ll_di->di_flags, name, false)) {
+ // existing variable, need to check if it can be changed
return NULL;
+ }
if (len == -1)
clear_tv(&var1);
@@ -2274,11 +2275,16 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
if (op != NULL && *op != '=') {
typval_T tv;
- /* handle +=, -= and .= */
+ // handle +=, -= and .=
+ di = NULL;
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
- &tv, TRUE, FALSE) == OK) {
- if (tv_op(&tv, rettv, op) == OK)
- set_var(lp->ll_name, &tv, FALSE);
+ &tv, &di, true, false) == OK) {
+ if ((di == NULL
+ || (!var_check_ro(di->di_flags, lp->ll_name, false) &&
+ !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
+ && tv_op(&tv, rettv, op) == OK) {
+ set_var(lp->ll_name, &tv, false);
+ }
clear_tv(&tv);
}
} else
@@ -2286,16 +2292,17 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
*endp = cc;
}
} else if (tv_check_lock(lp->ll_newkey == NULL
- ? lp->ll_tv->v_lock
- : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name))
- ;
- else if (lp->ll_range) {
+ ? lp->ll_tv->v_lock
+ : lp->ll_tv->vval.v_dict->dv_lock,
+ lp->ll_name, false)) {
+ } else if (lp->ll_range) {
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
// Check whether any of the list items is locked
- for (listitem_T *ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) {
- if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) {
+ for (listitem_T *ri = rettv->vval.v_list->lv_first;
+ ri != NULL && ll_li != NULL; ) {
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) {
return;
}
ri = ri->li_next;
@@ -2891,9 +2898,9 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
ret = FAIL;
*name_end = cc;
} else if ((lp->ll_list != NULL
- && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name))
+ && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name, false))
|| (lp->ll_dict != NULL
- && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name))) {
+ && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name, false))) {
return FAIL;
} else if (lp->ll_range) {
listitem_T *li;
@@ -2902,7 +2909,7 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) {
li = ll_li->li_next;
- if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name)) {
+ if (tv_check_lock(ll_li->li_tv.v_lock, lp->ll_name, false)) {
return false;
}
ll_li = li;
@@ -2975,9 +2982,9 @@ int do_unlet(char_u *name, int forceit)
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi)) {
di = HI2DI(hi);
- if (var_check_fixed(di->di_flags, name)
- || var_check_ro(di->di_flags, name)
- || tv_check_lock(d->dv_lock, name)) {
+ if (var_check_fixed(di->di_flags, name, false)
+ || var_check_ro(di->di_flags, name, false)
+ || tv_check_lock(d->dv_lock, name, false)) {
return FAIL;
}
typval_T oldtv;
@@ -3045,12 +3052,13 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
li = li->li_next;
++lp->ll_n1;
}
- } else if (lp->ll_list != NULL)
- /* (un)lock a List item. */
+ } else if (lp->ll_list != NULL) {
+ // (un)lock a List item.
item_lock(&lp->ll_li->li_tv, deep, lock);
- else
- /* un(lock) a Dictionary item. */
+ } else {
+ // (un)lock a Dictionary item.
item_lock(&lp->ll_di->di_tv, deep, lock);
+ }
return ret;
}
@@ -4239,7 +4247,7 @@ static int eval7(
ret = FAIL;
}
} else if (evaluate) {
- ret = get_var_tv(s, len, rettv, true, false);
+ ret = get_var_tv(s, len, rettv, NULL, true, false);
} else {
ret = OK;
}
@@ -7337,7 +7345,7 @@ static struct fst {
{ "sqrt", 1, 1, f_sqrt },
{ "str2float", 1, 1, f_str2float },
{ "str2nr", 1, 2, f_str2nr },
- { "strchars", 1, 1, f_strchars },
+ { "strchars", 1, 2, f_strchars },
{ "strdisplaywidth", 1, 2, f_strdisplaywidth },
{ "strftime", 1, 2, f_strftime },
{ "stridx", 2, 3, f_stridx },
@@ -7855,7 +7863,8 @@ static void f_add(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1; /* Default: Failed */
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("add() argument"))) {
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("add() argument"), true)) {
list_append_tv(l, &argvars[1]);
copy_tv(&argvars[0], rettv);
}
@@ -9130,9 +9139,10 @@ static void f_exists(typval_T *argvars, typval_T *rettv)
name = p;
len = get_name_len(&p, &tofree, TRUE, FALSE);
if (len > 0) {
- if (tofree != NULL)
+ if (tofree != NULL) {
name = tofree;
- n = (get_var_tv(name, len, &tv, FALSE, TRUE) == OK);
+ }
+ n = (get_var_tv(name, len, &tv, NULL, false, true) == OK);
if (n) {
/* handle d.key, l[idx], f(expr) */
n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
@@ -9230,7 +9240,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
hashitem_T *hi2;
int todo;
bool watched = is_watched(d1);
- char *arg_errmsg = N_("extend() argument");
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
todo = (int)d2->dv_hashtab.ht_used;
for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) {
@@ -9264,8 +9274,8 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
} else if (*action == 'f' && HI2DI(hi2) != di1) {
typval_T oldtv;
- if (tv_check_lock(di1->di_tv.v_lock, (char_u *)_(arg_errmsg))
- || var_check_ro(di1->di_flags, (char_u *)_(arg_errmsg))) {
+ if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, true)
+ || var_check_ro(di1->di_flags, arg_errmsg, true)) {
break;
}
@@ -9291,7 +9301,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
*/
static void f_extend(typval_T *argvars, typval_T *rettv)
{
- char *arg_errmsg = N_("extend() argument");
+ char_u *arg_errmsg = (char_u *)N_("extend() argument");
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
list_T *l1, *l2;
@@ -9301,7 +9311,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv)
l1 = argvars[0].vval.v_list;
l2 = argvars[1].vval.v_list;
- if (l1 != NULL && !tv_check_lock(l1->lv_lock, (char_u *)_(arg_errmsg))
+ if (l1 != NULL && !tv_check_lock(l1->lv_lock, arg_errmsg, true)
&& l2 != NULL) {
if (argvars[2].v_type != VAR_UNKNOWN) {
before = get_tv_number_chk(&argvars[2], &error);
@@ -9331,7 +9341,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv)
d1 = argvars[0].vval.v_dict;
d2 = argvars[1].vval.v_dict;
- if (d1 != NULL && !tv_check_lock(d1->dv_lock, (char_u *)_(arg_errmsg))
+ if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, true)
&& d2 != NULL) {
/* Check the third argument. */
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -9477,19 +9487,19 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
int rem;
int todo;
char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
- char *arg_errmsg = (map ? N_("map() argument")
- : N_("filter() argument"));
+ char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
+ : N_("filter() argument"));
int save_did_emsg;
int idx = 0;
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) == NULL
- || (!map && tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))) {
+ || (!map && tv_check_lock(l->lv_lock, arg_errmsg, true))) {
return;
}
} else if (argvars[0].v_type == VAR_DICT) {
if ((d = argvars[0].vval.v_dict) == NULL
- || (!map && tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))) {
+ || (!map && tv_check_lock(d->dv_lock, arg_errmsg, true))) {
return;
}
} else {
@@ -9523,8 +9533,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
di = HI2DI(hi);
if (map
- && (tv_check_lock(di->di_tv.v_lock, (char_u *)_(arg_errmsg))
- || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg)))) {
+ && (tv_check_lock(di->di_tv.v_lock, arg_errmsg, true)
+ || var_check_ro(di->di_flags, arg_errmsg, true))) {
break;
}
@@ -9534,8 +9544,8 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
if (r == FAIL || did_emsg)
break;
if (!map && rem) {
- if (var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg))
- || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) {
+ if (var_check_fixed(di->di_flags, arg_errmsg, true)
+ || var_check_ro(di->di_flags, arg_errmsg, true)) {
break;
}
dictitem_remove(d, di);
@@ -9547,7 +9557,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
vimvars[VV_KEY].vv_type = VAR_NUMBER;
for (li = l->lv_first; li != NULL; li = nli) {
- if (map && tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg))) {
+ if (map && tv_check_lock(li->li_tv.v_lock, arg_errmsg, true)) {
break;
}
nli = li->li_next;
@@ -11442,14 +11452,18 @@ static void f_insert(typval_T *argvars, typval_T *rettv)
list_T *l;
int error = FALSE;
- if (argvars[0].v_type != VAR_LIST)
+ if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "insert()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("insert() argument"))) {
- if (argvars[2].v_type != VAR_UNKNOWN)
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("insert() argument"), true)) {
+ if (argvars[2].v_type != VAR_UNKNOWN) {
before = get_tv_number_chk(&argvars[2], &error);
- if (error)
- return; /* type error; errmsg already given */
+ }
+ if (error) {
+ // type error; errmsg already given
+ return;
+ }
if (before == l->lv_len)
item = NULL;
@@ -13903,20 +13917,20 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
char_u *key;
dict_T *d;
dictitem_T *di;
- char *arg_errmsg = N_("remove() argument");
+ char_u *arg_errmsg = (char_u *)N_("remove() argument");
if (argvars[0].v_type == VAR_DICT) {
- if (argvars[2].v_type != VAR_UNKNOWN)
+ if (argvars[2].v_type != VAR_UNKNOWN) {
EMSG2(_(e_toomanyarg), "remove()");
- else if ((d = argvars[0].vval.v_dict) != NULL
- && !tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg))) {
+ } else if ((d = argvars[0].vval.v_dict) != NULL
+ && !tv_check_lock(d->dv_lock, arg_errmsg, true)) {
key = get_tv_string_chk(&argvars[1]);
if (key != NULL) {
di = dict_find(d, key, -1);
if (di == NULL) {
EMSG2(_(e_dictkey), key);
- } else if (!var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg))
- && !var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) {
+ } else if (!var_check_fixed(di->di_flags, arg_errmsg, true)
+ && !var_check_ro(di->di_flags, arg_errmsg, true)) {
*rettv = di->di_tv;
init_tv(&di->di_tv);
dictitem_remove(d, di);
@@ -13926,11 +13940,11 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
}
}
}
- } else if (argvars[0].v_type != VAR_LIST)
+ } else if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listdictarg), "remove()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg))) {
- int error = FALSE;
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock, arg_errmsg, true)) {
+ int error = (int)false;
idx = get_tv_number_chk(&argvars[1], &error);
if (error)
@@ -14204,10 +14218,11 @@ static void f_reverse(typval_T *argvars, typval_T *rettv)
list_T *l;
listitem_T *li, *ni;
- if (argvars[0].v_type != VAR_LIST)
+ if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "reverse()");
- else if ((l = argvars[0].vval.v_list) != NULL
- && !tv_check_lock(l->lv_lock, (char_u *)_("reverse() argument"))) {
+ } else if ((l = argvars[0].vval.v_list) != NULL
+ && !tv_check_lock(l->lv_lock,
+ (char_u *)N_("reverse() argument"), true)) {
li = l->lv_last;
l->lv_first = l->lv_last = NULL;
l->lv_len = 0;
@@ -15741,8 +15756,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
l = argvars[0].vval.v_list;
- if (l == NULL || tv_check_lock(l->lv_lock,
- (char_u *)(sort ? _("sort() argument") : _("uniq() argument")))) {
+ if (l == NULL ||
+ tv_check_lock(l->lv_lock,
+ (char_u *)(sort
+ ? N_("sort() argument")
+ : N_("uniq() argument")),
+ true)) {
return;
}
rettv->vval.v_list = l;
@@ -16213,13 +16232,23 @@ static void f_strlen(typval_T *argvars, typval_T *rettv)
static void f_strchars(typval_T *argvars, typval_T *rettv)
{
char_u *s = get_tv_string(&argvars[0]);
+ int skipcc = 0;
varnumber_T len = 0;
+ int (*func_mb_ptr2char_adv)(char_u **pp);
- while (*s != NUL) {
- mb_cptr2char_adv(&s);
- ++len;
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ skipcc = get_tv_number_chk(&argvars[1], NULL);
+ }
+ if (skipcc < 0 || skipcc > 1) {
+ EMSG(_(e_invarg));
+ } else {
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL) {
+ func_mb_ptr2char_adv(&s);
+ ++len;
+ }
+ rettv->vval.v_number = len;
}
- rettv->vval.v_number = len;
}
/*
@@ -18155,10 +18184,11 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
static int
get_var_tv (
char_u *name,
- int len, /* length of "name" */
- typval_T *rettv, /* NULL when only checking existence */
- int verbose, /* may give error message */
- int no_autoload /* do not use script autoloading */
+ int len, // length of "name"
+ typval_T *rettv, // NULL when only checking existence
+ dictitem_T **dip, // non-NULL when typval's dict item is needed
+ int verbose, // may give error message
+ int no_autoload // do not use script autoloading
)
{
int ret = OK;
@@ -18184,8 +18214,12 @@ get_var_tv (
*/
else {
v = find_var(name, NULL, no_autoload);
- if (v != NULL)
+ if (v != NULL) {
tv = &v->di_tv;
+ if (dip != NULL) {
+ *dip = v;
+ }
+ }
}
if (tv == NULL) {
@@ -18576,6 +18610,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
hashitem_T *hi;
*d = NULL;
+ if (name[0] == NUL) {
+ return NULL;
+ }
if (name[1] != ':') {
// name has implicit scope
if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) {
@@ -18625,6 +18662,7 @@ end:
}
// Find the hashtab used for a variable name.
+// Return NULL if the name is not valid.
// Set "varname" to the start of name without ':'.
static hashtab_T *find_var_ht(uint8_t *name, uint8_t **varname)
{
@@ -18848,10 +18886,11 @@ set_var (
return;
if (v != NULL) {
- /* existing variable, need to clear the value */
- if (var_check_ro(v->di_flags, name)
- || tv_check_lock(v->di_tv.v_lock, name))
+ // existing variable, need to clear the value
+ if (var_check_ro(v->di_flags, name, false)
+ || tv_check_lock(v->di_tv.v_lock, name, false)) {
return;
+ }
if (v->di_tv.v_type != tv->v_type
&& !((v->di_tv.v_type == VAR_STRING
|| v->di_tv.v_type == VAR_NUMBER)
@@ -18866,10 +18905,8 @@ set_var (
return;
}
- /*
- * Handle setting internal v: variables separately: we don't change
- * the type.
- */
+ // Handle setting internal v: variables separately where needed to
+ // prevent changing the type.
if (ht == &vimvarht) {
if (v->di_tv.v_type == VAR_STRING) {
xfree(v->di_tv.vval.v_string);
@@ -18880,9 +18917,8 @@ set_var (
v->di_tv.vval.v_string = tv->vval.v_string;
tv->vval.v_string = NULL;
}
- } else if (v->di_tv.v_type != VAR_NUMBER)
- EMSG2(_(e_intern2), "set_var()");
- else {
+ return;
+ } else if (v->di_tv.v_type == VAR_NUMBER) {
v->di_tv.vval.v_number = get_tv_number(tv);
if (STRCMP(varname, "searchforward") == 0)
set_search_direction(v->di_tv.vval.v_number ? '/' : '?');
@@ -18890,8 +18926,10 @@ set_var (
no_hlsearch = !v->di_tv.vval.v_number;
redraw_all_later(SOME_VALID);
}
+ return;
+ } else if (v->di_tv.v_type != tv->v_type) {
+ EMSG2(_(e_intern2), "set_var()");
}
- return;
}
if (watched) {
@@ -18936,34 +18974,31 @@ set_var (
}
}
-/*
- * Return TRUE if di_flags "flags" indicates variable "name" is read-only.
- * Also give an error message.
- */
-static int var_check_ro(int flags, char_u *name)
+// Return true if di_flags "flags" indicates variable "name" is read-only.
+// Also give an error message.
+static bool var_check_ro(int flags, char_u *name, bool use_gettext)
{
if (flags & DI_FLAGS_RO) {
- EMSG2(_(e_readonlyvar), name);
- return TRUE;
+ EMSG2(_(e_readonlyvar), use_gettext ? (char_u *)_(name) : name);
+ return true;
}
if ((flags & DI_FLAGS_RO_SBX) && sandbox) {
- EMSG2(_(e_readonlysbx), name);
- return TRUE;
+ EMSG2(_(e_readonlysbx), use_gettext ? (char_u *)_(name) : name);
+ return true;
}
- return FALSE;
+ return false;
}
-/*
- * Return TRUE if di_flags "flags" indicates variable "name" is fixed.
- * Also give an error message.
- */
-static int var_check_fixed(int flags, char_u *name)
+// Return true if di_flags "flags" indicates variable "name" is fixed.
+// Also give an error message.
+static bool var_check_fixed(int flags, char_u *name, bool use_gettext)
{
if (flags & DI_FLAGS_FIX) {
- EMSG2(_("E795: Cannot delete variable %s"), name);
- return TRUE;
+ EMSG2(_("E795: Cannot delete variable %s"),
+ use_gettext ? (char_u *)_(name) : name);
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -19011,23 +19046,28 @@ static int valid_varname(char_u *varname)
return TRUE;
}
-/*
- * Return TRUE if typeval "tv" is set to be locked (immutable).
- * Also give an error message, using "name".
- */
-static int tv_check_lock(int lock, char_u *name)
+// Return true if typeval "tv" is set to be locked (immutable).
+// Also give an error message, using "name" or _("name") when use_gettext is
+// true.
+static bool tv_check_lock(int lock, char_u *name, bool use_gettext)
{
if (lock & VAR_LOCKED) {
EMSG2(_("E741: Value is locked: %s"),
- name == NULL ? (char_u *)_("Unknown") : name);
- return TRUE;
+ name == NULL
+ ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return true;
}
if (lock & VAR_FIXED) {
EMSG2(_("E742: Cannot change value of %s"),
- name == NULL ? (char_u *)_("Unknown") : name);
- return TRUE;
+ name == NULL
+ ? (char_u *)_("Unknown")
+ : use_gettext ? (char_u *)_(name)
+ : name);
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -19620,7 +19660,10 @@ void ex_function(exarg_T *eap)
break;
}
}
- ++p; /* skip the ')' */
+ if (*p != ')') {
+ goto erret;
+ }
+ ++p; // skip the ')'
/* find extra arguments "range", "dict" and "abort" */
for (;; ) {
@@ -19844,13 +19887,14 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fudi.fd_di == NULL) {
- /* Can't add a function to a locked dictionary */
- if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg))
+ if (tv_check_lock(fudi.fd_dict->dv_lock, eap->arg, false)) {
+ // Can't add a function to a locked dictionary
goto erret;
- }
- /* Can't change an existing function if it is locked */
- else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg))
+ }
+ } else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, false)) {
+ // Can't change an existing function if it is locked
goto erret;
+ }
/* Give the function a sequential number. Can only be used with a
* Funcref! */
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a517037431..4d62dd0ff9 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -690,9 +690,17 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
{
char_u *str;
linenr_T l;
- linenr_T extra; /* Num lines added before line1 */
- linenr_T num_lines; /* Num lines moved */
- linenr_T last_line; /* Last line in file after adding new text */
+ linenr_T extra; // Num lines added before line1
+ linenr_T num_lines; // Num lines moved
+ linenr_T last_line; // Last line in file after adding new text
+
+ // Moving lines seems to corrupt the folds, delete folding info now
+ // and recreate it when finished. Don't do this for manual folding, it
+ // would delete all folds.
+ bool isFolded = hasAnyFolding(curwin) && !foldmethodIsManual(curwin);
+ if (isFolded) {
+ deleteFoldRecurse(&curwin->w_folds);
+ }
if (dest >= line1 && dest < line2) {
EMSG(_("E134: Move lines into themselves"));
@@ -777,8 +785,14 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
if (dest > last_line + 1)
dest = last_line + 1;
changed_lines(line1, 0, dest, 0L);
- } else
+ } else {
changed_lines(dest + 1, 0, line1 + num_lines, 0L);
+ }
+
+ // recreate folds
+ if (isFolded) {
+ foldUpdateAll(curwin);
+ }
return OK;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index cb8f91328d..50513c0a6a 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1702,9 +1702,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
p = vim_strnsave(ea.cmd, p - ea.cmd);
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL);
xfree(p);
- if (ret && !aborting()) {
- p = find_command(&ea, NULL);
- }
+ // If the autocommands did something and didn't cause an error, try
+ // finding the command again.
+ p = (ret && !aborting()) ? find_command(&ea, NULL) : NULL;
}
if (p == NULL) {
@@ -2348,8 +2348,11 @@ static char_u *find_command(exarg_T *eap, int *full)
eap->cmdidx = CMD_k;
++p;
} else if (p[0] == 's'
- && ((p[1] == 'c' && p[2] != 's' && p[2] != 'r'
- && p[3] != 'i' && p[4] != 'p')
+ && ((p[1] == 'c'
+ && (p[2] == NUL
+ || (p[2] != 's' && p[2] != 'r'
+ && (p[3] == NUL
+ || (p[3] != 'i' && p[4] != 'p')))))
|| p[1] == 'g'
|| (p[1] == 'i' && p[2] != 'm' && p[2] != 'l' && p[2] != 'g')
|| p[1] == 'I'
@@ -8368,8 +8371,7 @@ makeopens (
{
int only_save_windows = TRUE;
int nr;
- int cnr = 1;
- int restore_size = TRUE;
+ int restore_size = true;
win_T *wp;
char_u *sname;
win_T *edited_win = NULL;
@@ -8486,7 +8488,8 @@ makeopens (
tab_firstwin = firstwin; /* first window in tab page "tabnr" */
tab_topframe = topframe;
for (tabnr = 1;; ++tabnr) {
- int need_tabnew = FALSE;
+ int need_tabnew = false;
+ int cnr = 1;
if ((ssop_flags & SSOP_TABPAGES)) {
tabpage_T *tp = find_tabpage(tabnr);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 96bf2c78d2..d015f6b4a0 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -5136,6 +5136,8 @@ static int ex_window(void)
/* Don't execute autocommands while deleting the window. */
block_autocmds();
+ // Avoid command-line window first character being concealed
+ curwin->w_p_cole = 0;
wp = curwin;
bp = curbuf;
win_goto(old_curwin);
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 90987d0b3d..383cd47dbe 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -7160,10 +7160,11 @@ char_u * file_pat_to_reg_pat(
else
reg_pat[i++] = '^';
endp = pat_end - 1;
- if (*endp == '*') {
- while (endp - pat > 0 && *endp == '*')
+ if (endp >= pat && *endp == '*') {
+ while (endp - pat > 0 && *endp == '*') {
endp--;
- add_dollar = FALSE;
+ }
+ add_dollar = false;
}
for (p = pat; *p && nested >= 0 && p <= endp; p++) {
switch (*p) {
@@ -7218,12 +7219,12 @@ char_u * file_pat_to_reg_pat(
#ifdef BACKSLASH_IN_FILENAME
&& no_bslash
#endif
- )
+ ) {
reg_pat[i++] = '?';
- else if (*p == ',' || *p == '%' || *p == '#'
- || *p == ' ' || *p == '{' || *p == '}')
+ } else if (*p == ',' || *p == '%' || *p == '#'
+ || ascii_isspace(*p) || *p == '{' || *p == '}') {
reg_pat[i++] = *p;
- else if (*p == '\\' && p[1] == '\\' && p[2] == '{') {
+ } else if (*p == '\\' && p[1] == '\\' && p[2] == '{') {
reg_pat[i++] = '\\';
reg_pat[i++] = '{';
p += 2;
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 2e32e78062..6c135ef47b 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -767,9 +767,9 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
return;
}
- /* Mark all folds from top to bot as maybe-small. */
- (void)foldFind(&curwin->w_folds, top, &fp);
- while (fp < (fold_T *)curwin->w_folds.ga_data + curwin->w_folds.ga_len
+ // Mark all folds from top to bot as maybe-small.
+ (void)foldFind(&wp->w_folds, top, &fp);
+ while (fp < (fold_T *)wp->w_folds.ga_data + wp->w_folds.ga_len
&& fp->fd_top < bot) {
fp->fd_small = MAYBE;
++fp;
diff --git a/src/nvim/main.c b/src/nvim/main.c
index cef10d12d5..a8c2cebbbd 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -219,9 +219,10 @@ int main(int argc, char **argv)
{
argv0 = (char *)path_tail((char_u *)argv[0]);
- char_u *fname = NULL; /* file name from command line */
- mparm_T params; /* various parameters passed between
- * main() and other functions. */
+ char_u *fname = NULL; // file name from command line
+ mparm_T params; // various parameters passed between
+ // main() and other functions.
+ char_u *cwd = NULL; // current workding dir on startup
time_init();
/* Many variables are in "params" so that we can pass them to invoked
@@ -461,11 +462,10 @@ int main(int argc, char **argv)
TIME_MSG("jump to first error");
}
- /*
- * If opened more than one window, start editing files in the other
- * windows.
- */
- edit_buffers(&params);
+ // If opened more than one window, start editing files in the other
+ // windows.
+ edit_buffers(&params, cwd);
+ xfree(cwd);
if (params.diff_mode) {
/* set options in each window for "nvim -d". */
@@ -1182,12 +1182,19 @@ static char_u *get_fname(mparm_T *parmp)
* Expand wildcards in file names.
*/
if (!parmp->literal) {
- /* Temporarily add '(' and ')' to 'isfname'. These are valid
- * filename characters but are excluded from 'isfname' to make
- * "gf" work on a file name in parenthesis (e.g.: see vim.h). */
+ cwd = xmalloc(MAXPATHL);
+ if (cwd != NULL) {
+ os_dirname(cwd, MAXPATHL);
+ }
+ // Temporarily add '(' and ')' to 'isfname'. These are valid
+ // filename characters but are excluded from 'isfname' to make
+ // "gf" work on a file name in parenthesis (e.g.: see vim.h).
do_cmdline_cmd(":set isf+=(,)");
alist_expand(NULL, 0);
do_cmdline_cmd(":set isf&");
+ if (cwd != NULL) {
+ os_chdir((char *)cwd);
+ }
}
#endif
return alist_name(&GARGLIST[0]);
@@ -1417,11 +1424,9 @@ static void create_windows(mparm_T *parmp)
}
}
-/*
- * If opened more than one window, start editing files in the other
- * windows. make_windows() has already opened the windows.
- */
-static void edit_buffers(mparm_T *parmp)
+/// If opened more than one window, start editing files in the other
+/// windows. make_windows() has already opened the windows.
+static void edit_buffers(mparm_T *parmp, char_u *cwd)
{
int arg_idx; /* index in argument list */
int i;
@@ -1442,7 +1447,10 @@ static void edit_buffers(mparm_T *parmp)
arg_idx = 1;
for (i = 1; i < parmp->window_count; ++i) {
- /* When w_arg_idx is -1 remove the window (see create_windows()). */
+ if (cwd != NULL) {
+ os_chdir((char *)cwd);
+ }
+ // When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
++arg_idx;
win_close(curwin, TRUE);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e700f988f1..049d650f86 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -7804,20 +7804,23 @@ static void get_op_vcol(
}
getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
- getvvcol(curwin, &(oap->end), &start, NULL, &end);
+ if (!redo_VIsual_busy) {
+ getvvcol(curwin, &(oap->end), &start, NULL, &end);
- if (start < oap->start_vcol) {
- oap->start_vcol = start;
- }
- if (end > oap->end_vcol) {
- if (initial && *p_sel == 'e'
- && start >= 1
- && start - 1 >= oap->end_vcol) {
- oap->end_vcol = start - 1;
- } else {
- oap->end_vcol = end;
+ if (start < oap->start_vcol) {
+ oap->start_vcol = start;
+ }
+ if (end > oap->end_vcol) {
+ if (initial && *p_sel == 'e'
+ && start >= 1
+ && start - 1 >= oap->end_vcol) {
+ oap->end_vcol = start - 1;
+ } else {
+ oap->end_vcol = end;
+ }
}
}
+
// if '$' was used, get oap->end_vcol from longest line
if (curwin->w_curswant == MAXCOL) {
curwin->w_cursor.col = MAXCOL;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 24422c71fb..494683d254 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -3004,14 +3004,19 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
return;
next = skiptowhite(arg);
- if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8)
+ if (STRNICMP(arg, "toplevel", 8) == 0 && next - arg == 8) {
curwin->w_s->b_syn_spell = SYNSPL_TOP;
- else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10)
+ } else if (STRNICMP(arg, "notoplevel", 10) == 0 && next - arg == 10) {
curwin->w_s->b_syn_spell = SYNSPL_NOTOP;
- else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7)
+ } else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) {
curwin->w_s->b_syn_spell = SYNSPL_DEFAULT;
- else
+ } else {
EMSG2(_("E390: Illegal argument: %s"), arg);
+ return;
+ }
+
+ // assume spell checking changed, force a redraw
+ redraw_win_later(curwin, NOT_VALID);
}
/*
@@ -4183,12 +4188,14 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
break;
if (p[1] == NUL) {
EMSG2(_("E789: Missing ']': %s"), kw);
- kw = p + 2; /* skip over the NUL */
- break;
+ goto error;
}
if (p[1] == ']') {
- kw = p + 1; /* skip over the "]" */
- break;
+ if (p[2] != NUL) {
+ EMSG3(_("E890: trailing char after ']': %s]%s"),
+ kw, &p[2]);
+ goto error;
+ }
}
if (has_mbyte) {
int l = (*mb_ptr2len)(p + 1);
@@ -4203,6 +4210,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
}
}
+error:
xfree(keyword_copy);
xfree(syn_opt_arg.cont_in_list);
xfree(syn_opt_arg.next_list);
@@ -4843,9 +4851,10 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
int idx;
char_u *cpo_save;
- /* need at least three chars */
- if (arg == NULL || arg[1] == NUL || arg[2] == NUL)
+ // need at least three chars
+ if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) {
return NULL;
+ }
end = skip_regexp(arg + 1, *arg, TRUE, NULL);
if (*end != *arg) { /* end delimiter not found */
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index fe511166f2..d1a7abfbf7 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -15,7 +15,7 @@ SCRIPTS := \
test30.out \
test32.out test34.out \
test36.out test37.out test40.out \
- test42.out test45.out \
+ test42.out \
test47.out test48.out test49.out \
test52.out test53.out test55.out \
test64.out \
diff --git a/src/nvim/testdir/test45.in b/src/nvim/testdir/test45.in
deleted file mode 100644
index e5af5073d9..0000000000
--- a/src/nvim/testdir/test45.in
+++ /dev/null
@@ -1,80 +0,0 @@
-Tests for folding. vim: set ft=vim :
-
-STARTTEST
-:so small.vim
-:" We also need the +syntax feature here.
-:if !has("syntax")
- e! test.ok
- w! test.out
- qa!
-:endif
-:" basic test if a fold can be created, opened, moving to the end and closed
-/^1
-zf2j:call append("$", "manual " . getline(foldclosed(".")))
-zo:call append("$", foldclosed("."))
-]z:call append("$", getline("."))
-zc:call append("$", getline(foldclosed(".")))
-:" test folding with markers.
-:set fdm=marker fdl=1 fdc=3
-/^5
-:call append("$", "marker " . foldlevel("."))
-[z:call append("$", foldlevel("."))
-jo{{ r{jj:call append("$", foldlevel("."))
-kYpj:call append("$", foldlevel("."))
-:" test folding with indent
-:set fdm=indent sw=2
-/^2 b
-i jI :call append("$", "indent " . foldlevel("."))
-k:call append("$", foldlevel("."))
-:" test syntax folding
-:set fdm=syntax fdl=0
-:syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
-:syn region Fd1 start="ee" end="ff" fold contained
-:syn region Fd2 start="gg" end="hh" fold contained
-:syn region Fd3 start="commentstart" end="commentend" fold contained
-Gzk:call append("$", "folding " . getline("."))
-k:call append("$", getline("."))
-jAcommentstart Acommentend:set fdl=1
-3j:call append("$", getline("."))
-:set fdl=0
-zO j:call append("$", getline("."))
-:" test expression folding
-:fun Flvl()
- let l = getline(v:lnum)
- if l =~ "bb$"
- return 2
- elseif l =~ "gg$"
- return "s1"
- elseif l =~ "ii$"
- return ">2"
- elseif l =~ "kk$"
- return "0"
- endif
- return "="
-endfun
-:set fdm=expr fde=Flvl()
-/bb$
-:call append("$", "expr " . foldlevel("."))
-/hh$
-:call append("$", foldlevel("."))
-/ii$
-:call append("$", foldlevel("."))
-/kk$
-:call append("$", foldlevel("."))
-:/^last/+1,$w! test.out
-:delfun Flvl
-:qa!
-ENDTEST
-
-1 aa
-2 bb
-3 cc
-4 dd {{{
-5 ee {{{ }}}
-6 ff }}}
-7 gg
-8 hh
-9 ii
-a jj
-b kk
-last
diff --git a/src/nvim/testdir/test45.ok b/src/nvim/testdir/test45.ok
deleted file mode 100644
index f04996e337..0000000000
--- a/src/nvim/testdir/test45.ok
+++ /dev/null
@@ -1,18 +0,0 @@
-manual 1 aa
--1
-3 cc
-1 aa
-marker 2
-1
-1
-0
-indent 2
-1
-folding 9 ii
- 3 cc
-7 gg
-8 hh
-expr 2
-1
-2
-0
diff --git a/src/nvim/testdir/test47.in b/src/nvim/testdir/test47.in
index 13ad82462f..f15eaf0f8f 100644
--- a/src/nvim/testdir/test47.in
+++ b/src/nvim/testdir/test47.in
@@ -1,5 +1,7 @@
Tests for vertical splits and filler lines in diff mode
+Also tests restoration of saved options by :diffoff.
+
STARTTEST
:so small.vim
:" Disable the title to avoid xterm keeping the wrong one.
@@ -10,8 +12,19 @@ pkdd:w! Xtest
ddGpkkrXoxxx:w! Xtest2
:file Nop
ggoyyyjjjozzzz
+:set foldmethod=marker foldcolumn=4
+:redir => nodiffsettings
+:silent! :set diff? fdm? fdc? scb? crb? wrap?
+:redir END
:vert diffsplit Xtest
:vert diffsplit Xtest2
+:redir => diffsettings
+:silent! :set diff? fdm? fdc? scb? crb? wrap?
+:redir END
+:let diff_fdm = &fdm
+:let diff_fdc = &fdc
+:" repeat entering diff mode here to see if this saves the wrong settings
+:diffthis
:" jump to second window for a moment to have filler line appear at start of
:" first window
ggpgg:let one = winline()
@@ -36,8 +49,36 @@ j:let three = three . "-" . winline()
:call append("$", two)
:call append("$", three)
:$-2,$w! test.out
-:" Test that diffing shows correct filler lines
+:"
+:" Test diffoff
:diffoff!
+1
+:let &diff = 1
+:let &fdm = diff_fdm
+:let &fdc = diff_fdc
+4
+:diffoff!
+:$put =nodiffsettings
+:$put =diffsettings
+1
+:redir => nd1
+:silent! :set diff? fdm? fdc? scb? crb? wrap?
+:redir END
+
+:redir => nd2
+:silent! :set diff? fdm? fdc? scb? crb? wrap?
+:redir END
+
+:redir => nd3
+:silent! :set diff? fdm? fdc? scb? crb? wrap?
+:redir END
+
+:$put =nd1
+:$put =nd2
+:$put =nd3
+:$-39,$w >> test.out
+:"
+:" Test that diffing shows correct filler lines
:windo :bw!
:enew
:put =range(4,10)
@@ -51,7 +92,7 @@ j:let three = three . "-" . winline()
:enew
:put =w0
:.w >> test.out
-:unlet! one two three w0
+:unlet! one two three nodiffsettings diffsettings diff_fdm diff_fdc nd1 nd2 nd3 w0
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test47.ok b/src/nvim/testdir/test47.ok
index b1cba92b1c..83e96571ad 100644
--- a/src/nvim/testdir/test47.ok
+++ b/src/nvim/testdir/test47.ok
@@ -1,4 +1,44 @@
2-4-5-6-8-9
1-2-4-5-8
2-3-4-5-6-7-8
+
+
+nodiff
+ foldmethod=marker
+ foldcolumn=4
+noscrollbind
+nocursorbind
+ wrap
+
+
+ diff
+ foldmethod=diff
+ foldcolumn=2
+ scrollbind
+ cursorbind
+nowrap
+
+
+nodiff
+ foldmethod=marker
+ foldcolumn=4
+noscrollbind
+nocursorbind
+ wrap
+
+
+nodiff
+ foldmethod=marker
+ foldcolumn=4
+noscrollbind
+nocursorbind
+ wrap
+
+
+nodiff
+ foldmethod=marker
+ foldcolumn=4
+noscrollbind
+nocursorbind
+ wrap
1
diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in
index 7b6f684caa..9e3c1168cc 100644
--- a/src/nvim/testdir/test55.in
+++ b/src/nvim/testdir/test55.in
@@ -442,6 +442,17 @@ let l = [0, 1, 2, 3]
:unlockvar 1 b:
:unlet! b:testvar
:"
+:$put ='No :let += of locked list variable:'
+:let l = ['a', 'b', 3]
+:lockvar 1 l
+:try
+: let l += ['x']
+: $put ='did :let +='
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(l)
+:"
:unlet l
:let l = [1, 2, 3, 4]
:lockvar! l
diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok
index 4e0303c26e..607a95ead9 100644
--- a/src/nvim/testdir/test55.ok
+++ b/src/nvim/testdir/test55.ok
@@ -144,6 +144,9 @@ No extend() of write-protected scope-level variable:
Vim(put):E742:
No :unlet of variable in locked scope:
Vim(unlet):E741:
+No :let += of locked list variable:
+Vim(let):E741:
+['a', 'b', 3]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in
index 57202b46eb..f13eee121e 100644
--- a/src/nvim/testdir/test_listlbr.in
+++ b/src/nvim/testdir/test_listlbr.in
@@ -75,6 +75,12 @@ Golong line: 40afoobar aTARGET at end
:let g:test ="Test 8: set linebreak with visual char mode and changing block"
:$put =g:test
Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj.
+:let g:test ="Test 9: using redo after block visual mode"
+:$put =g:test
+Go
+aaa
+aaa
+a2k2j~e.
:%w! test.out
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok
index 82881234c4..323bcdee08 100644
--- a/src/nvim/testdir/test_listlbr.ok
+++ b/src/nvim/testdir/test_listlbr.ok
@@ -41,3 +41,8 @@ Test 7: set linebreak with visual block mode and v_b_A
long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end
Test 8: set linebreak with visual char mode and changing block
1111-2222-1111-11-1111-2222-1111
+Test 9: using redo after block visual mode
+
+AaA
+AaA
+A
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 9e77c85f20..0ebc1f6a7c 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -463,34 +463,34 @@ static int included_patches[] = {
// 828,
// 827,
826,
- // 825,
+ 825,
// 824 NA
823,
// 822,
// 821,
- // 820,
+ 820,
// 819,
// 818,
- // 817,
- // 816,
- // 815,
- // 814,
+ 817,
+ 816,
+ 815,
+ 814,
813,
// 812,
- // 811,
- // 810,
+ 811,
+ 810,
809,
// 808 NA
807,
806,
- // 805,
+ 805,
// 804,
803,
802,
- // 801,
- // 800,
+ 801,
+ 800,
799,
- // 798,
+ 798,
// 797,
// 796 NA
795,
@@ -519,8 +519,8 @@ static int included_patches[] = {
// 772 NA
// 771,
// 770 NA
- // 769,
- // 768,
+ 769,
+ 768,
// 767,
// 766 NA
765,
@@ -528,12 +528,12 @@ static int included_patches[] = {
// 763 NA
// 762 NA
// 761 NA
- // 760,
+ 760,
// 759 NA
- // 758,
+ 758,
// 757 NA
// 756 NA
- // 755,
+ 755,
754,
753,
// 752,
@@ -571,7 +571,7 @@ static int included_patches[] = {
// 720 NA
719,
718,
- // 717,
+ 717,
716,
715,
714,
@@ -580,7 +580,7 @@ static int included_patches[] = {
711,
710,
709,
- // 708,
+ 708,
707,
706,
// 705 NA
@@ -588,18 +588,18 @@ static int included_patches[] = {
// 703 NA
702,
// 701 NA
- // 700,
+ 700,
699,
698,
697,
696,
695,
694,
- // 693,
+ 693,
// 692 NA
// 691 NA
690,
- // 689,
+ 689,
688,
// 687 NA
686,