aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/map.txt3
-rw-r--r--runtime/doc/mbyte.txt7
-rw-r--r--runtime/doc/vim_diff.txt6
-rw-r--r--src/nvim/channel.c55
-rw-r--r--src/nvim/digraph.c6
-rw-r--r--src/nvim/edit.c5
-rw-r--r--src/nvim/eval.c16
-rw-r--r--src/nvim/event/time.c9
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c18
-rw-r--r--src/nvim/main.c11
-rw-r--r--src/nvim/memfile.c3
-rw-r--r--src/nvim/memline.c18
-rw-r--r--src/nvim/normal.c9
-rw-r--r--src/nvim/ops.c5
-rw-r--r--src/nvim/option.c12
-rw-r--r--src/nvim/os/stdpaths.c4
-rw-r--r--src/nvim/screen.c10
-rw-r--r--src/nvim/spell.c4
-rw-r--r--src/nvim/spellfile.c7
-rw-r--r--src/nvim/tag.c4
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/testdir/test_autocmd.vim3
-rw-r--r--test/functional/core/job_spec.lua20
-rw-r--r--test/functional/normal/macro_spec.lua30
-rw-r--r--test/functional/options/defaults_spec.lua45
-rw-r--r--test/functional/options/keymap_spec.lua233
-rw-r--r--test/functional/provider/nodejs_spec.lua12
-rw-r--r--test/functional/ui/inccommand_spec.lua15
-rw-r--r--test/functional/viml/completion_spec.lua145
-rw-r--r--third-party/cmake/UnibiliumCMakeLists.txt4
31 files changed, 516 insertions, 206 deletions
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 038e90fab0..7633dbf352 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -411,7 +411,8 @@ state for Insert mode is also used when typing a character as an argument to
command like "f" or "t".
Language mappings will never be applied to already mapped characters. They
are only used for typed characters. This assumes that the language mapping
-was already done when typing the mapping.
+was already done when typing the mapping. Correspondingly, language mappings
+are applied when recording macros, rather than when applying them.
1.4 LISTING MAPPINGS *map-listing*
diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt
index 531629fddc..2d4a20ed72 100644
--- a/runtime/doc/mbyte.txt
+++ b/runtime/doc/mbyte.txt
@@ -834,7 +834,7 @@ keyboards and encodings.
The actual mappings are in the lines below "loadkeymap". In the example "a"
is mapped to "A" and "b" to "B". Thus the first item is mapped to the second
item. This is done for each line, until the end of the file.
-These items are exactly the same as what can be used in a |:lnoremap| command,
+These items are exactly the same as what can be used in a |:lmap| command,
using "<buffer>" to make the mappings local to the buffer.
You can check the result with this command: >
:lmap
@@ -849,8 +849,9 @@ Since Vim doesn't know if the next character after a quote is really an "a",
it will wait for the next character. To be able to insert a single quote,
also add this line: >
'' '
-Since the mapping is defined with |:lnoremap| the resulting quote will not be
-used for the start of another character.
+Since the mapping is defined with |:lmap| the resulting quote will not be
+used for the start of another character defined in the 'keymap'.
+It can be used in a standard |:imap| mapping.
The "accents" keymap uses this. *keymap-accents*
The first column can also be in |<>| form:
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 6ec8220db6..04d78da45a 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -312,6 +312,12 @@ Highlight groups:
VimL (Vim script) compatibility:
`count` does not alias to |v:count|
+|:lmap|s are applied to macro recordings, in Vim if a macro is recorded while
+using |:lmap|ped keys then the behaviour during record and replay differs.
+'keymap' is implemented via |:lmap| instead of |:lnoremap| in order to allow
+using macros and 'keymap' at the same time.
+This means that you can use |:imap| on the results of keys from 'keymap'.
+
==============================================================================
5. Missing legacy features *nvim-features-missing*
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 4e6ca8d278..b37fa10b12 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -25,7 +25,8 @@ typedef struct {
Channel *chan;
Callback *callback;
const char *type;
- list_T *received;
+ // if reader is set, status is ignored.
+ CallbackReader *reader;
int status;
} ChannelEvent;
@@ -253,17 +254,12 @@ void channel_decref(Channel *chan)
void callback_reader_free(CallbackReader *reader)
{
callback_free(&reader->cb);
- if (reader->buffered) {
- ga_clear(&reader->buffer);
- }
+ ga_clear(&reader->buffer);
}
void callback_reader_start(CallbackReader *reader)
{
- if (reader->buffered) {
- ga_init(&reader->buffer, sizeof(char *), 32);
- ga_grow(&reader->buffer, 32);
- }
+ ga_init(&reader->buffer, sizeof(char *), 32);
}
static void free_channel_event(void **argv)
@@ -533,29 +529,27 @@ err:
///
/// @return [allocated] Converted list.
static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
list_T *const l = tv_list_alloc(kListLenMayKnow);
// Empty buffer should be represented by [''], encode_list_write() thinks
// empty list is fine for the case.
tv_list_append_string(l, "", 0);
- encode_list_write(l, buf, len);
+ if (len > 0) {
+ encode_list_write(l, buf, len);
+ }
return l;
}
// vimscript job callbacks must be executed on Nvim main loop
static inline void process_channel_event(Channel *chan, Callback *callback,
- const char *type, char *buf,
- size_t count, int status)
+ const char *type,
+ CallbackReader *reader, int status)
{
assert(callback);
ChannelEvent *event_data = xmalloc(sizeof(*event_data));
- event_data->received = NULL;
- if (buf) {
- event_data->received = buffer_to_tv_list(buf, count);
- } else {
- event_data->status = status;
- }
+ event_data->reader = reader;
+ event_data->status = status;
channel_incref(chan); // Hold on ref to callback
event_data->chan = chan;
event_data->callback = callback;
@@ -605,8 +599,7 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
if (eof) {
if (reader->buffered) {
if (reader->cb.type != kCallbackNone) {
- process_channel_event(chan, &reader->cb, type, reader->buffer.ga_data,
- (size_t)reader->buffer.ga_len, 0);
+ process_channel_event(chan, &reader->cb, type, reader, 0);
} else if (reader->self) {
if (tv_dict_find(reader->self, type, -1) == NULL) {
list_T *data = buffer_to_tv_list(reader->buffer.ga_data,
@@ -617,12 +610,12 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
channel_incref(chan);
multiqueue_put(chan->events, on_buffered_error, 2, chan, type);
}
+ ga_clear(&reader->buffer);
} else {
abort();
}
- ga_clear(&reader->buffer);
} else if (reader->cb.type != kCallbackNone) {
- process_channel_event(chan, &reader->cb, type, ptr, 0, 0);
+ process_channel_event(chan, &reader->cb, type, reader, 0);
}
return;
}
@@ -634,10 +627,12 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
}
rbuffer_consumed(buf, count);
- if (reader->buffered) {
- ga_concat_len(&reader->buffer, ptr, count);
- } else if (callback_reader_set(*reader)) {
- process_channel_event(chan, &reader->cb, type, ptr, count, 0);
+ // if buffer wasn't consumed, a pending callback is stalled. Aggregate the
+ // received data and avoid a "burst" of multiple callbacks.
+ bool buffer_set = reader->buffer.ga_len > 0;
+ ga_concat_len(&reader->buffer, ptr, count);
+ if (!reader->buffered && !buffer_set && callback_reader_set(*reader)) {
+ process_channel_event(chan, &reader->cb, type, reader, 0);
}
}
@@ -661,7 +656,7 @@ static void channel_process_exit_cb(Process *proc, int status, void *data)
// If process did not exit, we only closed the handle of a detached process.
bool exited = (status >= 0);
if (exited) {
- process_channel_event(chan, &chan->on_exit, "exit", NULL, 0, status);
+ process_channel_event(chan, &chan->on_exit, "exit", NULL, status);
}
channel_decref(chan);
@@ -677,11 +672,13 @@ static void on_channel_event(void **args)
argv[0].v_lock = VAR_UNLOCKED;
argv[0].vval.v_number = (varnumber_T)ev->chan->id;
- if (ev->received) {
+ if (ev->reader) {
argv[1].v_type = VAR_LIST;
argv[1].v_lock = VAR_UNLOCKED;
- argv[1].vval.v_list = ev->received;
+ argv[1].vval.v_list = buffer_to_tv_list(ev->reader->buffer.ga_data,
+ (size_t)ev->reader->buffer.ga_len);
tv_list_ref(argv[1].vval.v_list);
+ ga_clear(&ev->reader->buffer);
} else {
argv[1].v_type = VAR_NUMBER;
argv[1].v_lock = VAR_UNLOCKED;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 9e475bf66c..6dbb0d05e0 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1833,12 +1833,12 @@ void ex_loadkeymap(exarg_T *eap)
xfree(line);
}
- // setup ":lnoremap" to map the keys
- for (int i = 0; i < curbuf->b_kmap_ga.ga_len; ++i) {
+ // setup ":lmap" to map the keys
+ for (int i = 0; i < curbuf->b_kmap_ga.ga_len; i++) {
vim_snprintf((char *)buf, sizeof(buf), "<buffer> %s %s",
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].from,
((kmap_T *)curbuf->b_kmap_ga.ga_data)[i].to);
- (void)do_map(2, buf, LANGMAP, FALSE);
+ (void)do_map(0, buf, LANGMAP, false);
}
p_cpo = save_cpo;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 4e0b868374..462762aea0 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1389,8 +1389,8 @@ ins_redraw (
if (ready && has_event(EVENT_TEXTCHANGEDI)
&& curbuf->b_last_changedtick != curbuf->b_changedtick
&& !pum_visible()) {
- apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf);
- curbuf->b_last_changedtick = curbuf->b_changedtick;
+ apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf);
+ curbuf->b_last_changedtick = curbuf->b_changedtick;
}
// Trigger TextChangedP if b_changedtick differs. When the popupmenu closes
@@ -1422,7 +1422,6 @@ ins_redraw (
emsg_on_display = FALSE; /* may remove error message now */
}
-
/*
* Handle a CTRL-V or CTRL-Q typed in Insert mode.
*/
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 126e9e0da9..ffea88aa83 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -15712,6 +15712,9 @@ static void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv)
rettv->vval.v_list = list;
tv_list_ref(list);
char *const dirs = stdpaths_get_xdg_var(xdg);
+ if (dirs == NULL) {
+ return;
+ }
do {
size_t dir_len;
const char *dir;
@@ -15737,15 +15740,15 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return; // Type error; errmsg already given.
}
- if (strcmp(p, "config") == 0) {
+ if (strequal(p, "config")) {
rettv->vval.v_string = (char_u *)get_xdg_home(kXDGConfigHome);
- } else if (strcmp(p, "data") == 0) {
+ } else if (strequal(p, "data")) {
rettv->vval.v_string = (char_u *)get_xdg_home(kXDGDataHome);
- } else if (strcmp(p, "cache") == 0) {
+ } else if (strequal(p, "cache")) {
rettv->vval.v_string = (char_u *)get_xdg_home(kXDGCacheHome);
- } else if (strcmp(p, "config_dirs") == 0) {
+ } else if (strequal(p, "config_dirs")) {
get_xdg_var_list(kXDGConfigDirs, rettv);
- } else if (strcmp(p, "data_dirs") == 0) {
+ } else if (strequal(p, "data_dirs")) {
get_xdg_var_list(kXDGDataDirs, rettv);
} else {
EMSG2(_("E6100: \"%s\" is not a valid stdpath"), p);
@@ -17039,7 +17042,8 @@ static void timer_stop(timer_T *timer)
time_watcher_close(&timer->tw, timer_close_cb);
}
-// invoked on next event loop tick, so queue is empty
+// This will be run on the main loop after the last timer_due_cb, so at this
+// point it is safe to free the callback.
static void timer_close_cb(TimeWatcher *tw, void *data)
{
timer_T *timer = (timer_T *)data;
diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c
index 80289c27d1..b7e30e392b 100644
--- a/src/nvim/event/time.c
+++ b/src/nvim/event/time.c
@@ -61,10 +61,17 @@ static void time_watcher_cb(uv_timer_t *handle)
CREATE_EVENT(watcher->events, time_event, 1, watcher);
}
+static void close_event(void **argv)
+{
+ TimeWatcher *watcher = argv[0];
+ watcher->close_cb(watcher, watcher->data);
+}
+
static void close_cb(uv_handle_t *handle)
+ FUNC_ATTR_NONNULL_ALL
{
TimeWatcher *watcher = handle->data;
if (watcher->close_cb) {
- watcher->close_cb(watcher, watcher->data);
+ CREATE_EVENT(watcher->events, close_event, 1, watcher);
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 102af1dba9..520aedaac7 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3572,7 +3572,7 @@ restore_backup:
/* buf->b_changedtick is always incremented in unchanged() but that
* should not trigger a TextChanged event. */
if (buf->b_last_changedtick + 1 == buf->b_changedtick) {
- buf->b_last_changedtick = buf->b_changedtick;
+ buf->b_last_changedtick = buf->b_changedtick;
}
u_unchanged(buf);
u_update_save_nr(buf);
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index e2566c8c66..07a65c2611 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1852,8 +1852,11 @@ static int vgetorpeek(int advance)
keylen = KEYLEN_PART_MAP;
break;
}
- } else if (keylen > mp_match_len) {
- /* found a longer match */
+ } else if (keylen > mp_match_len
+ || (keylen == mp_match_len
+ && (mp_match->m_mode & LANGMAP) == 0
+ && (mp->m_mode & LANGMAP) != 0)) {
+ // found a longer match
mp_match = mp;
mp_match_len = keylen;
}
@@ -1947,8 +1950,9 @@ static int vgetorpeek(int advance)
char_u *save_m_keys;
char_u *save_m_str;
- // write chars to script file(s)
- if (keylen > typebuf.tb_maplen) {
+ // Write chars to script file(s)
+ // Note: :lmap mappings are written *after* being applied. #5658
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) == 0) {
gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
(size_t)(keylen - typebuf.tb_maplen));
}
@@ -2023,6 +2027,12 @@ static int vgetorpeek(int advance)
else {
int noremap;
+ // If this is a LANGMAP mapping, then we didn't record the keys
+ // at the start of the function and have to record them now.
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) != 0) {
+ gotchars(s, STRLEN(s));
+ }
+
if (save_m_noremap != REMAP_YES)
noremap = save_m_noremap;
else if (
diff --git a/src/nvim/main.c b/src/nvim/main.c
index a4ed868af1..8b0d3bb2cc 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -1735,7 +1735,7 @@ static bool do_user_initialization(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
bool do_exrc = p_exrc;
- if (process_env("VIMINIT", true) == OK) {
+ if (process_env("VIMINIT") == OK) {
do_exrc = p_exrc;
return do_exrc;
}
@@ -1780,7 +1780,7 @@ static bool do_user_initialization(void)
} while (iter != NULL);
xfree(config_dirs);
}
- if (process_env("EXINIT", false) == OK) {
+ if (process_env("EXINIT") == OK) {
do_exrc = p_exrc;
return do_exrc;
}
@@ -1844,17 +1844,14 @@ static void source_startup_scripts(const mparm_T *const parmp)
/// Get an environment variable, and execute it as Ex commands.
///
/// @param env environment variable to execute
-/// @param is_viminit when true, called for VIMINIT
///
/// @return FAIL if the environment variable was not executed,
/// OK otherwise.
-static int process_env(char *env, bool is_viminit)
+static int process_env(char *env)
+ FUNC_ATTR_NONNULL_ALL
{
const char *initstr = os_getenv(env);
if (initstr != NULL) {
- if (is_viminit) {
- vimrc_found(NULL, NULL);
- }
char_u *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
sourcing_name = (char_u *)env;
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index f6e03e2532..fe4d24ba11 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -76,8 +76,7 @@
/// @param flags Flags for open() call.
///
-/// @return - The open memory file, on success.
-/// - NULL, on failure.
+/// @return The open memory file.
memfile_T *mf_open(char_u *fname, int flags)
{
memfile_T *mfp = xmalloc(sizeof(memfile_T));
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 06de9fda67..3b0cac0456 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -246,7 +246,6 @@ typedef enum {
*/
int ml_open(buf_T *buf)
{
- memfile_T *mfp;
bhdr_T *hp = NULL;
ZERO_BL *b0p;
PTR_BL *pp;
@@ -275,12 +274,8 @@ int ml_open(buf_T *buf)
buf->b_may_swap = false;
}
- /*
- * Open the memfile. No swap file is created yet.
- */
- mfp = mf_open(NULL, 0);
- if (mfp == NULL)
- goto error;
+ // Open the memfile. No swap file is created yet.
+ memfile_T *mfp = mf_open(NULL, 0);
buf->b_ml.ml_mfp = mfp;
buf->b_ml.ml_flags = ML_EMPTY;
@@ -364,11 +359,10 @@ int ml_open(buf_T *buf)
return OK;
error:
- if (mfp != NULL) {
- if (hp)
- mf_put(mfp, hp, false, false);
- mf_close(mfp, true); /* will also xfree(mfp->mf_fname) */
+ if (hp) {
+ mf_put(mfp, hp, false, false);
}
+ mf_close(mfp, true); // will also xfree(mfp->mf_fname)
buf->b_ml.ml_mfp = NULL;
return FAIL;
}
@@ -842,7 +836,7 @@ void ml_recover(void)
mf_open() will consume "fname_used"! */
mfp = mf_open(fname_used, O_RDONLY);
fname_used = p;
- if (mfp == NULL || mfp->mf_fd < 0) {
+ if (mfp->mf_fd < 0) {
EMSG2(_("E306: Cannot open %s"), fname_used);
goto theend;
}
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e6d00f4d82..a2aaf8f9af 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1216,8 +1216,8 @@ static void normal_check_text_changed(NormalState *s)
// Trigger TextChanged if b_changedtick differs.
if (!finish_op && has_event(EVENT_TEXTCHANGED)
&& curbuf->b_last_changedtick != curbuf->b_changedtick) {
- apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, false, curbuf);
- curbuf->b_last_changedtick = curbuf->b_changedtick;
+ apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, false, curbuf);
+ curbuf->b_last_changedtick = curbuf->b_changedtick;
}
}
@@ -1808,7 +1808,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
} else {
(void)op_delete(oap);
if (oap->motion_type == kMTLineWise && has_format_option(FO_AUTO)) {
- u_save_cursor(); // cursor line wasn't saved yet
+ // cursor line wasn't saved yet
+ if (u_save_cursor() == FAIL) {
+ break;
+ }
}
auto_format(false, true);
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b39b139f9b..d874768dfc 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -2724,7 +2724,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// So the 'u' command restores cursor position after ".p, save the cursor
// position now (though not saving any text).
if (command_start_char == 'a') {
- u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1);
+ if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL) {
+ return;
+ }
}
return;
}
@@ -2742,7 +2744,6 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// Autocommands may be executed when saving lines for undo, which may make
// y_array invalid. Start undo now to avoid that.
if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL) {
- ELOG("Failed to save undo information");
return;
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 1da259e6b8..48c874196d 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -6583,15 +6583,13 @@ static void paste_option_changed(void)
/// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
void vimrc_found(char_u *fname, char_u *envname)
{
- char_u *p;
-
- if (fname != NULL) {
- p = (char_u *)vim_getenv((char *)envname);
+ if (fname != NULL && envname != NULL) {
+ char *p = vim_getenv((char *)envname);
if (p == NULL) {
- /* Set $MYVIMRC to the first vimrc file found. */
- p = (char_u *)FullName_save((char *)fname, FALSE);
+ // Set $MYVIMRC to the first vimrc file found.
+ p = FullName_save((char *)fname, false);
if (p != NULL) {
- vim_setenv((char *)envname, (char *)p);
+ vim_setenv((char *)envname, p);
xfree(p);
}
} else {
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 866a005228..f6503dfdb0 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -65,7 +65,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
const char *env_val = os_getenv(env);
#ifdef WIN32
- if (env_val == NULL) {
+ if (env_val == NULL && xdg_defaults_env_vars[idx] != NULL) {
env_val = os_getenv(xdg_defaults_env_vars[idx]);
}
#endif
@@ -74,7 +74,7 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
if (env_val != NULL) {
ret = xstrdup(env_val);
} else if (fallback) {
- ret = (char *) expand_env_save((char_u *)fallback);
+ ret = (char *)expand_env_save((char_u *)fallback);
}
return ret;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index f034ac33f1..f15afa619f 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -4898,12 +4898,10 @@ win_redr_status_matches (
xfree(buf);
}
-/*
- * Redraw the status line of window wp.
- *
- * If inversion is possible we use it. Else '=' characters are used.
- */
-void win_redr_status(win_T *wp)
+/// Redraw the status line of window `wp`.
+///
+/// If inversion is possible we use it. Else '=' characters are used.
+static void win_redr_status(win_T *wp)
{
int row;
char_u *p;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 84aeeda2bf..686962704a 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2487,7 +2487,9 @@ buf_T *open_spellbuf(void)
buf->b_spell = true;
buf->b_p_swf = true; // may create a swap file
- ml_open(buf);
+ if (ml_open(buf) == FAIL) {
+ abort();
+ }
ml_open_file(buf); // create swap file now
return buf;
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index dab9a2aacd..b844fd9ab8 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -5368,8 +5368,9 @@ spell_add_word (
// doesn't work for all systems, close the file first.
fclose(fd);
fd = mch_fopen((char *)fname, "r+");
- if (fd == NULL)
+ if (fd == NULL) {
break;
+ }
if (fseek(fd, fpos, SEEK_SET) == 0) {
fputc('#', fd);
if (undo) {
@@ -5378,7 +5379,9 @@ spell_add_word (
len, word, NameBuff);
}
}
- fseek(fd, fpos_next, SEEK_SET);
+ if (fseek(fd, fpos_next, SEEK_SET) <= 0) {
+ break;
+ }
}
}
if (fd != NULL)
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index f23465e501..ba2727f0d7 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2407,8 +2407,8 @@ jumpto_tag (
/* If it was a CTRL-W CTRL-] command split window now. For ":tab tag"
* open a new tab page. */
if (postponed_split || cmdmod.tab != 0) {
- win_split(postponed_split > 0 ? postponed_split : 0,
- postponed_split_flags);
+ (void)win_split(postponed_split > 0 ? postponed_split : 0,
+ postponed_split_flags);
RESET_BINDING(curwin);
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index f68bb2458d..31875fac31 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -403,6 +403,7 @@ void terminal_enter(void)
// erase the unfocused cursor
invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
showmode();
+ curwin->w_redr_status = true; // For mode() in statusline. #8323
ui_busy_start();
redraw(false);
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index e285ea2d00..238de5a87d 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1168,7 +1168,8 @@ endfunc
" Test TextChangedI and TextChangedP
func Test_ChangedP() abort
- throw 'skipped: Nvim does not support test_override()'
+ " Nvim does not support test_override().
+ throw 'skipped: see test/functional/viml/completion_spec.lua'
new
call setline(1, ['foo', 'bar', 'foobar'])
call test_override("char_avail", 1)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index e90339b0cd..4a21444ee0 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -433,9 +433,25 @@ describe('jobs', function()
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())
+
+ local expected = {'1', '2', '3', '4', '5', ''}
+ local chunks = eval('d.data')
+ local received = {''}
+ for i, chunk in ipairs(chunks) do
+ if i < #chunks then
+ -- if chunks got joined, a spurious [''] callback was not sent
+ neq({''}, chunk)
+ else
+ -- but EOF callback is still sent
+ eq({''}, chunk)
+ end
+ received[#received] = received[#received]..chunk[1]
+ for j = 2, #chunk do
+ received[#received+1] = chunk[j]
+ end
+ end
+ eq(expected, received)
end)
it('jobstart() works with partial functions', function()
diff --git a/test/functional/normal/macro_spec.lua b/test/functional/normal/macro_spec.lua
new file mode 100644
index 0000000000..102d8fc723
--- /dev/null
+++ b/test/functional/normal/macro_spec.lua
@@ -0,0 +1,30 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local clear = helpers.clear
+local expect = helpers.expect
+local command = helpers.command
+
+describe('macros', function()
+ before_each(clear)
+ it('can be recorded and replayed', function()
+ feed('qiahello<esc>q')
+ expect('hello')
+ eq(eval('@i'), 'ahello')
+ feed('@i')
+ expect('hellohello')
+ eq(eval('@i'), 'ahello')
+ end)
+ it('applies maps', function()
+ command('imap x l')
+ command('nmap l a')
+ feed('qilxxx<esc>q')
+ expect('lll')
+ eq(eval('@i'), 'lxxx')
+ feed('@i')
+ expect('llllll')
+ eq(eval('@i'), 'lxxx')
+ end)
+end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index f452cafd22..787ec366b8 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -10,6 +10,7 @@ local eval = helpers.eval
local eq = helpers.eq
local funcs = helpers.funcs
local insert = helpers.insert
+local iswin = helpers.iswin
local neq = helpers.neq
local mkdir = helpers.mkdir
local rmdir = helpers.rmdir
@@ -170,8 +171,7 @@ describe('startup defaults', function()
end)
describe('$NVIM_LOG_FILE', function()
- -- TODO(jkeyes): use stdpath('data') instead.
- local datasubdir = helpers.iswin() and 'nvim-data' or 'nvim'
+ local datasubdir = iswin() and 'nvim-data' or 'nvim'
local xdgdir = 'Xtest-startup-xdg-logpath'
local xdgdatadir = xdgdir..'/'..datasubdir
after_each(function()
@@ -428,7 +428,24 @@ end)
describe('stdpath()', function()
+ -- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions
+ -- due to XDG_CONFIG_HOME and XDG_DATA_HOME being the same.
+ local datadir = iswin() and 'nvim-data' or 'nvim'
+
+ it('acceptance', function()
+ clear() -- Do not explicitly set any env vars.
+
+ eq('nvim', funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
+ eq('nvim', funcs.fnamemodify(funcs.stdpath('config'), ':t'))
+ eq(datadir, funcs.fnamemodify(funcs.stdpath('data'), ':t'))
+ eq('table', type(funcs.stdpath('config_dirs')))
+ eq('table', type(funcs.stdpath('data_dirs')))
+ -- Check for crash. #8393
+ eq(2, eval('1+1'))
+ end)
+
context('returns a String', function()
+
describe('with "config"' , function ()
it('knows XDG_CONFIG_HOME', function()
clear({env={
@@ -463,32 +480,20 @@ describe('stdpath()', function()
end)
describe('with "data"' , function ()
- local appended_dir
- setup(function()
- -- Windows appends 'nvim-data' instead of just 'nvim' to
- -- prevent collisions due to XDG_CONFIG_HOME and XDG_DATA_HOME
- -- being the same.
- if helpers.iswin() then
- appended_dir = '/nvim-data'
- else
- appended_dir = '/nvim'
- end
- end)
-
it('knows XDG_DATA_HOME', function()
clear({env={
XDG_DATA_HOME=alter_slashes('/home/docwhat/.local'),
}})
- eq(alter_slashes('/home/docwhat/.local' .. appended_dir), funcs.stdpath('data'))
+ eq(alter_slashes('/home/docwhat/.local/'..datadir), funcs.stdpath('data'))
end)
it('handles changes during runtime', function()
clear({env={
XDG_DATA_HOME=alter_slashes('/home/original'),
}})
- eq(alter_slashes('/home/original' .. appended_dir), funcs.stdpath('data'))
+ eq(alter_slashes('/home/original/'..datadir), funcs.stdpath('data'))
command("let $XDG_DATA_HOME='"..alter_slashes('/home/new').."'")
- eq(alter_slashes('/home/new' .. appended_dir), funcs.stdpath('data'))
+ eq(alter_slashes('/home/new/'..datadir), funcs.stdpath('data'))
end)
it("doesn't expand $VARIABLES", function()
@@ -496,14 +501,14 @@ describe('stdpath()', function()
XDG_DATA_HOME='$VARIABLES',
VARIABLES='this-should-not-happen',
}})
- eq(alter_slashes('$VARIABLES' .. appended_dir), funcs.stdpath('data'))
+ eq(alter_slashes('$VARIABLES/'..datadir), funcs.stdpath('data'))
end)
it("doesn't expand ~/", function()
clear({env={
XDG_DATA_HOME=alter_slashes('~/frobnitz'),
}})
- eq(alter_slashes('~/frobnitz' .. appended_dir), funcs.stdpath('data'))
+ eq(alter_slashes('~/frobnitz/'..datadir), funcs.stdpath('data'))
end)
end)
@@ -544,7 +549,7 @@ describe('stdpath()', function()
context('returns a List', function()
-- Some OS specific variables the system would have set.
local function base_env()
- if helpers.iswin() then
+ if iswin() then
return {
HOME='C:\\Users\\docwhat', -- technically, is not a usual PATH
HOMEDRIVE='C:',
diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua
new file mode 100644
index 0000000000..7f6d623dc7
--- /dev/null
+++ b/test/functional/options/keymap_spec.lua
@@ -0,0 +1,233 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq
+local expect, command, eval = helpers.expect, helpers.command, helpers.eval
+local insert, call = helpers.insert, helpers.call
+local funcs, dedent = helpers.funcs, helpers.dedent
+
+-- First test it's implemented using the :lmap and :lnoremap commands, then
+-- check those mappings behave as expected.
+describe("'keymap' / :lmap", function()
+ clear()
+ before_each(function()
+ clear()
+ insert("lllaaa")
+ command('set iminsert=1')
+ command('set imsearch=1')
+ command('lmap l a')
+ feed('gg0')
+ end)
+
+ describe("'keymap' as :lmap", function()
+ -- Shows that 'keymap' sets language mappings that allows remapping.
+ -- This equivalence allows us to only test :lmap commands and assert they
+ -- behave the same as 'keymap' settings.
+ -- It does rely on the absence of special code that implements 'keymap'
+ -- and :lmap differently but shows mappings from the 'keymap' after
+ -- typing :lmap.
+ -- At the moment this is the case.
+ it("'keymap' mappings are shown with :lmap", function()
+ command('lmapclear')
+ command('lmapclear <buffer>')
+ command('set keymap=dvorak')
+ command('set nomore')
+ local bindings = funcs.nvim_command_output('lmap')
+ eq(dedent([[
+
+ l " @_
+ l ' @-
+ l + @}
+ l , @w
+ l - @[
+ l . @v
+ l / @z
+ l : @S
+ l ; @s
+ l < @W
+ l = @]
+ l > @V
+ l ? @Z
+ l A @A
+ l B @X
+ l C @J
+ l D @E
+ l E @>
+ l F @U
+ l G @I
+ l H @D
+ l I @C
+ l J @H
+ l K @T
+ l L @N
+ l M @M
+ l N @B
+ l O @R
+ l P @L
+ l Q @"
+ l R @P
+ l S @O
+ l T @Y
+ l U @G
+ l V @K
+ l W @<
+ l X @Q
+ l Y @F
+ l Z @:
+ l [ @/
+ l \ @\
+ l ] @=
+ l _ @{
+ l a @a
+ l b @x
+ l c @j
+ l d @e
+ l e @.
+ l f @u
+ l g @i
+ l h @d
+ l i @c
+ l j @h
+ l k @t
+ l l @n
+ l m @m
+ l n @b
+ l o @r
+ l p @l
+ l q @'
+ l r @p
+ l s @o
+ l t @y
+ l u @g
+ l v @k
+ l w @,
+ l x @q
+ l y @f
+ l z @;
+ l { @?
+ l | @|
+ l } @+]]), bindings)
+ end)
+ end)
+ describe("'iminsert' option", function()
+ it("Uses :lmap in insert mode when ON", function()
+ feed('il<esc>')
+ expect('alllaaa')
+ end)
+ it("Ignores :lmap in insert mode when OFF", function()
+ command('set iminsert=0')
+ feed('il<esc>')
+ expect('llllaaa')
+ end)
+ it("Can be toggled with <C-^> in insert mode", function()
+ feed('i<C-^>l<C-^>l<esc>')
+ expect('lalllaaa')
+ eq(eval('&iminsert'), 1)
+ feed('i<C-^><esc>')
+ eq(eval('&iminsert'), 0)
+ end)
+ end)
+ describe("'imsearch' option", function()
+ it("Uses :lmap at search prompt when ON", function()
+ feed('/lll<cr>3x')
+ expect('lll')
+ end)
+ it("Ignores :lmap at search prompt when OFF", function()
+ command('set imsearch=0')
+ feed('gg/lll<cr>3x')
+ expect('aaa')
+ end)
+ it("Can be toggled with C-^", function()
+ eq(eval('&imsearch'), 1)
+ feed('/<C-^>lll<cr>3x')
+ expect('aaa')
+ eq(eval('&imsearch'), 0)
+ feed('u0/<C-^>lll<cr>3x')
+ expect('lll')
+ eq(eval('&imsearch'), 1)
+ end)
+ it("can follow 'iminsert'", function()
+ command('set imsearch=-1')
+ feed('/lll<cr>3x')
+ expect('lll')
+ eq(eval('&imsearch'), -1)
+ eq(eval('&iminsert'), 1)
+ feed('u/<C-^>lll<cr>3x')
+ expect('aaa')
+ eq(eval('&imsearch'), -1)
+ eq(eval('&iminsert'), 0)
+ end)
+ end)
+ it(":lmap not applied to macros", function()
+ command("call setreg('a', 'il')")
+ feed('@a')
+ expect('llllaaa')
+ eq(call('getreg', 'a'), 'il')
+ end)
+ it(":lmap applied to macro recording", function()
+ feed('qail<esc>q@a')
+ expect('aalllaaa')
+ eq(call('getreg', 'a'), 'ia')
+ end)
+ it(":lmap not applied to mappings", function()
+ command('imap t l')
+ feed('it<esc>')
+ expect('llllaaa')
+ end)
+ it("mappings applied to keys created with :lmap", function()
+ command('imap a x')
+ feed('il<esc>')
+ expect('xlllaaa')
+ end)
+ it("mappings not applied to keys gotten with :lnoremap", function()
+ command('lmapclear')
+ command('lnoremap l a')
+ command('imap a x')
+ feed('il<esc>')
+ expect('alllaaa')
+ end)
+ -- This is a problem introduced when introducting :lmap and macro
+ -- compatibility. There are no plans to fix this as the complexity involved
+ -- seems too great.
+ pending('mappings not applied to macro replay of :lnoremap', function()
+ command('lmapclear')
+ command('lnoremap l a')
+ command('imap a x')
+ feed('qail<esc>q')
+ expect('alllaaa')
+ feed('@a')
+ expect('aalllaaa')
+ end)
+ it("is applied when using f/F t/T", function()
+ feed('flx')
+ expect('lllaa')
+ feed('0ia<esc>4lFlx')
+ expect('lllaa')
+ feed('tllx')
+ expect('llla')
+ feed('0ia<esc>4lTlhx')
+ expect('llla')
+ end)
+ it('takes priority over :imap mappings', function()
+ command('imap l x')
+ feed('il<esc>')
+ expect('alllaaa')
+ command('lmapclear')
+ command('lmap l a')
+ feed('il')
+ expect('aalllaaa')
+ end)
+ it('does not cause recursive mappings', function()
+ command('lmap a l')
+ feed('qaila<esc>q')
+ expect('allllaaa')
+ feed('u@a')
+ expect('allllaaa')
+ end)
+ it('can handle multicharacter mappings', function()
+ command("lmap 'a x")
+ command("lmap '' '")
+ feed("qai'a''a<esc>q")
+ expect("x'alllaaa")
+ feed('u@a')
+ expect("x'alllaaa")
+ end)
+end)
diff --git a/test/functional/provider/nodejs_spec.lua b/test/functional/provider/nodejs_spec.lua
index d9af020bfe..f69c3e7c78 100644
--- a/test/functional/provider/nodejs_spec.lua
+++ b/test/functional/provider/nodejs_spec.lua
@@ -45,15 +45,13 @@ describe('nodejs host', function()
const nvim = neovim.attach({socket: socket});
class TestPlugin {
- hello() {
- this.nvim.command('let g:job_out = "hello-plugin"')
- }
+ hello() {
+ this.nvim.command('let g:job_out = "hello-plugin"');
+ }
}
-
const PluginClass = neovim.Plugin(TestPlugin);
- const plugin = new PluginClass(nvim);
- plugin.hello();
- nvim.command('call jobstop(g:job_id)');
+ const plugin = new neovim.NvimPlugin(null, PluginClass, nvim);
+ plugin.instance.hello();
]])
command('let g:job_id = jobstart(["node", "'..fname..'"])')
retry(nil, 2000, function() eq('hello-plugin', eval('g:job_out')) end)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index ee1a3240a2..9cc697a4b6 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -1846,8 +1846,7 @@ describe("'inccommand' with 'gdefault'", function()
end)
describe(":substitute", function()
- local screen = Screen.new(30,15)
-
+ local screen = Screen.new(30,15)
before_each(function()
clear()
end)
@@ -2471,8 +2470,13 @@ describe(":substitute", function()
:%s/some\(thing\)\@!/every/^ |
]])
end)
+end)
+
+it(':substitute with inccommand during :terminal activity', function()
+ retry(2, nil, function()
+ local screen = Screen.new(30,15)
+ clear()
- it('with inccommand during :terminal activity', function()
command("set cmdwinheight=3")
if iswin() then
feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
@@ -2484,7 +2488,7 @@ describe(":substitute", function()
common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
command('wincmd =')
- -- Allow some terminal output.
+ -- Wait for terminal output.
screen:expect([[
bar baz fox |
bar foo ba^z |
@@ -2505,7 +2509,7 @@ describe(":substitute", function()
feed('gg')
feed(':%s/foo/ZZZ')
- sleep(50) -- Allow some terminal activity.
+ sleep(20) -- Allow some terminal activity.
screen:expect([[
{12:ZZZ} bar baz |
bar baz fox |
@@ -2523,5 +2527,6 @@ describe(":substitute", function()
{10:[Preview] }|
:%s/foo/ZZZ^ |
]])
+
end)
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua
index 93d3909568..c14f7fc1a6 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/viml/completion_spec.lua
@@ -975,90 +975,89 @@ describe('ui/ext_popupmenu', function()
end)
end)
- describe('TextChangeP autocommand', function()
- it('can trigger TextChangedP autocommand as expected',
- function()
- curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'})
- command('set complete=. completeopt=menuone')
- command('let g:foo = []')
- command('autocmd! TextChanged * :call add(g:foo, "N")')
- command('autocmd! TextChangedI * :call add(g:foo, "I")')
- command('autocmd! TextChangedP * :call add(g:foo, "P")')
- command('call cursor(3, 1)')
+ it('TextChangedP autocommand', function()
+ curbufmeths.set_lines(0, 1, false, { 'foo', 'bar', 'foobar'})
+ source([[
+ set complete=. completeopt=menuone
+ let g:foo = []
+ autocmd! TextChanged * :call add(g:foo, "N")
+ autocmd! TextChangedI * :call add(g:foo, "I")
+ autocmd! TextChangedP * :call add(g:foo, "P")
+ call cursor(3, 1)
+ ]])
- command('let g:foo = []')
- feed('o')
- wait()
- feed('<esc>')
- assert.same({'I'}, eval('g:foo'))
+ command('let g:foo = []')
+ feed('o')
+ wait()
+ feed('<esc>')
+ eq({'I'}, eval('g:foo'))
- command('let g:foo = []')
- feed('S')
- wait()
- feed('f')
- wait()
- assert.same({'I', 'I'}, eval('g:foo'))
- feed('<esc>')
+ command('let g:foo = []')
+ feed('S')
+ wait()
+ feed('f')
+ wait()
+ eq({'I', 'I'}, eval('g:foo'))
+ feed('<esc>')
- command('let g:foo = []')
- feed('S')
- wait()
- feed('f')
- wait()
- feed('<C-n>')
- wait()
- assert.same({'I', 'I', 'P'}, eval('g:foo'))
- feed('<esc>')
+ command('let g:foo = []')
+ feed('S')
+ wait()
+ feed('f')
+ wait()
+ feed('<C-N>')
+ wait()
+ eq({'I', 'I', 'P'}, eval('g:foo'))
+ feed('<esc>')
- command('let g:foo = []')
- feed('S')
- wait()
- feed('f')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- wait()
- assert.same({'I', 'I', 'P', 'P'}, eval('g:foo'))
- feed('<esc>')
+ command('let g:foo = []')
+ feed('S')
+ wait()
+ feed('f')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ wait()
+ eq({'I', 'I', 'P', 'P'}, eval('g:foo'))
+ feed('<esc>')
- command('let g:foo = []')
- feed('S')
- wait()
- feed('f')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- wait()
- assert.same({'I', 'I', 'P', 'P', 'P'}, eval('g:foo'))
- feed('<esc>')
+ command('let g:foo = []')
+ feed('S')
+ wait()
+ feed('f')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ wait()
+ eq({'I', 'I', 'P', 'P', 'P'}, eval('g:foo'))
+ feed('<esc>')
- command('let g:foo = []')
- feed('S')
- wait()
- feed('f')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- wait()
- feed('<C-n>')
- assert.same({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo'))
- feed('<esc>')
+ command('let g:foo = []')
+ feed('S')
+ wait()
+ feed('f')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ wait()
+ feed('<C-N>')
+ eq({'I', 'I', 'P', 'P', 'P', 'P'}, eval('g:foo'))
+ feed('<esc>')
- assert.same({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")'))
+ eq({'foo', 'bar', 'foobar', 'foo'}, eval('getline(1, "$")'))
- source([[
+ source([[
au! TextChanged
au! TextChangedI
au! TextChangedP
set complete&vim completeopt&vim
- ]])
- end)
+ ]])
end)
end)
diff --git a/third-party/cmake/UnibiliumCMakeLists.txt b/third-party/cmake/UnibiliumCMakeLists.txt
index 3c419654c4..49bc12c6b7 100644
--- a/third-party/cmake/UnibiliumCMakeLists.txt
+++ b/third-party/cmake/UnibiliumCMakeLists.txt
@@ -13,8 +13,10 @@ if(NOT WIN32)
ncurses5-config --terminfo-dirs 2>/dev/null || \
echo '/etc/terminfo:/lib/terminfo:/usr/share/terminfo:/usr/lib/terminfo:/usr/local/share/terminfo:/usr/local/lib/terminfo'"
OUTPUT_VARIABLE TERMINFO_DIRS)
+else()
+ set(TERMINFO_DIRS "\"\"")
endif()
-target_compile_definitions(unibilium PUBLIC TERMINFO_DIRS ${TERMINFO_DIRS})
+target_compile_definitions(unibilium PUBLIC TERMINFO_DIRS=${TERMINFO_DIRS})
if(MSVC)
target_include_directories(unibilium PUBLIC ${PROJECT_SOURCE_DIR}/msvc-compat)