diff options
73 files changed, 629 insertions, 486 deletions
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 1a7268a51e..4126f66d6c 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -10,6 +10,8 @@ ``` nvim -u NORC +# Alternative for shell-related problems: +# env -i TERM=ansi-256color "$(which nvim)" ``` diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 3d95dd58f7..22ad8e0633 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -14,8 +14,9 @@ Applications can also embed libnvim to work with the C API directly. Type |gO| to see the table of contents. ============================================================================== -API Types *api-types* +API Definitions *api-definitions* + *api-types* The Nvim C API defines custom types for all function parameters. Some are just typedefs around C99 standard types, others are Nvim-defined data structures. @@ -34,6 +35,17 @@ discriminated as separate types in an Object: Window -> enum value kObjectTypeWindow Tabpage -> enum value kObjectTypeTabpage + *api-indexing* +Most of the API uses 0-based indices, and ranges are end-exclusive. For the +end of a range, -1 denotes the last line/column. + +Exception: the following API functions use "mark-like" indexing (1-based +lines, 0-based columns): + + |nvim_buf_get_mark()| + |nvim_win_get_cursor()| + |nvim_win_set_cursor()| + ============================================================================== API metadata *api-metadata* @@ -1293,7 +1305,7 @@ nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement} Array of lines to use as replacement nvim_buf_get_offset({buffer}, {index}) *nvim_buf_get_offset()* - Returns the byte offset for a line. + Returns the byte offset of a line (0-indexed). |api-indexing| Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is one byte. 'fileformat' and 'fileencoding' are ignored. The @@ -1445,7 +1457,9 @@ nvim_buf_is_valid({buffer}) *nvim_buf_is_valid()* nvim_buf_get_mark({buffer}, {name}) *nvim_buf_get_mark()* Return a tuple (row,col) representing the position of the - named mark + named mark. + + Marks are (1,0)-indexed. |api-indexing| Parameters: ~ {buffer} Buffer handle, or 0 for current buffer @@ -1500,8 +1514,8 @@ nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end}) Clears namespaced objects, highlights and virtual text, from a line range - To clear the namespace in the entire buffer, pass in 0 and -1 - to line_start and line_end respectively. + Lines are 0-indexed. |api-indexing| To clear the namespace in + the entire buffer, specify line_start=0 and line_end=-1. Parameters: ~ {buffer} Buffer handle, or 0 for current buffer @@ -1570,7 +1584,8 @@ nvim_win_set_buf({window}, {buffer}) *nvim_win_set_buf()* {buffer} Buffer handle nvim_win_get_cursor({window}) *nvim_win_get_cursor()* - Gets the cursor position in the window + Gets the (1,0)-indexed cursor position in the window. + |api-indexing| Parameters: ~ {window} Window handle @@ -1579,7 +1594,8 @@ nvim_win_get_cursor({window}) *nvim_win_get_cursor()* (row, col) tuple nvim_win_set_cursor({window}, {pos}) *nvim_win_set_cursor()* - Sets the cursor position in the window + Sets the (1,0)-indexed cursor position in the window. + |api-indexing| Parameters: ~ {window} Window handle diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 7682a1a584..dfffe33b1f 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2377,6 +2377,7 @@ win_screenpos({nr}) List get screen position of window {nr} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight({nr}) Number height of window {nr} +winlayout([{tabnr}]) List layout of windows in tab {tabnr} winline() Number window line of the cursor winnr([{expr}]) Number number of current window winrestcmd() String returns command to restore window sizes @@ -6078,7 +6079,7 @@ nr2char({expr} [, {utf8}]) *nr2char()* characters. nr2char(0) is a real NUL and terminates the string, thus results in an empty string. -nvim_...({...}) *nvim_...()* *eval-api* +nvim_...({...}) *E5555* *nvim_...()* *eval-api* Call nvim |api| functions. The type checking of arguments will be stricter than for most other builtins. For instance, if Integer is expected, a |Number| must be passed in, a @@ -8538,6 +8539,35 @@ winheight({nr}) *winheight()* Examples: > :echo "The current window has " . winheight(0) . " lines." < +winlayout([{tabnr}]) *winlayout()* + The result is a nested List containing the layout of windows + in a tabpage. + + Without {tabnr} use the current tabpage, otherwise the tabpage + with number {tabnr}. If the tabpage {tabnr} is not found, + returns an empty list. + + For a leaf window, it returns: + ['leaf', {winid}] + For horizontally split windows, which form a column, it + returns: + ['col', [{nested list of windows}]] + For vertically split windows, which form a row, it returns: + ['row', [{nested list of windows}]] + + Example: > + " Only one window in the tab page + :echo winlayout() + ['leaf', 1000] + " Two horizontally split windows + :echo winlayout() + ['col', [['leaf', 1000], ['leaf', 1001]]] + " Three horizontally split windows, with two + " vertically split windows in the middle window + :echo winlayout(2) + ['col', [['leaf', 1002], ['row', ['leaf', 1003], + ['leaf', 1001]]], ['leaf', 1000]] +< *winline()* winline() The result is a Number, which is the screen line of the cursor in the window. This is counting screen lines from the top of diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 60d55bda61..ca10edccba 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -702,6 +702,8 @@ events, which the UI must handle. "echo" |:echo| message "echomsg" |:echomsg| message "echoerr" |:echoerr| message + "lua_error" Error in |:lua| code + "rpc_error" Error response from |rpcrequest()| "return_prompt" |press-enter| prompt after a multiple messages "quickfix" Quickfix navigation message "wmsg" Warning ("search hit BOTTOM", |W10|, …) diff --git a/src/clint.py b/src/clint.py index 6643d8956a..3e48ead7bf 100755 --- a/src/clint.py +++ b/src/clint.py @@ -234,38 +234,6 @@ _ERROR_CATEGORIES = [ # All entries here should start with a '-' or '+', as in the --filter= flag. _DEFAULT_FILTERS = ['-build/include_alpha'] -# We used to check for high-bit characters, but after much discussion we -# decided those were OK, as long as they were in UTF-8 and didn't represent -# hard-coded international strings, which belong in a separate i18n file. - -# Alternative tokens and their replacements. For full list, see section 2.5 -# Alternative tokens [lex.digraph] in the C++ standard. -# -# Digraphs (such as '%:') are not included here since it's a mess to -# match those on a word boundary. -_ALT_TOKEN_REPLACEMENT = { - 'and': '&&', - 'bitor': '|', - 'or': '||', - 'xor': '^', - 'compl': '~', - 'bitand': '&', - 'and_eq': '&=', - 'or_eq': '|=', - 'xor_eq': '^=', - 'not': '!', - 'not_eq': '!=' -} - -# Compile regular expression that matches all the above keywords. The "[ =()]" -# bit is meant to avoid matching these keywords outside of boolean expressions. -# -# False positives include C-style multi-line comments and multi-line strings -# but those have always been troublesome for cpplint. -_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( - r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') - - # These constants define types of headers for use with # _IncludeState.CheckNextIncludeOrder(). _C_SYS_HEADER = 1 @@ -2868,38 +2836,6 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error): 'Empty loop bodies should use {} or continue') -def CheckAltTokens(filename, clean_lines, linenum, error): - """Check alternative keywords being used in boolean expressions. - - Args: - filename: The name of the current file. - clean_lines: A CleansedLines instance containing the file. - linenum: The number of the line to check. - error: The function to call with any errors found. - """ - line = clean_lines.elided[linenum] - - # Avoid preprocessor lines - if Match(r'^\s*#', line): - return - - # Last ditch effort to avoid multi-line comments. This will not help - # if the comment started before the current line or ended after the - # current line, but it catches most of the false positives. At least, - # it provides a way to workaround this warning for people who use - # multi-line comments in preprocessor macros. - # - # TODO(unknown): remove this once cpplint has better support for - # multi-line comments. - if line.find('/*') >= 0 or line.find('*/') >= 0: - return - - for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): - error(filename, linenum, 'readability/alt_tokens', 2, - 'Use operator %s instead of %s' % ( - _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) - - def GetLineWidth(line): """Determines the width of the line in column positions. @@ -3023,7 +2959,6 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, CheckBraces(filename, clean_lines, linenum, error) CheckEmptyBlockBody(filename, clean_lines, linenum, error) CheckSpacing(filename, clean_lines, linenum, nesting_state, error) - CheckAltTokens(filename, clean_lines, linenum, error) _RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 9a5ffecad4..06d7c1810c 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -487,7 +487,7 @@ end: try_end(err); } -/// Returns the byte offset for a line. +/// Returns the byte offset of a line (0-indexed). |api-indexing| /// /// Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is one byte. /// 'fileformat' and 'fileencoding' are ignored. The line index just after the @@ -879,7 +879,9 @@ void buffer_insert(Buffer buffer, nvim_buf_set_lines(0, buffer, lnum, lnum, true, lines, err); } -/// Return a tuple (row,col) representing the position of the named mark +/// Return a tuple (row,col) representing the position of the named mark. +/// +/// Marks are (1,0)-indexed. |api-indexing| /// /// @param buffer Buffer handle, or 0 for current buffer /// @param name Mark name @@ -993,8 +995,8 @@ Integer nvim_buf_add_highlight(Buffer buffer, /// Clears namespaced objects, highlights and virtual text, from a line range /// -/// To clear the namespace in the entire buffer, pass in 0 and -1 to -/// line_start and line_end respectively. +/// Lines are 0-indexed. |api-indexing| To clear the namespace in the entire +/// buffer, specify line_start=0 and line_end=-1. /// /// @param buffer Buffer handle, or 0 for current buffer /// @param ns_id Namespace to clear, or -1 to clear all namespaces. diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index e1c50cb89d..9fd1818a5c 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -74,7 +74,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) restore_win(save_curwin, save_curtab, false); } -/// Gets the cursor position in the window +/// Gets the (1,0)-indexed cursor position in the window. |api-indexing| /// /// @param window Window handle /// @param[out] err Error details, if any @@ -93,7 +93,7 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err) return rv; } -/// Sets the cursor position in the window +/// Sets the (1,0)-indexed cursor position in the window. |api-indexing| /// /// @param window Window handle /// @param pos (row, col) tuple representing the new position diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 8a3d4ad418..a5ad1f1a11 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -809,8 +809,7 @@ free_buffer_stuff( bufhl_clear_all(buf); // delete any highligts map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs - xfree(buf->b_start_fenc); - buf->b_start_fenc = NULL; + XFREE_CLEAR(buf->b_start_fenc); buf_updates_unregister_all(buf); } @@ -1756,10 +1755,8 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) buf->b_wininfo = xcalloc(1, sizeof(wininfo_T)); if (ffname != NULL && (buf->b_ffname == NULL || buf->b_sfname == NULL)) { - xfree(buf->b_ffname); - buf->b_ffname = NULL; - xfree(buf->b_sfname); - buf->b_sfname = NULL; + XFREE_CLEAR(buf->b_ffname); + XFREE_CLEAR(buf->b_sfname); if (buf != curbuf) { free_buffer(buf); } @@ -2665,10 +2662,8 @@ setfname( if (ffname == NULL || *ffname == NUL) { // Removing the name. - xfree(buf->b_ffname); - xfree(buf->b_sfname); - buf->b_ffname = NULL; - buf->b_sfname = NULL; + XFREE_CLEAR(buf->b_ffname); + XFREE_CLEAR(buf->b_sfname); } else { fname_expand(buf, &ffname, &sfname); // will allocate ffname if (ffname == NULL) { // out of memory @@ -3791,8 +3786,7 @@ int build_stl_str_hl( if (str != NULL && *str != 0) { if (*skipdigits(str) == NUL) { num = atoi((char *)str); - xfree(str); - str = NULL; + XFREE_CLEAR(str); itemisflag = false; } } diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ee4a48ff5d..f720e702a4 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -662,8 +662,7 @@ static void diff_redraw(int dofold) static void clear_diffin(diffin_T *din) { if (din->din_fname == NULL) { - xfree(din->din_mmfile.ptr); - din->din_mmfile.ptr = NULL; + XFREE_CLEAR(din->din_mmfile.ptr); } else { os_remove((char *)din->din_fname); } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 49bc2ab2f0..a8dd115074 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2522,8 +2522,7 @@ static void ins_compl_del_pum(void) { if (compl_match_array != NULL) { pum_undisplay(false); - xfree(compl_match_array); - compl_match_array = NULL; + XFREE_CLEAR(compl_match_array); } } @@ -2587,16 +2586,16 @@ void ins_compl_show_pum(void) // Need to build the popup menu list. compl_match_arraysize = 0; compl = compl_first_match; - /* - * If it's user complete function and refresh_always, - * not use "compl_leader" as prefix filter. - */ - if (ins_compl_need_restart()){ - xfree(compl_leader); - compl_leader = NULL; - } - if (compl_leader != NULL) + // + // If it's user complete function and refresh_always, + // do not use "compl_leader" as prefix filter. + // + if (ins_compl_need_restart()) { + XFREE_CLEAR(compl_leader); + } + if (compl_leader != NULL) { lead_len = (int)STRLEN(compl_leader); + } do { if ((compl->cp_flags & ORIGINAL_TEXT) == 0 && (compl_leader == NULL @@ -2960,10 +2959,8 @@ static void ins_compl_free(void) compl_T *match; int i; - xfree(compl_pattern); - compl_pattern = NULL; - xfree(compl_leader); - compl_leader = NULL; + XFREE_CLEAR(compl_pattern); + XFREE_CLEAR(compl_leader); if (compl_first_match == NULL) return; @@ -2993,14 +2990,11 @@ static void ins_compl_clear(void) compl_cont_status = 0; compl_started = FALSE; compl_matches = 0; - xfree(compl_pattern); - compl_pattern = NULL; - xfree(compl_leader); - compl_leader = NULL; + XFREE_CLEAR(compl_pattern); + XFREE_CLEAR(compl_leader); edit_submode_extra = NULL; - xfree(compl_orig_text); - compl_orig_text = NULL; - compl_enter_selects = FALSE; + XFREE_CLEAR(compl_orig_text); + compl_enter_selects = false; // clear v:completed_item set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc()); } @@ -4960,10 +4954,8 @@ static int ins_complete(int c, bool enable_pum) compl_orig_text = vim_strnsave(line + compl_col, compl_length); if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0, ORIGINAL_TEXT, false, false) != OK) { - xfree(compl_pattern); - compl_pattern = NULL; - xfree(compl_orig_text); - compl_orig_text = NULL; + XFREE_CLEAR(compl_pattern); + XFREE_CLEAR(compl_orig_text); return FAIL; } @@ -6310,10 +6302,8 @@ void set_last_insert(int c) #if defined(EXITFREE) void free_last_insert(void) { - xfree(last_insert); - last_insert = NULL; - xfree(compl_orig_text); - compl_orig_text = NULL; + XFREE_CLEAR(last_insert); + XFREE_CLEAR(compl_orig_text); } #endif @@ -6840,8 +6830,7 @@ static void mb_replace_pop_ins(int cc) */ static void replace_flush(void) { - xfree(replace_stack); - replace_stack = NULL; + XFREE_CLEAR(replace_stack); replace_stack_len = 0; replace_stack_nr = 0; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index de510a8bca..9f56b42fba 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -622,8 +622,7 @@ void eval_clear(void) for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { p = &vimvars[i]; if (p->vv_di.di_tv.v_type == VAR_STRING) { - xfree(p->vv_str); - p->vv_str = NULL; + XFREE_CLEAR(p->vv_str); } else if (p->vv_di.di_tv.v_type == VAR_LIST) { tv_list_unref(p->vv_list); p->vv_list = NULL; @@ -842,15 +841,12 @@ void var_redir_stop(void) clear_lval(redir_lval); } - /* free the collected output */ - xfree(redir_ga.ga_data); - redir_ga.ga_data = NULL; + // free the collected output + XFREE_CLEAR(redir_ga.ga_data); - xfree(redir_lval); - redir_lval = NULL; + XFREE_CLEAR(redir_lval); } - xfree(redir_varname); - redir_varname = NULL; + XFREE_CLEAR(redir_varname); } int eval_charconvert(const char *const enc_from, const char *const enc_to, @@ -3201,8 +3197,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name); } - xfree(varnamebuf); - varnamebuf = NULL; + XFREE_CLEAR(varnamebuf); varnamebuflen = 0; return NULL; } @@ -5942,8 +5937,7 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate) // Next try expanding things like $VIM and ${HOME}. string = expand_env_save(name - 1); if (string != NULL && *string == '$') { - xfree(string); - string = NULL; + XFREE_CLEAR(string); } } name[len] = cc; @@ -6535,7 +6529,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr) Object result = fn(VIML_INTERNAL_CALL, args, &err); if (ERROR_SET(&err)) { - nvim_err_writeln(cstr_as_string(err.msg)); + emsgf_multiline((const char *)e_api_error, err.msg); goto end; } @@ -8874,8 +8868,8 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { len = strlen(fname); size_t usedlen = 0; - (void)modify_fname((char_u *)mods, &usedlen, (char_u **)&fname, &fbuf, - &len); + (void)modify_fname((char_u *)mods, false, &usedlen, + (char_u **)&fname, &fbuf, &len); } rettv->v_type = VAR_STRING; @@ -13815,8 +13809,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (*q != NUL) { STRMOVE(remain, q - 1); } else { - xfree(remain); - remain = NULL; + XFREE_CLEAR(remain); } } @@ -14125,8 +14118,11 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) Error err = ERROR_INIT; - Object result = rpc_send_call((uint64_t)argvars[0].vval.v_number, - tv_get_string(&argvars[1]), args, &err); + + uint64_t chan_id = (uint64_t)argvars[0].vval.v_number; + const char *method = tv_get_string(&argvars[1]); + + Object result = rpc_send_call(chan_id, method, args, &err); if (l_provider_call_nesting) { current_SID = save_current_SID; @@ -14139,7 +14135,20 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if (ERROR_SET(&err)) { - nvim_err_writeln(cstr_as_string(err.msg)); + const char *name = NULL; + Channel *chan = find_channel(chan_id); + if (chan) { + name = rpc_client_name(chan); + } + msg_ext_set_kind("rpc_error"); + if (name) { + emsgf_multiline("Error invoking '%s' on channel %"PRIu64" (%s):\n%s", + method, chan_id, name, err.msg); + } else { + emsgf_multiline("Error invoking '%s' on channel %"PRIu64":\n%s", + method, chan_id, err.msg); + } + goto end; } @@ -17879,6 +17888,25 @@ static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "winlayout()" function +static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tabpage_T *tp; + + tv_list_alloc_ret(rettv, 2); + + if (argvars[0].v_type == VAR_UNKNOWN) { + tp = curtab; + } else { + tp = find_tabpage((int)tv_get_number(&argvars[0])); + if (tp == NULL) { + return; + } + } + + get_framelayout(tp->tp_topframe, rettv->vval.v_list, true); +} + /* * "winline()" function */ @@ -20391,8 +20419,7 @@ void ex_function(exarg_T *eap) /* between ":append" and "." and between ":python <<EOF" and "EOF" * don't check for ":endfunc". */ if (STRCMP(theline, skip_until) == 0) { - xfree(skip_until); - skip_until = NULL; + XFREE_CLEAR(skip_until); } } else { /* skip ':' and blanks*/ @@ -20550,8 +20577,7 @@ void ex_function(exarg_T *eap) // redefine existing function ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); - xfree(name); - name = NULL; + XFREE_CLEAR(name); } } } else { @@ -22632,6 +22658,7 @@ void reset_v_option_vars(void) int modify_fname( char_u *src, // string with modifiers + bool tilde_file, // "~" is a file name, not $HOME size_t *usedlen, // characters after src that are used char_u **fnamep, // file name so far char_u **bufp, // buffer for allocated file name or NULL @@ -22661,8 +22688,8 @@ repeat: || (*fnamep)[1] == '\\' # endif || (*fnamep)[1] == NUL) - #endif + && !(tilde_file && (*fnamep)[1] == NUL) ) { *fnamep = expand_env_save(*fnamep); xfree(*bufp); /* free any allocated file name */ diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index aad2de5d30..dea00c3edd 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -352,6 +352,7 @@ return { winbufnr={args=1}, wincol={}, winheight={args=1}, + winlayout={args={0, 1}}, winline={}, winnr={args={0, 1}}, winrestcmd={}, diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index b3933ac9a6..e7f4736613 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3526,8 +3526,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, lnum += regmatch.startpos[0].lnum; sub_firstlnum += regmatch.startpos[0].lnum; nmatch -= regmatch.startpos[0].lnum; - xfree(sub_firstline); - sub_firstline = NULL; + XFREE_CLEAR(sub_firstline); } // Now we're at the line where the pattern match starts @@ -4058,11 +4057,11 @@ skip: line_breakcheck(); } - if (did_sub) - ++sub_nlines; - xfree(new_start); /* for when substitute was cancelled */ - xfree(sub_firstline); /* free the copy of the original line */ - sub_firstline = NULL; + if (did_sub) { + sub_nlines++; + } + xfree(new_start); // for when substitute was cancelled + XFREE_CLEAR(sub_firstline); // free the copy of the original line } line_breakcheck(); @@ -5077,9 +5076,8 @@ void fix_help_buffer(void) } if (fnamecmp(e1, ".txt") != 0 && fnamecmp(e1, fname + 4) != 0) { - /* Not .txt and not .abx, remove it. */ - xfree(fnames[i1]); - fnames[i1] = NULL; + // Not .txt and not .abx, remove it. + XFREE_CLEAR(fnames[i1]); continue; } if (e1 - f1 != e2 - f2 @@ -5088,9 +5086,8 @@ void fix_help_buffer(void) } if (fnamecmp(e1, ".txt") == 0 && fnamecmp(e2, fname + 4) == 0) { - /* use .abx instead of .txt */ - xfree(fnames[i1]); - fnames[i1] = NULL; + // use .abx instead of .txt + XFREE_CLEAR(fnames[i1]); } } } diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index a2ed37e37e..3202f82a29 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1040,12 +1040,9 @@ static void profile_reset(void) uf->uf_tm_self = profile_zero(); uf->uf_tm_children = profile_zero(); - xfree(uf->uf_tml_count); - xfree(uf->uf_tml_total); - xfree(uf->uf_tml_self); - uf->uf_tml_count = NULL; - uf->uf_tml_total = NULL; - uf->uf_tml_self = NULL; + XFREE_CLEAR(uf->uf_tml_count); + XFREE_CLEAR(uf->uf_tml_total); + XFREE_CLEAR(uf->uf_tml_self); uf->uf_tml_start = profile_zero(); uf->uf_tml_children = profile_zero(); @@ -1056,8 +1053,7 @@ static void profile_reset(void) } } - xfree(profile_fname); - profile_fname = NULL; + XFREE_CLEAR(profile_fname); } /// Start profiling a script. @@ -4003,8 +3999,7 @@ void free_locales(void) for (i = 0; locales[i] != NULL; i++) { xfree(locales[i]); } - xfree(locales); - locales = NULL; + XFREE_CLEAR(locales); } } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 9c4a3f389a..aa76355bad 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -431,8 +431,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) { /* Each '|' separated command is stored separately in lines_ga, to * be able to jump to it. Don't use next_cmdline now. */ - xfree(cmdline_copy); - cmdline_copy = NULL; + XFREE_CLEAR(cmdline_copy); /* Check if a function has returned or, unless it has an unclosed * try conditional, aborted. */ @@ -606,12 +605,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, current_line = cmd_loop_cookie.current_line; if (next_cmdline == NULL) { - xfree(cmdline_copy); - cmdline_copy = NULL; - /* - * If the command was typed, remember it for the ':' register. - * Do this AFTER executing the command to make :@: work. - */ + XFREE_CLEAR(cmdline_copy); + // + // If the command was typed, remember it for the ':' register. + // Do this AFTER executing the command to make :@: work. + // if (getline_equal(fgetline, cookie, getexline) && new_last_cmdline != NULL) { xfree(last_cmdline); @@ -4842,10 +4840,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, goto fail; } - xfree(cmd->uc_rep); - cmd->uc_rep = NULL; - xfree(cmd->uc_compl_arg); - cmd->uc_compl_arg = NULL; + XFREE_CLEAR(cmd->uc_rep); + XFREE_CLEAR(cmd->uc_compl_arg); break; } @@ -7232,11 +7228,8 @@ static char_u *prev_dir = NULL; #if defined(EXITFREE) void free_cd_dir(void) { - xfree(prev_dir); - prev_dir = NULL; - - xfree(globaldir); - globaldir = NULL; + XFREE_CLEAR(prev_dir); + XFREE_CLEAR(globaldir); } #endif @@ -7247,13 +7240,11 @@ void free_cd_dir(void) void post_chdir(CdScope scope, bool trigger_dirchanged) { // Always overwrite the window-local CWD. - xfree(curwin->w_localdir); - curwin->w_localdir = NULL; + XFREE_CLEAR(curwin->w_localdir); // Overwrite the tab-local CWD for :cd, :tcd. if (scope >= kCdScopeTab) { - xfree(curtab->tp_localdir); - curtab->tp_localdir = NULL; + XFREE_CLEAR(curtab->tp_localdir); } if (scope < kCdScopeGlobal) { @@ -7270,8 +7261,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged) switch (scope) { case kCdScopeGlobal: // We are now in the global directory, no need to remember its name. - xfree(globaldir); - globaldir = NULL; + XFREE_CLEAR(globaldir); break; case kCdScopeTab: curtab->tp_localdir = (char_u *)xstrdup(cwd); @@ -8562,6 +8552,7 @@ eval_vars ( size_t resultlen; buf_T *buf; int valid = VALID_HEAD | VALID_PATH; // Assume valid result. + bool tilde_file = false; int skip_mod = false; char strbuf[30]; @@ -8618,9 +8609,11 @@ eval_vars ( case SPEC_PERC: /* '%': current file */ if (curbuf->b_fname == NULL) { result = (char_u *)""; - valid = 0; /* Must have ":p:h" to be valid */ - } else + valid = 0; // Must have ":p:h" to be valid + } else { result = curbuf->b_fname; + tilde_file = STRCMP(result, "~") == 0; + } break; case SPEC_HASH: /* '#' or "#99": alternate file */ @@ -8669,9 +8662,11 @@ eval_vars ( *lnump = ECMD_LAST; if (buf->b_fname == NULL) { result = (char_u *)""; - valid = 0; /* Must have ":p:h" to be valid */ - } else + valid = 0; // Must have ":p:h" to be valid + } else { result = buf->b_fname; + tilde_file = STRCMP(result, "~") == 0; + } } break; @@ -8756,7 +8751,8 @@ eval_vars ( resultlen = (size_t)(s - result); } } else if (!skip_mod) { - valid |= modify_fname(src, usedlen, &result, &resultbuf, &resultlen); + valid |= modify_fname(src, tilde_file, usedlen, &result, + &resultbuf, &resultlen); if (result == NULL) { *errormsg = (char_u *)""; return NULL; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b16023b0ec..beac3cd9ec 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -592,8 +592,7 @@ static int command_line_execute(VimState *state, int key) && s->c != K_KPAGEDOWN && s->c != K_KPAGEUP && s->c != K_LEFT && s->c != K_RIGHT && (s->xpc.xp_numfiles > 0 || (s->c != Ctrl_P && s->c != Ctrl_N))) { - xfree(s->lookfor); - s->lookfor = NULL; + XFREE_CLEAR(s->lookfor); } // When there are matching completions to select <S-Tab> works like @@ -626,8 +625,7 @@ static int command_line_execute(VimState *state, int key) && s->c != Ctrl_L) { if (compl_match_array) { pum_undisplay(true); - xfree(compl_match_array); - compl_match_array = NULL; + XFREE_CLEAR(compl_match_array); } if (s->xpc.xp_numfiles != -1) { (void)ExpandOne(&s->xpc, NULL, NULL, 0, WILD_FREE); @@ -1260,8 +1258,7 @@ static int command_line_handle_key(CommandLineState *s) return command_line_not_changed(s); } - xfree(ccline.cmdbuff); // no commandline to return - ccline.cmdbuff = NULL; + XFREE_CLEAR(ccline.cmdbuff); // no commandline to return if (!cmd_silent && !ui_has(kUICmdline)) { if (cmdmsg_rl) { msg_col = Columns; @@ -1978,8 +1975,7 @@ static int command_line_changed(CommandLineState *s) /// Abandon the command line. static void abandon_cmdline(void) { - xfree(ccline.cmdbuff); - ccline.cmdbuff = NULL; + XFREE_CLEAR(ccline.cmdbuff); if (msg_scrolled == 0) { compute_cmdrow(); } @@ -2630,8 +2626,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) { // Nothing to do, exiting. - xfree(ccline_colors->cmdbuff); - ccline_colors->cmdbuff = NULL; + XFREE_CLEAR(ccline_colors->cmdbuff); return ret; } @@ -3650,8 +3645,7 @@ nextwild ( } } if ((int)STRLEN(p2) < j) { - xfree(p2); - p2 = NULL; + XFREE_CLEAR(p2); } } } @@ -3785,8 +3779,7 @@ ExpandOne ( if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) { FreeWild(xp->xp_numfiles, xp->xp_files); xp->xp_numfiles = -1; - xfree(orig_save); - orig_save = NULL; + XFREE_CLEAR(orig_save); } findex = 0; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index b468b7bb8c..3c45a1ad2e 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -885,8 +885,7 @@ retry: } if (tmpname != NULL) { os_remove((char *)tmpname); // delete converted file - xfree(tmpname); - tmpname = NULL; + XFREE_CLEAR(tmpname); } } @@ -1884,8 +1883,7 @@ failed: msg_add_lines(c, (long)linecnt, filesize); - xfree(keep_msg); - keep_msg = NULL; + XFREE_CLEAR(keep_msg); p = NULL; msg_scrolled_ign = TRUE; @@ -2171,8 +2169,7 @@ readfile_charconvert ( MSG(errmsg); if (tmpname != NULL) { os_remove((char *)tmpname); // delete converted file - xfree(tmpname); - tmpname = NULL; + XFREE_CLEAR(tmpname); } } @@ -2828,14 +2825,13 @@ buf_write ( */ if (os_fileinfo((char *)backup, &file_info_new)) { if (os_fileinfo_id_equal(&file_info_new, &file_info_old)) { - /* - * Backup file is same as original file. - * May happen when modname() gave the same file back (e.g. silly - * link). If we don't check here, we either ruin the file when - * copying or erase it after writing. - */ - xfree(backup); - backup = NULL; /* no backup file to delete */ + // + // Backup file is same as original file. + // May happen when modname() gave the same file back (e.g. silly + // link). If we don't check here, we either ruin the file when + // copying or erase it after writing. + // + XFREE_CLEAR(backup); // no backup file to delete } else if (!p_bk) { /* * We are not going to keep the backup file, so don't @@ -2853,8 +2849,7 @@ buf_write ( } /* They all exist??? Must be something wrong. */ if (*wp == 'a') { - xfree(backup); - backup = NULL; + XFREE_CLEAR(backup); } } } @@ -2969,8 +2964,7 @@ nobackup: } // They all exist??? Must be something wrong! if (*p == 'a') { - xfree(backup); - backup = NULL; + XFREE_CLEAR(backup); } } } @@ -2988,8 +2982,7 @@ nobackup: if (vim_rename(fname, backup) == 0) break; - xfree(backup); /* don't do the rename below */ - backup = NULL; + XFREE_CLEAR(backup); // don't do the rename below } } if (backup == NULL && !forceit) { @@ -3585,8 +3578,7 @@ restore_backup: EMSG(_("E205: Patchmode: can't save original file")); } else if (!os_path_exists((char_u *)org)) { vim_rename(backup, (char_u *)org); - xfree(backup); /* don't delete the file */ - backup = NULL; + XFREE_CLEAR(backup); // don't delete the file #ifdef UNIX set_file_time((char_u *)org, file_info_old.stat.st_atim.tv_sec, @@ -4313,8 +4305,7 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force) && (force || buf->b_sfname == NULL || path_is_absolute(buf->b_sfname))) { - xfree(buf->b_sfname); - buf->b_sfname = NULL; + XFREE_CLEAR(buf->b_sfname); p = path_shorten_fname(buf->b_ffname, dirname); if (p != NULL) { buf->b_sfname = vim_strsave(p); @@ -5352,8 +5343,7 @@ void vim_deltempdir(void) // remove the trailing path separator path_tail(vim_tempdir)[-1] = NUL; delete_recursive((const char *)vim_tempdir); - xfree(vim_tempdir); - vim_tempdir = NULL; + XFREE_CLEAR(vim_tempdir); } } @@ -5512,8 +5502,7 @@ static void show_autocmd(AutoPat *ap, event_T event) // Mark an autocommand handler for deletion. static void au_remove_pat(AutoPat *ap) { - xfree(ap->pat); - ap->pat = NULL; + XFREE_CLEAR(ap->pat); ap->buflocal_nr = -1; au_need_clean = true; } @@ -5522,8 +5511,7 @@ static void au_remove_pat(AutoPat *ap) static void au_remove_cmds(AutoPat *ap) { for (AutoCmd *ac = ap->cmds; ac != NULL; ac = ac->next) { - xfree(ac->cmd); - ac->cmd = NULL; + XFREE_CLEAR(ac->cmd); } au_need_clean = true; } @@ -5531,8 +5519,7 @@ static void au_remove_cmds(AutoPat *ap) // Delete one command from an autocmd pattern. static void au_del_cmd(AutoCmd *ac) { - xfree(ac->cmd); - ac->cmd = NULL; + XFREE_CLEAR(ac->cmd); au_need_clean = true; } @@ -6504,8 +6491,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) /* Make sure w_localdir and globaldir are NULL to avoid a chdir() in * win_enter_ext(). */ - xfree(aucmd_win->w_localdir); - aucmd_win->w_localdir = NULL; + XFREE_CLEAR(aucmd_win->w_localdir); aco->globaldir = globaldir; globaldir = NULL; @@ -7128,8 +7114,7 @@ auto_next_pat ( AutoCmd *cp; char *s; - xfree(sourcing_name); - sourcing_name = NULL; + XFREE_CLEAR(sourcing_name); for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) { apc->curpat = NULL; @@ -7737,12 +7722,12 @@ char_u * file_pat_to_reg_pat( reg_pat[i++] = '$'; reg_pat[i] = NUL; if (nested != 0) { - if (nested < 0) + if (nested < 0) { EMSG(_("E219: Missing {.")); - else + } else { EMSG(_("E220: Missing }.")); - xfree(reg_pat); - reg_pat = NULL; + } + XFREE_CLEAR(reg_pat); } return reg_pat; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ec14ada3d2..9fa294ba87 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1039,6 +1039,7 @@ EXTERN char_u e_au_recursive[] INIT(= N_( EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported")); EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long")); EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String")); + EXTERN char_u e_autocmd_err[] INIT(=N_( "E5500: autocmd has thrown an exception: %s")); EXTERN char_u e_cmdmap_err[] INIT(=N_( @@ -1047,6 +1048,10 @@ EXTERN char_u e_cmdmap_repeated[] INIT(=N_( "E5521: <Cmd> mapping must end with <CR> before second <Cmd>")); EXTERN char_u e_cmdmap_key[] INIT(=N_( "E5522: <Cmd> mapping must not include %s key")); + +EXTERN char_u e_api_error[] INIT(=N_( + "E5555: API call: %s")); + EXTERN char_u e_floatonly[] INIT(=N_( "E5601: Cannot close window, only floating window would remain")); EXTERN char_u e_floatexchange[] INIT(=N_( diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index 983dbb7bbe..bf2ac35554 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -1942,8 +1942,7 @@ void mch_print_cleanup(void) prt_file_error = FALSE; } if (prt_ps_file_name != NULL) { - xfree(prt_ps_file_name); - prt_ps_file_name = NULL; + XFREE_CLEAR(prt_ps_file_name); } } diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 8b6fd6c705..84721ee96c 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -425,9 +425,11 @@ cs_add_common( expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL); size_t len = STRLEN(fname); fbuf = (char_u *)fname; - (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&fname, &fbuf, &len); - if (fname == NULL) + (void)modify_fname((char_u *)":p", false, &usedlen, + (char_u **)&fname, &fbuf, &len); + if (fname == NULL) { goto add_err; + } fname = (char *)vim_strnsave((char_u *)fname, len); xfree(fbuf); FileInfo file_info; @@ -1530,11 +1532,9 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, } /* for all cscope connections */ if (totsofar == 0) { - /* No matches, free the arrays and return NULL in "*matches_p". */ - xfree(matches); - matches = NULL; - xfree(cntxts); - cntxts = NULL; + // No matches, free the arrays and return NULL in "*matches_p". + XFREE_CLEAR(matches); + XFREE_CLEAR(cntxts); } *matched = totsofar; *matches_p = matches; diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h index 704aa26010..33aeff1d89 100644 --- a/src/nvim/lib/kbtree.h +++ b/src/nvim/lib/kbtree.h @@ -72,7 +72,7 @@ *top++ = (b)->root; \ while (top != stack) { \ x = *--top; \ - if (x->is_internal == 0) { xfree(x); continue; } \ + if (x->is_internal == 0) { XFREE_CLEAR(x); continue; } \ for (i = 0; i <= x->n; ++i) \ if (__KB_PTR(b, x)[i]) { \ if (top - stack == (int)max) { \ @@ -82,10 +82,10 @@ } \ *top++ = __KB_PTR(b, x)[i]; \ } \ - xfree(x); \ + XFREE_CLEAR(x); \ } \ } \ - xfree(stack); \ + XFREE_CLEAR(stack); \ } while (0) #define __KB_GET_AUX1(name, key_t, kbnode_t, __cmp) \ @@ -253,7 +253,7 @@ memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \ --x->n; \ - xfree(z); \ + XFREE_CLEAR(z); \ return __kb_delp_aux_##name(b, y, k, s); \ } \ } \ @@ -281,7 +281,7 @@ memmove(&__KB_KEY(key_t, x)[i - 1], &__KB_KEY(key_t, x)[i], (unsigned int)(x->n - i) * sizeof(key_t)); \ memmove(&__KB_PTR(b, x)[i], &__KB_PTR(b, x)[i + 1], (unsigned int)(x->n - i) * sizeof(void*)); \ --x->n; \ - xfree(xp); \ + XFREE_CLEAR(xp); \ xp = y; \ } else if (i < x->n && (y = __KB_PTR(b, x)[i + 1])->n == T - 1) { \ __KB_KEY(key_t, xp)[xp->n++] = __KB_KEY(key_t, x)[i]; \ @@ -291,7 +291,7 @@ memmove(&__KB_KEY(key_t, x)[i], &__KB_KEY(key_t, x)[i + 1], (unsigned int)(x->n - i - 1) * sizeof(key_t)); \ memmove(&__KB_PTR(b, x)[i + 1], &__KB_PTR(b, x)[i + 2], (unsigned int)(x->n - i - 1) * sizeof(void*)); \ --x->n; \ - xfree(y); \ + XFREE_CLEAR(y); \ } \ } \ return __kb_delp_aux_##name(b, xp, k, s); \ @@ -306,7 +306,7 @@ --b->n_nodes; \ x = b->root; \ b->root = __KB_PTR(b, x)[0]; \ - xfree(x); \ + XFREE_CLEAR(x); \ } \ return ret; \ } \ diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h index b2994a3159..c999511543 100644 --- a/src/nvim/lib/khash.h +++ b/src/nvim/lib/khash.h @@ -181,7 +181,7 @@ typedef khint_t khiter_t; #define krealloc(P,Z) xrealloc(P,Z) #endif #ifndef kfree -#define kfree(P) xfree(P) +#define kfree(P) XFREE_CLEAR(P) #endif #define __ac_HASH_UPPER 0.77 diff --git a/src/nvim/lib/klist.h b/src/nvim/lib/klist.h index 7ee100ab8c..b80f4be3c2 100644 --- a/src/nvim/lib/klist.h +++ b/src/nvim/lib/klist.h @@ -46,9 +46,9 @@ static inline void kmp_destroy_##name(kmp_##name##_t *mp) { \ size_t k; \ for (k = 0; k < mp->n; k++) { \ - kmpfree_f(mp->buf[k]); xfree(mp->buf[k]); \ + kmpfree_f(mp->buf[k]); XFREE_CLEAR(mp->buf[k]); \ } \ - xfree(mp->buf); xfree(mp); \ + XFREE_CLEAR(mp->buf); XFREE_CLEAR(mp); \ } \ static inline kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \ mp->cnt++; \ @@ -100,7 +100,7 @@ } \ kmp_free(name, kl->mp, p); \ kmp_destroy(name, kl->mp); \ - xfree(kl); \ + XFREE_CLEAR(kl); \ } \ static inline void kl_push_##name(kl_##name##_t *kl, kltype_t d) { \ kl1_##name *q, *p = kmp_alloc(name, kl->mp); \ diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h index 93b2f053bc..5bd09930a3 100644 --- a/src/nvim/lib/kvec.h +++ b/src/nvim/lib/kvec.h @@ -58,7 +58,11 @@ } #define kv_init(v) ((v).size = (v).capacity = 0, (v).items = 0) -#define kv_destroy(v) xfree((v).items) +#define kv_destroy(v) \ + do { \ + xfree((v).items); \ + kv_init(v); \ + } while (0) #define kv_A(v, i) ((v).items[(i)]) #define kv_pop(v) ((v).items[--(v).size]) #define kv_size(v) ((v).size) @@ -88,7 +92,7 @@ } \ (v1).size = (v0).size; \ memcpy((v1).items, (v0).items, sizeof((v1).items[0]) * (v0).size); \ - } while (0) \ + } while (0) #define kv_pushp(v) \ ((((v).size == (v).capacity) ? (kv_resize_full(v), 0) : 0), \ @@ -138,7 +142,7 @@ static inline void *_memcpy_free(void *const restrict dest, FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_ALWAYS_INLINE { memcpy(dest, src, size); - xfree(src); + XFREE_CLEAR(src); return dest; } @@ -201,7 +205,7 @@ static inline void *_memcpy_free(void *const restrict dest, #define kvi_destroy(v) \ do { \ if ((v).items != (v).init_array) { \ - xfree((v).items); \ + XFREE_CLEAR((v).items); \ } \ } while (0) diff --git a/src/nvim/lib/ringbuf.h b/src/nvim/lib/ringbuf.h index e63eae70b0..cb79eaf742 100644 --- a/src/nvim/lib/ringbuf.h +++ b/src/nvim/lib/ringbuf.h @@ -136,14 +136,14 @@ static inline void funcprefix##_rb_free(TypeName##RingBuffer *const rb) \ RINGBUF_FORALL(rb, RBType, rbitem) { \ rbfree(rbitem); \ } \ - xfree(rb->buf); \ + XFREE_CLEAR(rb->buf); \ } \ \ static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ REAL_FATTR_UNUSED; \ static inline void funcprefix##_rb_dealloc(TypeName##RingBuffer *const rb) \ { \ - xfree(rb->buf); \ + XFREE_CLEAR(rb->buf); \ } \ \ static inline void funcprefix##_rb_push(TypeName##RingBuffer *const rb, \ diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 72b97736fc..4e94c10283 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -54,6 +54,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg) size_t len; const char *const str = lua_tolstring(lstate, -1, &len); + msg_ext_set_kind("lua_error"); emsgf_multiline(msg, (int)len, str); lua_pop(lstate, 1); diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 5c9367ab01..7809b6814f 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -523,8 +523,7 @@ static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf) && fm->fname != NULL && fnamecmp(name, fm->fname) == 0) { fm->fmark.fnum = buf->b_fnum; - xfree(fm->fname); - fm->fname = NULL; + XFREE_CLEAR(fm->fname); } } @@ -752,8 +751,7 @@ void ex_delmarks(exarg_T *eap) n = i - 'A'; } namedfm[n].fmark.mark.lnum = 0; - xfree(namedfm[n].fname); - namedfm[n].fname = NULL; + XFREE_CLEAR(namedfm[n].fname); } } } else diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 8cc91146cc..c161bad66f 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1421,8 +1421,7 @@ int utf16_to_utf8(const wchar_t *strw, char **str) NULL, NULL); if (utf8_len == 0) { - xfree(*str); - *str = NULL; + XFREE_CLEAR(*str); return GetLastError(); } (*str)[utf8_len] = '\0'; @@ -2119,9 +2118,8 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, from += l; fromlen -= l; } else if (ICONV_ERRNO != ICONV_E2BIG) { - /* conversion failed */ - xfree(result); - result = NULL; + // conversion failed + XFREE_CLEAR(result); break; } /* Not enough room or skipping illegal sequence. */ diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index 5a64c82e0e..7bed644da3 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -719,10 +719,8 @@ blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr) /// Frees mf_fname and mf_ffname. void mf_free_fnames(memfile_T *mfp) { - xfree(mfp->mf_fname); - xfree(mfp->mf_ffname); - mfp->mf_fname = NULL; - mfp->mf_ffname = NULL; + XFREE_CLEAR(mfp->mf_fname); + XFREE_CLEAR(mfp->mf_ffname); } /// Set the simple file name and the full file name of memfile's swapfile, out diff --git a/src/nvim/memline.c b/src/nvim/memline.c index a071314453..a4d2feb5e3 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -563,8 +563,7 @@ void ml_close(buf_T *buf, int del_file) if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY)) xfree(buf->b_ml.ml_line_ptr); xfree(buf->b_ml.ml_stack); - xfree(buf->b_ml.ml_chunksize); - buf->b_ml.ml_chunksize = NULL; + XFREE_CLEAR(buf->b_ml.ml_chunksize); buf->b_ml.ml_mfp = NULL; /* Reset the "recovered" flag, give the ATTENTION prompt the next time @@ -3341,11 +3340,11 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, (char_u *)dir_name); for (;; ) { - if (fname == NULL) /* must be out of memory */ + if (fname == NULL) { // must be out of memory break; - if ((n = strlen(fname)) == 0) { /* safety check */ - xfree(fname); - fname = NULL; + } + if ((n = strlen(fname)) == 0) { // safety check + XFREE_CLEAR(fname); break; } // check if the swapfile already exists @@ -3541,8 +3540,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, if (fname[n - 1] == 'a') { /* ".s?a" */ if (fname[n - 2] == 'a') { /* ".saa": tried enough, give up */ EMSG(_("E326: Too many swap files found")); - xfree(fname); - fname = NULL; + XFREE_CLEAR(fname); break; } --fname[n - 2]; /* ".svz", ".suz", etc. */ diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 4ed816b157..b8a29070ce 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -110,6 +110,8 @@ void *xmalloc(size_t size) } /// free() wrapper that delegates to the backing memory manager +/// +/// @note Use XFREE_CLEAR() instead, if possible. void xfree(void *ptr) { free(ptr); diff --git a/src/nvim/memory.h b/src/nvim/memory.h index 250ac3e08f..5b39d002c9 100644 --- a/src/nvim/memory.h +++ b/src/nvim/memory.h @@ -40,4 +40,15 @@ extern bool entered_free_all_mem; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "memory.h.generated.h" #endif + +#define XFREE_CLEAR(ptr) \ + do { \ + /* Take the address to avoid double evaluation. #1375 */ \ + void **ptr_ = (void **)&(ptr); \ + xfree(*ptr_); \ + /* coverity[dead-store] */ \ + *ptr_ = NULL; \ + (void)(*ptr_); \ + } while (0) + #endif // NVIM_MEMORY_H diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 472481bb30..368faf7d0b 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -388,8 +388,7 @@ add_menu_path( menup = &menu->children; parent = menu; name = next_name; - xfree(dname); - dname = NULL; + XFREE_CLEAR(dname); if (pri_tab[pri_idx + 1] != -1) { pri_idx++; } diff --git a/src/nvim/message.c b/src/nvim/message.c index cb83d6482c..077c28eb2c 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -420,8 +420,7 @@ static char_u *last_sourcing_name = NULL; */ void reset_last_sourcing(void) { - xfree(last_sourcing_name); - last_sourcing_name = NULL; + XFREE_CLEAR(last_sourcing_name); last_sourcing_lnum = 0; } @@ -1117,8 +1116,7 @@ void wait_return(int redraw) reset_last_sourcing(); if (keep_msg != NULL && vim_strsize(keep_msg) >= (Rows - cmdline_row - 1) * Columns + sc_col) { - xfree(keep_msg); - keep_msg = NULL; /* don't redisplay message, it's too long */ + XFREE_CLEAR(keep_msg); // don't redisplay message, it's too long } if (tmpState == SETWSIZE) { /* got resize event while in vgetc() */ @@ -1188,8 +1186,7 @@ void msg_start(void) int did_return = FALSE; if (!msg_silent) { - xfree(keep_msg); - keep_msg = NULL; /* don't display old message now */ + XFREE_CLEAR(keep_msg); // don't display old message now } if (need_clr_eos) { @@ -3000,9 +2997,8 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1) /* Don't want a hit-enter prompt here. */ ++no_wait_return; - set_vim_var_string(VV_WARNINGMSG, (char *) message, -1); - xfree(keep_msg); - keep_msg = NULL; + set_vim_var_string(VV_WARNINGMSG, (char *)message, -1); + XFREE_CLEAR(keep_msg); if (hl) { keep_msg_attr = HL_ATTR(HLF_W); } else { diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 4cc6c150e0..4ef0103c4f 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -2840,8 +2840,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, os_remove((char *)tempname); if (i != len) { EMSG2(_(e_notread), tempname); - xfree(buffer); - buffer = NULL; + XFREE_CLEAR(buffer); } else if (ret_len == NULL) { /* Change NUL into SOH, otherwise the string is truncated. */ for (i = 0; i < len; ++i) diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 3438949e2d..2f3af22b65 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -687,6 +687,22 @@ Dictionary rpc_client_info(Channel *chan) return copy_dictionary(chan->rpc.info); } +const char *rpc_client_name(Channel *chan) +{ + if (!chan->is_rpc) { + return NULL; + } + Dictionary info = chan->rpc.info; + for (size_t i = 0; i < info.size; i++) { + if (strequal("name", info.items[i].key.data) + && info.items[i].value.type == kObjectTypeString) { + return info.items[i].value.data.string.data; + } + } + + return NULL; +} + #if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL #define REQ "[request] " #define RES "[response] " diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 04eede18bd..50abd226fc 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1467,8 +1467,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { AppendToRedobuffLit(repeat_cmdline, -1); AppendToRedobuff(NL_STR); - xfree(repeat_cmdline); - repeat_cmdline = NULL; + XFREE_CLEAR(repeat_cmdline); } } } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 216bab4dda..1c5d4e98a7 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -983,9 +983,8 @@ do_execreg( EMSG(_(e_nolastcmd)); return FAIL; } - xfree(new_last_cmdline); /* don't keep the cmdline containing @: */ - new_last_cmdline = NULL; - /* Escape all control characters with a CTRL-V */ + XFREE_CLEAR(new_last_cmdline); // don't keep the cmdline containing @: + // Escape all control characters with a CTRL-V p = vim_strsave_escaped_ext( last_cmdline, (char_u *) @@ -2348,8 +2347,7 @@ void free_register(yankreg_T *reg) for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included xfree(reg->y_array[i]); } - xfree(reg->y_array); - reg->y_array = NULL; + XFREE_CLEAR(reg->y_array); } } diff --git a/src/nvim/option.c b/src/nvim/option.c index 743f6c8311..43ee6bf451 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1239,7 +1239,7 @@ int do_set( } len++; if (opt_idx == -1) { - key = find_key_option(arg + 1); + key = find_key_option(arg + 1, true); } } else { len = 0; @@ -1253,7 +1253,7 @@ int do_set( } opt_idx = findoption_len((const char *)arg, (size_t)len); if (opt_idx == -1) { - key = find_key_option(arg); + key = find_key_option(arg, false); } } @@ -1986,7 +1986,7 @@ static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) static int string_to_key(char_u *arg) { if (*arg == '<') { - return find_key_option(arg + 1); + return find_key_option(arg + 1, true); } if (*arg == '^') { return Ctrl_chr(arg[1]); @@ -4957,19 +4957,20 @@ char *set_option_value(const char *const name, const long number, return NULL; } -/* - * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. - */ -int find_key_option_len(const char_u *arg, size_t len) +// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. +// When "has_lt" is true there is a '<' before "*arg_arg". +// Returns 0 when the key is not recognized. +int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt) { - int key; + int key = 0; int modifiers; + const char_u *arg = arg_arg; // Don't use get_special_key_code() for t_xx, we don't want it to call // add_termcap_entry(). if (len >= 4 && arg[0] == 't' && arg[1] == '_') { key = TERMCAP2KEY(arg[2], arg[3]); - } else { + } else if (has_lt) { arg--; // put arg at the '<' modifiers = 0; key = find_special_key(&arg, len + 1, &modifiers, true, true, false); @@ -4980,9 +4981,9 @@ int find_key_option_len(const char_u *arg, size_t len) return key; } -static int find_key_option(const char_u *arg) +static int find_key_option(const char_u *arg, bool has_lt) { - return find_key_option_len(arg, STRLEN(arg)); + return find_key_option_len(arg, STRLEN(arg), has_lt); } /* diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 7d1021962c..b067de608b 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -870,8 +870,8 @@ size_t home_replace(const buf_T *const buf, const char_u *src, size_t usedlen = 0; size_t flen = strlen(homedir_env_mod); char_u *fbuf = NULL; - (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod, - &fbuf, &flen); + (void)modify_fname((char_u *)":p", false, &usedlen, + (char_u **)&homedir_env_mod, &fbuf, &flen); flen = strlen(homedir_env_mod); assert(homedir_env_mod != homedir_env); if (vim_ispathsep(homedir_env_mod[flen - 1])) { diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 8180a2e8ac..35a7942059 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -553,8 +553,7 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, *num_file = j; if (*num_file == 0) { // rejected all entries - xfree(*file); - *file = NULL; + XFREE_CLEAR(*file); goto notfound; } diff --git a/src/nvim/path.c b/src/nvim/path.c index 67b88a861a..b43a172991 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -2088,8 +2088,7 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, // Free empty array of matches if (*num_files == 0) { - xfree(*files); - *files = NULL; + XFREE_CLEAR(*files); return FAIL; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 550f742106..8036d3e3bc 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -848,8 +848,7 @@ qf_init_ext( int status; // Do not used the cached buffer, it may have been wiped out. - xfree(qf_last_bufname); - qf_last_bufname = NULL; + XFREE_CLEAR(qf_last_bufname); memset(&state, 0, sizeof(state)); memset(&fields, 0, sizeof(fields)); @@ -894,8 +893,7 @@ qf_init_ext( // parsed values. if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) { // free the previously parsed data - xfree(last_efm); - last_efm = NULL; + XFREE_CLEAR(last_efm); free_efm_list(&fmt_first); // parse the current 'efm' @@ -1019,8 +1017,7 @@ qf_init_end: /// Prepends ':' to the title. static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title) { - xfree(qi->qf_lists[qf_idx].qf_title); - qi->qf_lists[qf_idx].qf_title = NULL; + XFREE_CLEAR(qi->qf_lists[qf_idx].qf_title); if (title != NULL) { size_t len = STRLEN(title) + 1; @@ -2754,8 +2751,7 @@ static void qf_free(qf_info_T *qi, int idx) qf_list_T *qfl = &qi->qf_lists[idx]; qf_free_items(qi, idx); - xfree(qfl->qf_title); - qfl->qf_title = NULL; + XFREE_CLEAR(qfl->qf_title); tv_free(qfl->qf_ctx); qfl->qf_ctx = NULL; qfl->qf_id = 0; diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 39ce7ff844..8598da6376 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -3550,8 +3550,7 @@ theend: /* Free "reg_tofree" when it's a bit big. * Free regstack and backpos if they are bigger than their initial size. */ if (reg_tofreelen > 400) { - xfree(reg_tofree); - reg_tofree = NULL; + XFREE_CLEAR(reg_tofree); } if (regstack.ga_maxlen > REGSTACK_INITIAL) ga_clear(®stack); @@ -6618,8 +6617,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, if (eval_result != NULL) { STRCPY(dest, eval_result); dst += STRLEN(eval_result); - xfree(eval_result); - eval_result = NULL; + XFREE_CLEAR(eval_result); } } else { int prev_can_f_submatch = can_f_submatch; diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index ce7270ae65..dc1ab971ab 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -6594,8 +6594,7 @@ out: return (regprog_T *)prog; fail: - xfree(prog); - prog = NULL; + XFREE_CLEAR(prog); #ifdef REGEXP_DEBUG nfa_postfix_dump(expr, FAIL); #endif diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 4c830bb256..81ddbbfb74 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3135,8 +3135,7 @@ win_line ( int c0; if (p_extra_free != NULL) { - xfree(p_extra_free); - p_extra_free = NULL; + XFREE_CLEAR(p_extra_free); } // Get a character from the line itself. diff --git a/src/nvim/search.c b/src/nvim/search.c index 6e00602e66..3bd222b3de 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4290,9 +4290,8 @@ find_pattern_in_path( prev_fname = NULL; } } - xfree(new_fname); - new_fname = NULL; - already_searched = TRUE; + XFREE_CLEAR(new_fname); + already_searched = true; break; } } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 4440d3905f..4aafc669dc 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1358,8 +1358,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) case kSDItemGlobalMark: { buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname); if (buf != NULL) { - xfree(cur_entry.data.filemark.fname); - cur_entry.data.filemark.fname = NULL; + XFREE_CLEAR(cur_entry.data.filemark.fname); } xfmark_T fm = (xfmark_T) { .fname = (char_u *) (buf == NULL diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 0fc33bec81..6fd22a6537 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1708,19 +1708,13 @@ void slang_clear(slang_T *lp) { garray_T *gap; - xfree(lp->sl_fbyts); - lp->sl_fbyts = NULL; - xfree(lp->sl_kbyts); - lp->sl_kbyts = NULL; - xfree(lp->sl_pbyts); - lp->sl_pbyts = NULL; - - xfree(lp->sl_fidxs); - lp->sl_fidxs = NULL; - xfree(lp->sl_kidxs); - lp->sl_kidxs = NULL; - xfree(lp->sl_pidxs); - lp->sl_pidxs = NULL; + XFREE_CLEAR(lp->sl_fbyts); + XFREE_CLEAR(lp->sl_kbyts); + XFREE_CLEAR(lp->sl_pbyts); + + XFREE_CLEAR(lp->sl_fidxs); + XFREE_CLEAR(lp->sl_kidxs); + XFREE_CLEAR(lp->sl_pidxs); GA_DEEP_CLEAR(&lp->sl_rep, fromto_T, free_fromto); GA_DEEP_CLEAR(&lp->sl_repsal, fromto_T, free_fromto); @@ -1738,26 +1732,17 @@ void slang_clear(slang_T *lp) vim_regfree(lp->sl_prefprog[i]); } lp->sl_prefixcnt = 0; - xfree(lp->sl_prefprog); - lp->sl_prefprog = NULL; - - xfree(lp->sl_info); - lp->sl_info = NULL; - - xfree(lp->sl_midword); - lp->sl_midword = NULL; + XFREE_CLEAR(lp->sl_prefprog); + XFREE_CLEAR(lp->sl_info); + XFREE_CLEAR(lp->sl_midword); vim_regfree(lp->sl_compprog); - xfree(lp->sl_comprules); - xfree(lp->sl_compstartflags); - xfree(lp->sl_compallflags); lp->sl_compprog = NULL; - lp->sl_comprules = NULL; - lp->sl_compstartflags = NULL; - lp->sl_compallflags = NULL; + XFREE_CLEAR(lp->sl_comprules); + XFREE_CLEAR(lp->sl_compstartflags); + XFREE_CLEAR(lp->sl_compallflags); - xfree(lp->sl_syllable); - lp->sl_syllable = NULL; + XFREE_CLEAR(lp->sl_syllable); ga_clear(&lp->sl_syl_items); ga_clear_strings(&lp->sl_comppat); @@ -1779,10 +1764,8 @@ void slang_clear(slang_T *lp) // Clear the info from the .sug file in "lp". void slang_clear_sug(slang_T *lp) { - xfree(lp->sl_sbyts); - lp->sl_sbyts = NULL; - xfree(lp->sl_sidxs); - lp->sl_sidxs = NULL; + XFREE_CLEAR(lp->sl_sbyts); + XFREE_CLEAR(lp->sl_sidxs); close_spellbuf(lp->sl_sugbuf); lp->sl_sugbuf = NULL; lp->sl_sugloaded = false; @@ -2255,8 +2238,7 @@ theend: static void clear_midword(win_T *wp) { memset(wp->w_s->b_spell_ismw, 0, 256); - xfree(wp->w_s->b_spell_ismw_mb); - wp->w_s->b_spell_ismw_mb = NULL; + XFREE_CLEAR(wp->w_s->b_spell_ismw_mb); } // Use the "sl_midword" field of language "lp" for buffer "buf". @@ -2415,8 +2397,7 @@ void spell_delete_wordlist(void) os_remove((char *)int_wordlist); int_wordlist_spl(fname); os_remove((char *)fname); - xfree(int_wordlist); - int_wordlist = NULL; + XFREE_CLEAR(int_wordlist); } } @@ -2438,10 +2419,8 @@ void spell_free_all(void) spell_delete_wordlist(); - xfree(repl_to); - repl_to = NULL; - xfree(repl_from); - repl_from = NULL; + XFREE_CLEAR(repl_to); + XFREE_CLEAR(repl_from); } // Clear all spelling tables and reload them. @@ -2838,10 +2817,8 @@ void spell_suggest(int count) smsg(_("Sorry, only %" PRId64 " suggestions"), (int64_t)sug.su_ga.ga_len); } else { - xfree(repl_from); - repl_from = NULL; - xfree(repl_to); - repl_to = NULL; + XFREE_CLEAR(repl_from); + XFREE_CLEAR(repl_to); // When 'rightleft' is set the list is drawn right-left. cmdmsg_rl = curwin->w_p_rl; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 117939e7e9..5f5f74cf2e 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -1446,8 +1446,7 @@ static int read_compound(FILE *fd, slang_T *slang, int len) // Copy flag to "sl_comprules", unless we run into a wildcard. if (crp != NULL) { if (c == '?' || c == '+' || c == '*') { - xfree(slang->sl_comprules); - slang->sl_comprules = NULL; + XFREE_CLEAR(slang->sl_comprules); crp = NULL; } else *crp++ = c; diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 1b30161e94..4460c13ac6 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -992,10 +992,10 @@ static void syn_stack_free_block(synblock_T *block) synstate_T *p; if (block->b_sst_array != NULL) { - for (p = block->b_sst_first; p != NULL; p = p->sst_next) + for (p = block->b_sst_first; p != NULL; p = p->sst_next) { clear_syn_state(p); - xfree(block->b_sst_array); - block->b_sst_array = NULL; + } + XFREE_CLEAR(block->b_sst_array); block->b_sst_len = 0; } } @@ -3186,8 +3186,7 @@ void syntax_clear(synblock_T *block) vim_regfree(block->b_syn_linecont_prog); block->b_syn_linecont_prog = NULL; - xfree(block->b_syn_linecont_pat); - block->b_syn_linecont_pat = NULL; + XFREE_CLEAR(block->b_syn_linecont_pat); block->b_syn_folditems = 0; clear_string_option(&block->b_syn_isk); @@ -3230,8 +3229,7 @@ static void syntax_sync_clear(void) vim_regfree(curwin->w_s->b_syn_linecont_prog); curwin->w_s->b_syn_linecont_prog = NULL; - xfree(curwin->w_s->b_syn_linecont_pat); - curwin->w_s->b_syn_linecont_pat = NULL; + XFREE_CLEAR(curwin->w_s->b_syn_linecont_pat); clear_string_option(&curwin->w_s->b_syn_isk); syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */ @@ -3331,8 +3329,7 @@ static void syn_cmd_clear(exarg_T *eap, int syncing) // and make it empty. int scl_id = id - SYNID_CLUSTER; - xfree(SYN_CLSTR(curwin->w_s)[scl_id].scl_list); - SYN_CLSTR(curwin->w_s)[scl_id].scl_list = NULL; + XFREE_CLEAR(SYN_CLSTR(curwin->w_s)[scl_id].scl_list); } } else { id = syn_namen2id(arg, (int)(arg_end - arg)); @@ -5160,9 +5157,8 @@ static void syn_cmd_sync(exarg_T *eap, int syncing) syn_clear_time(&curwin->w_s->b_syn_linecont_time); if (curwin->w_s->b_syn_linecont_prog == NULL) { - xfree(curwin->w_s->b_syn_linecont_pat); - curwin->w_s->b_syn_linecont_pat = NULL; - finished = TRUE; + XFREE_CLEAR(curwin->w_s->b_syn_linecont_pat); + finished = true; break; } } @@ -6993,12 +6989,9 @@ static void highlight_clear(int idx) HL_TABLE()[idx].sg_rgb_fg = -1; HL_TABLE()[idx].sg_rgb_bg = -1; HL_TABLE()[idx].sg_rgb_sp = -1; - xfree(HL_TABLE()[idx].sg_rgb_fg_name); - HL_TABLE()[idx].sg_rgb_fg_name = NULL; - xfree(HL_TABLE()[idx].sg_rgb_bg_name); - HL_TABLE()[idx].sg_rgb_bg_name = NULL; - xfree(HL_TABLE()[idx].sg_rgb_sp_name); - HL_TABLE()[idx].sg_rgb_sp_name = NULL; + XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_fg_name); + XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name); + XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name); // Clear the script ID only when there is no link, since that is not // cleared. if (HL_TABLE()[idx].sg_link == 0) { diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 81af23f911..6e883a1c3d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -923,8 +923,7 @@ end_do_tag: */ void tag_freematch(void) { - xfree(tagmatchname); - tagmatchname = NULL; + XFREE_CLEAR(tagmatchname); } static void taglen_advance(int l) @@ -1987,8 +1986,7 @@ void free_tag_stuff(void) tag_freematch(); if (ptag_entry.tagname) { - xfree(ptag_entry.tagname); - ptag_entry.tagname = NULL; + XFREE_CLEAR(ptag_entry.tagname); } } diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 971623d3db..30e29bd05d 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -7,6 +7,7 @@ source test_cd.vim source test_changedtick.vim source test_compiler.vim source test_cursor_func.vim +source test_ex_equal.vim source test_ex_undo.vim source test_ex_z.vim source test_execute_func.vim @@ -28,27 +29,25 @@ source test_lambda.vim source test_mapping.vim source test_menu.vim source test_messages.vim +source test_modeline.vim source test_move.vim source test_partial.vim source test_popup.vim source test_put.vim source test_recover.vim -source test_regexp_utf8.vim source test_scroll_opt.vim source test_sort.vim -source test_source_utf8.vim source test_sha256.vim source test_statusline.vim source test_suspend.vim source test_syn_attr.vim source test_tabline.vim -" source test_tabpage.vim +source test_tabpage.vim source test_tagcase.vim source test_tagjump.vim source test_taglist.vim source test_true_false.vim source test_unlet.vim -source test_utf8.vim source test_virtualedit.vim source test_window_cmd.vim source test_wnext.vim diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim index 01a9a3f9ad..bcb0d0dec5 100644 --- a/src/nvim/testdir/test_cscope.vim +++ b/src/nvim/testdir/test_cscope.vim @@ -254,7 +254,30 @@ func Test_cscopeWithCscopeConnections() " CleanUp call CscopeSetupOrClean(0) +endfunc + +" Test ":cs add {dir}" (add the {dir}/cscope.out database) +func Test_cscope_add_dir() + call mkdir('Xcscopedir', 'p') + + " Cscope doesn't handle symlinks, so this needs to be resolved in case a + " shadow directory is being used. + let memfile = resolve('./samples/memfile_test.c') + call system('cscope -bk -fXcscopedir/cscope.out ' . memfile) + + cs add Xcscopedir + let a = execute('cscope show') + let lines = split(a, "\n", 1) + call assert_equal(3, len(lines)) + call assert_equal(' # pid database name prepend path', lines[0]) + call assert_equal('', lines[1]) + call assert_match('^ 0 \d\+.*Xcscopedir/cscope.out\s\+<none>$', lines[2]) + + cs kill -1 + call delete('Xcscopedir/cscope.out') + call assert_fails('cs add Xcscopedir', 'E563:') + call delete('Xcscopedir', 'd') endfunc func Test_cscopequickfix() diff --git a/src/nvim/testdir/test_ex_equal.vim b/src/nvim/testdir/test_ex_equal.vim new file mode 100644 index 0000000000..05ad276836 --- /dev/null +++ b/src/nvim/testdir/test_ex_equal.vim @@ -0,0 +1,32 @@ +" Test Ex := command. + +func Test_ex_equal() + new + call setline(1, ["foo\tbar", "bar\tfoo"]) + + let a = execute('=') + call assert_equal("\n2", a) + + let a = execute('=#') + call assert_equal("\n2\n 1 foo bar", a) + + let a = execute('=l') + call assert_equal("\n2\nfoo^Ibar$", a) + + let a = execute('=p') + call assert_equal("\n2\nfoo bar", a) + + let a = execute('=l#') + call assert_equal("\n2\n 1 foo^Ibar$", a) + + let a = execute('=p#') + call assert_equal("\n2\n 1 foo bar", a) + + let a = execute('.=') + call assert_equal("\n1", a) + + call assert_fails('3=', 'E16:') + call assert_fails('=x', 'E488:') + + bwipe! +endfunc diff --git a/src/nvim/testdir/test_glob2regpat.vim b/src/nvim/testdir/test_glob2regpat.vim index fdf17946b6..e6e41f13e7 100644 --- a/src/nvim/testdir/test_glob2regpat.vim +++ b/src/nvim/testdir/test_glob2regpat.vim @@ -1,12 +1,12 @@ " Test glob2regpat() -func Test_invalid() +func Test_glob2regpat_invalid() call assert_fails('call glob2regpat(1.33)', 'E806:') call assert_fails('call glob2regpat("}")', 'E219:') call assert_fails('call glob2regpat("{")', 'E220:') endfunc -func Test_valid() +func Test_glob2regpat_valid() call assert_equal('^foo\.', glob2regpat('foo.*')) call assert_equal('^foo.$', glob2regpat('foo?')) call assert_equal('\.vim$', glob2regpat('*.vim')) diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim index 75fe1d993c..091a833774 100644 --- a/src/nvim/testdir/test_modeline.vim +++ b/src/nvim/testdir/test_modeline.vim @@ -1,11 +1,15 @@ +" Tests for parsing the modeline. + func Test_modeline_invalid() - let modeline = &modeline - set modeline - call assert_fails('set Xmodeline', 'E518:') + " This was reading allocated memory in the past. + call writefile(['vi:0', 'nothing'], 'Xmodeline') + let modeline = &modeline + set modeline + call assert_fails('set Xmodeline', 'E518:') - let &modeline = modeline - bwipe! - call delete('Xmodeline') + let &modeline = modeline + bwipe! + call delete('Xmodeline') endfunc func Test_modeline_filetype() @@ -40,6 +44,9 @@ func Test_modeline_syntax() endfunc func Test_modeline_keymap() + if !has('keymap') + return + endif call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap') let modeline = &modeline set modeline @@ -80,5 +87,8 @@ func Test_modeline_syntax_fails() endfunc func Test_modeline_keymap_fails() + if !has('keymap') + return + endif call s:modeline_fails('keymap', 'keymap=evil$CMD') endfunc diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim index 0619e9c027..de209fa9ec 100644 --- a/src/nvim/testdir/test_regexp_latin.vim +++ b/src/nvim/testdir/test_regexp_latin.vim @@ -73,3 +73,15 @@ func Test_backref() call assert_fails('call search("\\%#=2\\(e\\1\\)")', 'E65:') bwipe! endfunc + +func Test_multi_failure() + set re=1 + call assert_fails('/a**', 'E61:') + call assert_fails('/a*\+', 'E62:') + call assert_fails('/a\{a}', 'E554:') + set re=2 + call assert_fails('/a**', 'E871:') + call assert_fails('/a*\+', 'E871:') + call assert_fails('/a\{a}', 'E870:') + set re=0 +endfunc diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim index b3b506d04d..d10d831650 100644 --- a/src/nvim/testdir/test_window_id.vim +++ b/src/nvim/testdir/test_window_id.vim @@ -101,3 +101,23 @@ func Test_win_getid_curtab() call assert_equal(win_getid(1), win_getid(1, 1)) tabclose! endfunc + +func Test_winlayout() + let w1 = win_getid() + call assert_equal(['leaf', w1], winlayout()) + + split + let w2 = win_getid() + call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout()) + + split + let w3 = win_getid() + call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout()) + + 2wincmd w + vsplit + let w4 = win_getid() + call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout()) + + only! +endfunc diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c index f5bd35a48e..8adb421ee1 100644 --- a/src/nvim/ugrid.c +++ b/src/nvim/ugrid.c @@ -95,8 +95,7 @@ static void destroy_cells(UGrid *grid) for (int i = 0; i < grid->height; i++) { xfree(grid->cells[i]); } - xfree(grid->cells); - grid->cells = NULL; + XFREE_CLEAR(grid->cells); } } diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index e24ab11a3a..f6573e7488 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -92,10 +92,8 @@ void ui_comp_detach(UI *ui) { composed_uis--; if (composed_uis == 0) { - xfree(linebuf); - xfree(attrbuf); - linebuf = NULL; - attrbuf = NULL; + XFREE_CLEAR(linebuf); + XFREE_CLEAR(attrbuf); bufsize = 0; } ui->composed = false; diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 2cc3e928f7..8c90c4bf30 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -714,8 +714,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) && (!reading || os_path_exists((char_u *)undo_file_name))) { break; } - xfree(undo_file_name); - undo_file_name = NULL; + XFREE_CLEAR(undo_file_name); } xfree(munged_name); @@ -2887,8 +2886,7 @@ void u_saveline(linenr_T lnum) void u_clearline(void) { if (curbuf->b_u_line_ptr != NULL) { - xfree(curbuf->b_u_line_ptr); - curbuf->b_u_line_ptr = NULL; + XFREE_CLEAR(curbuf->b_u_line_ptr); curbuf->b_u_line_lnum = 0; } } diff --git a/src/nvim/window.c b/src/nvim/window.c index 6bc082ffb2..e6b19cf88d 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -558,8 +558,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err) } int dir; winframe_remove(wp, &dir, NULL); - xfree(wp->w_frame); - wp->w_frame = NULL; + XFREE_CLEAR(wp->w_frame); (void)win_comp_pos(); // recompute window positions win_remove(wp, NULL); win_append(lastwin_nofloating(), wp); @@ -4297,9 +4296,8 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal); } } - xfree(globaldir); - globaldir = NULL; - shorten_fnames(TRUE); + XFREE_CLEAR(globaldir); + shorten_fnames(true); } if (trigger_new_autocmds) { @@ -6660,6 +6658,41 @@ void win_findbuf(typval_T *argvars, list_T *list) } } +// Get the layout of the given tab page for winlayout(). +void get_framelayout(const frame_T *fr, list_T *l, bool outer) +{ + list_T *fr_list; + + if (fr == NULL) { + return; + } + + if (outer) { + // outermost call from f_winlayout() + fr_list = l; + } else { + fr_list = tv_list_alloc(2); + tv_list_append_list(l, fr_list); + } + + if (fr->fr_layout == FR_LEAF) { + if (fr->fr_win != NULL) { + tv_list_append_string(fr_list, "leaf", -1); + tv_list_append_number(fr_list, fr->fr_win->handle); + } + } else { + tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1); + + list_T *const win_list = tv_list_alloc(kListLenUnknown); + tv_list_append_list(fr_list, win_list); + const frame_T *child = fr->fr_child; + while (child != NULL) { + get_framelayout(child, win_list, false); + child = child->fr_next; + } + } +} + void win_ui_flush_positions(void) { FOR_ALL_TAB_WINDOWS(tp, wp) { diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 7d9a8269d9..07218f11dd 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -10,7 +10,7 @@ local ok = helpers.ok local meths = helpers.meths local spawn, merge_args = helpers.spawn, helpers.merge_args local set_session = helpers.set_session -local expect_err = helpers.expect_err +local meth_pcall = helpers.meth_pcall describe('server -> client', function() local cid @@ -221,8 +221,8 @@ describe('server -> client', function() end) it('returns an error if the request failed', function() - expect_err('Vim:Invalid method: does%-not%-exist', - eval, "rpcrequest(vim, 'does-not-exist')") + eq({false, "Vim:Error invoking 'does-not-exist' on channel 3:\nInvalid method: does-not-exist" }, + meth_pcall(eval, "rpcrequest(vim, 'does-not-exist')")) end) end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index a7d8dc59ec..69bd584ab4 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -892,7 +892,7 @@ describe('API', function() eq({info=info}, meths.get_var("opened_event")) eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans()) eq(info, meths.get_chan_info(3)) - eval('rpcrequest(3, "nvim_set_client_info", "cat", {}, "remote",'.. + eval('rpcrequest(3, "nvim_set_client_info", "amazing-cat", {}, "remote",'.. '{"nvim_command":{"n_args":1}},'.. -- and so on '{"description":"The Amazing Cat"})') info = { @@ -900,7 +900,7 @@ describe('API', function() id=3, mode='rpc', client = { - name='cat', + name='amazing-cat', version={major=0}, type='remote', methods={nvim_command={n_args=1}}, @@ -909,6 +909,9 @@ describe('API', function() } eq({info=info}, meths.get_var("info_event")) eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans()) + + eq({false, "Vim:Error invoking 'nvim_set_current_buf' on channel 3 (amazing-cat):\nWrong type for argument 1, expecting Buffer"}, + meth_pcall(eval, 'rpcrequest(3, "nvim_set_current_buf", -1)')) end) it('works for :terminal channel', function() diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 337c5442ef..20538d7141 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -148,10 +148,10 @@ describe('autocmd', function() funcs.execute('autocmd Tabnew')) end) - it('window works', function() - -- Nvim uses a special window to execute certain actions for an invisible buffer, - -- internally called autcmd_win and mentioned in the docs at :help E813 - -- Do some safety checks for redrawing and api accesses to this window. + it('internal `aucmd_win` window', function() + -- Nvim uses a special internal window `aucmd_win` to execute certain + -- actions for an invisible buffer (:help E813). + -- Check redrawing and API accesses to this window. local screen = Screen.new(50, 10) screen:attach() @@ -219,7 +219,7 @@ describe('autocmd', function() eq(7, eval('g:test')) -- API calls are blocked when aucmd_win is not in scope - eq({false, 'Vim(call):Invalid window id'}, + eq({false, 'Vim(call):E5555: API call: Invalid window id'}, meth_pcall(command, "call nvim_set_current_win(g:winid)")) -- second time aucmd_win is needed, a different code path is invoked @@ -257,7 +257,7 @@ describe('autocmd', function() eq(0, eval('g:had_value')) eq(7, eval('g:test')) - eq({false, 'Vim(call):Invalid window id'}, + eq({false, 'Vim(call):E5555: API call: Invalid window id'}, meth_pcall(command, "call nvim_set_current_win(g:winid)")) end) end) diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua index 40d06b599f..0e3a88802d 100644 --- a/test/functional/eval/api_functions_spec.lua +++ b/test/functional/eval/api_functions_spec.lua @@ -34,16 +34,16 @@ describe('eval-API', function() eq('Vim(call):E119: Not enough arguments for function: nvim_set_option', err) err = exc_exec('call nvim_buf_set_lines(1, 0, -1, [], ["list"])') - eq('Vim(call):Wrong type for argument 4, expecting Boolean', err) + eq('Vim(call):E5555: API call: Wrong type for argument 4, expecting Boolean', err) err = exc_exec('call nvim_buf_set_lines(0, 0, -1, v:true, "string")') - eq('Vim(call):Wrong type for argument 5, expecting ArrayOf(String)', err) + eq('Vim(call):E5555: API call: Wrong type for argument 5, expecting ArrayOf(String)', err) err = exc_exec('call nvim_buf_get_number("0")') - eq('Vim(call):Wrong type for argument 1, expecting Buffer', err) + eq('Vim(call):E5555: API call: Wrong type for argument 1, expecting Buffer', err) err = exc_exec('call nvim_buf_line_count(17)') - eq('Vim(call):Invalid buffer id', err) + eq('Vim(call):E5555: API call: Invalid buffer id', err) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 35084f6cff..e2639f41e7 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -73,7 +73,7 @@ if prepend_argv then nvim_argv = new_nvim_argv end -local session, loop_running, last_error +local session, loop_running, last_error, method_error local function get_session() return session @@ -190,12 +190,21 @@ local function call_and_stop_on_error(lsession, ...) return result end +local function set_method_error(err) + method_error = err +end + local function run_session(lsession, request_cb, notification_cb, setup_cb, timeout) local on_request, on_notification, on_setup if request_cb then function on_request(method, args) - return call_and_stop_on_error(lsession, request_cb, method, args) + method_error = nil + local result = call_and_stop_on_error(lsession, request_cb, method, args) + if method_error ~= nil then + return method_error, true + end + return result end end @@ -806,6 +815,7 @@ local module = { run = run, run_session = run_session, set_session = set_session, + set_method_error = set_method_error, set_shell_powershell = set_shell_powershell, skip_fragile = skip_fragile, source = source, diff --git a/test/functional/legacy/expand_spec.lua b/test/functional/legacy/expand_spec.lua index 7bf6fb67dc..1b735080f4 100644 --- a/test/functional/legacy/expand_spec.lua +++ b/test/functional/legacy/expand_spec.lua @@ -62,6 +62,14 @@ describe('expand file name', function() call delete('Xdir ~ dir', 'd') call assert_false(isdirectory('Xdir ~ dir')) endfunc + + func Test_expand_tilde_filename() + split ~ + call assert_equal('~', expand('%')) + call assert_notequal(expand('%:p'), expand('~/')) + call assert_match('\~', expand('%:p')) + bwipe! + endfunc ]]) end) @@ -74,4 +82,9 @@ describe('expand file name', function() call('Test_with_tilde') expected_empty() end) + + it('does not expand tilde if it is a filename', function() + call('Test_expand_tilde_filename') + expected_empty() + end) end) diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua index 3a33109079..68d4d1e2a1 100644 --- a/test/functional/provider/python3_spec.lua +++ b/test/functional/provider/python3_spec.lua @@ -40,8 +40,8 @@ describe('python3 provider', function() -- mostly bogus. local very_long_symbol = string.rep('a', 1200) feed_command(':silent! py3 print('..very_long_symbol..' b)') - -- Truncated error message would not contain this (last) line. - eq('SyntaxError: invalid syntax', eval('v:errmsg')) + -- Error message will contain this (last) line. + eq('Error invoking \'python_execute\' on channel 3 (python3-script-host):\n File "<string>", line 1\n print('..very_long_symbol..' b)\n '..string.rep(' ',1200)..' ^\nSyntaxError: invalid syntax', eval('v:errmsg')) end) it('python3_execute with nested commands', function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index d49d2f0316..976dbe5893 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -4,6 +4,7 @@ local clear, feed = helpers.clear, helpers.feed local eval = helpers.eval local eq = helpers.eq local command = helpers.command +local set_method_error = helpers.set_method_error describe('ui/ext_messages', function() @@ -631,7 +632,7 @@ describe('ui/ext_messages', function() eq(0, eval('&cmdheight')) end) - it('supports multiline messages', function() + it('supports multiline messages from lua', function() feed(':lua error("such\\nmultiline\\nerror")<cr>') screen:expect{grid=[[ ^ | @@ -641,9 +642,61 @@ describe('ui/ext_messages', function() {1:~ }| ]], messages={{ content = {{'E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: such\nmultiline\nerror', 2}}, - kind = "emsg" + kind = "lua_error" }}} end) + + it('supports multiline messages from rpc', function() + feed(':call rpcrequest(1, "test_method")<cr>') + + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], messages={{ + content = {{"Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 2}}, + kind = "rpc_error" + }}, request_cb=function (name) + if name == "test_method" then + set_method_error("complete\nerror\n\nmessage") + end + end} + end) +end) + +describe('ui/builtin messages', function() + local screen + before_each(function() + clear() + screen = Screen.new(60, 7) + screen:attach({rgb=true, ext_popupmenu=true}) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [3] = {bold = true, reverse = true}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + end) + + it('supports multiline messages from rpc', function() + feed(':call rpcrequest(1, "test_method")<cr>') + + screen:expect{grid=[[ + {3: }| + {2:Error invoking 'test_method' on channel 1:} | + {2:complete} | + {2:error} | + | + {2:message} | + {4:Press ENTER or type command to continue}^ | + ]], request_cb=function (name) + if name == "test_method" then + set_method_error("complete\nerror\n\nmessage") + end + end} + end) end) describe('ui/ext_messages', function() diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index a81851cbba..044e4cc39c 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -322,7 +322,7 @@ function Screen:expect(expected, attr_ids, attr_ignore) assert(not (attr_ids ~= nil or attr_ignore ~= nil)) local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true, any=true, mode=true, unchanged=true, intermediate=true, - reset=true, timeout=true} + reset=true, timeout=true, request_cb=true} for _, v in ipairs(ext_keys) do is_key[v] = true end @@ -497,7 +497,7 @@ function Screen:_wait(check, flags) return true end - run_session(self._session, nil, notification_cb, nil, minimal_timeout) + run_session(self._session, flags.request_cb, notification_cb, nil, minimal_timeout) if not did_flush then err = "no flush received" elseif not checked then @@ -510,7 +510,7 @@ function Screen:_wait(check, flags) if not success_seen then did_miminal_timeout = true - run_session(self._session, nil, notification_cb, nil, timeout-minimal_timeout) + run_session(self._session, flags.request_cb, notification_cb, nil, timeout-minimal_timeout) end local did_warn = false @@ -565,12 +565,12 @@ asynchronous (feed(), nvim_input()) and synchronous API calls. end end -function Screen:sleep(ms) +function Screen:sleep(ms, request_cb) local function notification_cb(method, args) assert(method == 'redraw') self:_redraw(args) end - run_session(self._session, nil, notification_cb, nil, ms) + run_session(self._session, request_cb, notification_cb, nil, ms) end function Screen:_redraw(updates) @@ -1145,8 +1145,8 @@ end -- Use snapshot_util({},true) to generate a text-only (no attributes) test. -- -- @see Screen:redraw_debug() -function Screen:snapshot_util(attrs, ignore) - self:sleep(250) +function Screen:snapshot_util(attrs, ignore, request_cb) + self:sleep(250, request_cb) self:print_snapshot(attrs, ignore) end diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 3fbd47bda2..de4db35bfd 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -202,7 +202,7 @@ if(USE_BUNDLED_BUSTED) # DEPENDS on the previous module, because Luarocks breaks if parallel. add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client COMMAND ${LUAROCKS_BINARY} - ARGS build nvim-client 0.1.0-1 ${LUAROCKS_BUILDARGS} + ARGS build nvim-client 0.2.0-1 ${LUAROCKS_BUILDARGS} DEPENDS luv) add_custom_target(nvim-client DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client) |