diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/channel.c | 55 | ||||
-rw-r--r-- | src/nvim/digraph.c | 6 | ||||
-rw-r--r-- | src/nvim/edit.c | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 16 | ||||
-rw-r--r-- | src/nvim/event/time.c | 9 | ||||
-rw-r--r-- | src/nvim/fileio.c | 2 | ||||
-rw-r--r-- | src/nvim/getchar.c | 18 | ||||
-rw-r--r-- | src/nvim/main.c | 11 | ||||
-rw-r--r-- | src/nvim/memfile.c | 3 | ||||
-rw-r--r-- | src/nvim/memline.c | 18 | ||||
-rw-r--r-- | src/nvim/normal.c | 9 | ||||
-rw-r--r-- | src/nvim/ops.c | 5 | ||||
-rw-r--r-- | src/nvim/option.c | 12 | ||||
-rw-r--r-- | src/nvim/os/stdpaths.c | 4 | ||||
-rw-r--r-- | src/nvim/screen.c | 10 | ||||
-rw-r--r-- | src/nvim/spell.c | 4 | ||||
-rw-r--r-- | src/nvim/spellfile.c | 7 | ||||
-rw-r--r-- | src/nvim/tag.c | 4 | ||||
-rw-r--r-- | src/nvim/terminal.c | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 3 |
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) |