aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/colors/README.txt11
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer_updates.c2
-rw-r--r--src/nvim/eval.c60
-rw-r--r--src/nvim/eval/encode.c4
-rw-r--r--src/nvim/eval/typval.c36
-rw-r--r--src/nvim/ex_cmds.c23
-rw-r--r--src/nvim/ex_getln.c26
-rw-r--r--src/nvim/fileio.c11
-rw-r--r--src/nvim/garray.h2
-rw-r--r--src/nvim/getchar.c34
-rw-r--r--src/nvim/getchar.h7
-rw-r--r--src/nvim/log.c5
-rw-r--r--src/nvim/lua/executor.c2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/memline.c15
-rw-r--r--src/nvim/message.c8
-rw-r--r--src/nvim/misc1.c2
-rw-r--r--src/nvim/ops.c14
-rw-r--r--src/nvim/regexp_nfa.c10
-rw-r--r--src/nvim/shada.c6
-rw-r--r--src/nvim/spellfile.c32
-rw-r--r--src/nvim/strings.c2
-rw-r--r--src/nvim/syntax.c1
-rw-r--r--src/nvim/testdir/test_blockedit.vim13
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim13
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim13
-rw-r--r--src/nvim/testdir/test_functions.vim59
-rw-r--r--src/nvim/testdir/test_mapping.vim16
-rw-r--r--src/nvim/testdir/test_options.vim4
-rw-r--r--src/nvim/tui/terminfo.c4
-rw-r--r--src/nvim/tui/tui.c29
-rw-r--r--src/nvim/ugrid.c1
-rw-r--r--src/nvim/undo.c4
-rw-r--r--test/functional/terminal/tui_spec.lua15
35 files changed, 342 insertions, 145 deletions
diff --git a/runtime/colors/README.txt b/runtime/colors/README.txt
index 7e845680a9..4636979ef1 100644
--- a/runtime/colors/README.txt
+++ b/runtime/colors/README.txt
@@ -42,7 +42,16 @@ this autocmd might be useful:
Replace "blue_sky" with the name of the colorscheme.
In case you want to tweak a colorscheme after it was loaded, check out the
-ColorScheme autocmd event.
+ColorScheme autocommand event.
+
+To clean up just before loading another colorscheme, use the ColorSchemePre
+autocommand event. For example:
+ let g:term_ansi_colors = ...
+ augroup MyColorscheme
+ au!
+ au ColorSchemePre * unlet g:term_ansi_colors
+ au ColorSchemePre * au! MyColorscheme
+ augroup END
To customize a colorscheme use another name, e.g. "~/.vim/colors/mine.vim",
and use `:runtime` to load the original colorscheme:
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index d002aaae43..e6285c5c76 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -27,6 +27,7 @@ return {
'CmdWinEnter', -- after entering the cmdline window
'CmdWinLeave', -- before leaving the cmdline window
'ColorScheme', -- after loading a colorscheme
+ 'ColorSchemePre', -- before loading a colorscheme
'CompleteDone', -- after finishing insert complete
'CursorHold', -- cursor in same position for a while
'CursorHoldI', -- idem, in Insert mode
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 18b53a0685..9d9c998a68 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -180,7 +180,7 @@ void buf_updates_send_changes(buf_T *buf,
// change notifications are so frequent that many dead channels will be
// cleared up quickly.
if (badchannelid != 0) {
- ELOG("Disabling buffer updates for dead channel %llu", badchannelid);
+ ELOG("Disabling buffer updates for dead channel %"PRIu64, badchannelid);
buf_updates_unregister(buf, badchannelid);
}
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 2aab2d72a7..515dd0e69f 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1943,7 +1943,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
emsgf(_(e_letwrong), op);
} else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
- emsgf(_(e_letunexp));
+ EMSG(_(e_letunexp));
} else {
char_u *s;
@@ -2152,7 +2152,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
if (rettv != NULL && (rettv->v_type != VAR_LIST
|| rettv->vval.v_list == NULL)) {
if (!quiet) {
- emsgf(_("E709: [:] requires a List value"));
+ EMSG(_("E709: [:] requires a List value"));
}
tv_clear(&var1);
return NULL;
@@ -2179,7 +2179,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
if (*p != ']') {
if (!quiet) {
- emsgf(_(e_missbrac));
+ EMSG(_(e_missbrac));
}
tv_clear(&var1);
tv_clear(&var2);
@@ -3325,7 +3325,7 @@ static int eval1(char_u **arg, typval_T *rettv, int evaluate)
* Check for the ":".
*/
if ((*arg)[0] != ':') {
- emsgf(_("E109: Missing ':' after '?'"));
+ EMSG(_("E109: Missing ':' after '?'"));
if (evaluate && result) {
tv_clear(rettv);
}
@@ -4433,7 +4433,7 @@ eval_index(
/* Check for the ']'. */
if (**arg != ']') {
if (verbose) {
- emsgf(_(e_missbrac));
+ EMSG(_(e_missbrac));
}
tv_clear(&var1);
if (range) {
@@ -4545,7 +4545,7 @@ eval_index(
case VAR_DICT: {
if (range) {
if (verbose) {
- emsgf(_(e_dictrange));
+ EMSG(_(e_dictrange));
}
if (len == -1) {
tv_clear(&var1);
@@ -7795,7 +7795,7 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, FunPtr fptr)
noref = tv_get_number_chk(&argvars[1], NULL);
}
if (noref < 0 || noref > 1) {
- emsgf(_(e_invarg));
+ EMSG(_(e_invarg));
} else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID()
@@ -7835,7 +7835,7 @@ static void f_delete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// delete a directory recursively
rettv->vval.v_number = delete_recursive(name);
} else {
- EMSG2(_(e_invexpr2), flags);
+ emsgf(_(e_invexpr2), flags);
}
}
@@ -8963,7 +8963,7 @@ static void common_function(typval_T *argvars, typval_T *rettv,
} else if (trans_name != NULL
&& (is_funcref ? find_func(trans_name) == NULL
: !translated_function_exists((const char *)trans_name))) {
- EMSG2(_("E700: Unknown function: %s"), s);
+ emsgf(_("E700: Unknown function: %s"), s);
} else {
int dict_idx = 0;
int arg_idx = 0;
@@ -11190,7 +11190,7 @@ void get_user_input(const typval_T *const argvars,
char def[1] = { 0 };
if (argvars[0].v_type == VAR_DICT) {
if (argvars[1].v_type != VAR_UNKNOWN) {
- emsgf(_("E5050: {opts} must be the only argument"));
+ EMSG(_("E5050: {opts} must be the only argument"));
return;
}
dict_T *const dict = argvars[0].vval.v_dict;
@@ -11499,7 +11499,7 @@ static void dict_list(typval_T *const tv, typval_T *const rettv,
const DictListType what)
{
if (tv->v_type != VAR_DICT) {
- emsgf(_(e_dictreq));
+ EMSG(_(e_dictreq));
return;
}
if (tv->vval.v_dict == NULL) {
@@ -11929,7 +11929,7 @@ static void f_json_decode(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
if (json_decode_string(s, len, rettv) == FAIL) {
- emsgf(_("E474: Failed to parse %.*s"), (int) len, s);
+ emsgf(_("E474: Failed to parse %.*s"), (int)len, s);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
}
@@ -12919,7 +12919,7 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
if (num < 0) {
- emsgf(_("E5070: Character number must not be less than zero"));
+ EMSG(_("E5070: Character number must not be less than zero"));
return;
}
if (num > INT_MAX) {
@@ -13065,9 +13065,9 @@ static void f_range(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return; // Type error; errmsg already given.
}
if (stride == 0) {
- emsgf(_("E726: Stride is zero"));
+ EMSG(_("E726: Stride is zero"));
} else if (stride > 0 ? end + 1 < start : end - 1 > start) {
- emsgf(_("E727: Start past end"));
+ EMSG(_("E727: Start past end"));
} else {
tv_list_alloc_ret(rettv, (end - start) / stride);
for (i = start; stride > 0 ? i <= end : i >= end; i += stride) {
@@ -13404,7 +13404,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
if (li == NULL) { // Didn't find "item2" after "item".
- emsgf(_(e_invrange));
+ EMSG(_(e_invrange));
} else {
tv_list_move_items(l, item, item2, tv_list_alloc_ret(rettv, cnt),
cnt);
@@ -14719,7 +14719,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
} else if (title_arg->v_type == VAR_DICT) {
d = title_arg->vval.v_dict;
} else {
- emsgf(_(e_dictreq));
+ EMSG(_(e_dictreq));
return;
}
@@ -16217,7 +16217,7 @@ static void f_submatch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (no < 0 || no >= NSUBEXP) {
- EMSGN(_("E935: invalid submatch number: %d"), no);
+ emsgf(_("E935: invalid submatch number: %d"), no);
return;
}
int retList = 0;
@@ -17581,7 +17581,7 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type != VAR_DICT
|| (dict = argvars[0].vval.v_dict) == NULL) {
- emsgf(_(e_invarg));
+ EMSG(_(e_invarg));
} else {
dictitem_T *di;
if ((di = tv_dict_find(dict, S_LEN("lnum"))) != NULL) {
@@ -19367,7 +19367,7 @@ static bool var_check_fixed(const int flags, const char *name,
} else if (name_len == TV_CSTRING) {
name_len = strlen(name);
}
- emsgf(_("E795: Cannot delete variable %.*s"), (int)name_len, name);
+ EMSG3(_("E795: Cannot delete variable %.*s"), (int)name_len, name);
return true;
}
return false;
@@ -19976,7 +19976,7 @@ void ex_function(exarg_T *eap)
if (*p == '\n') {
line_arg = p + 1;
} else if (*p != NUL && *p != '"' && !eap->skip && !did_emsg) {
- emsgf(_(e_trailing));
+ EMSG(_(e_trailing));
}
/*
@@ -21797,15 +21797,15 @@ void ex_return(exarg_T *eap)
} else {
tv_clear(&rettv);
}
- }
- /* It's safer to return also on error. */
- else if (!eap->skip) {
- /*
- * Return unless the expression evaluation has been cancelled due to an
- * aborting error, an interrupt, or an exception.
- */
- if (!aborting())
- returning = do_return(eap, FALSE, TRUE, NULL);
+ } else if (!eap->skip) { // It's safer to return also on error.
+ // In return statement, cause_abort should be force_abort.
+ update_force_abort();
+
+ // Return unless the expression evaluation has been cancelled due to an
+ // aborting error, an interrupt, or an exception.
+ if (!aborting()) {
+ returning = do_return(eap, false, true, NULL);
+ }
}
/* When skipping or the return gets pending, advance to the next command
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 9bae436e3d..2563e38258 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -609,14 +609,14 @@ static inline int convert_to_json_string(garray_T *const gap,
if (ch > 0x7F && shift == 1) {
emsgf(_("E474: String \"%.*s\" contains byte that does not start "
"any UTF-8 character"),
- utf_len - (i - shift), utf_buf + i - shift);
+ (int)(utf_len - (i - shift)), utf_buf + i - shift);
xfree(tofree);
return FAIL;
} else if ((SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END)
|| (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END)) {
emsgf(_("E474: UTF-8 string contains code point which belongs "
"to a surrogate pair: %.*s"),
- utf_len - (i - shift), utf_buf + i - shift);
+ (int)(utf_len - (i - shift)), utf_buf + i - shift);
xfree(tofree);
return FAIL;
} else if (ENCODE_RAW(ch)) {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 55dcfcc198..6a93b20345 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -991,7 +991,7 @@ const char *tv_list_find_str(list_T *const l, const int n)
{
const listitem_T *const li = tv_list_find(l, n);
if (li == NULL) {
- emsgf(_(e_listidx), (int64_t)n);
+ EMSG2(_(e_listidx), (int64_t)n);
return NULL;
}
return tv_get_string(TV_LIST_ITEM_TV(li));
@@ -1532,7 +1532,7 @@ bool tv_dict_get_callback(dict_T *const d,
}
if (!tv_is_func(di->di_tv) && di->di_tv.v_type != VAR_STRING) {
- emsgf(_("E6000: Argument is not a function or function name"));
+ EMSG(_("E6000: Argument is not a function or function name"));
return false;
}
@@ -2298,7 +2298,7 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
static int recurse = 0;
if (recurse >= DICT_MAXNEST) {
- emsgf(_("E743: variable nested too deep for (un)lock"));
+ EMSG(_("E743: variable nested too deep for (un)lock"));
return;
}
if (deep == 0) {
@@ -2546,28 +2546,28 @@ bool tv_check_str_or_nr(const typval_T *const tv)
return true;
}
case VAR_FLOAT: {
- emsgf(_("E805: Expected a Number or a String, Float found"));
+ EMSG(_("E805: Expected a Number or a String, Float found"));
return false;
}
case VAR_PARTIAL:
case VAR_FUNC: {
- emsgf(_("E703: Expected a Number or a String, Funcref found"));
+ EMSG(_("E703: Expected a Number or a String, Funcref found"));
return false;
}
case VAR_LIST: {
- emsgf(_("E745: Expected a Number or a String, List found"));
+ EMSG(_("E745: Expected a Number or a String, List found"));
return false;
}
case VAR_DICT: {
- emsgf(_("E728: Expected a Number or a String, Dictionary found"));
+ EMSG(_("E728: Expected a Number or a String, Dictionary found"));
return false;
}
case VAR_SPECIAL: {
- emsgf(_("E5300: Expected a Number or a String"));
+ EMSG(_("E5300: Expected a Number or a String"));
return false;
}
case VAR_UNKNOWN: {
- emsgf(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
+ EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
return false;
}
}
@@ -2611,7 +2611,7 @@ bool tv_check_num(const typval_T *const tv)
case VAR_DICT:
case VAR_FLOAT:
case VAR_UNKNOWN: {
- emsgf(_(num_errors[tv->v_type]));
+ EMSG(_(num_errors[tv->v_type]));
return false;
}
}
@@ -2655,7 +2655,7 @@ bool tv_check_str(const typval_T *const tv)
case VAR_DICT:
case VAR_FLOAT:
case VAR_UNKNOWN: {
- emsgf(_(str_errors[tv->v_type]));
+ EMSG(_(str_errors[tv->v_type]));
return false;
}
}
@@ -2702,7 +2702,7 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
case VAR_LIST:
case VAR_DICT:
case VAR_FLOAT: {
- emsgf(_(num_errors[tv->v_type]));
+ EMSG(_(num_errors[tv->v_type]));
break;
}
case VAR_NUMBER: {
@@ -2778,23 +2778,23 @@ float_T tv_get_float(const typval_T *const tv)
}
case VAR_PARTIAL:
case VAR_FUNC: {
- emsgf(_("E891: Using a Funcref as a Float"));
+ EMSG(_("E891: Using a Funcref as a Float"));
break;
}
case VAR_STRING: {
- emsgf(_("E892: Using a String as a Float"));
+ EMSG(_("E892: Using a String as a Float"));
break;
}
case VAR_LIST: {
- emsgf(_("E893: Using a List as a Float"));
+ EMSG(_("E893: Using a List as a Float"));
break;
}
case VAR_DICT: {
- emsgf(_("E894: Using a Dictionary as a Float"));
+ EMSG(_("E894: Using a Dictionary as a Float"));
break;
}
case VAR_SPECIAL: {
- emsgf(_("E907: Using a special value as a Float"));
+ EMSG(_("E907: Using a special value as a Float"));
break;
}
case VAR_UNKNOWN: {
@@ -2840,7 +2840,7 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
case VAR_DICT:
case VAR_FLOAT:
case VAR_UNKNOWN: {
- emsgf(_(str_errors[tv->v_type]));
+ EMSG(_(str_errors[tv->v_type]));
return false;
}
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index a091862e42..4710ae669b 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1353,6 +1353,25 @@ do_shell(
apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf);
}
+#if !defined(UNIX)
+static char *find_pipe(const char *cmd)
+{
+ bool inquote = false;
+
+ for (const char *p = cmd; *p != NUL; p++) {
+ if (!inquote && *p == '|') {
+ return p;
+ }
+ if (*p == '"') {
+ inquote = !inquote;
+ } else if (rem_backslash((const char_u *)p)) {
+ p++;
+ }
+ }
+ return NULL;
+}
+#endif
+
/// Create a shell command from a command string, input redirection file and
/// output redirection file.
///
@@ -1406,7 +1425,7 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
// Don't do this when 'shellquote' is not empty, otherwise the
// redirection would be inside the quotes.
if (*p_shq == NUL) {
- char *const p = strchr(buf, '|');
+ char *const p = find_pipe(buf);
if (p != NULL) {
*p = NUL;
}
@@ -1414,7 +1433,7 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
xstrlcat(buf, " < ", len);
xstrlcat(buf, (const char *)itmp, len);
if (*p_shq == NUL) {
- const char *const p = strchr((const char *)cmd, '|');
+ const char *const p = find_pipe((const char *)cmd);
if (p != NULL) {
xstrlcat(buf, " ", len - 1); // Insert a space before the '|' for DOS
xstrlcat(buf, p, len - 1);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 4d6720ef23..247b9175aa 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2696,7 +2696,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
}
const list_T *const l = TV_LIST_ITEM_TV(li)->vval.v_list;
if (tv_list_len(l) != 3) {
- PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %li /= 3"),
+ PRINT_ERRMSG(_("E5402: List item %i has incorrect length: %d /= 3"),
i, tv_list_len(l));
goto color_cmdline_error;
}
@@ -3522,10 +3522,28 @@ void gotocmdline(int clr)
*/
static int ccheck_abbr(int c)
{
- if (p_paste || no_abbr) /* no abbreviations or in paste mode */
- return FALSE;
+ int spos = 0;
+
+ if (p_paste || no_abbr) { // no abbreviations or in paste mode
+ return false;
+ }
+
+ // Do not consider '<,'> be part of the mapping, skip leading whitespace.
+ // Actually accepts any mark.
+ while (ascii_iswhite(ccline.cmdbuff[spos]) && spos < ccline.cmdlen) {
+ spos++;
+ }
+ if (ccline.cmdlen - spos > 5
+ && ccline.cmdbuff[spos] == '\''
+ && ccline.cmdbuff[spos + 2] == ','
+ && ccline.cmdbuff[spos + 3] == '\'') {
+ spos += 5;
+ } else {
+ // check abbreviation from the beginning of the commandline
+ spos = 0;
+ }
- return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, 0);
+ return check_abbr(c, ccline.cmdbuff, ccline.cmdpos, spos);
}
static int sort_func_compare(const void *s1, const void *s2)
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index ae0b24f3c8..a5ff13552b 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3686,7 +3686,7 @@ nofail:
} else if (errmsgarg != 0) {
emsgf(errmsg, os_strerror(errmsgarg));
} else {
- emsgf(errmsg);
+ EMSG(errmsg);
}
if (errmsg_allocated) {
xfree(errmsg);
@@ -6216,8 +6216,8 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd,
/* refuse to add buffer-local ap if buffer number is invalid */
if (is_buflocal && (buflocal_nr == 0
|| buflist_findnr(buflocal_nr) == NULL)) {
- EMSGN(_("E680: <buffer=%d>: invalid buffer number "),
- buflocal_nr);
+ emsgf(_("E680: <buffer=%d>: invalid buffer number "),
+ buflocal_nr);
return FAIL;
}
@@ -6779,7 +6779,9 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
* invalid.
*/
if (fname_io == NULL) {
- if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET) {
+ if (event == EVENT_COLORSCHEME
+ || event == EVENT_COLORSCHEMEPRE
+ || event == EVENT_OPTIONSET) {
autocmd_fname = NULL;
} else if (fname != NULL && !ends_excmd(*fname)) {
autocmd_fname = fname;
@@ -6830,6 +6832,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
sfname = vim_strsave(fname);
// Don't try expanding the following events.
if (event == EVENT_COLORSCHEME
+ || event == EVENT_COLORSCHEMEPRE
|| event == EVENT_DIRCHANGED
|| event == EVENT_FILETYPE
|| event == EVENT_FUNCUNDEFINED
diff --git a/src/nvim/garray.h b/src/nvim/garray.h
index 94e1b61671..58738df691 100644
--- a/src/nvim/garray.h
+++ b/src/nvim/garray.h
@@ -37,7 +37,7 @@ typedef struct growarray {
static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size)
{
if ((int)item_size != gap->ga_itemsize) {
- WLOG("wrong item size (%d), should be %d", item_size, gap->ga_itemsize);
+ WLOG("wrong item size (%zu), should be %d", item_size, gap->ga_itemsize);
}
ga_grow(gap, 1);
return ((char *)gap->ga_data) + (item_size * (size_t)gap->ga_len++);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2eb2df399e..94702a9a3a 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -420,7 +420,7 @@ void typeahead_noflush(int c)
* typeahead buffer (used in case of an error). If "flush_typeahead" is true,
* flush all typeahead characters (used when interrupted by a CTRL-C).
*/
-void flush_buffers(int flush_typeahead)
+void flush_buffers(flush_buffers_T flush_typeahead)
{
init_typebuf();
@@ -428,22 +428,24 @@ void flush_buffers(int flush_typeahead)
while (read_readbuffers(TRUE) != NUL) {
}
- if (flush_typeahead) { /* remove all typeahead */
- /*
- * We have to get all characters, because we may delete the first part
- * of an escape sequence.
- * In an xterm we get one char at a time and we have to get them all.
- */
- while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) {
+ if (flush_typeahead == FLUSH_MINIMAL) {
+ // remove mapped characters at the start only
+ typebuf.tb_off += typebuf.tb_maplen;
+ typebuf.tb_len -= typebuf.tb_maplen;
+ } else {
+ // remove typeahead
+ if (flush_typeahead == FLUSH_INPUT) {
+ // We have to get all characters, because we may delete the first
+ // part of an escape sequence. In an xterm we get one char at a
+ // time and we have to get them all.
+ while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0) {
+ }
}
typebuf.tb_off = MAXMAPLEN;
typebuf.tb_len = 0;
// Reset the flag that text received from a client or from feedkeys()
// was inserted in the typeahead buffer.
typebuf_was_filled = false;
- } else { // remove mapped characters at the start only
- typebuf.tb_off += typebuf.tb_maplen;
- typebuf.tb_len -= typebuf.tb_maplen;
}
typebuf.tb_maplen = 0;
typebuf.tb_silent = 0;
@@ -1538,6 +1540,7 @@ int plain_vgetc(void)
* Check if a character is available, such that vgetc() will not block.
* If the next character is a special character or multi-byte, the returned
* character is not valid!.
+ * Returns NUL if no character is available.
*/
int vpeekc(void)
{
@@ -1602,7 +1605,8 @@ vungetc ( /* unget one character (can only be done once!) */
/// KeyTyped is set to TRUE in the case the user typed the key.
/// KeyStuffed is TRUE if the character comes from the stuff buffer.
/// if "advance" is FALSE (vpeekc()):
-/// just look whether there is a character available.
+/// Just look whether there is a character available.
+/// Return NUL if not.
///
/// When `no_mapping` (global) is zero, checks for mappings in the current mode.
/// Only returns one byte (of a multi-byte character).
@@ -1709,7 +1713,7 @@ static int vgetorpeek(int advance)
} else {
c = Ctrl_C;
}
- flush_buffers(true); // flush all typeahead
+ flush_buffers(FLUSH_INPUT); // flush all typeahead
if (advance) {
/* Also record this character, it might be needed to
@@ -1970,8 +1974,8 @@ static int vgetorpeek(int advance)
redrawcmdline();
else
setcursor();
- flush_buffers(FALSE);
- mapdepth = 0; /* for next one */
+ flush_buffers(FLUSH_MINIMAL);
+ mapdepth = 0; // for next one
c = -1;
break;
}
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index 38a2e75663..4f548d975a 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -16,6 +16,13 @@ enum {
REMAP_SKIP = -3, ///< No remapping for first char.
} RemapValues;
+// Argument for flush_buffers().
+typedef enum {
+ FLUSH_MINIMAL,
+ FLUSH_TYPEAHEAD, // flush current typebuf contents
+ FLUSH_INPUT // flush typebuf and inchar() input
+} flush_buffers_T;
+
#define KEYLEN_PART_KEY -1 /* keylen value for incomplete key-code */
#define KEYLEN_PART_MAP -2 /* keylen value for incomplete mapping */
#define KEYLEN_REMOVED 9999 /* keylen value for removed sequence */
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 719f0da340..4d912c452b 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -103,7 +103,7 @@ void log_unlock(void)
/// @param line_num source line number, or -1
bool logmsg(int log_level, const char *context, const char *func_name,
int line_num, bool eol, const char *fmt, ...)
- FUNC_ATTR_UNUSED
+ FUNC_ATTR_UNUSED FUNC_ATTR_PRINTF(6, 7)
{
if (log_level < MIN_LOG_LEVEL) {
return false;
@@ -245,7 +245,8 @@ end:
static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
const char *func_name, int line_num, bool eol,
- const char* fmt, ...)
+ const char *fmt, ...)
+ FUNC_ATTR_PRINTF(7, 8)
{
va_list args;
va_start(args, fmt);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 02eabb9c89..a7bda9d037 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -291,7 +291,7 @@ static int nlua_print(lua_State *const lstate)
return 0;
nlua_print_error:
emsgf(_("E5114: Error while converting print argument #%i: %.*s"),
- curargidx, errmsg_len, errmsg);
+ curargidx, (int)errmsg_len, errmsg);
ga_clear(&msg_ga);
lua_pop(lstate, lua_gettop(lstate));
return 0;
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 1db988b5f4..af54e62393 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -840,7 +840,7 @@ static void command_line_scan(mparm_T *parmp)
}
if (p == NULL) {
- emsgf(_(e_outofmem));
+ EMSG(_(e_outofmem));
}
Object md = DICTIONARY_OBJ(api_metadata());
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index ec0238e7c9..51f99db0de 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -49,6 +49,7 @@
#include "nvim/buffer.h"
#include "nvim/cursor.h"
#include "nvim/eval.h"
+#include "nvim/getchar.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
#include "nvim/main.h"
@@ -3358,12 +3359,16 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
choice = do_swapexists(buf, (char_u *) fname);
if (choice == 0) {
- /* Show info about the existing swap file. */
- attention_message(buf, (char_u *) fname);
+ // Show info about the existing swap file.
+ attention_message(buf, (char_u *)fname);
- /* We don't want a 'q' typed at the more-prompt
- * interrupt loading a file. */
- got_int = FALSE;
+ // We don't want a 'q' typed at the more-prompt
+ // interrupt loading a file.
+ got_int = false;
+
+ // If vimrc has "simalt ~x" we don't want it to
+ // interfere with the prompt here.
+ flush_buffers(FLUSH_TYPEAHEAD);
}
if (swap_exists_action != SEA_NONE && choice == 0) {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index fc7e96ac2c..1778e0048f 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -331,6 +331,7 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen)
*/
int smsg(char *s, ...)
+ FUNC_ATTR_PRINTF(1, 2)
{
va_list arglist;
@@ -341,6 +342,7 @@ int smsg(char *s, ...)
}
int smsg_attr(int attr, char *s, ...)
+ FUNC_ATTR_PRINTF(2, 3)
{
va_list arglist;
@@ -550,7 +552,7 @@ int emsg(const char_u *s_)
if (p_eb) {
beep_flush(); // also includes flush_buffers()
} else {
- flush_buffers(false); // flush internal buffers
+ flush_buffers(FLUSH_MINIMAL); // flush internal buffers
}
did_emsg = true; // flag for DoOneCmd()
}
@@ -581,6 +583,7 @@ void emsg_invreg(int name)
/// Print an error message with unknown number of arguments
bool emsgf(const char *const fmt, ...)
+ FUNC_ATTR_PRINTF(1, 2)
{
bool ret;
@@ -644,6 +647,7 @@ static void msg_emsgf_event(void **argv)
}
void msg_schedule_emsgf(const char *const fmt, ...)
+ FUNC_ATTR_PRINTF(1, 2)
{
va_list ap;
va_start(ap, fmt);
@@ -1672,7 +1676,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
/// @param[in] attr Highlight attributes.
/// @param[in] fmt Format string.
void msg_printf_attr(const int attr, const char *const fmt, ...)
- FUNC_ATTR_NONNULL_ARG(2)
+ FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PRINTF(2, 3)
{
static char msgbuf[IOSIZE];
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 2e7fe4d7a9..7e9d68a4b4 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -2548,7 +2548,7 @@ void msgmore(long n)
void beep_flush(void)
{
if (emsg_silent == 0) {
- flush_buffers(false);
+ flush_buffers(FLUSH_MINIMAL);
vim_beep(BO_ERROR);
}
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index e902127a40..5a6e56299d 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2159,9 +2159,17 @@ void op_insert(oparg_T *oap, long count1)
* Subsequent calls to ml_get() flush the firstline data - take a
* copy of the required string.
*/
- firstline = ml_get(oap->start.lnum) + bd.textcol;
- if (oap->op_type == OP_APPEND)
- firstline += bd.textlen;
+ firstline = ml_get(oap->start.lnum);
+ const size_t len = STRLEN(firstline);
+ colnr_T add = bd.textcol;
+ if (oap->op_type == OP_APPEND) {
+ add += bd.textlen;
+ }
+ if ((size_t)add > len) {
+ firstline += len; // short line, point to the NUL
+ } else {
+ firstline += add;
+ }
ins_len = (long)STRLEN(firstline) - pre_textlen;
if (pre_textlen >= 0 && ins_len > 0) {
ins_text = vim_strnsave(firstline, (size_t)ins_len);
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 65ddcf3b07..fe18cb4389 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1384,8 +1384,8 @@ static int nfa_regatom(void)
re_has_z = REX_SET;
break;
default:
- EMSGN(_("E867: (NFA) Unknown operator '\\z%c'"),
- no_Magic(c));
+ emsgf(_("E867: (NFA) Unknown operator '\\z%c'"),
+ no_Magic(c));
return FAIL;
}
break;
@@ -1524,8 +1524,8 @@ static int nfa_regatom(void)
break;
}
}
- EMSGN(_("E867: (NFA) Unknown operator '\\%%%c'"),
- no_Magic(c));
+ emsgf(_("E867: (NFA) Unknown operator '\\%%%c'"),
+ no_Magic(c));
return FAIL;
}
break;
@@ -1937,7 +1937,7 @@ static int nfa_regpiece(void)
break;
}
if (i == 0) {
- EMSGN(_("E869: (NFA) Unknown operator '\\@%c'"), op);
+ emsgf(_("E869: (NFA) Unknown operator '\\@%c'"), op);
return FAIL;
}
EMIT(i);
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index f4454504a4..11da7195bf 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -884,7 +884,7 @@ static int shada_read_file(const char *const file, const int flags)
if (p_verbose > 0) {
verbose_enter();
- smsg(_("Reading ShaDa file \"%s\"%s%s%s"),
+ smsg(_("Reading ShaDa file \"%s\"%s%s%s%s"),
fname,
(flags & kShaDaWantInfo) ? _(" info") : "",
(flags & kShaDaWantMarks) ? _(" marks") : "",
@@ -2033,7 +2033,7 @@ static const char *shada_format_entry(const ShadaEntry entry)
{
static char ret[1024];
ret[0] = 0;
- vim_snprintf(S_LEN(ret), "[ ] ts=%" PRIu64 " ");
+ vim_snprintf(S_LEN(ret), "%s", "[ ] ts=%" PRIu64 " ");
// ^ Space for `can_free_entry`
switch (entry.type) {
case kSDItemMissing: {
@@ -2091,7 +2091,7 @@ static const char *shada_format_entry(const ShadaEntry entry)
entry.data.filemark.mark.lnum, \
entry.data.filemark.mark.col, \
entry.data.filemark.mark.coladd, \
- entry.data.filemark.additional_data, \
+ (void *)entry.data.filemark.additional_data, \
ad_len, \
ad); \
} while (0)
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index f52ae61534..8be8d24b9f 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -3096,8 +3096,8 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
if (spin->si_verbose && spin->si_msg_count > 10000) {
spin->si_msg_count = 0;
vim_snprintf((char *)message, sizeof(message),
- _("line %6d, word %6d - %s"),
- lnum, spin->si_foldwcount + spin->si_keepwcount, w);
+ _("line %6d, word %6ld - %s"),
+ lnum, spin->si_foldwcount + spin->si_keepwcount, w);
msg_start();
msg_puts_long_attr(message, 0);
msg_clr_eos();
@@ -3570,7 +3570,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (spin->si_conv.vc_type != CONV_NONE) {
pc = string_convert(&spin->si_conv, rline, NULL);
if (pc == NULL) {
- smsg(_("Conversion failure for word in %s line %d: %s"),
+ smsg(_("Conversion failure for word in %s line %ld: %s"),
fname, lnum, rline);
continue;
}
@@ -3583,13 +3583,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (*line == '/') {
++line;
if (STRNCMP(line, "encoding=", 9) == 0) {
- if (spin->si_conv.vc_type != CONV_NONE)
- smsg(_("Duplicate /encoding= line ignored in %s line %d: %s"),
+ if (spin->si_conv.vc_type != CONV_NONE) {
+ smsg(_("Duplicate /encoding= line ignored in %s line %ld: %s"),
fname, lnum, line - 1);
- else if (did_word)
- smsg(_("/encoding= line after word ignored in %s line %d: %s"),
+ } else if (did_word) {
+ smsg(_("/encoding= line after word ignored in %s line %ld: %s"),
fname, lnum, line - 1);
- else {
+ } else {
char_u *enc;
// Setup for conversion to 'encoding'.
@@ -3607,13 +3607,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
}
if (STRNCMP(line, "regions=", 8) == 0) {
- if (spin->si_region_count > 1)
- smsg(_("Duplicate /regions= line ignored in %s line %d: %s"),
+ if (spin->si_region_count > 1) {
+ smsg(_("Duplicate /regions= line ignored in %s line %ld: %s"),
fname, lnum, line);
- else {
+ } else {
line += 8;
if (STRLEN(line) > MAXREGIONS * 2) {
- smsg(_("Too many regions in %s line %d: %s"),
+ smsg(_("Too many regions in %s line %ld: %s"),
fname, lnum, line);
} else {
spin->si_region_count = (int)STRLEN(line) / 2;
@@ -3626,7 +3626,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
continue;
}
- smsg(_("/ line ignored in %s line %d: %s"),
+ smsg(_("/ line ignored in %s line %ld: %s"),
fname, lnum, line - 1);
continue;
}
@@ -3652,13 +3652,13 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
l = *p - '0';
if (l == 0 || l > spin->si_region_count) {
- smsg(_("Invalid region nr in %s line %d: %s"),
+ smsg(_("Invalid region nr in %s line %ld: %s"),
fname, lnum, p);
break;
}
regionmask |= 1 << (l - 1);
} else {
- smsg(_("Unrecognized flags in %s line %d: %s"),
+ smsg(_("Unrecognized flags in %s line %ld: %s"),
fname, lnum, p);
break;
}
@@ -5136,7 +5136,7 @@ mkspell (
} else if (vim_strchr(path_tail(wfname), '_') != NULL) {
EMSG(_("E751: Output file name must not have region name"));
} else if (incount > MAXREGIONS) {
- EMSGN(_("E754: Only up to %ld regions supported"), MAXREGIONS);
+ emsgf(_("E754: Only up to %d regions supported"), MAXREGIONS);
} else {
// Check for overwriting before doing things that may take a lot of
// time.
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 17c4a75a64..3b0a950ff2 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -693,6 +693,7 @@ static float_T tv_float(typval_T *const tvs, int *const idxp)
///
/// @see vim_vsnprintf().
int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...)
+ FUNC_ATTR_PRINTF(3, 4)
{
const size_t len = strlen(str);
size_t space;
@@ -718,6 +719,7 @@ int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...)
/// @return Number of bytes excluding NUL byte that would be written to the
/// string if str_m was greater or equal to the return value.
int vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
+ FUNC_ATTR_PRINTF(3, 4)
{
va_list ap;
va_start(ap, fmt);
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index e0e1897b88..5c8b5899df 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -6326,6 +6326,7 @@ int load_colors(char_u *name)
recursive = true;
size_t buflen = STRLEN(name) + 12;
buf = xmalloc(buflen);
+ apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf);
snprintf((char *)buf, buflen, "colors/%s.vim", name);
retval = source_runtime(buf, DIP_START + DIP_OPT);
xfree(buf);
diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim
index 4a8d59952e..527224ccd2 100644
--- a/src/nvim/testdir/test_blockedit.vim
+++ b/src/nvim/testdir/test_blockedit.vim
@@ -16,5 +16,18 @@ func Test_blockinsert_indent()
bwipe!
endfunc
+func Test_blockinsert_delete()
+ new
+ let _bs = &bs
+ set bs=2
+ call setline(1, ['case Arg is ', ' when Name_Async,', ' when Name_Num_Gangs,', 'end if;'])
+ exe "norm! ggjVj\<c-v>$o$A\<bs>\<esc>"
+ "call feedkeys("Vj\<c-v>$o$A\<bs>\<esc>", 'ti')
+ call assert_equal(["case Arg is ", " when Name_Async", " when Name_Num_Gangs,", "end if;"],
+ \ getline(1,'$'))
+ " reset to sane state
+ let &bs = _bs
+ bwipe!
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
new file mode 100644
index 0000000000..92e1ec5335
--- /dev/null
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -0,0 +1,13 @@
+" Tests for various eval things.
+
+function s:foo() abort
+ try
+ return [] == 0
+ catch
+ return 1
+ endtry
+endfunction
+
+func Test_catch_return_with_error()
+ call assert_equal(1, s:foo())
+endfunc
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 5aa5fa64df..86347ab77f 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -74,3 +74,16 @@ func Test_filter_cmd_completion()
call assert_equal('filter /pat/ print', s:complete_filter_cmd('filter /pat/ pri'))
call assert_equal('filter #pat# print', s:complete_filter_cmd('filter #pat# pri'))
endfunc
+
+func Test_filter_cmd_with_filter()
+ new
+ set shelltemp
+ %!echo "a|b"
+ let out = getline(1)
+ bw!
+ if has('win32')
+ let out = trim(out, '" ')
+ endif
+ call assert_equal('a|b', out)
+ set shelltemp&
+endfunction
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 8fde63b55f..b1138bfc96 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -189,6 +189,52 @@ func Test_strftime()
call assert_fails('call strftime("%Y", [])', 'E745:')
endfunc
+func Test_resolve()
+ if !has('unix')
+ return
+ endif
+
+ " Xlink1 -> Xlink2
+ " Xlink2 -> Xlink3
+ silent !ln -s -f Xlink2 Xlink1
+ silent !ln -s -f Xlink3 Xlink2
+ call assert_equal('Xlink3', resolve('Xlink1'))
+ call assert_equal('./Xlink3', resolve('./Xlink1'))
+ call assert_equal('Xlink3/', resolve('Xlink2/'))
+ " FIXME: these tests result in things like "Xlink2/" instead of "Xlink3/"?!
+ "call assert_equal('Xlink3/', resolve('Xlink1/'))
+ "call assert_equal('./Xlink3/', resolve('./Xlink1/'))
+ "call assert_equal(getcwd() . '/Xlink3/', resolve(getcwd() . '/Xlink1/'))
+ call assert_equal(getcwd() . '/Xlink3', resolve(getcwd() . '/Xlink1'))
+
+ " Test resolve() with a symlink cycle.
+ " Xlink1 -> Xlink2
+ " Xlink2 -> Xlink3
+ " Xlink3 -> Xlink1
+ silent !ln -s -f Xlink1 Xlink3
+ call assert_fails('call resolve("Xlink1")', 'E655:')
+ call assert_fails('call resolve("./Xlink1")', 'E655:')
+ call assert_fails('call resolve("Xlink2")', 'E655:')
+ call assert_fails('call resolve("Xlink3")', 'E655:')
+ call delete('Xlink1')
+ call delete('Xlink2')
+ call delete('Xlink3')
+
+ silent !ln -s -f Xdir//Xfile Xlink
+ call assert_equal('Xdir/Xfile', resolve('Xlink'))
+ call delete('Xlink')
+
+ silent !ln -s -f Xlink2/ Xlink1
+ call assert_equal('Xlink2', resolve('Xlink1'))
+ call assert_equal('Xlink2/', resolve('Xlink1/'))
+ call delete('Xlink1')
+
+ silent !ln -s -f ./Xlink2 Xlink1
+ call assert_equal('Xlink2', resolve('Xlink1'))
+ call assert_equal('./Xlink2', resolve('./Xlink1'))
+ call delete('Xlink1')
+endfunc
+
func Test_simplify()
call assert_equal('', simplify(''))
call assert_equal('/', simplify('/'))
@@ -818,6 +864,19 @@ func Test_filewritable()
bw!
endfunc
+func Test_Executable()
+ if has('win32')
+ call assert_equal(1, executable('notepad'))
+ call assert_equal(1, executable('notepad.exe'))
+ call assert_equal(0, executable('notepad.exe.exe'))
+ call assert_equal(1, executable('shell32.dll'))
+ call assert_equal(1, executable('win.ini'))
+ elseif has('unix')
+ call assert_equal(1, executable('cat'))
+ call assert_equal(0, executable('nodogshere'))
+ endif
+endfunc
+
func Test_hostname()
let hostname_vim = hostname()
if has('unix')
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index f4fe1c2705..071b8b369b 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -198,3 +198,19 @@ func Test_map_timeout()
set timeoutlen&
delfunc ExitInsert
endfunc
+
+func Test_cabbr_visual_mode()
+ cabbr s su
+ call feedkeys(":s \<c-B>\"\<CR>", 'itx')
+ call assert_equal('"su ', getreg(':'))
+ call feedkeys(":'<,'>s \<c-B>\"\<CR>", 'itx')
+ let expected = '"'. "'<,'>su "
+ call assert_equal(expected, getreg(':'))
+ call feedkeys(": '<,'>s \<c-B>\"\<CR>", 'itx')
+ let expected = '" '. "'<,'>su "
+ call assert_equal(expected, getreg(':'))
+ call feedkeys(":'a,'bs \<c-B>\"\<CR>", 'itx')
+ let expected = '"'. "'a,'bsu "
+ call assert_equal(expected, getreg(':'))
+ cunabbr s
+endfunc
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 66acb79206..7b640ee2ff 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -262,7 +262,7 @@ func Test_set_ttytype()
" in travis on some builds. Why? Catch both for now
try
set ttytype=
- call assert_report('set ttype= did not fail')
+ call assert_report('set ttytype= did not fail')
catch /E529\|E522/
endtry
@@ -270,7 +270,7 @@ func Test_set_ttytype()
" check for failure of finding the entry and for missing 'cm' entry.
try
set ttytype=xxx
- call assert_report('set ttype=xxx did not fail')
+ call assert_report('set ttytype=xxx did not fail')
catch /E522\|E437/
endtry
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index c3dc4124b9..ad86dd928b 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -144,7 +144,7 @@ void terminfo_info_msg(const unibi_term *const ut)
for (enum unibi_numeric i = unibi_numeric_begin_ + 1;
i < unibi_numeric_end_; i++) {
int n = unibi_get_num(ut, i); // -1 means "empty"
- msg_printf_attr(0, " %-25s %-10s = %hd\n", unibi_name_num(i),
+ msg_printf_attr(0, " %-25s %-10s = %d\n", unibi_name_num(i),
unibi_short_name_num(i), n);
}
@@ -173,7 +173,7 @@ void terminfo_info_msg(const unibi_term *const ut)
if (unibi_count_ext_num(ut)) {
msg_puts("Extended numeric capabilities:\n");
for (size_t i = 0; i < unibi_count_ext_num(ut); i++) {
- msg_printf_attr(0, " %-25s = %hd\n",
+ msg_printf_attr(0, " %-25s = %d\n",
unibi_get_ext_num_name(ut, i),
unibi_get_ext_num(ut, i));
}
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 3ed0fe0cd6..dd22f00de0 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -88,7 +88,6 @@ typedef struct {
bool cont_received;
UGrid grid;
kvec_t(Rect) invalid_regions;
- bool did_resize;
int row, col;
int out_fd;
bool scroll_region_is_full_screen;
@@ -577,7 +576,7 @@ static void final_column_wrap(UI *ui)
{
TUIData *data = ui->data;
UGrid *grid = &data->grid;
- if (grid->col == ui->width) {
+ if (grid->row != -1 && grid->col == ui->width) {
grid->col = 0;
if (grid->row < MIN(ui->height, grid->height - 1)) {
grid->row++;
@@ -647,6 +646,9 @@ static void cursor_goto(UI *ui, int row, int col)
ugrid_goto(grid, row, col);
return;
}
+ if (grid->row == -1) {
+ goto safe_move;
+ }
if (0 == col ? col != grid->col :
row != grid->row ? false :
1 == col ? 2 < grid->col && cheap_to_print(ui, grid->row, 0, col) :
@@ -725,6 +727,8 @@ static void cursor_goto(UI *ui, int row, int col)
return;
}
}
+
+safe_move:
unibi_goto(ui, row, col);
ugrid_goto(grid, row, col);
}
@@ -773,18 +777,7 @@ static void clear_region(UI *ui, int top, int bot, int left, int right,
cursor_goto(ui, row, col);
print_cell(ui, cell);
});
-
- if (data->did_resize && top == 0) {
- // TODO(bfredl): the first line of the screen doesn't gets properly
- // cleared after resize by the loop above, so redraw the final state
- // after the next flush.
- invalidate(ui, 0, bot, left, right);
- data->did_resize = false;
- }
}
-
- // restore cursor
- cursor_goto(ui, data->row, data->col);
}
static void set_scroll_region(UI *ui, int top, int bot, int left, int right)
@@ -808,7 +801,7 @@ static void set_scroll_region(UI *ui, int top, int bot, int left, int right)
unibi_out(ui, unibi_set_right_margin_parm);
}
}
- unibi_goto(ui, grid->row, grid->col);
+ grid->row = -1;
}
static void reset_scroll_region(UI *ui, bool fullwidth)
@@ -836,7 +829,7 @@ static void reset_scroll_region(UI *ui, bool fullwidth)
}
unibi_out_ext(ui, data->unibi_ext.disable_lr_margin);
}
- unibi_goto(ui, grid->row, grid->col);
+ grid->row = -1;
}
static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
@@ -844,7 +837,6 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
TUIData *data = ui->data;
UGrid *grid = &data->grid;
ugrid_resize(grid, (int)width, (int)height);
- data->did_resize = true;
// resize might not always be followed by a clear before flush
// so clip the invalid region
@@ -864,6 +856,7 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
}
} else { // Already handled the SIGWINCH signal; avoid double-resize.
got_winch = false;
+ grid->row = -1;
}
}
@@ -880,9 +873,10 @@ static void tui_grid_clear(UI *ui, Integer g)
static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
{
TUIData *data = ui->data;
+
+ // cursor position is validated in tui_flush
data->row = (int)row;
data->col = (int)col;
- cursor_goto(ui, (int)row, (int)col);
}
CursorShape tui_cursor_decode_shape(const char *shape_str)
@@ -1070,7 +1064,6 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
if (!data->scroll_region_is_full_screen) {
reset_scroll_region(ui, fullwidth);
}
- cursor_goto(ui, data->row, data->col);
if (!(data->bce || no_bg(ui, data->clear_attrs))) {
// Scrolling will leave wrong background in the cleared area on non-BCE
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index e2b92d7112..b741a61d8c 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -32,7 +32,6 @@ void ugrid_resize(UGrid *grid, int width, int height)
grid->cells[i] = xcalloc((size_t)width, sizeof(UCell));
}
- grid->row = grid->col = 0;
grid->width = width;
grid->height = height;
}
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 7dd101cb90..df0507ed41 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2503,8 +2503,8 @@ void ex_undolist(exarg_T *eap)
while (uhp != NULL) {
if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark
&& uhp->uh_walk != mark) {
- vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7ld ",
- uhp->uh_seq, changes);
+ vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ",
+ uhp->uh_seq, changes);
u_add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
uhp->uh_time);
if (uhp->uh_save_nr > 0) {
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 09f80ca849..834720edc6 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -17,7 +17,6 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
-local wait = helpers.wait
if helpers.pending_win32(pending) then return end
@@ -473,14 +472,24 @@ describe("tui 't_Co' (terminal colors)", function()
nvim_prog,
nvim_set))
- feed_data(":echo &t_Co\n")
- wait()
local tline
if maxcolors == 8 or maxcolors == 16 then
tline = "~ "
else
tline = "{4:~ }"
end
+
+ screen:expect(string.format([[
+ {1: } |
+ %s|
+ %s|
+ %s|
+ %s|
+ |
+ {3:-- TERMINAL --} |
+ ]], tline, tline, tline, tline))
+
+ feed_data(":echo &t_Co\n")
screen:expect(string.format([[
{1: } |
%s|