aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
20 files changed, 108 insertions, 94 deletions
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)