aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/build.bat23
-rw-r--r--runtime/doc/autocmd.txt6
-rw-r--r--scripts/genoptions.lua1
-rwxr-xr-xsrc/clint.py5
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer.c20
-rw-r--r--src/nvim/eval.c50
-rw-r--r--src/nvim/fileio.c105
-rw-r--r--src/nvim/keymap.c6
-rw-r--r--src/nvim/mark.c8
-rw-r--r--src/nvim/option.c31
-rw-r--r--src/nvim/options.lua6
-rw-r--r--src/nvim/screen.c20
-rw-r--r--src/nvim/testdir/runtest.vim6
-rw-r--r--src/nvim/testdir/setup.vim7
-rw-r--r--src/nvim/testdir/test17.in14
-rw-r--r--src/nvim/testdir/test73.in11
-rw-r--r--src/nvim/testdir/test_autocmd.vim105
-rw-r--r--src/nvim/testdir/test_expr.vim72
-rw-r--r--src/nvim/testdir/test_goto.vim15
-rw-r--r--src/nvim/testdir/test_syn_attr.vim2
-rw-r--r--src/nvim/version.c28
-rw-r--r--src/nvim/window.c42
-rw-r--r--test/functional/autocmd/autocmd_spec.lua2
-rw-r--r--test/functional/core/job_spec.lua18
-rw-r--r--test/functional/eval/setpos_spec.lua64
26 files changed, 491 insertions, 177 deletions
diff --git a/.ci/build.bat b/.ci/build.bat
index d21957718d..87a171b994 100644
--- a/.ci/build.bat
+++ b/.ci/build.bat
@@ -3,11 +3,11 @@
:: in MSYS2, but we cannot build inside the MSYS2 shell.
echo on
if "%CONFIGURATION%" == "MINGW_32" (
- set ARCH=i686
- set BITS=32
+ set ARCH=i686
+ set BITS=32
) else (
- set ARCH=x86_64
- set BITS=64
+ set ARCH=x86_64
+ set BITS=64
)
:: We cannot have sh.exe in the PATH (MinGW)
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
@@ -19,12 +19,15 @@ set PATH=C:\Program Files (x86)\CMake\bin\cpack.exe;%PATH%
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" || goto :error
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-%ARCH%-cmake mingw-w64-%ARCH%-perl mingw-w64-%ARCH%-diffutils gperf" || goto :error
-:: Use Appveyor's python
-set PATH=C:\Python27;C:\Python27\Scripts;%PATH%
-set PATH=C:\Python35;C:\Python35\Scripts;%PATH%
-copy c:\Python35\python.exe c:\Python35\python3.exe
-pip2 install neovim || goto error
-pip3 install neovim || goto error
+:: Setup python (use AppVeyor system python)
+C:\Python27\python.exe -m pip install neovim || goto :error
+C:\Python35\python.exe -m pip install neovim || goto :error
+:: Disambiguate python3
+move c:\Python35\python.exe c:\Python35\python3.exe
+set PATH=C:\Python35;C:\Python27;%PATH%
+:: Sanity check
+python -c "import neovim; print(str(neovim))" || goto :error
+python3 -c "import neovim; print(str(neovim))" || goto :error
mkdir .deps
cd .deps
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 9074141d77..320c821f21 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -296,6 +296,7 @@ Name triggered by ~
|CursorMoved| the cursor was moved in Normal mode
|CursorMovedI| the cursor was moved in Insert mode
+|WinNew| after creating a new window
|WinEnter| after entering another window
|WinLeave| before leaving a window
|TabEnter| after entering another tab page
@@ -1004,6 +1005,11 @@ WinLeave Before leaving a window. If the window to be
WinLeave autocommands (but not for ":new").
Not used for ":qa" or ":q" when exiting Vim.
+ *WinNew*
+WinNew When a new window was created. Not done for
+ the fist window, when Vim has just started.
+ Before a WinEnter event.
+
==============================================================================
6. Patterns *autocmd-patterns* *{pat}*
diff --git a/scripts/genoptions.lua b/scripts/genoptions.lua
index 9f7d94969d..9d7f235a3b 100644
--- a/scripts/genoptions.lua
+++ b/scripts/genoptions.lua
@@ -31,6 +31,7 @@ local type_flags={
local redraw_flags={
statuslines='P_RSTAT',
current_window='P_RWIN',
+ current_window_only='P_RWINONLY',
current_buffer='P_RBUF',
all_windows='P_RALL',
everything='P_RCLR',
diff --git a/src/clint.py b/src/clint.py
index e0f4d3eec5..0c9f55c71e 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -3434,8 +3434,9 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
# When reading from stdin, the extension is unknown, so no cpplint tests
# should rely on the extension.
if filename != '-' and file_extension not in _valid_extensions:
- sys.stderr.write('Ignoring %s; not a valid file name '
- '(%s)\n' % (filename, ', '.join(_valid_extensions)))
+ sys.stderr.write('Ignoring {}; only linting {} files\n'.format(
+ filename,
+ ', '.join('.{}'.format(ext) for ext in _valid_extensions)))
else:
ProcessFileData(filename, file_extension, lines, Error,
extra_check_functions)
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 6c62748aae..68a47c244f 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -90,6 +90,7 @@ return {
'VimLeave', -- before exiting Vim
'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
+ 'WinNew', -- when entering a new window
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
},
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 04a3235dc6..600cf575fc 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -409,9 +409,6 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
buf->b_nwindows = nwindows;
buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
- if (win_valid_any_tab(win) && win->w_buffer == buf) {
- win->w_buffer = NULL; // make sure we don't use the buffer now
- }
/* Autocommands may have deleted the buffer. */
if (!buf_valid(buf))
@@ -419,11 +416,6 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
if (aborting()) /* autocmds may abort script processing */
return;
- /* Autocommands may have opened or closed windows for this buffer.
- * Decrement the count for the close we do here. */
- if (buf->b_nwindows > 0)
- --buf->b_nwindows;
-
/*
* It's possible that autocommands change curbuf to the one being deleted.
* This might cause the previous curbuf to be deleted unexpectedly. But
@@ -434,6 +426,16 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
if (buf == curbuf && !is_curbuf)
return;
+ if (win_valid_any_tab(win) && win->w_buffer == buf) {
+ win->w_buffer = NULL; // make sure we don't use the buffer now
+ }
+
+ // Autocommands may have opened or closed windows for this buffer.
+ // Decrement the count for the close we do here.
+ if (buf->b_nwindows > 0) {
+ buf->b_nwindows--;
+ }
+
/* Change directories when the 'acd' option is set. */
do_autochdir();
@@ -3443,7 +3445,7 @@ int build_stl_str_hl(
case STL_KEYMAP:
fillable = false;
- if (get_keymap_str(wp, tmp, TMPLEN))
+ if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN))
str = tmp;
break;
case STL_PAGENUM:
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index cdf60d9765..6b14d21da7 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -6726,6 +6726,7 @@ static bool get_dict_callback(dict_T *d, char *key, Callback *result)
/// Get a string item from a dictionary.
///
/// @param save whether memory should be allocated for the return value
+/// when false a shared buffer is used, can only be used once!
///
/// @return the entry or NULL if the entry doesn't exist.
char_u *get_dict_string(dict_T *d, char *key, bool save)
@@ -9573,24 +9574,29 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
+ linenr_T foldstart;
+ linenr_T foldend;
+ char_u *dashes;
+ linenr_T lnum;
char_u *s;
char_u *r;
- int len;
+ int len;
char *txt;
+ long count;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
- if ((linenr_T)vimvars[VV_FOLDSTART].vv_nr > 0
- && (linenr_T)vimvars[VV_FOLDEND].vv_nr
- <= curbuf->b_ml.ml_line_count
- && vimvars[VV_FOLDDASHES].vv_str != NULL) {
+
+ foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
+ foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
+ dashes = get_vim_var_str(VV_FOLDDASHES);
+ if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
+ && dashes != NULL) {
/* Find first non-empty line in the fold. */
- lnum = (linenr_T)vimvars[VV_FOLDSTART].vv_nr;
- while (lnum < (linenr_T)vimvars[VV_FOLDEND].vv_nr) {
- if (!linewhite(lnum))
+ for (lnum = foldstart; lnum < foldend; ++lnum) {
+ if (!linewhite(lnum)) {
break;
- ++lnum;
+ }
}
/* Find interesting text in this line. */
@@ -9598,21 +9604,19 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/* skip C comment-start */
if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) {
s = skipwhite(s + 2);
- if (*skipwhite(s) == NUL
- && lnum + 1 < (linenr_T)vimvars[VV_FOLDEND].vv_nr) {
+ if (*skipwhite(s) == NUL && lnum + 1 < foldend) {
s = skipwhite(ml_get(lnum + 1));
if (*s == '*')
s = skipwhite(s + 1);
}
}
+ count = (long)(foldend - foldstart + 1);
txt = _("+-%s%3ld lines: ");
r = xmalloc(STRLEN(txt)
- + STRLEN(vimvars[VV_FOLDDASHES].vv_str) // for %s
- + 20 // for %3ld
- + STRLEN(s)); // concatenated
- sprintf((char *)r, txt, vimvars[VV_FOLDDASHES].vv_str,
- (long)((linenr_T)vimvars[VV_FOLDEND].vv_nr
- - (linenr_T)vimvars[VV_FOLDSTART].vv_nr + 1));
+ + STRLEN(dashes) // for %s
+ + 20 // for %3ld
+ + STRLEN(s)); // concatenated
+ sprintf((char *)r, txt, dashes, count);
len = (int)STRLEN(r);
STRCAT(r, s);
/* remove 'foldmarker' and 'commentstring' */
@@ -15445,12 +15449,11 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- char_u *group = get_dict_string(d, "group", false);
+ char_u *group = get_dict_string(d, "group", true);
int priority = get_dict_number(d, "priority");
int id = get_dict_number(d, "id");
char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
- ? get_dict_string(d, "conceal",
- false)
+ ? get_dict_string(d, "conceal", true)
: NULL;
if (i == 0) {
match_add(curwin, group,
@@ -15461,6 +15464,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_unref(s);
s = NULL;
}
+ xfree(group);
+ xfree(conceal);
li = li->li_next;
}
rettv->vval.v_number = 0;
@@ -23183,11 +23188,10 @@ static void on_job_output(Stream *stream, TerminalJobData *data, RBuffer *buf,
terminal_receive(data->term, ptr, count);
}
+ rbuffer_consumed(buf, count);
if (callback->type != kCallbackNone) {
process_job_event(data, callback, type, ptr, count, 0);
}
-
- rbuffer_consumed(buf, count);
}
static void eval_job_process_exit_cb(Process *proc, int status, void *d)
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 3f5152aea3..13329d771b 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -281,7 +281,7 @@ readfile (
int wasempty; /* buffer was empty before reading */
colnr_T len;
long size = 0;
- char_u *p;
+ char_u *p = NULL;
off_t filesize = 0;
int skip_read = FALSE;
context_sha256_T sha_ctx;
@@ -1883,16 +1883,20 @@ failed:
xfree(keep_msg);
keep_msg = NULL;
msg_scrolled_ign = TRUE;
- p = msg_trunc_attr(IObuff, FALSE, 0);
+
+ if (!read_stdin && !read_buffer) {
+ p = msg_trunc_attr(IObuff, FALSE, 0);
+ }
+
if (read_stdin || read_buffer || restart_edit != 0
- || (msg_scrolled != 0 && !need_wait_return))
- /* Need to repeat the message after redrawing when:
- * - When reading from stdin (the screen will be cleared next).
- * - When restart_edit is set (otherwise there will be a delay
- * before redrawing).
- * - When the screen was scrolled but there is no wait-return
- * prompt. */
+ || (msg_scrolled != 0 && !need_wait_return)) {
+ // Need to repeat the message after redrawing when:
+ // - When reading from stdin (the screen will be cleared next).
+ // - When restart_edit is set (otherwise there will be a delay before
+ // redrawing).
+ // - When the screen was scrolled but there is no wait-return prompt.
set_keep_msg(p, 0);
+ }
msg_scrolled_ign = FALSE;
}
@@ -5373,6 +5377,8 @@ static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
*/
static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
+// use get_deleted_augroup() to get this
+static char_u *deleted_augroup = NULL;
/*
* The ID of the current group. Group 0 is the default one.
@@ -5387,6 +5393,14 @@ static event_T last_event;
static int last_group;
static int autocmd_blocked = 0; /* block all autocmds */
+static char_u *get_deleted_augroup(void)
+{
+ if (deleted_augroup == NULL) {
+ deleted_augroup = (char_u *)_("--Deleted--");
+ }
+ return deleted_augroup;
+}
+
/*
* Show the autocommands for one AutoPat.
*/
@@ -5406,10 +5420,11 @@ static void show_autocmd(AutoPat *ap, event_T event)
return;
if (event != last_event || ap->group != last_group) {
if (ap->group != AUGROUP_DEFAULT) {
- if (AUGROUP_NAME(ap->group) == NULL)
- msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
- else
+ if (AUGROUP_NAME(ap->group) == NULL) {
+ msg_puts_attr(get_deleted_augroup(), hl_attr(HLF_E));
+ } else {
msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
+ }
msg_puts((char_u *)" ");
}
msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
@@ -5575,11 +5590,33 @@ static void au_del_group(char_u *name)
int i;
i = au_find_group(name);
- if (i == AUGROUP_ERROR) /* the group doesn't exist */
+ if (i == AUGROUP_ERROR) { // the group doesn't exist
EMSG2(_("E367: No such group: \"%s\""), name);
- else {
+ } else if (i == current_augroup) {
+ EMSG(_("E936: Cannot delete the current group"));
+ } else {
+ event_T event;
+ AutoPat *ap;
+ int in_use = false;
+
+ for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ event = (event_T)((int)event + 1)) {
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
+ if (ap->group == i && ap->pat != NULL) {
+ give_warning((char_u *)
+ _("W19: Deleting augroup that is still in use"), true);
+ in_use = true;
+ event = NUM_EVENTS;
+ break;
+ }
+ }
+ }
xfree(AUGROUP_NAME(i));
- AUGROUP_NAME(i) = NULL;
+ if (in_use) {
+ AUGROUP_NAME(i) = get_deleted_augroup();
+ } else {
+ AUGROUP_NAME(i) = NULL;
+ }
}
}
@@ -5591,8 +5628,9 @@ static void au_del_group(char_u *name)
static int au_find_group(const char_u *name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- for (int i = 0; i < augroups.ga_len; ++i) {
- if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0) {
+ for (int i = 0; i < augroups.ga_len; i++) {
+ if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
+ && STRCMP(AUGROUP_NAME(i), name) == 0) {
return i;
}
}
@@ -5640,10 +5678,21 @@ void do_augroup(char_u *arg, int del_group)
#if defined(EXITFREE)
void free_all_autocmds(void)
{
+ int i;
+ char_u *s;
+
for (current_augroup = -1; current_augroup < augroups.ga_len;
- ++current_augroup)
- do_autocmd((char_u *)"", TRUE);
- ga_clear_strings(&augroups);
+ current_augroup++) {
+ do_autocmd((char_u *)"", true);
+ }
+
+ for (i = 0; i < augroups.ga_len; i++) {
+ s = ((char_u **)(augroups.ga_data))[i];
+ if (s != get_deleted_augroup()) {
+ xfree(s);
+ }
+ }
+ ga_clear(&augroups);
}
#endif
@@ -7107,9 +7156,11 @@ char_u *get_augroup_name(expand_T *xp, int idx)
return (char_u *)"END";
if (idx >= augroups.ga_len) /* end of list */
return NULL;
- if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
+ if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) {
+ // skip deleted entries
return (char_u *)"";
- return AUGROUP_NAME(idx); /* return a name */
+ }
+ return AUGROUP_NAME(idx); // return a name
}
static int include_groups = FALSE;
@@ -7166,10 +7217,12 @@ set_context_in_autocmd (
*/
char_u *get_event_name(expand_T *xp, int idx)
{
- if (idx < augroups.ga_len) { /* First list group names, if wanted */
- if (!include_groups || AUGROUP_NAME(idx) == NULL)
- return (char_u *)""; /* skip deleted entries */
- return AUGROUP_NAME(idx); /* return a name */
+ if (idx < augroups.ga_len) { // First list group names, if wanted
+ if (!include_groups || AUGROUP_NAME(idx) == NULL
+ || AUGROUP_NAME(idx) == get_deleted_augroup()) {
+ return (char_u *)""; // skip deleted entries
+ }
+ return AUGROUP_NAME(idx); // return a name
}
return (char_u *)event_names[idx - augroups.ga_len].name;
}
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 99e94fc60f..94bbaf4239 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -573,8 +573,10 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
} else {
l = 1;
}
- if (end - bp > l && bp[l + 1] == '>') {
- bp += l; // anything accepted, like <C-?>
+ if (end - bp > l && bp[l] != '"' && bp[l + 1] == '>') {
+ // Anything accepted, like <C-?>, except <C-">, because the "
+ // ends the string.
+ bp += l;
}
}
}
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index bb5b8e8178..4e05845eb5 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -130,9 +130,15 @@ int setmark_pos(int c, pos_T *pos, int fnum)
return OK;
}
+ buf_T *buf = buflist_findnr(fnum);
+ // Can't set a mark in a non-existant buffer.
+ if (buf == NULL) {
+ return FAIL;
+ }
+
if (ASCII_ISLOWER(c)) {
i = c - 'a';
- RESET_FMARK(curbuf->b_namedm + i, *pos, curbuf->b_fnum);
+ RESET_FMARK(buf->b_namedm + i, *pos, fnum);
return OK;
}
if (ASCII_ISUPPER(c) || ascii_isdigit(c)) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 52a8b19ca4..a4e7da770e 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -213,12 +213,12 @@ typedef struct vimoption {
#define P_VI_DEF 0x400U /* Use Vi default for Vim */
#define P_VIM 0x800U /* Vim option */
-/* when option changed, what to display: */
-#define P_RSTAT 0x1000U /* redraw status lines */
-#define P_RWIN 0x2000U /* redraw current window */
-#define P_RBUF 0x4000U /* redraw current buffer */
-#define P_RALL 0x6000U /* redraw all windows */
-#define P_RCLR 0x7000U /* clear and redraw all */
+// when option changed, what to display:
+#define P_RSTAT 0x1000U ///< redraw status lines
+#define P_RWIN 0x2000U ///< redraw current window and recompute text
+#define P_RBUF 0x4000U ///< redraw current buffer and recompute text
+#define P_RALL 0x6000U ///< redraw all windows
+#define P_RCLR 0x7000U ///< clear and redraw all
#define P_COMMA 0x8000U ///< comma separated list
#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive
@@ -238,6 +238,8 @@ typedef struct vimoption {
///< when there is a redraw flag
#define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value.
+#define P_RWINONLY 0x10000000U ///< only redraw current window
+
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
"d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr," \
@@ -4357,17 +4359,24 @@ static void check_redraw(uint32_t flags)
bool doclear = (flags & P_RCLR) == P_RCLR;
bool all = ((flags & P_RALL) == P_RALL || doclear);
- if ((flags & P_RSTAT) || all) /* mark all status lines dirty */
+ if ((flags & P_RSTAT) || all) { // mark all status lines dirty
status_redraw_all();
+ }
- if ((flags & P_RBUF) || (flags & P_RWIN) || all)
+ if ((flags & P_RBUF) || (flags & P_RWIN) || all) {
changed_window_setting();
- if (flags & P_RBUF)
+ }
+ if (flags & P_RBUF) {
redraw_curbuf_later(NOT_VALID);
- if (doclear)
+ }
+ if (flags & P_RWINONLY) {
+ redraw_later(NOT_VALID);
+ }
+ if (doclear) {
redraw_all_later(CLEAR);
- else if (all)
+ } else if (all) {
redraw_all_later(NOT_VALID);
+ }
}
/// Find index for named option
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 70d1f73cf4..859658e40d 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -17,8 +17,8 @@
-- types: bool, number, string
-- lists: (nil), comma, onecomma, flags, flagscomma
-- scopes: global, buffer, window
--- redraw options: statuslines, current_window, current_buffer, all_windows,
--- everything, curswant
+-- redraw options: statuslines, current_window, curent_window_only,
+-- current_buffer, all_windows, everything, curswant
-- default: {vi=…[, vim=…]}
-- defaults: {condition=#if condition, if_true=default, if_false=default}
-- #if condition:
@@ -539,7 +539,7 @@ return {
full_name='cursorline', abbreviation='cul',
type='bool', scope={'window'},
vi_def=true,
- redraw={'current_window'},
+ redraw={'current_window_only'},
defaults={if_true={vi=false}}
},
{
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 41acc48f97..c0db076eff 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -4912,7 +4912,7 @@ void win_redr_status(win_T *wp)
screen_fill(row, row + 1, len + wp->w_wincol,
this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
- if (get_keymap_str(wp, NameBuff, MAXPATHL)
+ if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
&& this_ru_col - len > (int)(STRLEN(NameBuff) + 1))
screen_puts(NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff)
- 1 + wp->w_wincol), attr);
@@ -4993,8 +4993,9 @@ int stl_connected(win_T *wp)
int
get_keymap_str (
win_T *wp,
- char_u *buf, /* buffer for the result */
- int len /* length of buffer */
+ char_u *fmt, // format string containing one %s item
+ char_u *buf, // buffer for the result
+ int len // length of buffer
)
{
char_u *p;
@@ -5021,10 +5022,9 @@ get_keymap_str (
else
p = (char_u *)"lang";
}
- if ((int)(STRLEN(p) + 3) < len)
- sprintf((char *)buf, "<%s>", p);
- else
+ if (vim_snprintf((char *)buf, len, (char *)fmt, p) > len - 1) {
buf[0] = NUL;
+ }
xfree(s);
}
return buf[0] != NUL;
@@ -6752,10 +6752,12 @@ int showmode(void)
if (p_fkmap)
MSG_PUTS_ATTR(farsi_text_5, attr);
if (State & LANGMAP) {
- if (curwin->w_p_arab)
+ if (curwin->w_p_arab) {
MSG_PUTS_ATTR(_(" Arabic"), attr);
- else
- MSG_PUTS_ATTR(_(" (lang)"), attr);
+ } else if (get_keymap_str(curwin, (char_u *)" (%s)",
+ NameBuff, MAXPATHL)) {
+ MSG_PUTS_ATTR(NameBuff, attr);
+ }
}
if ((State & INSERT) && p_paste)
MSG_PUTS_ATTR(_(" (paste)"), attr);
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 20863bbaf3..eb5912086b 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -39,6 +39,9 @@ if &lines < 24 || &columns < 80
cquit
endif
+" Common with all tests on all systems.
+source setup.vim
+
" This also enables use of line continuation.
set viminfo+=nviminfo
@@ -59,9 +62,6 @@ lang mess C
" Always use forward slashes.
set shellslash
-" Make sure $HOME does not get read or written.
-let $HOME = '/does/not/exist'
-
" Align with vim defaults.
set directory^=.
set nohidden
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
new file mode 100644
index 0000000000..52876d1e6c
--- /dev/null
+++ b/src/nvim/testdir/setup.vim
@@ -0,0 +1,7 @@
+" Common preparations for running tests.
+
+" Make sure 'runtimepath' does not include $HOME.
+set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
+
+" Make sure $HOME does not get read or written.
+let $HOME = '/does/not/exist'
diff --git a/src/nvim/testdir/test17.in b/src/nvim/testdir/test17.in
index 83abe17770..1a4ac6b6d1 100644
--- a/src/nvim/testdir/test17.in
+++ b/src/nvim/testdir/test17.in
@@ -4,13 +4,7 @@ Tests for:
STARTTEST
:set isfname=@,48-57,/,.,-,_,+,,,$,:,~,{,}
-:function! DeleteDirectory(dir)
-: if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32")
-: exec "silent !rmdir /Q /S " . a:dir
-: else
-: exec "silent !rm -rf " . a:dir
-: endif
-:endfun
+:"
:if has("unix")
:let $CDIR = "."
/CDIR
@@ -36,7 +30,7 @@ STARTTEST
:" check for 'include' without \zs or \ze
:lang C
:call delete("./Xbase.a")
-:call DeleteDirectory("Xdir1")
+:call delete("Xdir1", "rf")
:!mkdir Xdir1
:!mkdir "Xdir1/dir2"
:e! Xdir1/dir2/foo.a
@@ -61,7 +55,7 @@ ENDTEST
STARTTEST
:" check for 'include' with \zs and \ze
:call delete("./Xbase.b")
-:call DeleteDirectory("Xdir1")
+:call delete("Xdir1", "rf")
:!mkdir Xdir1
:!mkdir "Xdir1/dir2"
:let &include='^\s*%inc\s*/\zs[^/]\+\ze'
@@ -91,7 +85,7 @@ ENDTEST
STARTTEST
:" check for 'include' with \zs and no \ze
:call delete("./Xbase.c")
-:call DeleteDirectory("Xdir1")
+:call delete("Xdir1", "rf")
:!mkdir Xdir1
:!mkdir "Xdir1/dir2"
:let &include='^\s*%inc\s*\%([[:upper:]][^[:space:]]*\s\+\)\?\zs\S\+\ze'
diff --git a/src/nvim/testdir/test73.in b/src/nvim/testdir/test73.in
index 7d6c7287a5..9d50f7a789 100644
--- a/src/nvim/testdir/test73.in
+++ b/src/nvim/testdir/test73.in
@@ -8,16 +8,9 @@ STARTTEST
:" This will cause a few errors, do it silently.
:set visualbell
:"
-:function! DeleteDirectory(dir)
-: if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32")
-: exec "silent !rmdir /Q /S " . a:dir
-: else
-: exec "silent !rm -rf " . a:dir
-: endif
-:endfun
:" On windows a stale "Xfind" directory may exist, remove it so that
:" we start from a clean state.
-:call DeleteDirectory("Xfind")
+:call delete("Xfind", "rf")
:new
:let cwd=getcwd()
:let test_out = cwd . '/test.out'
@@ -169,7 +162,7 @@ SVoyager 2:w
:exec "w >>" . test_out
:q
:exec "cd " . cwd
-:call DeleteDirectory("Xfind")
+:call delete("Xfind", "rf")
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 5675697dc4..f05a55f1aa 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -64,6 +64,66 @@ function Test_bufunload()
augroup! test_bufunload_group
endfunc
+" SEGV occurs in older versions. (At least 7.4.2005 or older)
+function Test_autocmd_bufunload_with_tabnext()
+ tabedit
+ tabfirst
+
+ augroup test_autocmd_bufunload_with_tabnext_group
+ autocmd!
+ autocmd BufUnload <buffer> tabnext
+ augroup END
+
+ quit
+ call assert_equal(2, tabpagenr('$'))
+
+ augroup! test_autocmd_bufunload_with_tabnext_group
+ tablast
+ quit
+endfunc
+
+func Test_win_tab_autocmd()
+ let g:record = []
+
+ augroup testing
+ au WinNew * call add(g:record, 'WinNew')
+ au WinEnter * call add(g:record, 'WinEnter')
+ au WinLeave * call add(g:record, 'WinLeave')
+ au TabNew * call add(g:record, 'TabNew')
+ au TabClosed * call add(g:record, 'TabClosed')
+ au TabEnter * call add(g:record, 'TabEnter')
+ au TabLeave * call add(g:record, 'TabLeave')
+ augroup END
+
+ split
+ tabnew
+ close
+ close
+
+ call assert_equal([
+ \ 'WinLeave', 'WinNew', 'WinEnter',
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
+ \ 'WinLeave', 'WinEnter'
+ \ ], g:record)
+
+ let g:record = []
+ tabnew somefile
+ tabnext
+ bwipe somefile
+
+ call assert_equal([
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
+ \ 'TabClosed'
+ \ ], g:record)
+
+ augroup testing
+ au!
+ augroup END
+ unlet g:record
+endfunc
+
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
@@ -91,3 +151,48 @@ func Test_early_bar()
au! vimBarTest|echo 'hello'
call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
endfunc
+
+func RemoveGroup()
+ autocmd! StartOK
+ augroup! StartOK
+endfunc
+
+func Test_augroup_warning()
+ augroup TheWarning
+ au VimEnter * echo 'entering'
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "TheWarning.*VimEnter") >= 0)
+ redir => res
+ augroup! TheWarning
+ redir END
+ call assert_true(match(res, "W19:") >= 0)
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+
+ " check "Another" does not take the pace of the deleted entry
+ augroup Another
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+
+ " no warning for postpone aucmd delete
+ augroup StartOK
+ au VimEnter * call RemoveGroup()
+ augroup END
+ call assert_true(match(execute('au VimEnter'), "StartOK.*VimEnter") >= 0)
+ redir => res
+ doautocmd VimEnter
+ redir END
+ call assert_true(match(res, "W19:") < 0)
+ au! VimEnter
+endfunc
+
+func Test_augroup_deleted()
+ " This caused a crash before E936 was introduced
+ augroup x
+ call assert_fails('augroup! x', 'E936:')
+ au VimEnter * echo
+ augroup end
+ augroup! x
+ call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
+ au! VimEnter
+endfunc
+
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 7483973fca..39dcacb55f 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -1,20 +1,5 @@
" Tests for expressions.
-func Test_version()
- call assert_true(has('patch-7.4.001'))
- call assert_true(has('patch-7.4.01'))
- call assert_true(has('patch-7.4.1'))
- call assert_true(has('patch-6.9.999'))
- call assert_true(has('patch-7.1.999'))
- call assert_true(has('patch-7.4.123'))
-
- call assert_false(has('patch-7'))
- call assert_false(has('patch-7.4'))
- call assert_false(has('patch-7.4.'))
- call assert_false(has('patch-9.1.0'))
- call assert_false(has('patch-9.9.1'))
-endfunc
-
func Test_equal()
let base = {}
func base.method()
@@ -37,6 +22,35 @@ func Test_equal()
call assert_fails('echo base.method > instance.method')
endfunc
+func Test_version()
+ call assert_true(has('patch-7.4.001'))
+ call assert_true(has('patch-7.4.01'))
+ call assert_true(has('patch-7.4.1'))
+ call assert_true(has('patch-6.9.999'))
+ call assert_true(has('patch-7.1.999'))
+ call assert_true(has('patch-7.4.123'))
+
+ call assert_false(has('patch-7'))
+ call assert_false(has('patch-7.4'))
+ call assert_false(has('patch-7.4.'))
+ call assert_false(has('patch-9.1.0'))
+ call assert_false(has('patch-9.9.1'))
+endfunc
+
+func Test_dict()
+ let d = {'': 'empty', 'a': 'a', 0: 'zero'}
+ call assert_equal('empty', d[''])
+ call assert_equal('a', d['a'])
+ call assert_equal('zero', d[0])
+ call assert_true(has_key(d, ''))
+ call assert_true(has_key(d, 'a'))
+
+ let d[''] = 'none'
+ let d['a'] = 'aaa'
+ call assert_equal('none', d[''])
+ call assert_equal('aaa', d['a'])
+endfunc
+
func Test_strgetchar()
call assert_equal(char2nr('a'), strgetchar('axb', 0))
call assert_equal(char2nr('x'), strgetchar('axb', 1))
@@ -61,20 +75,6 @@ func Test_strcharpart()
call assert_equal('a', strcharpart('axb', -1, 2))
endfunc
-func Test_dict()
- let d = {'': 'empty', 'a': 'a', 0: 'zero'}
- call assert_equal('empty', d[''])
- call assert_equal('a', d['a'])
- call assert_equal('zero', d[0])
- call assert_true(has_key(d, ''))
- call assert_true(has_key(d, 'a'))
-
- let d[''] = 'none'
- let d['a'] = 'aaa'
- call assert_equal('none', d[''])
- call assert_equal('aaa', d['a'])
-endfunc
-
func Test_loop_over_null_list()
let null_list = submatch(1, 1)
for i in null_list
@@ -92,3 +92,17 @@ endfunc
func Test_set_reg_null_list()
call setreg('x', v:_null_list)
endfunc
+
+func Test_special_char()
+ " The failure is only visible using valgrind.
+ call assert_fails('echo "\<C-">')
+endfunc
+
+func Test_setmatches()
+ hi def link 1 Comment
+ hi def link 2 PreProc
+ let set = [{"group": 1, "pattern": 2, "id": 3, "priority": 4, "conceal": 5}]
+ let exp = [{"group": '1', "pattern": '2', "id": 3, "priority": 4, "conceal": '5'}]
+ call setmatches(set)
+ call assert_equal(exp, getmatches())
+endfunc
diff --git a/src/nvim/testdir/test_goto.vim b/src/nvim/testdir/test_goto.vim
index 2afd96b296..b6ac5720c3 100644
--- a/src/nvim/testdir/test_goto.vim
+++ b/src/nvim/testdir/test_goto.vim
@@ -18,3 +18,18 @@ func Test_gee_dee()
call assert_equal(14, col('.'))
quit!
endfunc
+
+" Check that setting 'cursorline' does not change curswant
+func Test_cursorline_keep_col()
+ new
+ call setline(1, ['long long long line', 'short line'])
+ normal ggfi
+ let pos = getcurpos()
+ normal j
+ set cursorline
+ normal k
+ call assert_equal(pos, getcurpos())
+ bwipe!
+ set nocursorline
+endfunc
+
diff --git a/src/nvim/testdir/test_syn_attr.vim b/src/nvim/testdir/test_syn_attr.vim
index 94d6b8735f..64aab3411d 100644
--- a/src/nvim/testdir/test_syn_attr.vim
+++ b/src/nvim/testdir/test_syn_attr.vim
@@ -20,7 +20,7 @@ func Test_missing_attr()
if fontname == ''
let fontname = 'something'
endif
- exe 'hi Mine guifg=blue guibg=red font=' . escape(fontname, ' \')
+ exe "hi Mine guifg=blue guibg=red font='" . fontname . "'"
call assert_equal('blue', synIDattr(hlID("Mine"), "fg", 'gui'))
call assert_equal('red', synIDattr(hlID("Mine"), "bg", 'gui'))
call assert_equal(fontname, synIDattr(hlID("Mine"), "font", 'gui'))
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 3e9cccda20..93dd72f7fa 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -126,8 +126,8 @@ static int included_patches[] = {
// 2317,
// 2316 NA
// 2315,
- // 2314,
- // 2313,
+ 2314,
+ 2313,
2312,
// 2311 NA
// 2310 NA
@@ -140,7 +140,7 @@ static int included_patches[] = {
// 2303,
// 2302 NA
// 2301 NA
- // 2300,
+ 2300,
// 2299,
// 2298 NA
// 2297 NA
@@ -280,7 +280,7 @@ static int included_patches[] = {
2163,
2162,
// 2161,
- // 2160,
+ 2160,
// 2159,
2158,
// 2157 NA
@@ -323,7 +323,7 @@ static int included_patches[] = {
// 2120,
// 2119,
// 2118 NA
- // 2117,
+ 2117,
// 2116 NA
// 2115 NA
// 2114 NA
@@ -341,7 +341,7 @@ static int included_patches[] = {
// 2102 NA
// 2101,
2100,
- // 2099,
+ 2099,
// 2098,
// 2097,
// 2096,
@@ -363,9 +363,9 @@ static int included_patches[] = {
// 2080,
// 2079 NA
// 2078 NA
- // 2077,
+ 2077,
// 2076,
- // 2075,
+ 2075,
// 2074,
// 2073 NA
// 2072,
@@ -375,7 +375,7 @@ static int included_patches[] = {
// 2068,
// 2067,
2066,
- // 2065,
+ 2065,
// 2064,
// 2063 NA
// 2062,
@@ -409,7 +409,7 @@ static int included_patches[] = {
// 2034 NA
2033,
// 2032 NA
- // 2031,
+ 2031,
// 2030 NA
// 2029,
2028,
@@ -434,7 +434,7 @@ static int included_patches[] = {
2009,
2008,
2007,
- // 2006,
+ 2006,
2005,
// 2004 NA
// 2003 NA
@@ -472,7 +472,7 @@ static int included_patches[] = {
1971,
1970,
// 1969 NA
- // 1968,
+ 1968,
1967,
1966,
// 1965 NA
@@ -530,7 +530,7 @@ static int included_patches[] = {
1913,
1912,
// 1911 NA
- // 1910,
+ 1910,
1909,
// 1908 NA
// 1907 NA
@@ -589,7 +589,7 @@ static int included_patches[] = {
// 1854 NA
// 1853 NA
// 1852 NA
- // 1851,
+ 1851,
// 1850 NA
// 1849 NA
// 1848 NA
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 00229ccca9..89228e1b0f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -973,11 +973,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/*
* make the new window the current window
*/
- win_enter(wp, false);
- if (flags & WSP_VERT)
+ win_enter_ext(wp, false, false, true, true, true);
+ if (flags & WSP_VERT) {
p_wiw = i;
- else
+ } else {
p_wh = i;
+ }
return OK;
}
@@ -1718,6 +1719,7 @@ close_windows (
{
tabpage_T *tp, *nexttp;
int h = tabline_height();
+ int count = tabpage_index(NULL);
++RedrawingDisabled;
@@ -1754,9 +1756,14 @@ close_windows (
--RedrawingDisabled;
- redraw_tabline = TRUE;
- if (h != tabline_height())
+ if (count != tabpage_index(NULL)) {
+ apply_autocmds(EVENT_TABCLOSED, NULL, NULL, false, curbuf);
+ }
+
+ redraw_tabline = true;
+ if (h != tabline_height()) {
shell_new_rows();
+ }
}
/// Check that current window is the last one.
@@ -2014,10 +2021,11 @@ int win_close(win_T *win, int free_buf)
}
if (close_curwin) {
- win_enter_ext(wp, false, TRUE, TRUE, TRUE);
- if (other_buffer)
- /* careful: after this wp and win may be invalid! */
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ win_enter_ext(wp, false, true, false, true, true);
+ if (other_buffer) {
+ // careful: after this wp and win may be invalid!
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
+ }
}
/*
@@ -3045,8 +3053,9 @@ int win_new_tabpage(int after, char_u *filename)
redraw_all_later(CLEAR);
- apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
return OK;
@@ -3204,8 +3213,8 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
/* We would like doing the TabEnter event first, but we don't have a
* valid current window yet, which may break some commands.
* This triggers autocommands, thus may make "tp" invalid. */
- win_enter_ext(tp->tp_curwin, false, TRUE,
- trigger_enter_autocmds, trigger_leave_autocmds);
+ win_enter_ext(tp->tp_curwin, false, true, false,
+ trigger_enter_autocmds, trigger_leave_autocmds);
prevwin = next_prevwin;
last_status(FALSE); /* status line may appear or disappear */
@@ -3546,7 +3555,7 @@ end:
*/
void win_enter(win_T *wp, bool undo_sync)
{
- win_enter_ext(wp, undo_sync, FALSE, TRUE, TRUE);
+ win_enter_ext(wp, undo_sync, false, false, true, true);
}
/*
@@ -3554,7 +3563,9 @@ void win_enter(win_T *wp, bool undo_sync)
* Can be called with "curwin_invalid" TRUE, which means that curwin has just
* been closed and isn't valid.
*/
-static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int trigger_enter_autocmds, int trigger_leave_autocmds)
+static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
+ int trigger_new_autocmds, int trigger_enter_autocmds,
+ int trigger_leave_autocmds)
{
int other_buffer = FALSE;
@@ -3630,6 +3641,9 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
shorten_fnames(TRUE);
}
+ if (trigger_new_autocmds) {
+ apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
+ }
if (trigger_enter_autocmds) {
apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
if (other_buffer)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 162e112047..c38bd75c69 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -12,8 +12,8 @@ describe('autocmds:', function()
local expected = {
'WinLeave',
'TabLeave',
- 'TabNew',
'WinEnter',
+ 'TabNew',
'TabEnter',
'BufLeave',
'BufEnter'
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 75b50aad0a..48a4689545 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -312,6 +312,24 @@ describe('jobs', function()
end)
end)
+ it('does not repeat output with slow output handlers', function()
+ source([[
+ let d = {'data': []}
+ function! d.on_stdout(job, data, event) dict
+ call add(self.data, a:data)
+ sleep 200m
+ endfunction
+ if has('win32')
+ let cmd = '1,2,3,4,5 | foreach-object -process {echo $_; sleep 0.1}'
+ else
+ let cmd = ['sh', '-c', 'for i in $(seq 1 5); do echo $i; sleep 0.1; done']
+ endif
+ call jobwait([jobstart(cmd, d)])
+ call rpcnotify(g:channel, 'data', d.data)
+ ]])
+ eq({'notification', 'data', {{{'1', ''}, {'2', ''}, {'3', ''}, {'4', ''}, {'5', ''}}}}, next_msg())
+ end)
+
describe('jobwait', function()
it('returns a list of status codes', function()
source([[
diff --git a/test/functional/eval/setpos_spec.lua b/test/functional/eval/setpos_spec.lua
new file mode 100644
index 0000000000..2e27cd8ac0
--- /dev/null
+++ b/test/functional/eval/setpos_spec.lua
@@ -0,0 +1,64 @@
+local helpers = require('test.functional.helpers')(after_each)
+local setpos = helpers.funcs.setpos
+local getpos = helpers.funcs.getpos
+local insert = helpers.insert
+local clear = helpers.clear
+local execute = helpers.execute
+local eval = helpers.eval
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+
+
+describe('setpos() function', function()
+ before_each(function()
+ clear()
+ insert([[
+ First line of text
+ Second line of text
+ Third line of text]])
+ execute('new')
+ insert([[
+ Line of text 1
+ Line of text 2
+ Line of text 3]])
+ end)
+ it('can set the current cursor position', function()
+ setpos(".", {0, 2, 1, 0})
+ eq(getpos("."), {0, 2, 1, 0})
+ setpos(".", {2, 1, 1, 0})
+ eq(getpos("."), {0, 1, 1, 0})
+ -- Ensure get an error attempting to set position to another buffer
+ local ret = exc_exec('call setpos(".", [1, 1, 1, 0])')
+ eq('Vim(call):E474: Invalid argument', ret)
+ end)
+ it('can set lowercase marks in the current buffer', function()
+ setpos("'d", {0, 2, 1, 0})
+ eq(getpos("'d"), {0, 2, 1, 0})
+ execute('undo', 'call setpos("\'d", [2, 3, 1, 0])')
+ eq(getpos("'d"), {0, 3, 1, 0})
+ end)
+ it('can set lowercase marks in other buffers', function()
+ local retval = setpos("'d", {1, 2, 1, 0})
+ eq(0, retval)
+ setpos("'d", {1, 2, 1, 0})
+ eq(getpos("'d"), {0, 0, 0, 0})
+ execute('wincmd w')
+ eq(eval('bufnr("%")'), 1)
+ eq(getpos("'d"), {0, 2, 1, 0})
+ end)
+ it("fails when setting a mark in a buffer that doesn't exist", function()
+ local retval = setpos("'d", {3, 2, 1, 0})
+ eq(-1, retval)
+ eq(getpos("'d"), {0, 0, 0, 0})
+ retval = setpos("'D", {3, 2, 1, 0})
+ eq(-1, retval)
+ eq(getpos("'D"), {0, 0, 0, 0})
+ end)
+ it('can set uppercase marks', function()
+ setpos("'D", {2, 2, 3, 0})
+ eq(getpos("'D"), {2, 2, 3, 0})
+ -- Can set a mark in another buffer
+ setpos("'D", {1, 2, 2, 0})
+ eq(getpos("'D"), {1, 2, 2, 0})
+ end)
+end)