aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUE_TEMPLATE.md2
-rw-r--r--runtime/doc/api.txt30
-rw-r--r--runtime/doc/eval.txt32
-rw-r--r--runtime/doc/ui.txt2
-rwxr-xr-xsrc/clint.py65
-rw-r--r--src/nvim/api/buffer.c10
-rw-r--r--src/nvim/api/window.c4
-rw-r--r--src/nvim/buffer.c18
-rw-r--r--src/nvim/diff.c3
-rw-r--r--src/nvim/edit.c53
-rw-r--r--src/nvim/eval.c79
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/ex_cmds.c23
-rw-r--r--src/nvim/ex_cmds2.c15
-rw-r--r--src/nvim/ex_docmd.c52
-rw-r--r--src/nvim/ex_getln.c21
-rw-r--r--src/nvim/fileio.c65
-rw-r--r--src/nvim/globals.h5
-rw-r--r--src/nvim/hardcopy.c3
-rw-r--r--src/nvim/if_cscope.c14
-rw-r--r--src/nvim/lib/kbtree.h14
-rw-r--r--src/nvim/lib/khash.h2
-rw-r--r--src/nvim/lib/klist.h6
-rw-r--r--src/nvim/lib/kvec.h12
-rw-r--r--src/nvim/lib/ringbuf.h4
-rw-r--r--src/nvim/lua/executor.c1
-rw-r--r--src/nvim/mark.c6
-rw-r--r--src/nvim/mbyte.c8
-rw-r--r--src/nvim/memfile.c6
-rw-r--r--src/nvim/memline.c14
-rw-r--r--src/nvim/memory.c2
-rw-r--r--src/nvim/memory.h11
-rw-r--r--src/nvim/menu.c3
-rw-r--r--src/nvim/message.c14
-rw-r--r--src/nvim/misc1.c3
-rw-r--r--src/nvim/msgpack_rpc/channel.c16
-rw-r--r--src/nvim/normal.c3
-rw-r--r--src/nvim/ops.c8
-rw-r--r--src/nvim/option.c23
-rw-r--r--src/nvim/os/env.c4
-rw-r--r--src/nvim/os_unix.c3
-rw-r--r--src/nvim/path.c3
-rw-r--r--src/nvim/quickfix.c12
-rw-r--r--src/nvim/regexp.c6
-rw-r--r--src/nvim/regexp_nfa.c3
-rw-r--r--src/nvim/screen.c3
-rw-r--r--src/nvim/search.c5
-rw-r--r--src/nvim/shada.c3
-rw-r--r--src/nvim/spell.c67
-rw-r--r--src/nvim/spellfile.c3
-rw-r--r--src/nvim/syntax.c29
-rw-r--r--src/nvim/tag.c6
-rw-r--r--src/nvim/testdir/test_alot.vim7
-rw-r--r--src/nvim/testdir/test_cscope.vim23
-rw-r--r--src/nvim/testdir/test_ex_equal.vim32
-rw-r--r--src/nvim/testdir/test_glob2regpat.vim4
-rw-r--r--src/nvim/testdir/test_modeline.vim22
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim12
-rw-r--r--src/nvim/testdir/test_window_id.vim20
-rw-r--r--src/nvim/ugrid.c3
-rw-r--r--src/nvim/ui_compositor.c6
-rw-r--r--src/nvim/undo.c6
-rw-r--r--src/nvim/window.c43
-rw-r--r--test/functional/api/server_requests_spec.lua6
-rw-r--r--test/functional/api/vim_spec.lua7
-rw-r--r--test/functional/autocmd/autocmd_spec.lua12
-rw-r--r--test/functional/eval/api_functions_spec.lua8
-rw-r--r--test/functional/helpers.lua14
-rw-r--r--test/functional/legacy/expand_spec.lua13
-rw-r--r--test/functional/provider/python3_spec.lua4
-rw-r--r--test/functional/ui/messages_spec.lua57
-rw-r--r--test/functional/ui/screen.lua14
-rw-r--r--third-party/cmake/BuildLuarocks.cmake2
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(&regstack);
@@ -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)