aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/vim.c2
-rw-r--r--src/nvim/api/window.c29
-rw-r--r--src/nvim/buffer.c16
-rw-r--r--src/nvim/buffer_defs.h6
-rw-r--r--src/nvim/change.c40
-rw-r--r--src/nvim/charset.c11
-rw-r--r--src/nvim/edit.c93
-rw-r--r--src/nvim/eval.c67
-rw-r--r--src/nvim/eval.lua3
-rw-r--r--src/nvim/eval/funcs.c49
-rw-r--r--src/nvim/eval/typval.c32
-rw-r--r--src/nvim/eval/typval.h1
-rw-r--r--src/nvim/event/multiqueue.c6
-rw-r--r--src/nvim/ex_cmds.c79
-rw-r--r--src/nvim/ex_cmds2.c5
-rw-r--r--src/nvim/ex_docmd.c2
-rw-r--r--src/nvim/ex_getln.c11
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c502
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/hardcopy.c7
-rw-r--r--src/nvim/indent.c102
-rw-r--r--src/nvim/indent_c.c628
-rw-r--r--src/nvim/lib/queue.h16
-rw-r--r--src/nvim/lua/executor.c11
-rw-r--r--src/nvim/lua/treesitter.c7
-rw-r--r--src/nvim/message.c35
-rw-r--r--src/nvim/mouse.c2
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/ops.c70
-rw-r--r--src/nvim/option.c515
-rw-r--r--src/nvim/option_defs.h6
-rw-r--r--src/nvim/options.lua17
-rw-r--r--src/nvim/os/pty_process_win.c18
-rw-r--r--src/nvim/os/shell.c8
-rw-r--r--src/nvim/os/time.c16
-rw-r--r--src/nvim/popupmnu.c14
-rw-r--r--src/nvim/quickfix.c9
-rw-r--r--src/nvim/regexp.c3
-rw-r--r--src/nvim/regexp_nfa.c4
-rw-r--r--src/nvim/screen.c44
-rw-r--r--src/nvim/testdir/Makefile11
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_alot_latin.vim3
-rw-r--r--src/nvim/testdir/test_assert.vim31
-rw-r--r--src/nvim/testdir/test_autochdir.vim8
-rw-r--r--src/nvim/testdir/test_autocmd.vim14
-rw-r--r--src/nvim/testdir/test_breakindent.vim609
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim2
-rw-r--r--src/nvim/testdir/test_functions.vim34
-rw-r--r--src/nvim/testdir/test_gn.vim4
-rw-r--r--src/nvim/testdir/test_listchars.vim29
-rw-r--r--src/nvim/testdir/test_listlbr.vim6
-rw-r--r--src/nvim/testdir/test_mapping.vim24
-rw-r--r--src/nvim/testdir/test_messages.vim3
-rw-r--r--src/nvim/testdir/test_options.vim30
-rw-r--r--src/nvim/testdir/test_popup.vim2
-rw-r--r--src/nvim/testdir/test_quickfix.vim2
-rw-r--r--src/nvim/testdir/test_quotestar.vim2
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim16
-rw-r--r--src/nvim/testdir/test_registers.vim2
-rw-r--r--src/nvim/testdir/test_rename.vim119
-rw-r--r--src/nvim/testdir/test_search.vim73
-rw-r--r--src/nvim/testdir/test_signs.vim7
-rw-r--r--src/nvim/testdir/test_startup.vim88
-rw-r--r--src/nvim/testdir/test_statusline.vim21
-rw-r--r--src/nvim/testdir/test_substitute.vim9
-rw-r--r--src/nvim/testdir/test_syntax.vim4
-rw-r--r--src/nvim/testdir/test_system.vim4
-rw-r--r--src/nvim/testdir/test_tab.vim45
-rw-r--r--src/nvim/testdir/test_tabpage.vim3
-rw-r--r--src/nvim/testdir/test_timers.vim4
-rw-r--r--src/nvim/testdir/test_undo.vim6
-rw-r--r--src/nvim/testdir/test_vartabs.vim381
-rw-r--r--src/nvim/testdir/test_visual.vim2
-rw-r--r--src/nvim/window.c4
76 files changed, 3072 insertions, 1026 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 9dde62f0ee..787b6addc9 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -2960,7 +2960,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
size_t j;
- for (j = 0; cbs[j].name; j++) {
+ for (j = 0; cbs[j].name && cbs[j].dest; j++) {
if (strequal(cbs[j].name, k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation,
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index f4af1632ec..89fa2f86fb 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -492,6 +492,35 @@ Dictionary nvim_win_get_config(Window window, Error *err)
return rv;
}
+/// Closes the window and hide the buffer it contains (like |:hide| with a
+/// |window-ID|).
+///
+/// Like |:hide| the buffer becomes hidden unless another window is editing it,
+/// or 'bufhidden' is `unload`, `delete` or `wipe` as opposed to |:close| or
+/// |nvim_win_close|, which will close the buffer.
+///
+/// @param window Window handle, or 0 for current window
+/// @param[out] err Error details, if any
+void nvim_win_hide(Window window, Error *err)
+ FUNC_API_SINCE(7)
+ FUNC_API_CHECK_TEXTLOCK
+{
+ win_T *win = find_window_by_handle(window, err);
+ if (!win) {
+ return;
+ }
+
+ tabpage_T *tabpage = win_find_tabpage(win);
+ TryState tstate;
+ try_enter(&tstate);
+ if (tabpage == curtab) {
+ win_close(win, false);
+ } else {
+ win_close_othertab(win, false, tabpage);
+ }
+ vim_ignored = try_leave(&tstate, err);
+}
+
/// Closes the window (like |:close| with a |window-ID|).
///
/// @param window Window handle, or 0 for current window
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index c42a0e2dad..c7ec3a456c 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -282,7 +282,7 @@ int open_buffer(
// Set/reset the Changed flag first, autocmds may change the buffer.
// Apply the automatic commands, before processing the modelines.
- // So the modelines have priority over auto commands.
+ // So the modelines have priority over autocommands.
// When reading stdin, the buffer contents always needs writing, so set
// the changed flag. Unless in readonly mode: "ls | nvim -R -".
@@ -1946,6 +1946,13 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_fo);
clear_string_option(&buf->b_p_flp);
clear_string_option(&buf->b_p_isk);
+ clear_string_option(&buf->b_p_vsts);
+ xfree(buf->b_p_vsts_nopaste);
+ buf->b_p_vsts_nopaste = NULL;
+ xfree(buf->b_p_vsts_array);
+ buf->b_p_vsts_array = NULL;
+ clear_string_option(&buf->b_p_vts);
+ XFREE_CLEAR(buf->b_p_vts_array);
clear_string_option(&buf->b_p_keymap);
keymap_ga_clear(&buf->b_kmap_ga);
ga_clear(&buf->b_kmap_ga);
@@ -5375,8 +5382,8 @@ bool bt_terminal(const buf_T *const buf)
return buf != NULL && buf->b_p_bt[0] == 't';
}
-// Return true if "buf" is a "nofile", "acwrite" or "terminal" buffer.
-// This means the buffer name is not a file name.
+// Return true if "buf" is a "nofile", "acwrite", "terminal" or "prompt"
+// buffer. This means the buffer name is not a file name.
bool bt_nofile(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -5386,7 +5393,8 @@ bool bt_nofile(const buf_T *const buf)
|| buf->b_p_bt[0] == 'p');
}
-// Return true if "buf" is a "nowrite", "nofile" or "terminal" buffer.
+// Return true if "buf" is a "nowrite", "nofile", "terminal" or "prompt"
+// buffer.
bool bt_dontwrite(const buf_T *const buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index e8038e7281..b36b7beab8 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -743,6 +743,11 @@ struct file_buffer {
long b_p_wm; ///< 'wrapmargin'
long b_p_wm_nobin; ///< b_p_wm saved for binary mode
long b_p_wm_nopaste; ///< b_p_wm saved for paste mode
+ char_u *b_p_vsts; ///< 'varsofttabstop'
+ long *b_p_vsts_array; ///< 'varsofttabstop' in internal format
+ char_u *b_p_vsts_nopaste; ///< b_p_vsts saved for paste mode
+ char_u *b_p_vts; ///< 'vartabstop'
+ long *b_p_vts_array; ///< 'vartabstop' in internal format
char_u *b_p_keymap; ///< 'keymap'
// local values for options which are normally global
@@ -1196,6 +1201,7 @@ struct window_S {
int tab1; ///< first tab character
int tab2; ///< second tab character
int tab3; ///< third tab character
+ int lead;
int trail;
int conceal;
} w_p_lcs_chars;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 0f5081c94c..38bd591eca 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -828,6 +828,7 @@ int copy_indent(int size, char_u *src)
int tab_pad;
int ind_done;
int round;
+ int ind_col;
// Round 1: compute the number of characters needed for the indent
// Round 2: copy the characters.
@@ -835,13 +836,15 @@ int copy_indent(int size, char_u *src)
todo = size;
ind_len = 0;
ind_done = 0;
+ ind_col = 0;
s = src;
// Count/copy the usable portion of the source line.
while (todo > 0 && ascii_iswhite(*s)) {
if (*s == TAB) {
- tab_pad = (int)curbuf->b_p_ts
- - (ind_done % (int)curbuf->b_p_ts);
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
@@ -849,9 +852,11 @@ int copy_indent(int size, char_u *src)
}
todo -= tab_pad;
ind_done += tab_pad;
+ ind_col += tab_pad;
} else {
todo--;
ind_done++;
+ ind_col++;
}
ind_len++;
@@ -862,11 +867,12 @@ int copy_indent(int size, char_u *src)
}
// Fill to next tabstop with a tab, if possible.
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+ tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts, curbuf->b_p_vts_array);
if ((todo >= tab_pad) && !curbuf->b_p_et) {
todo -= tab_pad;
ind_len++;
+ ind_col += tab_pad;
if (p != NULL) {
*p++ = TAB;
@@ -874,12 +880,20 @@ int copy_indent(int size, char_u *src)
}
// Add tabs required for indent.
- while (todo >= (int)curbuf->b_p_ts && !curbuf->b_p_et) {
- todo -= (int)curbuf->b_p_ts;
- ind_len++;
-
- if (p != NULL) {
- *p++ = TAB;
+ if (!curbuf->b_p_et) {
+ for (;;) {
+ tab_pad = tabstop_padding(ind_col,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ if (todo < tab_pad) {
+ break;
+ }
+ todo -= tab_pad;
+ ind_len++;
+ ind_col += tab_pad;
+ if (p != NULL) {
+ *p++ = TAB;
+ }
}
}
@@ -1029,7 +1043,9 @@ int open_line(
|| do_si
) {
// count white space on current line
- newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, false);
+ newindent = get_indent_str_vtab(saved_line,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array, false);
if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) {
newindent = second_line_indent; // for ^^D command in insert mode
}
@@ -1453,7 +1469,9 @@ int open_line(
if (curbuf->b_p_ai
|| do_si
) {
- newindent = get_indent_str(leader, (int)curbuf->b_p_ts, false);
+ newindent = get_indent_str_vtab(leader,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array, false);
}
// Add the indent offset
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 5ad1fe0dfd..e2d844a351 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -744,8 +744,7 @@ int vim_strnsize(char_u *s, int len)
/// @return Number of characters.
#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
if (*(p) == TAB && (!(wp)->w_p_list || wp->w_p_lcs_chars.tab1)) { \
- const int ts = (int)(buf)->b_p_ts; \
- return (ts - (int)(col % ts)); \
+ return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \
} else { \
return ptr2cells(p); \
}
@@ -1143,8 +1142,9 @@ static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
int n;
if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
- n = (int)wp->w_buffer->b_p_ts;
- return n - (col % n);
+ return tabstop_padding(col,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array);
}
n = ptr2cells(s);
@@ -1211,6 +1211,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
char_u *line; // start of the line
int incr;
int head;
+ long *vts = wp->w_buffer->b_p_vts_array;
int ts = (int)wp->w_buffer->b_p_ts;
int c;
@@ -1251,7 +1252,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
// A tab gets expanded, depending on the current column
if (c == TAB) {
- incr = ts - (vcol % ts);
+ incr = tabstop_padding(vcol, ts, vts);
} else {
// For utf-8, if the byte is >= 0x80, need to look at
// further bytes to find the cell width.
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index b5d5d67e90..49bd170bcd 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -597,7 +597,10 @@ static int insert_check(VimState *state)
s->mincol = curwin->w_wcol;
validate_cursor_col();
- if (curwin->w_wcol < s->mincol - curbuf->b_p_ts
+ if (
+ curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(),
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array)
&& curwin->w_wrow == curwin->w_winrow
+ curwin->w_height_inner - 1 - get_scrolloff_value(curwin)
&& (curwin->w_cursor.lnum != curwin->w_topline
@@ -7266,7 +7269,6 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
char_u *p;
char_u *line;
int icase;
- int i;
if (keytyped == NUL) {
// Can happen with CTRL-Y and CTRL-E on a short line.
@@ -7351,8 +7353,9 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
&& p[curwin->w_cursor.col - 1] == ':'
&& p[curwin->w_cursor.col - 2] == ':') {
p[curwin->w_cursor.col - 1] = ' ';
- i = (cin_iscase(p, FALSE) || cin_isscopedecl(p)
- || cin_islabel());
+ const bool i = cin_iscase(p, false)
+ || cin_isscopedecl(p)
+ || cin_islabel();
p = get_cursor_line_ptr();
p[curwin->w_cursor.col - 1] = ':';
if (i) {
@@ -8178,24 +8181,20 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
/*
* Handle deleting one 'shiftwidth' or 'softtabstop'.
*/
- if ( mode == BACKSPACE_CHAR
- && ((p_sta && in_indent)
- || (get_sts_value() != 0
- && curwin->w_cursor.col > 0
- && (*(get_cursor_pos_ptr() - 1) == TAB
- || (*(get_cursor_pos_ptr() - 1) == ' '
- && (!*inserted_space_p
- || arrow_used)))))) {
+ if (mode == BACKSPACE_CHAR
+ && ((p_sta && in_indent)
+ || ((get_sts_value() != 0
+ || tabstop_count(curbuf->b_p_vsts_array))
+ && curwin->w_cursor.col > 0
+ && (*(get_cursor_pos_ptr() - 1) == TAB
+ || (*(get_cursor_pos_ptr() - 1) == ' '
+ && (!*inserted_space_p || arrow_used)))))) {
int ts;
colnr_T vcol;
colnr_T want_vcol;
colnr_T start_vcol;
- *inserted_space_p = FALSE;
- if (p_sta && in_indent)
- ts = get_sw_value(curbuf);
- else
- ts = get_sts_value();
+ *inserted_space_p = false;
// Compute the virtual column where we want to be. Since
// 'showbreak' may get in the way, need to get the last column of
// the previous character.
@@ -8204,7 +8203,14 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
dec_cursor();
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
inc_cursor();
- want_vcol = (want_vcol / ts) * ts;
+ if (p_sta && in_indent) {
+ ts = (int)get_sw_value(curbuf);
+ want_vcol = (want_vcol / ts) * ts;
+ } else {
+ want_vcol = tabstop_start(want_vcol,
+ get_sts_value(),
+ curbuf->b_p_vsts_array);
+ }
// delete characters until we are at or before want_vcol
while (vcol > want_vcol
@@ -8669,10 +8675,19 @@ static bool ins_tab(void)
can_cindent = false;
}
- // When nothing special, insert TAB like a normal character
+ // When nothing special, insert TAB like a normal character.
if (!curbuf->b_p_et
- && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf))
- && get_sts_value() == 0) {
+ && !(
+ p_sta
+ && ind
+ // These five lines mean 'tabstop' != 'shiftwidth'
+ && ((tabstop_count(curbuf->b_p_vts_array) > 1)
+ || (tabstop_count(curbuf->b_p_vts_array) == 1
+ && tabstop_first(curbuf->b_p_vts_array)
+ != get_sw_value(curbuf))
+ || (tabstop_count(curbuf->b_p_vts_array) == 0
+ && curbuf->b_p_ts != get_sw_value(curbuf))))
+ && tabstop_count(curbuf->b_p_vsts_array) == 0 && get_sts_value() == 0) {
return true;
}
@@ -8686,16 +8701,22 @@ static bool ins_tab(void)
can_si_back = false;
AppendToRedobuff("\t");
- if (p_sta && ind) { // insert tab in indent, use "shiftwidth"
- temp = get_sw_value(curbuf);
- } else if (curbuf->b_p_sts != 0) { // use "softtabstop" when set
- temp = get_sts_value();
- } else { // otherwise use "tabstop"
- temp = (int)curbuf->b_p_ts;
+ if (p_sta && ind) { // insert tab in indent, use 'shiftwidth'
+ temp = (int)get_sw_value(curbuf);
+ temp -= get_nolist_virtcol() % temp;
+ } else if (tabstop_count(curbuf->b_p_vsts_array) > 0
+ || curbuf->b_p_sts != 0) {
+ // use 'softtabstop' when set
+ temp = tabstop_padding(get_nolist_virtcol(),
+ get_sts_value(),
+ curbuf->b_p_vsts_array);
+ } else {
+ // otherwise use 'tabstop'
+ temp = tabstop_padding(get_nolist_virtcol(),
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
}
- temp -= get_nolist_virtcol() % temp;
-
/*
* Insert the first space with ins_char(). It will delete one char in
* replace mode. Insert the rest with ins_str(); it will not delete any
@@ -8716,7 +8737,9 @@ static bool ins_tab(void)
/*
* When 'expandtab' not set: Replace spaces by TABs where possible.
*/
- if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) {
+ if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0
+ || get_sts_value() > 0
+ || (p_sta && ind))) {
char_u *ptr;
char_u *saved_line = NULL; // init for GCC
pos_T pos;
@@ -9133,10 +9156,16 @@ static void ins_try_si(int c)
* Get the value that w_virtcol would have when 'list' is off.
* Unless 'cpo' contains the 'L' flag.
*/
-static colnr_T get_nolist_virtcol(void)
+colnr_T get_nolist_virtcol(void)
{
- if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
+ // check validity of cursor in current buffer
+ if (curwin->w_buffer == NULL || curwin->w_buffer->b_ml.ml_mfp == NULL
+ || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) {
+ return 0;
+ }
+ if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) {
return getvcol_nolist(&curwin->w_cursor);
+ }
validate_virtcol();
return curwin->w_virtcol;
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index e1fcbdce25..9c3941b0fd 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -5289,10 +5289,10 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
QUEUE *w = NULL;
DictWatcher *watcher = NULL;
- QUEUE_FOREACH(w, &dd->watchers) {
+ QUEUE_FOREACH(w, &dd->watchers, {
watcher = tv_dict_watcher_node_data(w);
set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack);
- }
+ })
}
break;
}
@@ -5867,26 +5867,53 @@ int assert_inrange(typval_T *argvars)
FUNC_ATTR_NONNULL_ALL
{
bool error = false;
- const varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
- const varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
- const varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
- if (error) {
- return 0;
- }
- if (actual < lower || actual > upper) {
- garray_T ga;
- prepare_assert_error(&ga);
+ if (argvars[0].v_type == VAR_FLOAT
+ || argvars[1].v_type == VAR_FLOAT
+ || argvars[2].v_type == VAR_FLOAT) {
+ const float_T flower = tv_get_float(&argvars[0]);
+ const float_T fupper = tv_get_float(&argvars[1]);
+ const float_T factual = tv_get_float(&argvars[2]);
- char msg[55];
- vim_snprintf(msg, sizeof(msg),
- "range %" PRIdVARNUMBER " - %" PRIdVARNUMBER ",",
- lower, upper);
- fill_assert_error(&ga, &argvars[3], (char_u *)msg, NULL, &argvars[2],
- ASSERT_INRANGE);
- assert_error(&ga);
- ga_clear(&ga);
- return 1;
+ if (factual < flower || factual > fupper) {
+ garray_T ga;
+ prepare_assert_error(&ga);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ char_u *const tofree = (char_u *)encode_tv2string(&argvars[3], NULL);
+ ga_concat(&ga, tofree);
+ xfree(tofree);
+ } else {
+ char msg[80];
+ vim_snprintf(msg, sizeof(msg), "Expected range %g - %g, but got %g",
+ flower, fupper, factual);
+ ga_concat(&ga, (char_u *)msg);
+ }
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
+ } else {
+ const varnumber_T lower = tv_get_number_chk(&argvars[0], &error);
+ const varnumber_T upper = tv_get_number_chk(&argvars[1], &error);
+ const varnumber_T actual = tv_get_number_chk(&argvars[2], &error);
+
+ if (error) {
+ return 0;
+ }
+ if (actual < lower || actual > upper) {
+ garray_T ga;
+ prepare_assert_error(&ga);
+
+ char msg[55];
+ vim_snprintf(msg, sizeof(msg),
+ "range %" PRIdVARNUMBER " - %" PRIdVARNUMBER ",",
+ lower, upper);
+ fill_assert_error(&ga, &argvars[3], (char_u *)msg, NULL, &argvars[2],
+ ASSERT_INRANGE);
+ assert_error(&ga);
+ ga_clear(&ga);
+ return 1;
+ }
}
return 0;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index e94d7831b0..72168060cc 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -309,7 +309,7 @@ return {
setwinvar={args=3},
sha256={args=1},
shellescape={args={1, 2}},
- shiftwidth={},
+ shiftwidth={args={0, 1}},
sign_define={args={1, 2}},
sign_getdefined={args={0, 1}},
sign_getplaced={args={0, 2}},
@@ -341,6 +341,7 @@ return {
string={args=1},
strlen={args=1},
strpart={args={2, 4}},
+ strptime={args=2},
strridx={args={2, 3}},
strtrans={args=1},
strwidth={args=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 01d23654de..deeda28571 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -4312,6 +4312,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"title",
"user-commands", // was accidentally included in 5.4
"user_commands",
+ "vartabs",
"vertsplit",
"virtualedit",
"visual",
@@ -8848,6 +8849,18 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
+ rettv->vval.v_number = 0;
+
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ long col;
+
+ col = (long)tv_get_number_chk(argvars, NULL);
+ if (col < 0) {
+ return; // type error; errmsg already given
+ }
+ rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ return;
+ }
rettv->vval.v_number = get_sw_value(curbuf);
}
@@ -8989,7 +9002,7 @@ static void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
- // Sign identifer
+ // Sign identifier
sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
if (notanum) {
return;
@@ -9037,7 +9050,7 @@ static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
- // Sign identifer
+ // Sign identifier
sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
if (notanum) {
return;
@@ -10189,6 +10202,38 @@ static void f_strpart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = (char_u *)xmemdupz(p + n, (size_t)len);
}
+// "strptime({format}, {timestring})" function
+static void f_strptime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char fmt_buf[NUMBUFLEN];
+ char str_buf[NUMBUFLEN];
+
+ struct tm tmval = {
+ .tm_isdst = -1,
+ };
+ char *fmt = (char *)tv_get_string_buf(&argvars[0], fmt_buf);
+ char *str = (char *)tv_get_string_buf(&argvars[1], str_buf);
+
+ vimconv_T conv = {
+ .vc_type = CONV_NONE,
+ };
+ char_u *enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE) {
+ fmt = (char *)string_convert(&conv, (char_u *)fmt, NULL);
+ }
+ if (fmt == NULL
+ || os_strptime(str, fmt, &tmval) == NULL
+ || (rettv->vval.v_number = mktime(&tmval)) == -1) {
+ rettv->vval.v_number = 0;
+ }
+ if (conv.vc_type != CONV_NONE) {
+ xfree(fmt);
+ }
+ convert_setup(&conv, NULL, NULL);
+ xfree(enc);
+}
+
/*
* "strridx()" function
*/
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 9be487f4fd..fe3d147040 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1109,6 +1109,7 @@ void tv_dict_watcher_add(dict_T *const dict, const char *const key_pattern,
watcher->key_pattern_len = key_pattern_len;
watcher->callback = callback;
watcher->busy = false;
+ watcher->needs_free = false;
QUEUE_INSERT_TAIL(&dict->watchers, &watcher->node);
}
@@ -1182,22 +1183,30 @@ bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern,
QUEUE *w = NULL;
DictWatcher *watcher = NULL;
bool matched = false;
- QUEUE_FOREACH(w, &dict->watchers) {
+ bool queue_is_busy = false;
+ QUEUE_FOREACH(w, &dict->watchers, {
watcher = tv_dict_watcher_node_data(w);
+ if (watcher->busy) {
+ queue_is_busy = true;
+ }
if (tv_callback_equal(&watcher->callback, &callback)
&& watcher->key_pattern_len == key_pattern_len
&& memcmp(watcher->key_pattern, key_pattern, key_pattern_len) == 0) {
matched = true;
break;
}
- }
+ })
if (!matched) {
return false;
}
- QUEUE_REMOVE(w);
- tv_dict_watcher_free(watcher);
+ if (queue_is_busy) {
+ watcher->needs_free = true;
+ } else {
+ QUEUE_REMOVE(w);
+ tv_dict_watcher_free(watcher);
+ }
return true;
}
@@ -1258,9 +1267,10 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
typval_T rettv;
+ bool any_needs_free = false;
dict->dv_refcount++;
QUEUE *w;
- QUEUE_FOREACH(w, &dict->watchers) {
+ QUEUE_FOREACH(w, &dict->watchers, {
DictWatcher *watcher = tv_dict_watcher_node_data(w);
if (!watcher->busy && tv_dict_watcher_matches(watcher, key)) {
rettv = TV_INITIAL_VALUE;
@@ -1268,7 +1278,19 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
callback_call(&watcher->callback, 3, argv, &rettv);
watcher->busy = false;
tv_clear(&rettv);
+ if (watcher->needs_free) {
+ any_needs_free = true;
+ }
}
+ })
+ if (any_needs_free) {
+ QUEUE_FOREACH(w, &dict->watchers, {
+ DictWatcher *watcher = tv_dict_watcher_node_data(w);
+ if (watcher->needs_free) {
+ QUEUE_REMOVE(w);
+ tv_dict_watcher_free(watcher);
+ }
+ })
}
tv_dict_unref(dict);
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 531b17cb59..2b4612016b 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -89,6 +89,7 @@ typedef struct dict_watcher {
size_t key_pattern_len;
QUEUE node;
bool busy; // prevent recursion if the dict is changed in the callback
+ bool needs_free;
} DictWatcher;
/// Bool variable values
diff --git a/src/nvim/event/multiqueue.c b/src/nvim/event/multiqueue.c
index c9aa3acc4d..1e6d62135c 100644
--- a/src/nvim/event/multiqueue.c
+++ b/src/nvim/event/multiqueue.c
@@ -119,8 +119,8 @@ static MultiQueue *multiqueue_new(MultiQueue *parent, put_callback put_cb,
void multiqueue_free(MultiQueue *this)
{
assert(this);
- while (!QUEUE_EMPTY(&this->headtail)) {
- QUEUE *q = QUEUE_HEAD(&this->headtail);
+ QUEUE *q;
+ QUEUE_FOREACH(q, &this->headtail, {
MultiQueueItem *item = multiqueue_node_data(q);
if (this->parent) {
QUEUE_REMOVE(&item->data.item.parent_item->node);
@@ -128,7 +128,7 @@ void multiqueue_free(MultiQueue *this)
}
QUEUE_REMOVE(q);
xfree(item);
- }
+ })
xfree(this);
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 854faf5377..d34282419a 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -712,14 +712,15 @@ void ex_retab(exarg_T *eap)
long len;
long col;
long vcol;
- long start_col = 0; /* For start of white-space string */
- long start_vcol = 0; /* For start of white-space string */
- int temp;
+ long start_col = 0; // For start of white-space string
+ long start_vcol = 0; // For start of white-space string
long old_len;
char_u *ptr;
- char_u *new_line = (char_u *)1; /* init to non-NULL */
- int did_undo; /* called u_save for current line */
- int new_ts;
+ char_u *new_line = (char_u *)1; // init to non-NULL
+ int did_undo; // called u_save for current line
+ long *new_vts_array = NULL;
+ char_u *new_ts_str; // string value of tab argument
+
int save_list;
linenr_T first_line = 0; /* first changed line */
linenr_T last_line = 0; /* last changed line */
@@ -727,14 +728,24 @@ void ex_retab(exarg_T *eap)
save_list = curwin->w_p_list;
curwin->w_p_list = 0; /* don't want list mode here */
- new_ts = getdigits_int(&(eap->arg), false, -1);
- if (new_ts < 0) {
- EMSG(_(e_positive));
+ new_ts_str = eap->arg;
+ if (!tabstop_set(eap->arg, &new_vts_array)) {
return;
}
- if (new_ts == 0)
- new_ts = curbuf->b_p_ts;
- for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum) {
+ while (ascii_isdigit(*(eap->arg)) || *(eap->arg) == ',') {
+ (eap->arg)++;
+ }
+
+ // This ensures that either new_vts_array and new_ts_str are freshly
+ // allocated, or new_vts_array points to an existing array and new_ts_str
+ // is null.
+ if (new_vts_array == NULL) {
+ new_vts_array = curbuf->b_p_vts_array;
+ new_ts_str = NULL;
+ } else {
+ new_ts_str = vim_strnsave(new_ts_str, eap->arg - new_ts_str);
+ }
+ for (lnum = eap->line1; !got_int && lnum <= eap->line2; lnum++) {
ptr = ml_get(lnum);
col = 0;
vcol = 0;
@@ -758,13 +769,12 @@ void ex_retab(exarg_T *eap)
len = num_spaces = vcol - start_vcol;
num_tabs = 0;
if (!curbuf->b_p_et) {
- temp = new_ts - (start_vcol % new_ts);
- if (num_spaces >= temp) {
- num_spaces -= temp;
- num_tabs++;
- }
- num_tabs += num_spaces / new_ts;
- num_spaces -= (num_spaces / new_ts) * new_ts;
+ int t, s;
+
+ tabstop_fromto(start_vcol, vcol,
+ curbuf->b_p_ts, new_vts_array, &t, &s);
+ num_tabs = t;
+ num_spaces = s;
}
if (curbuf->b_p_et || got_tab
|| (num_spaces + num_tabs < len)) {
@@ -817,15 +827,42 @@ void ex_retab(exarg_T *eap)
if (got_int)
EMSG(_(e_interr));
- if (curbuf->b_p_ts != new_ts)
+ // If a single value was given then it can be considered equal to
+ // either the value of 'tabstop' or the value of 'vartabstop'.
+ if (tabstop_count(curbuf->b_p_vts_array) == 0
+ && tabstop_count(new_vts_array) == 1
+ && curbuf->b_p_ts == tabstop_first(new_vts_array)) {
+ // not changed
+ } else if (tabstop_count(curbuf->b_p_vts_array) > 0
+ && tabstop_eq(curbuf->b_p_vts_array, new_vts_array)) {
+ // not changed
+ } else {
redraw_curbuf_later(NOT_VALID);
+ }
if (first_line != 0) {
changed_lines(first_line, 0, last_line + 1, 0L, true);
}
curwin->w_p_list = save_list; /* restore 'list' */
- curbuf->b_p_ts = new_ts;
+ if (new_ts_str != NULL) { // set the new tabstop
+ // If 'vartabstop' is in use or if the value given to retab has more
+ // than one tabstop then update 'vartabstop'.
+ long *old_vts_ary = curbuf->b_p_vts_array;
+
+ if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) {
+ set_string_option_direct("vts", -1, new_ts_str,
+ OPT_FREE | OPT_LOCAL, 0);
+ curbuf->b_p_vts_array = new_vts_array;
+ xfree(old_vts_ary);
+ } else {
+ // 'vartabstop' wasn't in use and a single value was given to
+ // retab then update 'tabstop'.
+ curbuf->b_p_ts = tabstop_first(new_vts_array);
+ xfree(new_vts_array);
+ }
+ xfree(new_ts_str);
+ }
coladvance(curwin->w_curswant);
u_clearline();
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index c4c18c4324..cc0ec71627 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2535,7 +2535,7 @@ void ex_source(exarg_T *eap)
static void cmd_source(char_u *fname, exarg_T *eap)
{
- if (*fname == NUL) {
+ if (eap != NULL && *fname == NUL) {
cmd_source_buffer(eap);
} else if (eap != NULL && eap->forceit) {
// ":source!": read Normal mode commands
@@ -2575,7 +2575,8 @@ static char_u *get_buffer_line(int c, void *cookie, int indent, bool do_concat)
return (char_u *)xstrdup((const char *)curr_line);
}
-static void cmd_source_buffer(exarg_T *eap)
+static void cmd_source_buffer(const exarg_T *eap)
+ FUNC_ATTR_NONNULL_ALL
{
GetBufferLineCookie cookie = {
.curr_lnum = eap->line1,
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index bc3d29a03f..3aaf171b2c 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7494,7 +7494,7 @@ static void ex_syncbind(exarg_T *eap)
ctrl_o[0] = Ctrl_O;
ctrl_o[1] = 0;
- ins_typebuf(ctrl_o, REMAP_NONE, 0, TRUE, FALSE);
+ ins_typebuf(ctrl_o, REMAP_NONE, 0, true, false);
}
}
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 9977be56ca..38385d19b2 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -775,9 +775,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
redrawcmd();
}
- // redraw the statusline for statuslines that display the current mode
- // using the mode() function.
- if (!cmd_silent && msg_scrolled == 0) {
+ // Redraw the statusline in case it uses the current mode using the mode()
+ // function.
+ if (!cmd_silent && msg_scrolled == 0 && *p_stl != NUL) {
curwin->w_redr_status = true;
redraw_statuslines();
}
@@ -4093,9 +4093,10 @@ ExpandOne (
}
if (mode == WILD_CANCEL) {
- ss = vim_strsave(orig_save);
+ ss = vim_strsave(orig_save ? orig_save : (char_u *)"");
} else if (mode == WILD_APPLY) {
- ss = vim_strsave(findex == -1 ? orig_save : xp->xp_files[findex]);
+ ss = vim_strsave(findex == -1 ? (orig_save ? orig_save : (char_u *)"") :
+ xp->xp_files[findex]);
}
/* free old names */
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 714bbb5780..65bd809436 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -4280,7 +4280,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
if (fname == NULL || *fname == NUL) {
retval = xmalloc(MAXPATHL + extlen + 3); // +3 for PATHSEP, "_" (Win), NUL
if (os_dirname((char_u *)retval, MAXPATHL) == FAIL
- || (fnamelen = strlen(retval)) == 0) {
+ || strlen(retval) == 0) {
xfree(retval);
return NULL;
}
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2e2993ed26..9afce6e9d5 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -78,7 +78,7 @@ FileDescriptor *scriptin[NSCRIPT] = { NULL };
* Un-escaping is done by vgetc().
*/
-#define MINIMAL_SIZE 20 /* minimal size for b_str */
+#define MINIMAL_SIZE 20 // minimal size for b_str
static buffheader_T redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
@@ -90,7 +90,7 @@ static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 };
// Second read ahead buffer. Used for redo.
static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
-static int typeahead_char = 0; /* typeahead char that's not flushed */
+static int typeahead_char = 0; // typeahead char that's not flushed
/*
* when block_redo is TRUE redo buffer will not be changed
@@ -116,9 +116,9 @@ static bool maphash_valid = false;
/*
* List used for abbreviations.
*/
-static mapblock_T *first_abbr = NULL; /* first entry in abbrlist */
+static mapblock_T *first_abbr = NULL; // first entry in abbrlist
-static int KeyNoremap = 0; /* remapping flags */
+static int KeyNoremap = 0; // remapping flags
/*
* Variables used by vgetorpeek() and flush_buffers()
@@ -139,18 +139,18 @@ static int KeyNoremap = 0; /* remapping flags */
* typebuf.tb_noremap[typebuf.tb_off] is the first valid flag.
* (typebuf has been put in globals.h, because check_termcode() needs it).
*/
-#define RM_YES 0 /* tb_noremap: remap */
-#define RM_NONE 1 /* tb_noremap: don't remap */
-#define RM_SCRIPT 2 /* tb_noremap: remap local script mappings */
-#define RM_ABBR 4 /* tb_noremap: don't remap, do abbrev. */
+#define RM_YES 0 // tb_noremap: remap
+#define RM_NONE 1 // tb_noremap: don't remap
+#define RM_SCRIPT 2 // tb_noremap: remap local script mappings
+#define RM_ABBR 4 // tb_noremap: don't remap, do abbrev.
/* typebuf.tb_buf has three parts: room in front (for result of mappings), the
* middle for typeahead and room for new characters (which needs to be 3 *
* MAXMAPLEN) for the Amiga).
*/
#define TYPELEN_INIT (5 * (MAXMAPLEN + 3))
-static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
-static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
+static char_u typebuf_init[TYPELEN_INIT]; // initial typebuf.tb_buf
+static char_u noremapbuf_init[TYPELEN_INIT]; // initial typebuf.tb_noremap
static size_t last_recorded_len = 0; // number of last recorded chars
@@ -707,8 +707,9 @@ static int read_redo(bool init, bool old_redo)
break;
}
c = *p;
- if (c == NUL) /* cannot happen? */
+ if (c == NUL) { // cannot happen?
break;
+ }
}
return c;
@@ -744,14 +745,15 @@ int start_redo(long count, bool old_redo)
c = read_redo(false, old_redo);
- /* copy the buffer name, if present */
+ // copy the buffer name, if present
if (c == '"') {
add_buff(&readbuf2, "\"", 1L);
c = read_redo(false, old_redo);
- /* if a numbered buffer is used, increment the number */
- if (c >= '1' && c < '9')
- ++c;
+ // if a numbered buffer is used, increment the number
+ if (c >= '1' && c < '9') {
+ c++;
+ }
add_char_buff(&readbuf2, c);
// the expression register should be re-evaluated
@@ -763,7 +765,7 @@ int start_redo(long count, bool old_redo)
c = read_redo(false, old_redo);
}
- if (c == 'v') { /* redo Visual */
+ if (c == 'v') { // redo Visual
VIsual = curwin->w_cursor;
VIsual_active = true;
VIsual_select = false;
@@ -780,7 +782,7 @@ int start_redo(long count, bool old_redo)
add_num_buff(&readbuf2, count);
}
- /* copy from the redo buffer into the stuff buffer */
+ // copy from the redo buffer into the stuff buffer
add_char_buff(&readbuf2, c);
copy_redo(old_redo);
return OK;
@@ -838,26 +840,25 @@ static void init_typebuf(void)
}
}
-/*
- * insert a string in position 'offset' in the typeahead buffer (for "@r"
- * and ":normal" command, vgetorpeek() and check_termcode())
- *
- * If noremap is REMAP_YES, new string can be mapped again.
- * If noremap is REMAP_NONE, new string cannot be mapped again.
- * If noremap is REMAP_SKIP, fist char of new string cannot be mapped again,
- * but abbreviations are allowed.
- * If noremap is REMAP_SCRIPT, new string cannot be mapped again, except for
- * script-local mappings.
- * If noremap is > 0, that many characters of the new string cannot be mapped.
- *
- * If nottyped is TRUE, the string does not return KeyTyped (don't use when
- * offset is non-zero!).
- *
- * If silent is true, cmd_silent is set when the characters are obtained.
- *
- * return FAIL for failure, OK otherwise
- */
-int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
+// Insert a string in position 'offset' in the typeahead buffer (for "@r"
+// and ":normal" command, vgetorpeek() and check_termcode())
+//
+// If noremap is REMAP_YES, new string can be mapped again.
+// If noremap is REMAP_NONE, new string cannot be mapped again.
+// If noremap is REMAP_SKIP, fist char of new string cannot be mapped again,
+// but abbreviations are allowed.
+// If noremap is REMAP_SCRIPT, new string cannot be mapped again, except for
+// script-local mappings.
+// If noremap is > 0, that many characters of the new string cannot be mapped.
+//
+// If nottyped is true, the string does not return KeyTyped (don't use when
+// offset is non-zero!).
+//
+// If silent is true, cmd_silent is set when the characters are obtained.
+//
+// return FAIL for failure, OK otherwise
+int ins_typebuf(char_u *str, int noremap, int offset,
+ bool nottyped, bool silent)
{
char_u *s1, *s2;
int newlen;
@@ -890,8 +891,8 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
// often.
newoff = MAXMAPLEN + 4;
newlen = typebuf.tb_len + addlen + newoff + 4 * (MAXMAPLEN + 4);
- if (newlen < 0) { /* string is getting too long */
- EMSG(_(e_toocompl)); /* also calls flush_buffers */
+ if (newlen < 0) { // string is getting too long
+ EMSG(_(e_toocompl)); // also calls flush_buffers
setcursor();
return FAIL;
}
@@ -927,13 +928,14 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
}
typebuf.tb_len += addlen;
- /* If noremap == REMAP_SCRIPT: do remap script-local mappings. */
- if (noremap == REMAP_SCRIPT)
+ // If noremap == REMAP_SCRIPT: do remap script-local mappings.
+ if (noremap == REMAP_SCRIPT) {
val = RM_SCRIPT;
- else if (noremap == REMAP_SKIP)
+ } else if (noremap == REMAP_SKIP) {
val = RM_ABBR;
- else
+ } else {
val = RM_NONE;
+ }
/*
* Adjust typebuf.tb_noremap[] for the new characters:
@@ -962,8 +964,9 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
typebuf.tb_silent += addlen;
cmd_silent = true;
}
- if (typebuf.tb_no_abbr_cnt && offset == 0) /* and not used for abbrev.s */
+ if (typebuf.tb_no_abbr_cnt && offset == 0) { // and not used for abbrev.s
typebuf.tb_no_abbr_cnt += addlen;
+ }
return OK;
}
@@ -997,9 +1000,8 @@ void ins_char_typebuf(int c)
* Or "typebuf.tb_off" may have been changed and we would overwrite characters
* that was just added.
*/
-int
-typebuf_changed (
- int tb_change_cnt /* old value of typebuf.tb_change_cnt */
+bool typebuf_changed(
+ int tb_change_cnt // old value of typebuf.tb_change_cnt
)
{
return tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt
@@ -1031,8 +1033,9 @@ void del_typebuf(int len, int offset)
{
int i;
- if (len == 0)
- return; /* nothing to do */
+ if (len == 0) {
+ return; // nothing to do
+ }
typebuf.tb_len -= len;
@@ -1068,23 +1071,26 @@ void del_typebuf(int len, int offset)
(size_t)(typebuf.tb_len - offset));
}
- if (typebuf.tb_maplen > offset) { /* adjust tb_maplen */
- if (typebuf.tb_maplen < offset + len)
+ if (typebuf.tb_maplen > offset) { // adjust tb_maplen
+ if (typebuf.tb_maplen < offset + len) {
typebuf.tb_maplen = offset;
- else
+ } else {
typebuf.tb_maplen -= len;
+ }
}
- if (typebuf.tb_silent > offset) { /* adjust tb_silent */
- if (typebuf.tb_silent < offset + len)
+ if (typebuf.tb_silent > offset) { // adjust tb_silent
+ if (typebuf.tb_silent < offset + len) {
typebuf.tb_silent = offset;
- else
+ } else {
typebuf.tb_silent -= len;
+ }
}
- if (typebuf.tb_no_abbr_cnt > offset) { /* adjust tb_no_abbr_cnt */
- if (typebuf.tb_no_abbr_cnt < offset + len)
+ if (typebuf.tb_no_abbr_cnt > offset) { // adjust tb_no_abbr_cnt
+ if (typebuf.tb_no_abbr_cnt < offset + len) {
typebuf.tb_no_abbr_cnt = offset;
- else
+ } else {
typebuf.tb_no_abbr_cnt -= len;
+ }
}
/* Reset the flag that text received from a client or from feedkeys()
@@ -1135,8 +1141,8 @@ static void gotchars(const char_u *chars, size_t len)
may_sync_undo();
- /* output "debug mode" message next time in debug mode */
- debug_did_msg = FALSE;
+ // output "debug mode" message next time in debug mode
+ debug_did_msg = false;
/* Since characters have been typed, consider the following to be in
* another mapping. Search string will be kept in history. */
@@ -1253,10 +1259,9 @@ void restore_typeahead(tasave_T *tp)
/*
* Open a new script file for the ":source!" command.
*/
-void
-openscript (
+void openscript(
char_u *name,
- int directly /* when TRUE execute directly */
+ bool directly // when true execute directly
)
{
if (curscript + 1 == NSCRIPT) {
@@ -1275,9 +1280,10 @@ openscript (
return;
}
- if (scriptin[curscript] != NULL) /* already reading script */
- ++curscript;
- /* use NameBuff for expanded name */
+ if (scriptin[curscript] != NULL) { // already reading script
+ curscript++;
+ }
+ // use NameBuff for expanded name
expand_env(name, NameBuff, MAXPATHL);
int error;
if ((scriptin[curscript] = file_open_new(&error, (char *)NameBuff,
@@ -1306,11 +1312,11 @@ openscript (
int save_msg_scroll = msg_scroll;
State = NORMAL;
- msg_scroll = FALSE; /* no msg scrolling in Normal mode */
- restart_edit = 0; /* don't go to Insert mode */
- p_im = FALSE; /* don't use 'insertmode' */
+ msg_scroll = false; // no msg scrolling in Normal mode
+ restart_edit = 0; // don't go to Insert mode
+ p_im = false; // don't use 'insertmode'
clear_oparg(&oa);
- finish_op = FALSE;
+ finish_op = false;
oldcurscript = curscript;
do {
@@ -1626,10 +1632,8 @@ int char_avail(void)
return retval != NUL;
}
-void
-vungetc ( /* unget one character (can only be done once!) */
- int c
-)
+// unget one character (can only be done once!)
+void vungetc(int c)
{
old_char = c;
old_mod_mask = mod_mask;
@@ -1669,10 +1673,10 @@ static int vgetorpeek(bool advance)
mapblock_T *mp2;
mapblock_T *mp_match;
int mp_match_len = 0;
- int timedout = FALSE; /* waited for more than 1 second
- for mapping to complete */
- int mapdepth = 0; /* check for recursive mapping */
- int mode_deleted = FALSE; /* set when mode has been deleted */
+ bool timedout = false; // waited for more than 1 second
+ // for mapping to complete
+ int mapdepth = 0; // check for recursive mapping
+ bool mode_deleted = false; // set when mode has been deleted
int local_State;
int mlen;
int max_mlen;
@@ -1729,8 +1733,9 @@ static int vgetorpeek(bool advance)
// needed for CTRL-W CTRL-] to open a fold, for example.
KeyStuffed = true;
}
- if (typebuf.tb_no_abbr_cnt == 0)
- typebuf.tb_no_abbr_cnt = 1; /* no abbreviations now */
+ if (typebuf.tb_no_abbr_cnt == 0) {
+ typebuf.tb_no_abbr_cnt = 1; // no abbreviations now
+ }
} else {
/*
* Loop until we either find a matching mapped key, or we
@@ -1744,10 +1749,11 @@ static int vgetorpeek(bool advance)
* inside a mapping. But call it each time for typed
* characters.
*/
- if (typebuf.tb_maplen)
+ if (typebuf.tb_maplen) {
line_breakcheck();
- else
- os_breakcheck(); /* check for CTRL-C */
+ } else {
+ os_breakcheck(); // check for CTRL-C
+ }
keylen = 0;
if (got_int) {
// flush all input
@@ -1814,11 +1820,11 @@ static int vgetorpeek(bool advance)
&& get_real_state() != SELECTMODE);
nolmaplen = 0;
}
- /* First try buffer-local mappings. */
+ // First try buffer-local mappings.
mp = curbuf->b_maphash[MAP_HASH(local_State, c1)];
mp2 = maphash[MAP_HASH(local_State, c1)];
if (mp == NULL) {
- /* There are no buffer-local mappings. */
+ // There are no buffer-local mappings.
mp = mp2;
mp2 = NULL;
}
@@ -1845,8 +1851,8 @@ static int vgetorpeek(bool advance)
|| typebuf.tb_maplen == 0)) {
int nomap = nolmaplen;
int c2;
- /* find the match length of this mapping */
- for (mlen = 1; mlen < typebuf.tb_len; ++mlen) {
+ // find the match length of this mapping
+ for (mlen = 1; mlen < typebuf.tb_len; mlen++) {
c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
if (nomap > 0)
--nomap;
@@ -1901,7 +1907,7 @@ static int vgetorpeek(bool advance)
if (keylen > typebuf.tb_len) {
if (!timedout && !(mp_match != NULL
&& mp_match->m_nowait)) {
- /* break at a partly match */
+ // break at a partly match
keylen = KEYLEN_PART_MAP;
break;
}
@@ -1953,13 +1959,14 @@ static int vgetorpeek(bool advance)
setcursor();
continue;
}
- /* Need more chars for partly match. */
- if (mlen == typebuf.tb_len)
+ // Need more chars for partly match.
+ if (mlen == typebuf.tb_len) {
keylen = KEYLEN_PART_KEY;
- else if (max_mlen < mlen)
- /* no match, may have to check for termcode at
- * next character */
+ } else if (max_mlen < mlen) {
+ // no match, may have to check for termcode at
+ // next character
max_mlen = mlen + 1;
+ }
}
if ((mp == NULL || max_mlen >= mp_match_len)
@@ -1991,13 +1998,11 @@ static int vgetorpeek(bool advance)
}
}
- /* complete match */
+ // complete match
if (keylen >= 0 && keylen <= typebuf.tb_len) {
int save_m_expr;
int save_m_noremap;
int save_m_silent;
- char_u *save_m_keys;
- char_u *save_m_str;
// Write chars to script file(s)
// Note: :lmap mappings are written *after* being applied. #5658
@@ -2007,7 +2012,7 @@ static int vgetorpeek(bool advance)
}
cmd_silent = (typebuf.tb_silent > 0);
- del_typebuf(keylen, 0); /* remove the mapped keys */
+ del_typebuf(keylen, 0); // remove the mapped keys
/*
* Put the replacement string in front of mapstr.
@@ -2032,9 +2037,8 @@ static int vgetorpeek(bool advance)
*/
if (VIsual_active && VIsual_select
&& (mp->m_mode & VISUAL)) {
- VIsual_select = FALSE;
- (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE,
- 0, TRUE, FALSE);
+ VIsual_select = false;
+ (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, 0, true, false);
}
/* Copy the values from *mp that are used, because
@@ -2044,8 +2048,8 @@ static int vgetorpeek(bool advance)
save_m_expr = mp->m_expr;
save_m_noremap = mp->m_noremap;
save_m_silent = mp->m_silent;
- save_m_keys = NULL; /* only saved when needed */
- save_m_str = NULL; /* only saved when needed */
+ char_u *save_m_keys = NULL; // only saved when needed
+ char_u *save_m_str = NULL; // only saved when needed
/*
* Handle ":map <expr>": evaluate the {rhs} as an
@@ -2141,14 +2145,14 @@ static int vgetorpeek(bool advance)
char_u *ptr;
if (mode_displayed) {
- unshowmode(TRUE);
- mode_deleted = TRUE;
+ unshowmode(true);
+ mode_deleted = true;
}
validate_cursor();
old_wcol = curwin->w_wcol;
old_wrow = curwin->w_wrow;
- /* move cursor left, if possible */
+ // move cursor left, if possible
if (curwin->w_cursor.col != 0) {
if (curwin->w_wcol > 0) {
if (did_ai) {
@@ -2170,7 +2174,7 @@ static int vgetorpeek(bool advance)
+ curwin->w_wcol / curwin->w_width_inner;
curwin->w_wcol %= curwin->w_width_inner;
curwin->w_wcol += curwin_col_off();
- col = 0; /* no correction needed */
+ col = 0; // no correction needed
} else {
--curwin->w_wcol;
col = curwin->w_cursor.col - 1;
@@ -2197,8 +2201,9 @@ static int vgetorpeek(bool advance)
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
}
- if (c < 0)
- continue; /* end of input script reached */
+ if (c < 0) {
+ continue; // end of input script reached
+ }
// Allow mapping for just typed characters. When we get here c
// is the number of extra bytes and typebuf.tb_len is 1.
@@ -2207,20 +2212,20 @@ static int vgetorpeek(bool advance)
}
typebuf.tb_len += c;
- /* buffer full, don't map */
+ // buffer full, don't map
if (typebuf.tb_len >= typebuf.tb_maplen + MAXMAPLEN) {
- timedout = TRUE;
+ timedout = true;
continue;
}
if (ex_normal_busy > 0) {
static int tc = 0;
- /* No typeahead left and inside ":normal". Must return
- * something to avoid getting stuck. When an incomplete
- * mapping is present, behave like it timed out. */
+ // No typeahead left and inside ":normal". Must return
+ // something to avoid getting stuck. When an incomplete
+ // mapping is present, behave like it timed out.
if (typebuf.tb_len > 0) {
- timedout = TRUE;
+ timedout = true;
continue;
}
/* When 'insertmode' is set, ESC just beeps in Insert
@@ -2254,7 +2259,7 @@ static int vgetorpeek(bool advance)
if (((State & INSERT) != 0 || p_lz) && (State & CMDLINE) == 0
&& advance && must_redraw != 0 && !need_wait_return) {
update_screen(0);
- setcursor(); /* put cursor back where it belongs */
+ setcursor(); // put cursor back where it belongs
}
/*
@@ -2267,16 +2272,16 @@ static int vgetorpeek(bool advance)
if (typebuf.tb_len > 0 && advance && !exmode_active) {
if (((State & (NORMAL | INSERT)) || State == LANGMAP)
&& State != HITRETURN) {
- /* this looks nice when typing a dead character map */
+ // this looks nice when typing a dead character map
if (State & INSERT
&& ptr2cells(typebuf.tb_buf + typebuf.tb_off
- + typebuf.tb_len - 1) == 1) {
- edit_putchar(typebuf.tb_buf[typebuf.tb_off
- + typebuf.tb_len - 1], FALSE);
- setcursor(); /* put cursor back where it belongs */
+ + typebuf.tb_len - 1) == 1) {
+ edit_putchar(typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len - 1],
+ false);
+ setcursor(); // put cursor back where it belongs
c1 = 1;
}
- /* need to use the col and row from above here */
+ // need to use the col and row from above here
old_wcol = curwin->w_wcol;
old_wrow = curwin->w_wrow;
curwin->w_wcol = new_wcol;
@@ -2332,31 +2337,34 @@ static int vgetorpeek(bool advance)
if (i != 0)
pop_showcmd();
if (c1 == 1) {
- if (State & INSERT)
+ if (State & INSERT) {
edit_unputchar();
- if (State & CMDLINE)
+ }
+ if (State & CMDLINE) {
unputcmdline();
- else
- setcursor(); /* put cursor back where it belongs */
+ } else {
+ setcursor(); // put cursor back where it belongs
+ }
}
- if (c < 0)
- continue; /* end of input script reached */
- if (c == NUL) { /* no character available */
- if (!advance)
+ if (c < 0) {
+ continue; // end of input script reached
+ }
+ if (c == NUL) { // no character available
+ if (!advance) {
break;
- if (wait_tb_len > 0) { /* timed out */
- timedout = TRUE;
+ }
+ if (wait_tb_len > 0) { // timed out
+ timedout = true;
continue;
}
- } else { /* allow mapping for just typed characters */
- while (typebuf.tb_buf[typebuf.tb_off
- + typebuf.tb_len] != NUL)
- typebuf.tb_noremap[typebuf.tb_off
- + typebuf.tb_len++] = RM_YES;
+ } else { // allow mapping for just typed characters
+ while (typebuf.tb_buf[typebuf.tb_off + typebuf.tb_len] != NUL) {
+ typebuf.tb_noremap[typebuf.tb_off + typebuf.tb_len++] = RM_YES;
+ }
}
- } /* for (;;) */
- } /* if (!character from stuffbuf) */
+ } // for (;;)
+ } // if (!character from stuffbuf)
// if advance is false don't loop on NULs
} while (c < 0 || (advance && c == NUL));
@@ -2368,15 +2376,17 @@ static int vgetorpeek(bool advance)
*/
if (advance && p_smd && msg_silent == 0 && (State & INSERT)) {
if (c == ESC && !mode_deleted && !no_mapping && mode_displayed) {
- if (typebuf.tb_len && !KeyTyped)
- redraw_cmdline = TRUE; /* delete mode later */
- else
- unshowmode(FALSE);
+ if (typebuf.tb_len && !KeyTyped) {
+ redraw_cmdline = true; // delete mode later
+ } else {
+ unshowmode(false);
+ }
} else if (c != ESC && mode_deleted) {
- if (typebuf.tb_len && !KeyTyped)
- redraw_cmdline = TRUE; /* show mode later */
- else
+ if (typebuf.tb_len && !KeyTyped) {
+ redraw_cmdline = true; // show mode later
+ } else {
showmode();
+ }
}
}
@@ -2440,8 +2450,8 @@ int inchar(
* on char wait, flush swapfile, write error....).
*/
if (State != HITRETURN) {
- did_outofmem_msg = FALSE; /* display out of memory message (again) */
- did_swapwrite_msg = FALSE; /* display swap file write error again */
+ did_outofmem_msg = false; // display out of memory message (again)
+ did_swapwrite_msg = false; // display swap file write error again
}
// Get a character from a script file if there is one.
@@ -3175,7 +3185,7 @@ static void validate_maphash(void)
/*
* Get the mapping mode from the command name.
*/
-int get_map_mode(char_u **cmdp, int forceit)
+int get_map_mode(char_u **cmdp, bool forceit)
{
char_u *p;
int modec;
@@ -3183,30 +3193,31 @@ int get_map_mode(char_u **cmdp, int forceit)
p = *cmdp;
modec = *p++;
- if (modec == 'i')
- mode = INSERT; /* :imap */
- else if (modec == 'l')
- mode = LANGMAP; /* :lmap */
- else if (modec == 'c')
- mode = CMDLINE; /* :cmap */
- else if (modec == 'n' && *p != 'o') /* avoid :noremap */
- mode = NORMAL; /* :nmap */
- else if (modec == 'v')
- mode = VISUAL + SELECTMODE; /* :vmap */
- else if (modec == 'x')
- mode = VISUAL; /* :xmap */
- else if (modec == 's')
- mode = SELECTMODE; /* :smap */
- else if (modec == 'o')
- mode = OP_PENDING; /* :omap */
- else if (modec == 't')
- mode = TERM_FOCUS; // :tmap
- else {
- --p;
- if (forceit)
- mode = INSERT + CMDLINE; /* :map ! */
- else
- mode = VISUAL + SELECTMODE + NORMAL + OP_PENDING; /* :map */
+ if (modec == 'i') {
+ mode = INSERT; // :imap
+ } else if (modec == 'l') {
+ mode = LANGMAP; // :lmap
+ } else if (modec == 'c') {
+ mode = CMDLINE; // :cmap
+ } else if (modec == 'n' && *p != 'o') { // avoid :noremap
+ mode = NORMAL; // :nmap
+ } else if (modec == 'v') {
+ mode = VISUAL + SELECTMODE; // :vmap
+ } else if (modec == 'x') {
+ mode = VISUAL; // :xmap
+ } else if (modec == 's') {
+ mode = SELECTMODE; // :smap
+ } else if (modec == 'o') {
+ mode = OP_PENDING; // :omap
+ } else if (modec == 't') {
+ mode = TERM_FOCUS; // :tmap
+ } else {
+ p--;
+ if (forceit) {
+ mode = INSERT + CMDLINE; // :map !
+ } else {
+ mode = VISUAL + SELECTMODE + NORMAL + OP_PENDING; // :map
+ }
}
*cmdp = p;
@@ -3237,12 +3248,11 @@ void map_clear_mode(char_u *cmdp, char_u *arg, int forceit, int abbr)
/*
* Clear all mappings in "mode".
*/
-void
-map_clear_int (
- buf_T *buf, /* buffer for local mappings */
- int mode, /* mode in which to delete */
- int local, /* TRUE for buffer-local mappings */
- int abbr /* TRUE for abbreviations */
+void map_clear_int(
+ buf_T *buf, // buffer for local mappings
+ int mode, // mode in which to delete
+ bool local, // true for buffer-local mappings
+ bool abbr // true for abbreviations
)
{
mapblock_T *mp, **mpp;
@@ -3253,12 +3263,14 @@ map_clear_int (
for (hash = 0; hash < 256; ++hash) {
if (abbr) {
- if (hash > 0) /* there is only one abbrlist */
+ if (hash > 0) { // there is only one abbrlist
break;
- if (local)
+ }
+ if (local) {
mpp = &buf->b_first_abbr;
- else
+ } else {
mpp = &first_abbr;
+ }
} else {
if (local)
mpp = &buf->b_maphash[hash];
@@ -3286,7 +3298,7 @@ map_clear_int (
mp->m_next = maphash[new_hash];
maphash[new_hash] = mp;
}
- continue; /* continue with *mpp */
+ continue; // continue with *mpp
}
}
mpp = &(mp->m_next);
@@ -3341,10 +3353,9 @@ char *map_mode_to_chars(int mode)
return (char *)mapmode.ga_data;
}
-static void
-showmap (
+static void showmap(
mapblock_T *mp,
- int local /* TRUE for buffer-local map */
+ bool local // true for buffer-local map
)
{
size_t len = 1;
@@ -3355,8 +3366,9 @@ showmap (
if (msg_didout || msg_silent != 0) {
msg_putchar('\n');
- if (got_int) /* 'q' typed at MORE prompt */
+ if (got_int) { // 'q' typed at MORE prompt
return;
+ }
}
{
@@ -3372,8 +3384,8 @@ showmap (
// Display the LHS. Get length of what we write.
len = (size_t)msg_outtrans_special(mp->m_keys, true, 0);
do {
- msg_putchar(' '); /* padd with blanks */
- ++len;
+ msg_putchar(' '); // padd with blanks
+ len++;
} while (len < 12);
if (mp->m_noremap == REMAP_NONE) {
@@ -3506,21 +3518,20 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
* Used below when expanding mapping/abbreviation names.
*/
static int expand_mapmodes = 0;
-static int expand_isabbrev = 0;
-static int expand_buffer = FALSE;
+static bool expand_isabbrev = false;
+static bool expand_buffer = false;
/*
* Work out what to complete when doing command line completion of mapping
* or abbreviation names.
*/
-char_u *
-set_context_in_map_cmd (
+char_u *set_context_in_map_cmd(
expand_T *xp,
char_u *cmd,
char_u *arg,
- int forceit, /* TRUE if '!' given */
- int isabbrev, /* TRUE if abbreviation */
- int isunmap, /* TRUE if unmap/unabbrev command */
+ bool forceit, // true if '!' given
+ bool isabbrev, // true if abbreviation
+ bool isunmap, // true if unmap/unabbrev command
cmdidx_T cmdidx
)
{
@@ -3536,10 +3547,10 @@ set_context_in_map_cmd (
}
expand_isabbrev = isabbrev;
xp->xp_context = EXPAND_MAPPINGS;
- expand_buffer = FALSE;
+ expand_buffer = false;
for (;; ) {
if (STRNCMP(arg, "<buffer>", 8) == 0) {
- expand_buffer = TRUE;
+ expand_buffer = true;
arg = skipwhite(arg + 8);
continue;
}
@@ -3589,7 +3600,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
validate_maphash();
- *num_file = 0; /* return values in case of FAIL */
+ *num_file = 0; // return values in case of FAIL
*file = NULL;
/*
@@ -3628,8 +3639,9 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
for (hash = 0; hash < 256; ++hash) {
if (expand_isabbrev) {
- if (hash > 0) /* only one abbrev list */
- break; /* for (hash) */
+ if (hash > 0) { // only one abbrev list
+ break; // for (hash)
+ }
mp = first_abbr;
} else if (expand_buffer)
mp = curbuf->b_maphash[hash];
@@ -3648,26 +3660,27 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
}
xfree(p);
}
- } /* for (mp) */
- } /* for (hash) */
+ } // for (mp)
+ } // for (hash)
- if (count == 0) /* no match found */
- break; /* for (round) */
+ if (count == 0) { // no match found
+ break; // for (round)
+ }
if (round == 1) {
*file = (char_u **)xmalloc((size_t)count * sizeof(char_u *));
}
- } /* for (round) */
+ } // for (round)
if (count > 1) {
char_u **ptr1;
char_u **ptr2;
char_u **ptr3;
- /* Sort the matches */
+ // Sort the matches
sort_strings(*file, count);
- /* Remove multiple entries */
+ // Remove multiple entries
ptr1 = *file;
ptr2 = ptr1 + 1;
ptr3 = ptr1 + count;
@@ -3705,7 +3718,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
bool check_abbr(int c, char_u *ptr, int col, int mincol)
{
int len;
- int scol; /* starting column of the abbr. */
+ int scol; // starting column of the abbr.
int j;
char_u *s;
char_u tb[MB_MAXBYTES + 4];
@@ -3756,7 +3769,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
if (scol < mincol)
scol = mincol;
- if (scol < col) { /* there is a word in front of the cursor */
+ if (scol < col) { // there is a word in front of the cursor
ptr += scol;
len = col - scol;
mp = curbuf->b_first_abbr;
@@ -3778,7 +3791,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
vim_unescape_csi(q);
qlen = (int)STRLEN(q);
}
- /* find entries with right mode and keys */
+ // find entries with right mode and keys
match = (mp->m_mode & State)
&& qlen == len
&& !STRNCMP(q, ptr, (size_t)len);
@@ -3805,7 +3818,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
*/
j = 0;
if (c != Ctrl_RSB) {
- /* special key code, split up */
+ // special key code, split up
if (IS_SPECIAL(c) || c == K_SPECIAL) {
tb[j++] = K_SPECIAL;
tb[j++] = (char_u)K_SECOND(c);
@@ -3821,17 +3834,17 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
j += utf_char2bytes(c, tb + j);
}
tb[j] = NUL;
- /* insert the last typed char */
- (void)ins_typebuf(tb, 1, 0, TRUE, mp->m_silent);
+ // insert the last typed char
+ (void)ins_typebuf(tb, 1, 0, true, mp->m_silent);
}
if (mp->m_expr)
s = eval_map_expr(mp->m_str, c);
else
s = mp->m_str;
if (s != NULL) {
- /* insert the to string */
- (void)ins_typebuf(s, mp->m_noremap, 0, TRUE, mp->m_silent);
- /* no abbrev. for these chars */
+ // insert the to string
+ (void)ins_typebuf(s, mp->m_noremap, 0, true, mp->m_silent);
+ // no abbrev. for these chars
typebuf.tb_no_abbr_cnt += (int)STRLEN(s) + j + 1;
if (mp->m_expr)
xfree(s);
@@ -3856,7 +3869,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
static char_u *
eval_map_expr (
char_u *str,
- int c /* NUL or typed character for abbreviation */
+ int c // NUL or typed character for abbreviation
)
{
char_u *res;
@@ -3874,11 +3887,11 @@ eval_map_expr (
save_cmd = save_cmdline_alloc();
- /* Forbid changing text or using ":normal" to avoid most of the bad side
- * effects. Also restore the cursor position. */
- ++textlock;
- ++ex_normal_lock;
- set_vim_var_char(c); /* set v:char to the typed character */
+ // Forbid changing text or using ":normal" to avoid most of the bad side
+ // effects. Also restore the cursor position.
+ textlock++;
+ ex_normal_lock++;
+ set_vim_var_char(c); // set v:char to the typed character
save_cursor = curwin->w_cursor;
save_msg_col = msg_col;
save_msg_row = msg_row;
@@ -3894,7 +3907,7 @@ eval_map_expr (
if (p == NULL)
return NULL;
- /* Escape CSI in the result to be able to use the string as typeahead. */
+ // Escape CSI in the result to be able to use the string as typeahead.
res = vim_strsave_escape_csi(p);
xfree(p);
@@ -3914,7 +3927,7 @@ char_u *vim_strsave_escape_csi(char_u *p)
char_u *d = res;
for (char_u *s = p; *s != NUL; ) {
if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
- /* Copy special key unmodified. */
+ // Copy special key unmodified.
*d++ = *s++;
*d++ = *s++;
*d++ = *s++;
@@ -4213,9 +4226,10 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
c = TO_SPECIAL(str[1], str[2]);
str += 2;
}
- if (IS_SPECIAL(c) || modifiers) { /* special key */
- if (fputs((char *)get_special_key_name(c, modifiers), fd) < 0)
+ if (IS_SPECIAL(c) || modifiers) { // special key
+ if (fputs((char *)get_special_key_name(c, modifiers), fd) < 0) {
return FAIL;
+ }
continue;
}
}
@@ -4271,35 +4285,36 @@ char_u *
check_map (
char_u *keys,
int mode,
- int exact, /* require exact match */
- int ign_mod, /* ignore preceding modifier */
- int abbr, /* do abbreviations */
- mapblock_T **mp_ptr, /* return: pointer to mapblock or NULL */
- int *local_ptr /* return: buffer-local mapping or NULL */
+ int exact, // require exact match
+ int ign_mod, // ignore preceding modifier
+ int abbr, // do abbreviations
+ mapblock_T **mp_ptr, // return: pointer to mapblock or NULL
+ int *local_ptr // return: buffer-local mapping or NULL
)
{
- int hash;
int len, minlen;
mapblock_T *mp;
- int local;
validate_maphash();
len = (int)STRLEN(keys);
- for (local = 1; local >= 0; --local)
- /* loop over all hash lists */
- for (hash = 0; hash < 256; ++hash) {
+ for (int local = 1; local >= 0; local--) {
+ // loop over all hash lists
+ for (int hash = 0; hash < 256; hash++) {
if (abbr) {
- if (hash > 0) /* there is only one list. */
+ if (hash > 0) { // there is only one list.
break;
- if (local)
+ }
+ if (local) {
mp = curbuf->b_first_abbr;
- else
+ } else {
mp = first_abbr;
- } else if (local)
+ }
+ } else if (local) {
mp = curbuf->b_maphash[hash];
- else
+ } else {
mp = maphash[hash];
+ }
for (; mp != NULL; mp = mp->m_next) {
/* skip entries with wrong mode, wrong length and not matching
* ones */
@@ -4322,6 +4337,7 @@ check_map (
}
}
}
+ }
return NULL;
}
@@ -4336,7 +4352,7 @@ void add_map(char_u *map, int mode)
char_u *s;
char_u *cpo_save = p_cpo;
- p_cpo = (char_u *)""; /* Allow <> notation */
+ p_cpo = (char_u *)""; // Allow <> notation
s = vim_strsave(map);
(void)do_map(0, s, mode, FALSE);
xfree(s);
@@ -4384,7 +4400,7 @@ static char_u * translate_mapping (
}
if (IS_SPECIAL(c) || modifiers) { // special key
ga_concat(&ga, get_special_key_name(c, modifiers));
- continue; /* for (str) */
+ continue; // for (str)
}
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 7b8e809de7..ffe0357bd8 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -256,7 +256,7 @@ EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file
EXTERN int ex_nesting_level INIT(= 0); // nesting level
EXTERN int debug_break_level INIT(= -1); // break below this level
-EXTERN int debug_did_msg INIT(= false); // did "debug mode" message
+EXTERN bool debug_did_msg INIT(= false); // did "debug mode" message
EXTERN int debug_tick INIT(= 0); // breakpoint change count
EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 4ec949759c..abba5425e7 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -890,8 +890,11 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
* Appropriately expand any tabs to spaces.
*/
if (line[col] == TAB || tab_spaces != 0) {
- if (tab_spaces == 0)
- tab_spaces = (int)(curbuf->b_p_ts - (print_pos % curbuf->b_p_ts));
+ if (tab_spaces == 0) {
+ tab_spaces = tabstop_padding(print_pos,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ }
while (tab_spaces > 0) {
need_break = mch_print_text_out((char_u *)" ", 1);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index fae971b3b3..8fa61515ef 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -34,14 +34,20 @@
// Count the size (in window cells) of the indent in the current line.
int get_indent(void)
{
- return get_indent_str(get_cursor_line_ptr(), (int)curbuf->b_p_ts, false);
+ return get_indent_str_vtab(get_cursor_line_ptr(),
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array,
+ false);
}
// Count the size (in window cells) of the indent in line "lnum".
int get_indent_lnum(linenr_T lnum)
{
- return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, false);
+ return get_indent_str_vtab(ml_get(lnum),
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array,
+ false);
}
@@ -49,7 +55,10 @@ int get_indent_lnum(linenr_T lnum)
// "buf".
int get_indent_buf(buf_T *buf, linenr_T lnum)
{
- return get_indent_str(ml_get_buf(buf, lnum, false), (int)buf->b_p_ts, false);
+ return get_indent_str_vtab(ml_get_buf(buf, lnum, false),
+ curbuf->b_p_ts,
+ buf->b_p_vts_array,
+ false);
}
@@ -82,6 +91,30 @@ int get_indent_str(const char_u *ptr, int ts, int list)
return count;
}
+// Count the size (in window cells) of the indent in line "ptr", using
+// variable tabstops.
+// if "list" is true, count only screen size for tabs.
+int get_indent_str_vtab(const char_u *ptr, long ts, long *vts, bool list)
+{
+ int count = 0;
+
+ for (; *ptr; ptr++) {
+ if (*ptr == TAB) { // count a tab for what it is worth
+ if (!list || curwin->w_p_lcs_chars.tab1) {
+ count += tabstop_padding(count, ts, vts);
+ } else {
+ // In list mode, when tab is not set, count screen char width
+ // for Tab, displays: ^I
+ count += ptr2cells(ptr);
+ }
+ } else if (*ptr == ' ') {
+ count++; // count a space for one
+ } else {
+ break;
+ }
+ }
+ return count;
+}
// Set the indent of the current line.
// Leaves the cursor on the first non-blank in the line.
@@ -104,6 +137,7 @@ int set_indent(int size, int flags)
int line_len;
int doit = false;
int ind_done = 0; // Measured in spaces.
+ int ind_col = 0;
int tab_pad;
int retval = false;
@@ -130,7 +164,9 @@ int set_indent(int size, int flags)
// Count as many characters as we can use.
while (todo > 0 && ascii_iswhite(*p)) {
if (*p == TAB) {
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
@@ -147,35 +183,41 @@ int set_indent(int size, int flags)
p++;
}
+ // These diverge from this point.
+ ind_col = ind_done;
// Set initial number of whitespace chars to copy if we are
// preserving indent but expandtab is set.
if (curbuf->b_p_et) {
orig_char_len = ind_len;
}
-
// Fill to next tabstop with a tab, if possible.
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
-
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
if ((todo >= tab_pad) && (orig_char_len == -1)) {
doit = true;
todo -= tab_pad;
ind_len++;
// ind_done += tab_pad;
+ ind_col += tab_pad;
}
}
// Count tabs required for indent.
- while (todo >= (int)curbuf->b_p_ts) {
+ for (;;) {
+ tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts, curbuf->b_p_vts_array);
+ if (todo < tab_pad) {
+ break;
+ }
if (*p != TAB) {
doit = true;
} else {
p++;
}
- todo -= (int)curbuf->b_p_ts;
+ todo -= tab_pad;
ind_len++;
-
- // ind_done += (int)curbuf->b_p_ts;
+ ind_col += tab_pad;
}
}
@@ -255,7 +297,9 @@ int set_indent(int size, int flags)
while (todo > 0 && ascii_iswhite(*p)) {
if (*p == TAB) {
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
// Stop if this tab will overshoot the target.
if (todo < tab_pad) {
@@ -272,18 +316,28 @@ int set_indent(int size, int flags)
}
// Fill to next tabstop with a tab, if possible.
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
if (todo >= tab_pad) {
*s++ = TAB;
todo -= tab_pad;
+ ind_done += tab_pad;
}
p = skipwhite(p);
}
- while (todo >= (int)curbuf->b_p_ts) {
+ for (;;) {
+ tab_pad = tabstop_padding(ind_done,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array);
+ if (todo < tab_pad) {
+ break;
+ }
*s++ = TAB;
- todo -= (int)curbuf->b_p_ts;
+ todo -= tab_pad;
+ ind_done += tab_pad;
}
}
@@ -375,11 +429,9 @@ int get_number_indent(linenr_T lnum)
return (int)col;
}
-/*
- * Return appropriate space number for breakindent, taking influencing
- * parameters into account. Window must be specified, since it is not
- * necessarily always the current one.
- */
+// Return appropriate space number for breakindent, taking influencing
+// parameters into account. Window must be specified, since it is not
+// necessarily always the current one.
int get_breakindent_win(win_T *wp, const char_u *line)
FUNC_ATTR_NONNULL_ALL
{
@@ -387,6 +439,7 @@ int get_breakindent_win(win_T *wp, const char_u *line)
static long prev_ts = 0; // Cached tabstop value.
static const char_u *prev_line = NULL; // cached pointer to line.
static varnumber_T prev_tick = 0; // Changedtick of cached value.
+ static long *prev_vts = NULL; // Cached vartabs values.
int bri = 0;
// window width minus window margin space, i.e. what rests for text
const int eff_wwidth = wp->w_width_inner
@@ -396,11 +449,16 @@ int get_breakindent_win(win_T *wp, const char_u *line)
// used cached indent, unless pointer or 'tabstop' changed
if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
- || prev_tick != buf_get_changedtick(wp->w_buffer)) {
+ || prev_tick != buf_get_changedtick(wp->w_buffer)
+ || prev_vts != wp->w_buffer->b_p_vts_array) {
prev_line = line;
prev_ts = wp->w_buffer->b_p_ts;
prev_tick = buf_get_changedtick(wp->w_buffer);
- prev_indent = get_indent_str(line, (int)wp->w_buffer->b_p_ts, wp->w_p_list);
+ prev_vts = wp->w_buffer->b_p_vts_array;
+ prev_indent = get_indent_str_vtab(line,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array,
+ wp->w_p_list);
}
bri = prev_indent + wp->w_briopt_shift;
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 9298e57411..771bf923b2 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -33,15 +33,12 @@ typedef struct {
* Search starts at w_cursor.lnum and goes backwards.
* Return NULL when not inside a comment.
*/
-static pos_T *ind_find_start_comment(void)
-{ /* XXX */
+static pos_T *ind_find_start_comment(void) // XXX
+{
return find_start_comment(curbuf->b_ind_maxcomment);
}
-pos_T *
-find_start_comment ( /* XXX */
- int ind_maxcomment
-)
+pos_T *find_start_comment(int ind_maxcomment) // XXX
{
pos_T *pos;
char_u *line;
@@ -109,8 +106,8 @@ static pos_T *ind_find_start_CORS(linenr_T *is_raw)
* Search starts at w_cursor.lnum and goes backwards.
* Return NULL when not inside a raw string.
*/
-static pos_T *find_start_rawstring(int ind_maxcomment)
-{ /* XXX */
+static pos_T *find_start_rawstring(int ind_maxcomment) // XXX
+{
pos_T *pos;
char_u *line;
char_u *p;
@@ -152,31 +149,35 @@ static char_u *skip_string(char_u *p)
/*
* We loop, because strings may be concatenated: "date""time".
*/
- for (;; ++p) {
- if (p[0] == '\'') { /* 'c' or '\n' or '\000' */
- if (!p[1]) /* ' at end of line */
+ for (;; p++) {
+ if (p[0] == '\'') { // 'c' or '\n' or '\000'
+ if (!p[1]) { // ' at end of line
break;
+ }
i = 2;
- if (p[1] == '\\') { /* '\n' or '\000' */
- ++i;
- while (ascii_isdigit(p[i - 1])) /* '\000' */
- ++i;
+ if (p[1] == '\\') { // '\n' or '\000'
+ i++;
+ while (ascii_isdigit(p[i - 1])) { // '\000'
+ i++;
+ }
}
- if (p[i] == '\'') { /* check for trailing ' */
+ if (p[i] == '\'') { // check for trailing '
p += i;
continue;
}
- } else if (p[0] == '"') { /* start of string */
- for (++p; p[0]; ++p) {
- if (p[0] == '\\' && p[1] != NUL)
- ++p;
- else if (p[0] == '"') /* end of string */
+ } else if (p[0] == '"') { // start of string
+ for (++p; p[0]; p++) {
+ if (p[0] == '\\' && p[1] != NUL) {
+ p++;
+ } else if (p[0] == '"') { // end of string
break;
+ }
+ }
+ if (p[0] == '"') {
+ continue; // continue for another string
}
- if (p[0] == '"')
- continue; /* continue for another string */
} else if (p[0] == 'R' && p[1] == '"') {
- /* Raw string: R"[delim](...)[delim]" */
+ // Raw string: R"[delim](...)[delim]"
char_u *delim = p + 2;
char_u *paren = vim_strchr(delim, '(');
@@ -190,14 +191,16 @@ static char_u *skip_string(char_u *p)
p += delim_len + 1;
break;
}
- if (p[0] == '"')
- continue; /* continue for another string */
+ if (p[0] == '"') {
+ continue; // continue for another string
+ }
}
}
- break; /* no string found */
+ break; // no string found
+ }
+ if (!*p) {
+ p--; // backup from NUL
}
- if (!*p)
- --p; /* backup from NUL */
return p;
}
@@ -255,20 +258,22 @@ static char_u *cin_skipcomment(char_u *s)
s += STRLEN(s);
break;
}
- if (*s != '/')
+ if (*s != '/') {
break;
- ++s;
- if (*s == '/') { /* slash-slash comment continues till eol */
+ }
+ s++;
+ if (*s == '/') { // slash-slash comment continues till eol
s += STRLEN(s);
break;
}
if (*s != '*')
break;
- for (++s; *s; ++s) /* skip slash-star comment */
+ for (++s; *s; s++) { // skip slash-star comment
if (s[0] == '*' && s[1] == '/') {
s += 2;
break;
}
+ }
}
return s;
}
@@ -285,7 +290,7 @@ static int cin_nocode(char_u *s)
/*
* Check previous lines for a "//" line comment, skipping over blank lines.
*/
-static pos_T *find_line_comment(void) /* XXX */
+static pos_T *find_line_comment(void) // XXX
{
static pos_T pos;
char_u *line;
@@ -335,39 +340,38 @@ static bool cin_has_js_key(char_u *text)
/// Checks if string matches "label:"; move to character after ':' if true.
/// "*s" must point to the start of the label, if there is one.
-static int cin_islabel_skip(char_u **s)
+static bool cin_islabel_skip(char_u **s)
+ FUNC_ATTR_NONNULL_ALL
{
- if (!vim_isIDc(**s)) /* need at least one ID character */
- return FALSE;
+ if (!vim_isIDc(**s)) { // need at least one ID character
+ return false;
+ }
while (vim_isIDc(**s))
(*s)++;
*s = cin_skipcomment(*s);
- /* "::" is not a label, it's C++ */
+ // "::" is not a label, it's C++
return **s == ':' && *++*s != ':';
}
-/*
- * Recognize a label: "label:".
- * Note: curwin->w_cursor must be where we are looking for the label.
- */
-int cin_islabel(void)
-{ /* XXX */
+// Recognize a label: "label:".
+// Note: curwin->w_cursor must be where we are looking for the label.
+bool cin_islabel(void) // XXX
+{
char_u *s = cin_skipcomment(get_cursor_line_ptr());
- /*
- * Exclude "default" from labels, since it should be indented
- * like a switch label. Same for C++ scope declarations.
- */
- if (cin_isdefault(s))
- return FALSE;
- if (cin_isscopedecl(s))
- return FALSE;
-
+ // Exclude "default" from labels, since it should be indented
+ // like a switch label. Same for C++ scope declarations.
+ if (cin_isdefault(s)) {
+ return false;
+ }
+ if (cin_isscopedecl(s)) {
+ return false;
+ }
if (!cin_islabel_skip(&s)) {
- return FALSE;
+ return false;
}
/*
@@ -392,21 +396,24 @@ int cin_islabel(void)
}
line = get_cursor_line_ptr();
- if (cin_ispreproc(line)) /* ignore #defines, #if, etc. */
+ if (cin_ispreproc(line)) { // ignore #defines, #if, etc.
continue;
- if (*(line = cin_skipcomment(line)) == NUL)
+ }
+ if (*(line = cin_skipcomment(line)) == NUL) {
continue;
+ }
curwin->w_cursor = cursor_save;
if (cin_isterminated(line, TRUE, FALSE)
|| cin_isscopedecl(line)
- || cin_iscase(line, TRUE)
- || (cin_islabel_skip(&line) && cin_nocode(line)))
- return TRUE;
- return FALSE;
+ || cin_iscase(line, true)
+ || (cin_islabel_skip(&line) && cin_nocode(line))) {
+ return true;
+ }
+ return false;
}
curwin->w_cursor = cursor_save;
- return TRUE; /* label at start of file??? */
+ return true; // label at start of file???
}
/*
@@ -451,10 +458,9 @@ static int cin_isinit(void)
/*
* Recognize a switch label: "case .*:" or "default:".
*/
-int
-cin_iscase (
+bool cin_iscase(
char_u *s,
- int strict /* Allow relaxed check of case statement for JS */
+ bool strict // Allow relaxed check of case statement for JS
)
{
s = cin_skipcomment(s);
@@ -465,29 +471,32 @@ cin_iscase (
break;
}
if (*s == ':') {
- if (s[1] == ':') /* skip over "::" for C++ */
- ++s;
- else
- return TRUE;
+ if (s[1] == ':') { // skip over "::" for C++
+ s++;
+ } else {
+ return true;
+ }
}
- if (*s == '\'' && s[1] && s[2] == '\'')
- s += 2; /* skip over ':' */
- else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
- return FALSE; /* stop at comment */
- else if (*s == '"') {
- /* JS etc. */
- if (strict)
- return FALSE; /* stop at string */
- else
- return TRUE;
+ if (*s == '\'' && s[1] && s[2] == '\'') {
+ s += 2; // skip over ':'
+ } else if (*s == '/' && (s[1] == '*' || s[1] == '/')) {
+ return false; // stop at comment
+ } else if (*s == '"') {
+ // JS etc.
+ if (strict) {
+ return false; // stop at string
+ } else {
+ return true;
+ }
}
}
- return FALSE;
+ return false;
}
- if (cin_isdefault(s))
- return TRUE;
- return FALSE;
+ if (cin_isdefault(s)) {
+ return true;
+ }
+ return false;
}
/*
@@ -503,23 +512,24 @@ static int cin_isdefault(char_u *s)
/*
* Recognize a "public/private/protected" scope declaration label.
*/
-int cin_isscopedecl(char_u *s)
+bool cin_isscopedecl(char_u *s)
{
int i;
s = cin_skipcomment(s);
- if (STRNCMP(s, "public", 6) == 0)
+ if (STRNCMP(s, "public", 6) == 0) {
i = 6;
- else if (STRNCMP(s, "protected", 9) == 0)
+ } else if (STRNCMP(s, "protected", 9) == 0) {
i = 9;
- else if (STRNCMP(s, "private", 7) == 0)
+ } else if (STRNCMP(s, "private", 7) == 0) {
i = 7;
- else
- return FALSE;
+ } else {
+ return false;
+ }
return *(s = cin_skipcomment(s + i)) == ':' && s[1] != ':';
}
-/* Maximum number of lines to search back for a "namespace" line. */
+// Maximum number of lines to search back for a "namespace" line.
#define FIND_NAMESPACE_LIM 20
// Recognize a "namespace" scope declaration.
@@ -569,12 +579,14 @@ static char_u *after_label(char_u *l)
{
for (; *l; ++l) {
if (*l == ':') {
- if (l[1] == ':') /* skip over "::" for C++ */
- ++l;
- else if (!cin_iscase(l + 1, FALSE))
+ if (l[1] == ':') { // skip over "::" for C++
+ l++;
+ } else if (!cin_iscase(l + 1, false)) {
break;
- } else if (*l == '\'' && l[1] && l[2] == '\'')
- l += 2; /* skip over 'x' */
+ }
+ } else if (*l == '\'' && l[1] && l[2] == '\'') {
+ l += 2; // skip over 'x'
+ }
}
if (*l == NUL)
return NULL;
@@ -588,10 +600,7 @@ static char_u *after_label(char_u *l)
* Get indent of line "lnum", skipping a label.
* Return 0 if there is nothing after the label.
*/
-static int
-get_indent_nolabel ( /* XXX */
- linenr_T lnum
-)
+static int get_indent_nolabel(linenr_T lnum) // XXX
{
char_u *l;
pos_T fp;
@@ -624,12 +633,13 @@ static int skip_label(linenr_T lnum, char_u **pp)
cursor_save = curwin->w_cursor;
curwin->w_cursor.lnum = lnum;
l = get_cursor_line_ptr();
- /* XXX */
- if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel()) {
+ // XXX
+ if (cin_iscase(l, false) || cin_isscopedecl(l) || cin_islabel()) {
amount = get_indent_nolabel(lnum);
l = after_label(get_cursor_line_ptr());
- if (l == NULL) /* just in case */
+ if (l == NULL) { // just in case
l = get_cursor_line_ptr();
+ }
} else {
amount = get_indent();
l = get_cursor_line_ptr();
@@ -710,10 +720,11 @@ static int cin_get_equal_amount(linenr_T lnum)
line = s = ml_get(lnum);
while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL) {
- if (cin_iscomment(s)) /* ignore comments */
+ if (cin_iscomment(s)) { // ignore comments
s = cin_skipcomment(s);
- else
- ++s;
+ } else {
+ s++;
+ }
}
if (*s != '=')
return 0;
@@ -722,8 +733,9 @@ static int cin_get_equal_amount(linenr_T lnum)
if (cin_nocode(s))
return 0;
- if (*s == '"') /* nice alignment for continued strings */
- ++s;
+ if (*s == '"') { // nice alignment for continued strings
+ s++;
+ }
fp.lnum = lnum;
fp.col = (colnr_T)(s - line);
@@ -806,8 +818,8 @@ static int cin_islinecomment(char_u *p)
static char_u
cin_isterminated (
char_u *s,
- int incl_open, /* include '{' at the end as terminator */
- int incl_comma /* recognize a trailing comma */
+ int incl_open, // include '{' at the end as terminator
+ int incl_comma // recognize a trailing comma
)
{
char_u found_start = 0;
@@ -823,7 +835,7 @@ cin_isterminated (
is_else = cin_iselse(s);
while (*s) {
- /* skip over comments, "" strings and 'c'haracters */
+ // skip over comments, "" strings and 'c'haracters
s = skip_string(cin_skipcomment(s));
if (*s == '}' && n_open > 0)
--n_open;
@@ -942,12 +954,12 @@ static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum)
s = skipwhite(s);
if (!just_started && (!comma && *s != ',' && *s != ')'))
break;
- just_started = FALSE;
- } else if (cin_iscomment(s)) /* ignore comments */
+ just_started = false;
+ } else if (cin_iscomment(s)) { // ignore comments
s = cin_skipcomment(s);
- else {
- ++s;
- just_started = FALSE;
+ } else {
+ s++;
+ just_started = false;
}
}
@@ -965,8 +977,9 @@ static int cin_isif(char_u *p)
static int cin_iselse(char_u *p)
{
- if (*p == '}') /* accept "} else" */
+ if (*p == '}') { // accept "} else"
p = cin_skipcomment(p + 1);
+ }
return STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]);
}
@@ -980,27 +993,24 @@ static int cin_isdo(char_u *p)
* We only accept a "while (condition) ;", with only white space between the
* ')' and ';'. The condition may be spread over several lines.
*/
-static int
-cin_iswhileofdo ( /* XXX */
- char_u *p,
- linenr_T lnum
-)
+static int cin_iswhileofdo(char_u *p, linenr_T lnum) // XXX
{
pos_T cursor_save;
pos_T *trypos;
int retval = FALSE;
p = cin_skipcomment(p);
- if (*p == '}') /* accept "} while (cond);" */
+ if (*p == '}') { // accept "} while (cond);"
p = cin_skipcomment(p + 1);
+ }
if (cin_starts_with(p, "while")) {
cursor_save = curwin->w_cursor;
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = 0;
p = get_cursor_line_ptr();
- while (*p && *p != 'w') { /* skip any '}', until the 'w' of the "while" */
- ++p;
- ++curwin->w_cursor.col;
+ while (*p && *p != 'w') { // skip any '}', until the 'w' of the "while"
+ p++;
+ curwin->w_cursor.col++;
}
if ((trypos = findmatchlimit(NULL, 0, 0,
curbuf->b_ind_maxparen)) != NULL
@@ -1067,8 +1077,9 @@ static int cin_iswhileofdo_end(int terminated)
pos_T *trypos;
int i;
- if (terminated != ';') /* there must be a ';' at the end */
- return FALSE;
+ if (terminated != ';') { // there must be a ';' at the end
+ return false;
+ }
p = line = get_cursor_line_ptr();
while (*p != NUL) {
@@ -1083,15 +1094,16 @@ static int cin_iswhileofdo_end(int terminated)
trypos = find_match_paren(curbuf->b_ind_maxparen);
if (trypos != NULL) {
s = cin_skipcomment(ml_get(trypos->lnum));
- if (*s == '}') /* accept "} while (cond);" */
+ if (*s == '}') { // accept "} while (cond);"
s = cin_skipcomment(s + 1);
+ }
if (cin_starts_with(s, "while")) {
curwin->w_cursor.lnum = trypos->lnum;
return TRUE;
}
}
- /* Searching may have made "line" invalid, get it again. */
+ // Searching may have made "line" invalid, get it again.
line = get_cursor_line_ptr();
p = line + i;
}
@@ -1134,8 +1146,9 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) {
pos->col = 0;
s = skipwhite(line);
- if (*s == '#') /* skip #define FOO x ? (x) : x */
- return FALSE;
+ if (*s == '#') { // skip #define FOO x ? (x) : x
+ return false;
+ }
s = cin_skipcomment(s);
if (*s == NUL)
return FALSE;
@@ -1230,23 +1243,23 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) {
class_or_struct = FALSE;
lookfor_ctor_init = TRUE;
} else if (s[0] == '?') {
- /* Avoid seeing '() :' after '?' as constructor init. */
- return FALSE;
+ // Avoid seeing '() :' after '?' as constructor init.
+ return false;
} else if (!vim_isIDc(s[0])) {
- /* if it is not an identifier, we are wrong */
+ // if it is not an identifier, we are wrong
class_or_struct = false;
lookfor_ctor_init = false;
} else if (pos->col == 0) {
- /* it can't be a constructor-initialization any more */
- lookfor_ctor_init = FALSE;
+ // it can't be a constructor-initialization any more
+ lookfor_ctor_init = false;
- /* the first statement starts here: lineup with this one... */
+ // the first statement starts here: lineup with this one...
if (cpp_base_class) {
pos->col = (colnr_T)(s - line);
}
}
- /* When the line ends in a comma don't align with it. */
+ // When the line ends in a comma don't align with it.
if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1)) {
pos->col = 0;
}
@@ -1271,10 +1284,12 @@ static int get_baseclass_amount(int col)
if (col == 0) {
amount = get_indent();
if (find_last_paren(get_cursor_line_ptr(), '(', ')')
- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
- amount = get_indent_lnum(trypos->lnum); /* XXX */
- if (!cin_ends_in(get_cursor_line_ptr(), (char_u *)",", NULL))
+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) {
+ amount = get_indent_lnum(trypos->lnum); // XXX
+ }
+ if (!cin_ends_in(get_cursor_line_ptr(), (char_u *)",", NULL)) {
amount += curbuf->b_ind_cpp_baseclass;
+ }
} else {
curwin->w_cursor.col = col;
getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
@@ -1389,12 +1404,12 @@ static int cin_skip2pos(pos_T *trypos)
* Return NULL if no match found.
* Ignore a '{' that is in a comment, makes indenting the next three lines
* work. */
-/* foo() */
-/* { */
-/* } */
+// foo()
+// {
+// }
-static pos_T *find_start_brace(void)
-{ /* XXX */
+static pos_T *find_start_brace(void) // XXX
+{
pos_T cursor_save;
pos_T *trypos;
pos_T *pos;
@@ -1402,11 +1417,11 @@ static pos_T *find_start_brace(void)
cursor_save = curwin->w_cursor;
while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL) {
- pos_copy = *trypos; /* copy pos_T, next findmatch will change it */
+ pos_copy = *trypos; // copy pos_T, next findmatch will change it
trypos = &pos_copy;
curwin->w_cursor = *trypos;
pos = NULL;
- /* ignore the { if it's in a // or / * * / comment */
+ // ignore the { if it's in a // or / * * / comment
if ((colnr_T)cin_skip2pos(trypos) == trypos->col
&& (pos = ind_find_start_CORS(NULL)) == NULL) { // XXX
break;
@@ -1449,7 +1464,7 @@ retry:
} else {
pos_T *trypos_wk;
- pos_copy = *trypos; /* copy trypos, findmatch will change it */
+ pos_copy = *trypos; // copy trypos, findmatch will change it
trypos = &pos_copy;
curwin->w_cursor = *trypos;
if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) { // XXX
@@ -1515,17 +1530,17 @@ static int find_last_paren(char_u *l, int start, int end)
int retval = FALSE;
int open_count = 0;
- curwin->w_cursor.col = 0; /* default is start of line */
+ curwin->w_cursor.col = 0; // default is start of line
for (i = 0; l[i] != NUL; i++) {
- i = (int)(cin_skipcomment(l + i) - l); /* ignore parens in comments */
- i = (int)(skip_string(l + i) - l); /* ignore parens in quotes */
- if (l[i] == start)
- ++open_count;
- else if (l[i] == end) {
- if (open_count > 0)
- --open_count;
- else {
+ i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments
+ i = (int)(skip_string(l + i) - l); // ignore parens in quotes
+ if (l[i] == start) {
+ open_count++;
+ } else if (l[i] == end) {
+ if (open_count > 0) {
+ open_count--;
+ } else {
curwin->w_cursor.col = i;
retval = TRUE;
}
@@ -1561,7 +1576,7 @@ void parse_cino(buf_T *buf)
* an opening brace. */
buf->b_ind_no_brace = 0;
- /* Column where the first { of a function should be located }. */
+ // Column where the first { of a function should be located }.
buf->b_ind_first_open = 0;
/* Spaces from the prevailing indent a leftmost open brace should be
@@ -1581,26 +1596,26 @@ void parse_cino(buf_T *buf)
* otherwise the jump label will be put to column 1. */
buf->b_ind_jump_label = -1;
- /* Spaces from the switch() indent a "case xx" label should be located. */
+ // Spaces from the switch() indent a "case xx" label should be located.
buf->b_ind_case = sw;
- /* Spaces from the "case xx:" code after a switch() should be located. */
+ // Spaces from the "case xx:" code after a switch() should be located.
buf->b_ind_case_code = sw;
- /* Lineup break at end of case in switch() with case label. */
+ // Lineup break at end of case in switch() with case label.
buf->b_ind_case_break = 0;
/* Spaces from the class declaration indent a scope declaration label
* should be located. */
buf->b_ind_scopedecl = sw;
- /* Spaces from the scope declaration label code should be located. */
+ // Spaces from the scope declaration label code should be located.
buf->b_ind_scopedecl_code = sw;
- /* Amount K&R-style parameters should be indented. */
+ // Amount K&R-style parameters should be indented.
buf->b_ind_param = sw;
- /* Amount a function type spec should be indented. */
+ // Amount a function type spec should be indented.
buf->b_ind_func_type = sw;
/* Amount a cpp base class declaration or constructor initialization
@@ -1611,7 +1626,7 @@ void parse_cino(buf_T *buf)
* should be located. */
buf->b_ind_continuation = sw;
- /* Spaces from the indent of the line with an unclosed parentheses. */
+ // Spaces from the indent of the line with an unclosed parentheses.
buf->b_ind_unclosed = sw * 2;
/* Spaces from the indent of the line with an unclosed parentheses, which
@@ -1635,35 +1650,35 @@ void parse_cino(buf_T *buf)
* opening parentheses. */
buf->b_ind_matching_paren = 0;
- /* Indent a closing parentheses under the previous line. */
+ // Indent a closing parentheses under the previous line.
buf->b_ind_paren_prev = 0;
- /* Extra indent for comments. */
+ // Extra indent for comments.
buf->b_ind_comment = 0;
- /* Spaces from the comment opener when there is nothing after it. */
+ // Spaces from the comment opener when there is nothing after it.
buf->b_ind_in_comment = 3;
/* Boolean: if non-zero, use b_ind_in_comment even if there is something
* after the comment opener. */
buf->b_ind_in_comment2 = 0;
- /* Max lines to search for an open paren. */
+ // Max lines to search for an open paren.
buf->b_ind_maxparen = 20;
- /* Max lines to search for an open comment. */
+ // Max lines to search for an open comment.
buf->b_ind_maxcomment = 70;
- /* Handle braces for java code. */
+ // Handle braces for java code.
buf->b_ind_java = 0;
- /* Not to confuse JS object properties with labels. */
+ // Not to confuse JS object properties with labels.
buf->b_ind_js = 0;
- /* Handle blocked cases correctly. */
+ // Handle blocked cases correctly.
buf->b_ind_keep_case_label = 0;
- /* Handle C++ namespace. */
+ // Handle C++ namespace.
buf->b_ind_cpp_namespace = 0;
/* Handle continuation lines containing conditions of if(), for() and
@@ -1777,9 +1792,9 @@ int get_c_indent(void)
pos_T our_paren_pos;
char_u *start;
int start_brace;
-#define BRACE_IN_COL0 1 /* '{' is in column 0 */
-#define BRACE_AT_START 2 /* '{' is at start of line */
-#define BRACE_AT_END 3 /* '{' is at end of line */
+#define BRACE_IN_COL0 1 // '{' is in column 0
+#define BRACE_AT_START 2 // '{' is at start of line
+#define BRACE_AT_END 3 // '{' is at end of line
linenr_T ourscope;
char_u *l;
char_u *look;
@@ -1802,24 +1817,24 @@ int get_c_indent(void)
int whilelevel;
linenr_T lnum;
int n;
- int iscase;
int lookfor_break;
- int lookfor_cpp_namespace = FALSE;
- int cont_amount = 0; /* amount for continuation line */
+ bool lookfor_cpp_namespace = false;
+ int cont_amount = 0; // amount for continuation line
int original_line_islabel;
int added_to_amount = 0;
linenr_T raw_string_start = 0;
cpp_baseclass_cache_T cache_cpp_baseclass = { false, { MAXLNUM, 0 } };
- /* make a copy, value is changed below */
+ // make a copy, value is changed below
int ind_continuation = curbuf->b_ind_continuation;
- /* remember where the cursor was when we started */
+ // remember where the cursor was when we started
cur_curpos = curwin->w_cursor;
- /* if we are at line 1 zero indent is fine, right? */
- if (cur_curpos.lnum == 1)
+ // if we are at line 1 zero indent is fine, right?
+ if (cur_curpos.lnum == 1) {
return 0;
+ }
/* Get a copy of the current contents of the line.
* This is required, because only the most recent line obtained with
@@ -1840,11 +1855,11 @@ int get_c_indent(void)
theline = skipwhite(linecopy);
- /* move the cursor to the start of the line */
+ // move the cursor to the start of the line
curwin->w_cursor.col = 0;
- original_line_islabel = cin_islabel(); /* XXX */
+ original_line_islabel = cin_islabel(); // XXX
/*
* If we are inside a raw string don't change the indent.
@@ -1852,7 +1867,7 @@ int get_c_indent(void)
*/
comment_pos = ind_find_start_comment();
if (comment_pos != NULL) {
- /* findmatchlimit() static pos is overwritten, make a copy */
+ // findmatchlimit() static pos is overwritten, make a copy
tryposCopy = *comment_pos;
comment_pos = &tryposCopy;
}
@@ -1887,8 +1902,8 @@ int get_c_indent(void)
* previous line, lineup with that one.
*/
if (cin_islinecomment(theline)
- && (trypos = find_line_comment()) != NULL) { /* XXX */
- /* find how indented the line beginning the comment is */
+ && (trypos = find_line_comment()) != NULL) { // XXX
+ // find how indented the line beginning the comment is
getvcol(curwin, trypos, &col, NULL, NULL);
amount = col;
goto theend;
@@ -1897,18 +1912,18 @@ int get_c_indent(void)
* If we're inside a comment and not looking at the start of the
* comment, try using the 'comments' option.
*/
- if (!cin_iscomment(theline) && comment_pos != NULL) { /* XXX */
+ if (!cin_iscomment(theline) && comment_pos != NULL) { // XXX
int lead_start_len = 2;
int lead_middle_len = 1;
- char_u lead_start[COM_MAX_LEN]; /* start-comment string */
- char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */
- char_u lead_end[COM_MAX_LEN]; /* end-comment string */
+ char_u lead_start[COM_MAX_LEN]; // start-comment string
+ char_u lead_middle[COM_MAX_LEN]; // middle-comment string
+ char_u lead_end[COM_MAX_LEN]; // end-comment string
char_u *p;
int start_align = 0;
int start_off = 0;
int done = FALSE;
- /* find how indented the line beginning the comment is */
+ // find how indented the line beginning the comment is
getvcol(curwin, comment_pos, &col, NULL, NULL);
amount = col;
*lead_start = NUL;
@@ -1981,13 +1996,13 @@ int get_c_indent(void)
if (STRNCMP(theline, lead_middle, lead_middle_len) != 0
&& STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) {
amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
- /* XXX */
- if (off != 0)
+ // XXX
+ if (off != 0) {
amount += off;
- else if (align == COM_RIGHT)
- amount += vim_strsize(lead_start)
- - vim_strsize(lead_middle);
- done = TRUE;
+ } else if (align == COM_RIGHT) {
+ amount += vim_strsize(lead_start) - vim_strsize(lead_middle);
+ }
+ done = true;
break;
}
}
@@ -2010,18 +2025,20 @@ int get_c_indent(void)
* otherwise, add the amount specified by "c" in 'cino'
*/
amount = -1;
- for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum) {
- if (linewhite(lnum)) /* skip blank lines */
+ for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; lnum--) {
+ if (linewhite(lnum)) { // skip blank lines
continue;
- amount = get_indent_lnum(lnum); /* XXX */
+ }
+ amount = get_indent_lnum(lnum); // XXX
break;
}
- if (amount == -1) { /* use the comment opener */
+ if (amount == -1) { // use the comment opener
if (!curbuf->b_ind_in_comment2) {
- start = ml_get(comment_pos->lnum);
- look = start + comment_pos->col + 2; /* skip / and * */
- if (*look != NUL) /* if something after it */
- comment_pos->col = (colnr_T)(skipwhite(look) - start);
+ start = ml_get(comment_pos->lnum);
+ look = start + comment_pos->col + 2; // skip / and *
+ if (*look != NUL) { // if something after it
+ comment_pos->col = (colnr_T)(skipwhite(look) - start);
+ }
}
getvcol(curwin, comment_pos, &col, NULL, NULL);
amount = col;
@@ -2038,9 +2055,8 @@ int get_c_indent(void)
amount = get_indent_lnum(trypos->lnum);
goto theend;
}
- /*
- * Are we inside parentheses or braces?
- */ /* XXX */
+ // Are we inside parentheses or braces?
+ // XXX
if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
&& curbuf->b_ind_java == 0)
|| (tryposBrace = find_start_brace()) != NULL
@@ -2063,8 +2079,8 @@ int get_c_indent(void)
* a previous non-empty line that matches the same paren.
*/
if (theline[0] == ')' && curbuf->b_ind_paren_prev) {
- /* Line up with the start of the matching paren line. */
- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); /* XXX */
+ // Line up with the start of the matching paren line.
+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX
} else {
amount = -1;
for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) {
@@ -2083,12 +2099,12 @@ int get_c_indent(void)
continue;
}
- /* XXX */
+ // XXX
if ((trypos = find_match_paren(
corr_ind_maxparen(&cur_curpos))) != NULL
&& trypos->lnum == our_paren_pos.lnum
&& trypos->col == our_paren_pos.col) {
- amount = get_indent_lnum(lnum); /* XXX */
+ amount = get_indent_lnum(lnum); // XXX
if (theline[0] == ')') {
if (our_paren_pos.lnum != lnum
@@ -2200,10 +2216,11 @@ int get_c_indent(void)
col = our_paren_pos.col + 1;
while (ascii_iswhite(l[col]))
col++;
- if (l[col] != NUL) /* In case of trailing space */
+ if (l[col] != NUL) { // In case of trailing space
our_paren_pos.col = col;
- else
+ } else {
our_paren_pos.col++;
+ }
}
}
@@ -2219,7 +2236,7 @@ int get_c_indent(void)
}
if (theline[0] == ')' && curbuf->b_ind_matching_paren) {
- /* Line up with the start of the matching paren line. */
+ // Line up with the start of the matching paren line.
} else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0)
|| (!curbuf->b_ind_unclosed_noignore
&& *look == '(' && ignore_paren_col == 0)) {
@@ -2271,9 +2288,10 @@ int get_c_indent(void)
}
}
- /* add extra indent for a comment */
- if (cin_iscomment(theline))
+ // add extra indent for a comment
+ if (cin_iscomment(theline)) {
amount += curbuf->b_ind_comment;
+ }
} else {
// We are inside braces, there is a { before this line at the position
// stored in tryposBrace.
@@ -2317,7 +2335,7 @@ int get_c_indent(void)
// ldfd) {
// }
if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
- && cin_iscase(skipwhite(get_cursor_line_ptr()), FALSE)) {
+ && cin_iscase(skipwhite(get_cursor_line_ptr()), false)) {
amount = get_indent();
} else if (curbuf->b_ind_js) {
amount = get_indent_lnum(lnum);
@@ -2348,14 +2366,15 @@ int get_c_indent(void)
* to match it with.
*/
lookfor = LOOKFOR_INITIAL;
- if (cin_iselse(theline))
+ if (cin_iselse(theline)) {
lookfor = LOOKFOR_IF;
- else if (cin_iswhileofdo(theline, cur_curpos.lnum)) /* XXX */
+ } else if (cin_iswhileofdo(theline, cur_curpos.lnum)) { // XXX
lookfor = LOOKFOR_DO;
+ }
if (lookfor != LOOKFOR_INITIAL) {
curwin->w_cursor.lnum = cur_curpos.lnum;
if (find_match(lookfor, ourscope) == OK) {
- amount = get_indent(); /* XXX */
+ amount = get_indent(); // XXX
goto theend;
}
}
@@ -2390,7 +2409,7 @@ int get_c_indent(void)
amount += curbuf->b_ind_cpp_extern_c;
}
} else {
- /* Compensate for adding b_ind_open_extra later. */
+ // Compensate for adding b_ind_open_extra later.
amount -= curbuf->b_ind_open_extra;
if (amount < 0)
amount = 0;
@@ -2399,19 +2418,20 @@ int get_c_indent(void)
lookfor_break = FALSE;
- if (cin_iscase(theline, FALSE)) { /* it's a switch() label */
- lookfor = LOOKFOR_CASE; /* find a previous switch() label */
+ if (cin_iscase(theline, false)) { // it's a switch() label
+ lookfor = LOOKFOR_CASE; // find a previous switch() label
amount += curbuf->b_ind_case;
- } else if (cin_isscopedecl(theline)) { /* private:, ... */
- lookfor = LOOKFOR_SCOPEDECL; /* class decl is this block */
+ } else if (cin_isscopedecl(theline)) { // private:, ...
+ lookfor = LOOKFOR_SCOPEDECL; // class decl is this block
amount += curbuf->b_ind_scopedecl;
} else {
- if (curbuf->b_ind_case_break && cin_isbreak(theline))
- /* break; ... */
- lookfor_break = TRUE;
+ if (curbuf->b_ind_case_break && cin_isbreak(theline)) {
+ // break; ...
+ lookfor_break = true;
+ }
lookfor = LOOKFOR_INITIAL;
- /* b_ind_level from start of block */
+ // b_ind_level from start of block
amount += curbuf->b_ind_level;
}
scope_amount = amount;
@@ -2503,16 +2523,17 @@ int get_c_indent(void)
if (terminated != ';' && cin_isinit())
break;
- /* nothing useful found */
- if (terminated == 0 || terminated == '{')
+ // nothing useful found
+ if (terminated == 0 || terminated == '{') {
continue;
+ }
}
if (terminated != ';') {
- /* Skip parens and braces. Position the cursor
- * over the rightmost paren, so that matching it
- * will take us back to the start of the line.
- */ /* XXX */
+ // Skip parens and braces. Position the cursor
+ // over the rightmost paren, so that matching it
+ // will take us back to the start of the line.
+ // XXX
trypos = NULL;
if (find_last_paren(l, '(', ')'))
trypos = find_match_paren(
@@ -2582,7 +2603,7 @@ int get_c_indent(void)
continue;
}
- /* Finally the actual check for "namespace". */
+ // Finally the actual check for "namespace".
if (cin_is_cpp_namespace(l)) {
amount += curbuf->b_ind_cpp_namespace
- added_to_amount;
@@ -2614,7 +2635,7 @@ int get_c_indent(void)
* If this is a switch() label, may line up relative to that.
* If this is a C++ scope declaration, do the same.
*/
- iscase = cin_iscase(l, FALSE);
+ bool iscase = cin_iscase(l, false);
if (iscase || cin_isscopedecl(l)) {
/* we are only looking for cpp base class
* declaration/initialization any longer */
@@ -2640,27 +2661,24 @@ int get_c_indent(void)
break;
}
- /*
- * case xx: <- line up with this case
- * x = 333;
- * case yy:
- */
- if ( (iscase && lookfor == LOOKFOR_CASE)
- || (iscase && lookfor_break)
- || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) {
- /*
- * Check that this case label is not for another
- * switch()
- */ /* XXX */
+ // case xx: <- line up with this case
+ // x = 333;
+ // case yy:
+ if ((iscase && lookfor == LOOKFOR_CASE)
+ || (iscase && lookfor_break)
+ || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) {
+ // Check that this case label is not for another
+ // switch()
+ // XXX
if ((trypos = find_start_brace()) == NULL
|| trypos->lnum == ourscope) {
- amount = get_indent(); /* XXX */
+ amount = get_indent(); // XXX
break;
}
continue;
}
- n = get_indent_nolabel(curwin->w_cursor.lnum); /* XXX */
+ n = get_indent_nolabel(curwin->w_cursor.lnum); // XXX
/*
* case xx: if (cond) <- line up with this if
@@ -2708,7 +2726,7 @@ int get_c_indent(void)
* case xx:
* -> y = 1;
*/
- scope_amount = get_indent() + (iscase /* XXX */
+ scope_amount = get_indent() + (iscase // XXX
? curbuf->b_ind_case_code
: curbuf->b_ind_scopedecl_code);
lookfor = curbuf->b_ind_case_break
@@ -2750,11 +2768,10 @@ int get_c_indent(void)
continue;
}
- /*
- * Are we at the start of a cpp base class declaration or
- * constructor initialization?
- */ /* XXX */
- n = FALSE;
+ // Are we at the start of a cpp base class declaration or
+ // constructor initialization?
+ // XXX
+ n = 0;
if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) {
n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
l = get_cursor_line_ptr();
@@ -2766,13 +2783,14 @@ int get_c_indent(void)
else
amount += ind_continuation;
} else if (theline[0] == '{') {
- /* Need to find start of the declaration. */
+ // Need to find start of the declaration.
lookfor = LOOKFOR_UNTERM;
ind_continuation = 0;
continue;
- } else
- /* XXX */
+ } else {
+ // XXX
amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
+ }
break;
} else if (lookfor == LOOKFOR_CPP_BASECLASS) {
/* only look, whether there is a cpp base class
@@ -2871,8 +2889,8 @@ int get_c_indent(void)
*/
curwin->w_cursor = *trypos;
l = get_cursor_line_ptr();
- if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) {
- ++curwin->w_cursor.lnum;
+ if (cin_iscase(l, false) || cin_isscopedecl(l)) {
+ curwin->w_cursor.lnum++;
curwin->w_cursor.col = 0;
continue;
}
@@ -3025,9 +3043,10 @@ int get_c_indent(void)
* -> here;
*/
if (lookfor == LOOKFOR_UNTERM) {
- /* When line ends in a comma add extra indent */
- if (terminated == ',')
+ // When line ends in a comma add extra indent
+ if (terminated == ',') {
amount += ind_continuation;
+ }
break;
}
@@ -3144,9 +3163,10 @@ int get_c_indent(void)
if (whilelevel == 0) {
lookfor = LOOKFOR_TERM;
- amount = get_indent(); /* XXX */
- if (theline[0] == '{')
+ amount = get_indent(); // XXX
+ if (theline[0] == '{') {
amount += curbuf->b_ind_open_extra;
+ }
}
++whilelevel;
}
@@ -3174,8 +3194,8 @@ int get_c_indent(void)
if (whilelevel > 0) {
l = cin_skipcomment(get_cursor_line_ptr());
if (cin_isdo(l)) {
- amount = get_indent(); /* XXX */
- --whilelevel;
+ amount = get_indent(); // XXX
+ whilelevel--;
continue;
}
}
@@ -3240,8 +3260,8 @@ term_again:
*/
curwin->w_cursor = *trypos;
l = get_cursor_line_ptr();
- if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) {
- ++curwin->w_cursor.lnum;
+ if (cin_iscase(l, false) || cin_isscopedecl(l)) {
+ curwin->w_cursor.lnum++;
curwin->w_cursor.col = 0;
continue;
}
@@ -3256,8 +3276,7 @@ term_again:
* stat;
* }
*/
- iscase = (curbuf->b_ind_keep_case_label
- && cin_iscase(l, FALSE));
+ iscase = curbuf->b_ind_keep_case_label && cin_iscase(l, false);
/*
* Get indent and pointer to text for current line,
@@ -3267,7 +3286,7 @@ term_again:
if (theline[0] == '{')
amount += curbuf->b_ind_open_extra;
- /* See remark above: "Only add b_ind_open_extra.." */
+ // See remark above: "Only add b_ind_open_extra.."
l = skipwhite(l);
if (*l == '{')
amount -= curbuf->b_ind_open_extra;
@@ -3297,11 +3316,11 @@ term_again:
* that block.
*/
l = get_cursor_line_ptr();
- if (find_last_paren(l, '{', '}') /* XXX */
+ if (find_last_paren(l, '{', '}') // XXX
&& (trypos = find_start_brace()) != NULL) {
curwin->w_cursor = *trypos;
- /* if not "else {" check for terminated again */
- /* but skip block for "} else {" */
+ // if not "else {" check for terminated again
+ // but skip block for "} else {"
l = cin_skipcomment(get_cursor_line_ptr());
if (*l == '}' || !cin_iselse(l))
goto term_again;
@@ -3314,13 +3333,14 @@ term_again:
}
}
- /* add extra indent for a comment */
- if (cin_iscomment(theline))
+ // add extra indent for a comment
+ if (cin_iscomment(theline)) {
amount += curbuf->b_ind_comment;
-
- /* subtract extra left-shift for jump labels */
- if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
+ }
+ // subtract extra left-shift for jump labels
+ if (curbuf->b_ind_jump_label > 0 && original_line_islabel) {
amount -= curbuf->b_ind_jump_label;
+ }
goto theend;
}
@@ -3360,7 +3380,7 @@ term_again:
goto theend;
}
- /* search backwards until we find something we recognize */
+ // search backwards until we find something we recognize
amount = 0;
curwin->w_cursor = cur_curpos;
while (curwin->w_cursor.lnum > 1) {
@@ -3386,7 +3406,7 @@ term_again:
l = get_cursor_line_ptr();
}
if (n) {
- /* XXX */
+ // XXX
amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
break;
}
@@ -3415,11 +3435,11 @@ term_again:
*/
if (cin_ends_in(l, (char_u *)",", NULL)
|| (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) {
- /* take us back to opening paren */
+ // take us back to opening paren
if (find_last_paren(l, '(', ')')
- && (trypos = find_match_paren(
- curbuf->b_ind_maxparen)) != NULL)
+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) {
curwin->w_cursor = *trypos;
+ }
/* For a line ending in ',' that is a continuation line go
* back to the first line with a backslash:
@@ -3435,7 +3455,7 @@ term_again:
curwin->w_cursor.col = 0;
}
- amount = get_indent(); /* XXX */
+ amount = get_indent(); // XXX
if (amount == 0)
amount = cin_first_id_amount();
@@ -3448,8 +3468,9 @@ term_again:
* If the line looks like a function declaration, and we're
* not in a comment, put it the left margin.
*/
- if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) /* XXX */
+ if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) { // XXX
break;
+ }
l = get_cursor_line_ptr();
/*
@@ -3535,13 +3556,14 @@ term_again:
if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
curwin->w_cursor = *trypos;
- amount = get_indent(); /* XXX */
+ amount = get_indent(); // XXX
break;
}
- /* add extra indent for a comment */
- if (cin_iscomment(theline))
+ // add extra indent for a comment
+ if (cin_iscomment(theline)) {
amount += curbuf->b_ind_comment;
+ }
/* add extra indent if the previous line ended in a backslash:
* "asdfasdf\
@@ -3565,7 +3587,7 @@ theend:
amount = 0;
laterend:
- /* put the cursor back where it belongs */
+ // put the cursor back where it belongs
curwin->w_cursor = cur_curpos;
xfree(linecopy);
@@ -3598,7 +3620,7 @@ static int find_match(int lookfor, linenr_T ourscope)
look = cin_skipcomment(get_cursor_line_ptr());
if (!cin_iselse(look)
&& !cin_isif(look)
- && !cin_isdo(look) /* XXX */
+ && !cin_isdo(look) // XXX
&& !cin_iswhileofdo(look, curwin->w_cursor.lnum)) {
continue;
}
@@ -3607,9 +3629,10 @@ static int find_match(int lookfor, linenr_T ourscope)
* if we've gone outside the braces entirely,
* we must be out of scope...
*/
- theirscope = find_start_brace(); /* XXX */
- if (theirscope == NULL)
+ theirscope = find_start_brace(); // XXX
+ if (theirscope == NULL) {
break;
+ }
/*
* and if the brace enclosing this is further
@@ -3649,7 +3672,7 @@ static int find_match(int lookfor, linenr_T ourscope)
continue;
}
- /* If it's an "if" decrement elselevel */
+ // If it's an "if" decrement elselevel
look = cin_skipcomment(get_cursor_line_ptr());
if (cin_isif(look)) {
elselevel--;
@@ -3661,9 +3684,10 @@ static int find_match(int lookfor, linenr_T ourscope)
whilelevel = 0;
}
- /* If it's a "do" decrement whilelevel */
- if (cin_isdo(look))
+ // If it's a "do" decrement whilelevel
+ if (cin_isdo(look)) {
whilelevel--;
+ }
/*
* if we've used up all the elses, then
diff --git a/src/nvim/lib/queue.h b/src/nvim/lib/queue.h
index ab9270081e..452998a5a4 100644
--- a/src/nvim/lib/queue.h
+++ b/src/nvim/lib/queue.h
@@ -33,11 +33,17 @@ typedef struct _queue {
#define QUEUE_DATA(ptr, type, field) \
((type *)((char *)(ptr) - offsetof(type, field)))
-// Important note: mutating the list while QUEUE_FOREACH is
-// iterating over its elements results in undefined behavior.
-#define QUEUE_FOREACH(q, h) \
- for ( /* NOLINT(readability/braces) */ \
- (q) = (h)->next; (q) != (h); (q) = (q)->next)
+// Important note: the node currently being processed can be safely deleted.
+// otherwise, mutating the list while QUEUE_FOREACH is iterating over its
+// elements results in undefined behavior.
+#define QUEUE_FOREACH(q, h, code) \
+ (q) = (h)->next; \
+ while((q) != (h)) { \
+ QUEUE *next = q->next; \
+ code \
+ (q) = next; \
+ }
+
// ffi.cdef is unable to swallow `bool` in place of `int` here.
static inline int QUEUE_EMPTY(const QUEUE *const q)
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 310b194c8c..03d178467b 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1272,6 +1272,12 @@ bool nlua_exec_file(const char *path)
return true;
}
+int tslua_get_language_version(lua_State *L)
+{
+ lua_pushnumber(L, TREE_SITTER_LANGUAGE_VERSION);
+ return 1;
+}
+
static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
tslua_init(lstate);
@@ -1288,8 +1294,11 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, tslua_inspect_lang);
lua_setfield(lstate, -2, "_ts_inspect_language");
- lua_pushcfunction(lstate, ts_lua_parse_query);
+ lua_pushcfunction(lstate, tslua_parse_query);
lua_setfield(lstate, -2, "_ts_parse_query");
+
+ lua_pushcfunction(lstate, tslua_get_language_version);
+ lua_setfield(lstate, -2, "_ts_get_language_version");
}
int nlua_expand_pat(expand_T *xp,
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 33974c71cb..38848b0266 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -222,8 +222,9 @@ int tslua_inspect_lang(lua_State *L)
lua_setfield(L, -2, "symbols"); // [retval]
size_t nfields = (size_t)ts_language_field_count(lang);
- lua_createtable(L, nfields-1, 1); // [retval, fields]
- for (size_t i = 0; i < nfields; i++) {
+ lua_createtable(L, nfields, 1); // [retval, fields]
+ // Field IDs go from 1 to nfields inclusive (extra index 0 maps to NULL)
+ for (size_t i = 1; i <= nfields; i++) {
lua_pushstring(L, ts_language_field_name_for_id(lang, i));
lua_rawseti(L, -2, i); // [retval, fields]
}
@@ -1109,7 +1110,7 @@ static int querycursor_gc(lua_State *L)
// Query methods
-int ts_lua_parse_query(lua_State *L)
+int tslua_parse_query(lua_State *L)
{
if (lua_gettop(L) < 2 || !lua_isstring(L, 1) || !lua_isstring(L, 2)) {
return luaL_error(L, "string expected");
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 71cb345878..7c98d3c6b5 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -869,18 +869,18 @@ char_u *msg_trunc_attr(char_u *s, int force, int attr)
*/
char_u *msg_may_trunc(int force, char_u *s)
{
- int n;
int room;
room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
if ((force || (shortmess(SHM_TRUNC) && !exmode_active))
- && (n = (int)STRLEN(s) - room) > 0) {
+ && (int)STRLEN(s) - room > 0) {
int size = vim_strsize(s);
// There may be room anyway when there are multibyte chars.
if (size <= room) {
return s;
}
+ int n;
for (n = 0; size >= room; ) {
size -= utf_ptr2cells(s + n);
n += utfc_ptr2len(s + n);
@@ -1705,6 +1705,7 @@ void msg_prt_line(char_u *s, int list)
char_u *p_extra = NULL; // init to make SASC shut up
int n;
int attr = 0;
+ char_u *lead = NULL;
char_u *trail = NULL;
int l;
@@ -1712,11 +1713,24 @@ void msg_prt_line(char_u *s, int list)
list = true;
}
- // find start of trailing whitespace
- if (list && curwin->w_p_lcs_chars.trail) {
- trail = s + STRLEN(s);
- while (trail > s && ascii_iswhite(trail[-1])) {
- trail--;
+ if (list) {
+ // find start of trailing whitespace
+ if (curwin->w_p_lcs_chars.trail) {
+ trail = s + STRLEN(s);
+ while (trail > s && ascii_iswhite(trail[-1])) {
+ trail--;
+ }
+ }
+ // find end of leading whitespace
+ if (curwin->w_p_lcs_chars.lead) {
+ lead = s;
+ while (ascii_iswhite(lead[0])) {
+ lead++;
+ }
+ // in a line full of spaces all of them are treated as trailing
+ if (*lead == NUL) {
+ lead = NULL;
+ }
}
}
@@ -1758,7 +1772,9 @@ void msg_prt_line(char_u *s, int list)
c = *s++;
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
// tab amount depends on current column
- n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
+ n_extra = tabstop_padding(col,
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array) - 1;
if (!list) {
c = ' ';
c_extra = ' ';
@@ -1791,6 +1807,9 @@ void msg_prt_line(char_u *s, int list)
/* Use special coloring to be able to distinguish <hex> from
* the same in plain text. */
attr = HL_ATTR(HLF_8);
+ } else if (c == ' ' && lead != NULL && s <= lead) {
+ c = curwin->w_p_lcs_chars.lead;
+ attr = HL_ATTR(HLF_8);
} else if (c == ' ' && trail != NULL && s > trail) {
c = curwin->w_p_lcs_chars.trail;
attr = HL_ATTR(HLF_8);
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index fa9787a3ac..4c0339e5f4 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -748,7 +748,7 @@ int mouse_check_fold(void)
}
}
- if (mouse_char == wp->w_p_fcs_chars.foldclosed) {
+ if (wp && mouse_char == wp->w_p_fcs_chars.foldclosed) {
return MOUSE_FOLD_OPEN;
} else if (mouse_char != ' ') {
return MOUSE_FOLD_CLOSE;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 0b4e2e1f23..3587b12277 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -6777,9 +6777,10 @@ static void nv_g_cmd(cmdarg_T *cap)
}
coladvance((colnr_T)i);
if (flag) {
- do
+ do {
i = gchar_cursor();
- while (ascii_iswhite(i) && oneright());
+ } while (ascii_iswhite(i) && oneright());
+ curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = true;
break;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 0ff427c261..2cd71f2360 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -288,7 +288,7 @@ void shift_line(
{
int count;
int i, j;
- int p_sw = get_sw_value(curbuf);
+ int p_sw = (int)get_sw_value_indent(curbuf);
count = get_indent(); // get current indent
@@ -332,8 +332,9 @@ static void shift_block(oparg_T *oap, int amount)
const int oldstate = State;
char_u *newp;
const int oldcol = curwin->w_cursor.col;
- const int p_sw = get_sw_value(curbuf);
- const int p_ts = (int)curbuf->b_p_ts;
+ int p_sw = (int)get_sw_value_indent(curbuf);
+ long *p_vts = curbuf->b_p_vts_array;
+ const long p_ts = curbuf->b_p_ts;
struct block_def bd;
int incr;
int i = 0, j = 0;
@@ -383,12 +384,11 @@ static void shift_block(oparg_T *oap, int amount)
}
/* OK, now total=all the VWS reqd, and textstart points at the 1st
* non-ws char in the block. */
- if (!curbuf->b_p_et)
- i = ((ws_vcol % p_ts) + total) / p_ts; /* number of tabs */
- if (i)
- j = ((ws_vcol % p_ts) + total) % p_ts; /* number of spp */
- else
+ if (!curbuf->b_p_et) {
+ tabstop_fromto(ws_vcol, ws_vcol + total, p_ts, p_vts, &i, &j);
+ } else {
j = total;
+ }
// if we're splitting a TAB, allow for it
int col_pre = bd.pre_whitesp_c - (bd.startspaces != 0);
@@ -1079,13 +1079,15 @@ do_execreg(
}
}
escaped = vim_strsave_escape_csi(reg->y_array[i]);
- retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
+ retval = ins_typebuf(escaped, remap, 0, true, silent);
xfree(escaped);
- if (retval == FAIL)
+ if (retval == FAIL) {
return FAIL;
- if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
- == FAIL)
+ }
+ if (colon
+ && ins_typebuf((char_u *)":", remap, 0, true, silent) == FAIL) {
return FAIL;
+ }
}
reg_executing = regname == 0 ? '"' : regname; // disable the 'q' command
}
@@ -1109,8 +1111,9 @@ static void put_reedit_in_typebuf(int silent)
buf[0] = (char_u)(restart_edit == 'I' ? 'i' : restart_edit);
buf[1] = NUL;
}
- if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
+ if (ins_typebuf(buf, REMAP_NONE, 0, true, silent) == OK) {
restart_edit = NUL;
+ }
}
}
@@ -1130,25 +1133,29 @@ static int put_in_typebuf(
int retval = OK;
put_reedit_in_typebuf(silent);
- if (colon)
- retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
+ if (colon) {
+ retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, true, silent);
+ }
if (retval == OK) {
char_u *p;
- if (esc)
+ if (esc) {
p = vim_strsave_escape_csi(s);
- else
+ } else {
p = s;
- if (p == NULL)
+ }
+ if (p == NULL) {
retval = FAIL;
- else
- retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
- 0, TRUE, silent);
- if (esc)
+ } else {
+ retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES, 0, true, silent);
+ }
+ if (esc) {
xfree(p);
+ }
+ }
+ if (colon && retval == OK) {
+ retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, true, silent);
}
- if (colon && retval == OK)
- retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
return retval;
}
@@ -2800,7 +2807,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
size_t y_size;
size_t oldlen;
int y_width = 0;
- colnr_T vcol;
+ colnr_T vcol = 0;
int delcount;
int incr = 0;
struct block_def bd;
@@ -3061,14 +3068,17 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (gchar_cursor() == TAB) {
/* Don't need to insert spaces when "p" on the last position of a
* tab or "P" on the first position. */
+ int viscol = getviscol();
if (dir == FORWARD
- ? (int)curwin->w_cursor.coladd < curbuf->b_p_ts - 1
- : curwin->w_cursor.coladd > 0)
- coladvance_force(getviscol());
- else
+ ? tabstop_padding(viscol, curbuf->b_p_ts, curbuf->b_p_vts_array) != 1
+ : curwin->w_cursor.coladd > 0) {
+ coladvance_force(viscol);
+ } else {
curwin->w_cursor.coladd = 0;
- } else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
+ }
+ } else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL) {
coladvance_force(getviscol() + (dir == FORWARD));
+ }
}
lnum = curwin->w_cursor.lnum;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index d04329e104..612ecca96a 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -180,6 +180,8 @@ static long p_ts;
static long p_tw;
static int p_udf;
static long p_wm;
+static char_u *p_vsts;
+static char_u *p_vts;
static char_u *p_keymap;
// Saved values for when 'bin' is set.
@@ -194,6 +196,7 @@ static int p_et_nopaste;
static long p_sts_nopaste;
static long p_tw_nopaste;
static long p_wm_nopaste;
+static char_u *p_vsts_nopaste;
typedef struct vimoption {
char *fullname; // full option name
@@ -379,8 +382,8 @@ void set_init_1(bool clean_arg)
# else
static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
# endif
- int len;
garray_T ga;
+ opt_idx = findoption("backupskip");
ga_init(&ga, 1, 100);
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
@@ -401,15 +404,23 @@ void set_init_1(bool clean_arg)
}
if (p != NULL && *p != NUL) {
// First time count the NUL, otherwise count the ','.
- len = (int)strlen(p) + 3;
- ga_grow(&ga, len);
- if (!GA_EMPTY(&ga)) {
- STRCAT(ga.ga_data, ",");
+ const size_t len = strlen(p) + 3;
+ char *item = xmalloc(len);
+ xstrlcpy(item, p, len);
+ add_pathsep(item);
+ xstrlcat(item, "*", len);
+ if (find_dup_item(ga.ga_data, (char_u *)item, options[opt_idx].flags)
+ == NULL) {
+ ga_grow(&ga, (int)len);
+ if (!GA_EMPTY(&ga)) {
+ STRCAT(ga.ga_data, ",");
+ }
+ STRCAT(ga.ga_data, p);
+ add_pathsep(ga.ga_data);
+ STRCAT(ga.ga_data, "*");
+ ga.ga_len += (int)len;
}
- STRCAT(ga.ga_data, p);
- add_pathsep(ga.ga_data);
- STRCAT(ga.ga_data, "*");
- ga.ga_len += len;
+ xfree(item);
}
if(mustfree) {
xfree(p);
@@ -713,6 +724,38 @@ static void set_string_default(const char *name, char *val, bool allocated)
}
}
+// For an option value that contains comma separated items, find "newval" in
+// "origval". Return NULL if not found.
+static char_u *find_dup_item(char_u *origval, const char_u *newval,
+ uint32_t flags)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ int bs = 0;
+
+ if (origval == NULL) {
+ return NULL;
+ }
+
+ const size_t newlen = STRLEN(newval);
+ for (char_u *s = origval; *s != NUL; s++) {
+ if ((!(flags & P_COMMA) || s == origval || (s[-1] == ',' && !(bs & 1)))
+ && STRNCMP(s, newval, newlen) == 0
+ && (!(flags & P_COMMA) || s[newlen] == ',' || s[newlen] == NUL)) {
+ return s;
+ }
+ // Count backslashes. Only a comma with an even number of backslashes
+ // or a single backslash preceded by a comma before it is recognized as
+ // a separator.
+ if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
+ || (s == origval + 1 && s[-1] == '\\')) {
+ bs++;
+ } else {
+ bs = 0;
+ }
+ }
+ return NULL;
+}
+
/// Set the Vi-default value of a number option.
/// Used for 'lines' and 'columns'.
void set_number_default(char *name, long val)
@@ -1285,9 +1328,7 @@ int do_set(
char *saved_newval = NULL;
unsigned newlen;
int comma;
- int bs;
- int new_value_alloced; /* new string option
- was allocated */
+ bool new_value_alloced = false; // new string option was allocated
/* When using ":set opt=val" for a global option
* with a local value the local value will be
@@ -1486,34 +1527,20 @@ int do_set(
i = 0; // init for GCC
if (removing || (flags & P_NODUP)) {
i = (int)STRLEN(newval);
- bs = 0;
- for (s = origval; *s; s++) {
- if ((!(flags & P_COMMA)
- || s == origval
- || (s[-1] == ',' && !(bs & 1)))
- && STRNCMP(s, newval, i) == 0
- && (!(flags & P_COMMA)
- || s[i] == ','
- || s[i] == NUL)) {
- break;
- }
- // Count backslashes. Only a comma with an even number of
- // backslashes or a single backslash preceded by a comma
- // before it is recognized as a separator
- if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
- || (s == origval + 1 && s[-1] == '\\')) {
- bs++;
- } else {
- bs = 0;
- }
- }
+ s = find_dup_item(origval, newval, flags);
// do not add if already there
- if ((adding || prepending) && *s) {
+ if ((adding || prepending) && s != NULL) {
prepending = false;
adding = false;
STRCPY(newval, origval);
}
+
+ // if no duplicate, move pointer to end of
+ // original value
+ if (s == NULL) {
+ s = origval + (int)STRLEN(origval);
+ }
}
/* concatenate the two strings; add a ',' if
@@ -1974,6 +2001,10 @@ static void didset_options2(void)
// Parse default for 'wildmode'.
check_opt_wim();
+ xfree(curbuf->b_p_vsts_array);
+ tabstop_set(curbuf->b_p_vsts, &curbuf->b_p_vsts_array);
+ xfree(curbuf->b_p_vts_array);
+ tabstop_set(curbuf->b_p_vts, &curbuf->b_p_vts_array);
}
/// Check for string options that are NULL (normally only termcap options).
@@ -2040,6 +2071,8 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_lw);
check_string_option(&buf->b_p_bkc);
check_string_option(&buf->b_p_menc);
+ check_string_option(&buf->b_p_vsts);
+ check_string_option(&buf->b_p_vts);
}
/// Free the string allocated for an option.
@@ -2310,7 +2343,7 @@ static char_u *
did_set_string_option(
int opt_idx, // index in options[] table
char_u **varp, // pointer to the option variable
- int new_value_alloced, // new value was allocated
+ bool new_value_alloced, // new value was allocated
char_u *oldval, // previous value of the option
char_u *errbuf, // buffer for errors, or NULL
size_t errbuflen, // length of errors buffer
@@ -3086,6 +3119,65 @@ ambw_end:
if (opt_strings_flags(p_tpf, p_tpf_values, &tpf_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (varp == &(curbuf->b_p_vsts)) { // 'varsofttabstop'
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
+ if (curbuf->b_p_vsts_array) {
+ xfree(curbuf->b_p_vsts_array);
+ curbuf->b_p_vsts_array = 0;
+ }
+ } else {
+ for (cp = *varp; *cp; cp++) {
+ if (ascii_isdigit(*cp)) {
+ continue;
+ }
+ if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
+ continue;
+ }
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL) {
+ long *oldarray = curbuf->b_p_vsts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vsts_array))) {
+ xfree(oldarray);
+ } else {
+ errmsg = e_invarg;
+ }
+ }
+ }
+ } else if (varp == &(curbuf->b_p_vts)) { // 'vartabstop'
+ char_u *cp;
+
+ if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
+ if (curbuf->b_p_vts_array) {
+ xfree(curbuf->b_p_vts_array);
+ curbuf->b_p_vts_array = NULL;
+ }
+ } else {
+ for (cp = *varp; *cp; cp++) {
+ if (ascii_isdigit(*cp)) {
+ continue;
+ }
+ if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
+ continue;
+ }
+ errmsg = e_invarg;
+ break;
+ }
+ if (errmsg == NULL) {
+ long *oldarray = curbuf->b_p_vts_array;
+ if (tabstop_set(*varp, &(curbuf->b_p_vts_array))) {
+ xfree(oldarray);
+ if (foldmethodIsIndent(curwin)) {
+ foldUpdateAll(curwin);
+ }
+ } else {
+ errmsg = e_invarg;
+ }
+ }
+ }
} else {
// Options that are a list of flags.
p = NULL;
@@ -3385,6 +3477,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
{ &wp->w_p_lcs_chars.prec, "precedes", NUL },
{ &wp->w_p_lcs_chars.space, "space", NUL },
{ &wp->w_p_lcs_chars.tab2, "tab", NUL },
+ { &wp->w_p_lcs_chars.lead, "lead", NUL },
{ &wp->w_p_lcs_chars.trail, "trail", NUL },
{ &wp->w_p_lcs_chars.conceal, "conceal", NUL },
};
@@ -5660,6 +5753,8 @@ static char_u *get_varp(vimoption_T *p)
case PV_TW: return (char_u *)&(curbuf->b_p_tw);
case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
case PV_WM: return (char_u *)&(curbuf->b_p_wm);
+ case PV_VSTS: return (char_u *)&(curbuf->b_p_vsts);
+ case PV_VTS: return (char_u *)&(curbuf->b_p_vts);
case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
case PV_SCL: return (char_u *)&(curwin->w_p_scl);
case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
@@ -5911,6 +6006,15 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_tfu = vim_strsave(p_tfu);
buf->b_p_sts = p_sts;
buf->b_p_sts_nopaste = p_sts_nopaste;
+ buf->b_p_vsts = vim_strsave(p_vsts);
+ if (p_vsts && p_vsts != empty_option) {
+ tabstop_set(p_vsts, &buf->b_p_vsts_array);
+ } else {
+ buf->b_p_vsts_array = 0;
+ }
+ buf->b_p_vsts_nopaste = p_vsts_nopaste
+ ? vim_strsave(p_vsts_nopaste)
+ : NULL;
buf->b_p_com = vim_strsave(p_com);
buf->b_p_cms = vim_strsave(p_cms);
buf->b_p_fo = vim_strsave(p_fo);
@@ -5982,10 +6086,21 @@ void buf_copy_options(buf_T *buf, int flags)
*/
if (dont_do_help) {
buf->b_p_isk = save_p_isk;
+ if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) {
+ tabstop_set(p_vts, &buf->b_p_vts_array);
+ } else {
+ buf->b_p_vts_array = NULL;
+ }
} else {
buf->b_p_isk = vim_strsave(p_isk);
did_isk = true;
buf->b_p_ts = p_ts;
+ buf->b_p_vts = vim_strsave(p_vts);
+ if (p_vts && p_vts != empty_option && !buf->b_p_vts_array) {
+ tabstop_set(p_vts, &buf->b_p_vts_array);
+ } else {
+ buf->b_p_vts_array = NULL;
+ }
buf->b_help = false;
if (buf->b_p_bt[0] == 'h') {
clear_string_option(&buf->b_p_bt);
@@ -6600,6 +6715,12 @@ static void paste_option_changed(void)
buf->b_p_sts_nopaste = buf->b_p_sts;
buf->b_p_ai_nopaste = buf->b_p_ai;
buf->b_p_et_nopaste = buf->b_p_et;
+ if (buf->b_p_vsts_nopaste) {
+ xfree(buf->b_p_vsts_nopaste);
+ }
+ buf->b_p_vsts_nopaste = buf->b_p_vsts && buf->b_p_vsts != empty_option
+ ? vim_strsave(buf->b_p_vsts)
+ : NULL;
}
// save global options
@@ -6614,6 +6735,12 @@ static void paste_option_changed(void)
p_sts_nopaste = p_sts;
p_tw_nopaste = p_tw;
p_wm_nopaste = p_wm;
+ if (p_vsts_nopaste) {
+ xfree(p_vsts_nopaste);
+ }
+ p_vsts_nopaste = p_vsts && p_vsts != empty_option
+ ? vim_strsave(p_vsts)
+ : NULL;
}
// Always set the option values, also when 'paste' is set when it is
@@ -6625,6 +6752,14 @@ static void paste_option_changed(void)
buf->b_p_sts = 0; // softtabstop is 0
buf->b_p_ai = 0; // no auto-indent
buf->b_p_et = 0; // no expandtab
+ if (buf->b_p_vsts) {
+ free_string_option(buf->b_p_vsts);
+ }
+ buf->b_p_vsts = empty_option;
+ if (buf->b_p_vsts_array) {
+ xfree(buf->b_p_vsts_array);
+ }
+ buf->b_p_vsts_array = 0;
}
// set global options
@@ -6641,6 +6776,10 @@ static void paste_option_changed(void)
p_wm = 0;
p_sts = 0;
p_ai = 0;
+ if (p_vsts) {
+ free_string_option(p_vsts);
+ }
+ p_vsts = empty_option;
} else if (old_p_paste) {
// Paste switched from on to off: Restore saved values.
@@ -6651,6 +6790,20 @@ static void paste_option_changed(void)
buf->b_p_sts = buf->b_p_sts_nopaste;
buf->b_p_ai = buf->b_p_ai_nopaste;
buf->b_p_et = buf->b_p_et_nopaste;
+ if (buf->b_p_vsts) {
+ free_string_option(buf->b_p_vsts);
+ }
+ buf->b_p_vsts = buf->b_p_vsts_nopaste
+ ? vim_strsave(buf->b_p_vsts_nopaste)
+ : empty_option;
+ if (buf->b_p_vsts_array) {
+ xfree(buf->b_p_vsts_array);
+ }
+ if (buf->b_p_vsts && buf->b_p_vsts != empty_option) {
+ tabstop_set(buf->b_p_vsts, &buf->b_p_vsts_array);
+ } else {
+ buf->b_p_vsts_array = 0;
+ }
}
// restore global options
@@ -6668,6 +6821,10 @@ static void paste_option_changed(void)
p_sts = p_sts_nopaste;
p_tw = p_tw_nopaste;
p_wm = p_wm_nopaste;
+ if (p_vsts) {
+ free_string_option(p_vsts);
+ }
+ p_vsts = p_vsts_nopaste ? vim_strsave(p_vsts_nopaste) : empty_option;
}
old_p_paste = p_paste;
@@ -6917,17 +7074,301 @@ int check_ff_value(char_u *p)
return check_opt_strings(p, p_ff_values, false);
}
+// Set the integer values corresponding to the string setting of 'vartabstop'.
+// "array" will be set, caller must free it if needed.
+bool tabstop_set(char_u *var, long **array)
+{
+ long valcount = 1;
+ int t;
+ char_u *cp;
+
+ if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) {
+ *array = NULL;
+ return true;
+ }
+
+ for (cp = var; *cp != NUL; cp++) {
+ if (cp == var || cp[-1] == ',') {
+ char_u *end;
+
+ if (strtol((char *)cp, (char **)&end, 10) <= 0) {
+ if (cp != end) {
+ EMSG(_(e_positive));
+ } else {
+ EMSG(_(e_invarg));
+ }
+ return false;
+ }
+ }
+
+ if (ascii_isdigit(*cp)) {
+ continue;
+ }
+ if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) {
+ valcount++;
+ continue;
+ }
+ EMSG(_(e_invarg));
+ return false;
+ }
+
+ *array = (long *)xmalloc((unsigned)(valcount + 1) * sizeof(long));
+ (*array)[0] = valcount;
+
+ t = 1;
+ for (cp = var; *cp != NUL;) {
+ (*array)[t++] = atoi((char *)cp);
+ while (*cp != NUL && *cp != ',') {
+ cp++;
+ }
+ if (*cp != NUL) {
+ cp++;
+ }
+ }
+
+ return true;
+}
+
+// Calculate the number of screen spaces a tab will occupy.
+// If "vts" is set then the tab widths are taken from that array,
+// otherwise the value of ts is used.
+int tabstop_padding(colnr_T col, long ts_arg, long *vts)
+{
+ long ts = ts_arg == 0 ? 8 : ts_arg;
+ colnr_T tabcol = 0;
+ int t;
+ long padding = 0;
+
+ if (vts == NULL || vts[0] == 0) {
+ return (int)(ts - (col % ts));
+ }
+
+ const long tabcount = vts[0];
+
+ for (t = 1; t <= tabcount; t++) {
+ tabcol += (colnr_T)vts[t];
+ if (tabcol > col) {
+ padding = tabcol - col;
+ break;
+ }
+ }
+ if (t > tabcount) {
+ padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]);
+ }
+
+ return (int)padding;
+}
+
+// Find the size of the tab that covers a particular column.
+int tabstop_at(colnr_T col, long ts, long *vts)
+{
+ colnr_T tabcol = 0;
+ int t;
+ long tab_size = 0;
+
+ if (vts == NULL || vts[0] == 0) {
+ return (int)ts;
+ }
+
+ const long tabcount = vts[0];
+ for (t = 1; t <= tabcount; t++) {
+ tabcol += (colnr_T)vts[t];
+ if (tabcol > col) {
+ tab_size = vts[t];
+ break;
+ }
+ }
+ if (t > tabcount) {
+ tab_size = vts[tabcount];
+ }
+
+ return (int)tab_size;
+}
+
+// Find the column on which a tab starts.
+colnr_T tabstop_start(colnr_T col, long ts, long *vts)
+{
+ colnr_T tabcol = 0;
+ int t;
+
+ if (vts == NULL || vts[0] == 0) {
+ return (int)((col / ts) * ts);
+ }
+
+ const long tabcount = vts[0];
+ for (t = 1; t <= tabcount; t++) {
+ tabcol += (colnr_T)vts[t];
+ if (tabcol > col) {
+ return (int)(tabcol - vts[t]);
+ }
+ }
+
+ const int excess = (int)(tabcol % vts[tabcount]);
+ return (int)(excess + ((col - excess) / vts[tabcount]) * vts[tabcount]);
+}
+
+// Find the number of tabs and spaces necessary to get from one column
+// to another.
+void tabstop_fromto(colnr_T start_col,
+ colnr_T end_col,
+ long ts_arg,
+ long *vts,
+ int *ntabs,
+ int *nspcs)
+{
+ int spaces = end_col - start_col;
+ colnr_T tabcol = 0;
+ long padding = 0;
+ int t;
+ long ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
+
+ if (vts == NULL || vts[0] == 0) {
+ int tabs = 0;
+
+ const int initspc = (int)(ts - (start_col % ts));
+ if (spaces >= initspc) {
+ spaces -= initspc;
+ tabs++;
+ }
+ tabs += (int)(spaces / ts);
+ spaces -= (int)((spaces / ts) * ts);
+
+ *ntabs = tabs;
+ *nspcs = spaces;
+ return;
+ }
+
+ // Find the padding needed to reach the next tabstop.
+ const long tabcount = vts[0];
+ for (t = 1; t <= tabcount; t++) {
+ tabcol += (colnr_T)vts[t];
+ if (tabcol > start_col) {
+ padding = tabcol - start_col;
+ break;
+ }
+ }
+ if (t > tabcount) {
+ padding = vts[tabcount] - ((start_col - tabcol) % vts[tabcount]);
+ }
+
+ // If the space needed is less than the padding no tabs can be used.
+ if (spaces < padding) {
+ *ntabs = 0;
+ *nspcs = spaces;
+ return;
+ }
+
+ *ntabs = 1;
+ spaces -= (int)padding;
+
+ // At least one tab has been used. See if any more will fit.
+ while (spaces != 0 && ++t <= tabcount) {
+ padding = vts[t];
+ if (spaces < padding) {
+ *nspcs = spaces;
+ return;
+ }
+ *ntabs += 1;
+ spaces -= (int)padding;
+ }
+
+ *ntabs += spaces / (int)vts[tabcount];
+ *nspcs = spaces % (int)vts[tabcount];
+}
+
+// See if two tabstop arrays contain the same values.
+bool tabstop_eq(long *ts1, long *ts2)
+{
+ int t;
+
+ if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0)) {
+ return false;
+ }
+ if (ts1 == ts2) {
+ return true;
+ }
+ if (ts1[0] != ts2[0]) {
+ return false;
+ }
+
+ for (t = 1; t <= ts1[0]; t++) {
+ if (ts1[t] != ts2[t]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Copy a tabstop array, allocating space for the new array.
+int *tabstop_copy(long *oldts)
+{
+ long *newts;
+ int t;
+
+ if (oldts == 0) {
+ return 0;
+ }
+
+ newts = xmalloc((unsigned)(oldts[0] + 1) * sizeof(long));
+ for (t = 0; t <= oldts[0]; t++) {
+ newts[t] = oldts[t];
+ }
+
+ return (int *)newts;
+}
+
+// Return a count of the number of tabstops.
+int tabstop_count(long *ts)
+{
+ return ts != NULL ? (int)ts[0] : 0;
+}
+
+// Return the first tabstop, or 8 if there are no tabstops defined.
+int tabstop_first(long *ts)
+{
+ return ts != NULL ? (int)ts[1] : 8;
+}
+
/// Return the effective shiftwidth value for current buffer, using the
/// 'tabstop' value when 'shiftwidth' is zero.
int get_sw_value(buf_T *buf)
{
- long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
+ long result = get_sw_value_col(buf, 0);
assert(result >= 0 && result <= INT_MAX);
return (int)result;
}
+// Idem, using the first non-black in the current line.
+long get_sw_value_indent(buf_T *buf)
+{
+ pos_T pos = curwin->w_cursor;
+
+ pos.col = (colnr_T)getwhitecols_curline();
+ return get_sw_value_pos(buf, &pos);
+}
+
+// Idem, using "pos".
+long get_sw_value_pos(buf_T *buf, pos_T *pos)
+{
+ pos_T save_cursor = curwin->w_cursor;
+ long sw_value;
+
+ curwin->w_cursor = *pos;
+ sw_value = get_sw_value_col(buf, get_nolist_virtcol());
+ curwin->w_cursor = save_cursor;
+ return sw_value;
+}
+
+// Idem, using virtual column "col".
+long get_sw_value_col(buf_T *buf, colnr_T col)
+{
+ return buf->b_p_sw ? buf->b_p_sw
+ : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+}
+
/// Return the effective softtabstop value for the current buffer,
-/// using the effective shiftwidth value when 'softtabstop' is negative.
+/// using the shiftwidth value when 'softtabstop' is negative.
int get_sts_value(void)
{
long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 43b0107800..16749ba86b 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -165,8 +165,8 @@ enum {
SHM_WRI = 'w', ///< "[w]" instead of "written".
SHM_ABBREVIATIONS = 'a', ///< Use abbreviations from #SHM_ALL_ABBREVIATIONS.
SHM_WRITE = 'W', ///< Don't use "written" at all.
- SHM_TRUNC = 't', ///< Trunctate file messages.
- SHM_TRUNCALL = 'T', ///< Trunctate all messages.
+ SHM_TRUNC = 't', ///< Truncate file messages.
+ SHM_TRUNCALL = 'T', ///< Truncate all messages.
SHM_OVER = 'o', ///< Overwrite file messages.
SHM_OVERALL = 'O', ///< Overwrite more messages.
SHM_SEARCH = 's', ///< No search hit bottom messages.
@@ -824,6 +824,8 @@ enum {
, BV_UDF
, BV_UL
, BV_WM
+ , BV_VSTS
+ , BV_VTS
, BV_COUNT // must be the last one
};
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index f4c1ac9131..d12b31bcaf 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2999,6 +2999,23 @@ return {
defaults={if_true={vi=4000}}
},
{
+ full_name='varsofttabstop', abbreviation='vsts',
+ short_desc=N_("list of numbers of spaces that <Tab> uses while editing"),
+ type='string', list='comma', scope={'buffer'},
+ vi_def=true,
+ varname='p_vsts',
+ defaults={if_true={vi=""}}
+ },
+ {
+ full_name='vartabstop', abbreviation='vts',
+ short_desc=N_("list of numbers of spaces that <Tab> in file uses"),
+ type='string', list='comma', scope={'buffer'},
+ vi_def=true,
+ varname='p_vts',
+ redraw={'current_buffer'},
+ defaults={if_true={vi=""}}
+ },
+ {
full_name='verbose', abbreviation='vbs',
short_desc=N_("give informative messages"),
type='number', scope={'global'},
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 52d2f84ace..94444e4d23 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -343,19 +343,17 @@ static int build_cmd_line(char **argv, wchar_t **cmd_line, bool is_cmdexe)
utf8_cmd_line_len += argc;
char *utf8_cmd_line = xmalloc(utf8_cmd_line_len);
*utf8_cmd_line = NUL;
- while (1) {
- QUEUE *head = QUEUE_HEAD(&args_q);
- QUEUE_REMOVE(head);
- ArgNode *arg_node = QUEUE_DATA(head, ArgNode, node);
+ QUEUE *q;
+ QUEUE_FOREACH(q, &args_q, {
+ ArgNode *arg_node = QUEUE_DATA(q, ArgNode, node);
xstrlcat(utf8_cmd_line, arg_node->arg, utf8_cmd_line_len);
xfree(arg_node->arg);
xfree(arg_node);
- if (QUEUE_EMPTY(&args_q)) {
- break;
- } else {
+ QUEUE_REMOVE(q);
+ if (!QUEUE_EMPTY(&args_q)) {
xstrlcat(utf8_cmd_line, " ", utf8_cmd_line_len);
}
- }
+ })
int result = utf8_to_utf16(utf8_cmd_line, -1, cmd_line);
xfree(utf8_cmd_line);
@@ -507,11 +505,11 @@ static int build_env_block(dict_T *denv, wchar_t **env_block)
*env_block = xmalloc(sizeof(**env_block) * env_block_len);
wchar_t *pos = *env_block;
- QUEUE_FOREACH(q, &env_q) {
+ QUEUE_FOREACH(q, &env_q, {
EnvNode *env_node = QUEUE_DATA(q, EnvNode, node);
memcpy(pos, env_node->str, env_node->len * sizeof(*pos));
pos += env_node->len;
- }
+ })
*pos = L'\0';
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index b5d890bf52..2974245857 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -123,7 +123,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
int shell_style = STYLE_ECHO;
int check_spaces;
static bool did_find_nul = false;
- bool ampersent = false;
+ bool ampersand = false;
// vimglob() function to define for Posix shell
static char *sh_vimglob_func =
"vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
@@ -245,7 +245,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
p--;
}
if (*p == '&') { // remove trailing '&'
- ampersent = true;
+ ampersand = true;
*p = ' ';
}
STRCAT(command, ">");
@@ -309,7 +309,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
shellopts |= kShellOptHideMess;
}
- if (ampersent) {
+ if (ampersand) {
STRCAT(command, "&"); // put the '&' after the redirection
}
@@ -331,7 +331,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
// When running in the background, give it some time to create the temp
// file, but don't wait for it to finish.
- if (ampersent) {
+ if (ampersand) {
os_delay(10L, true);
}
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 5cf628935f..e7e0dc4013 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -196,6 +196,22 @@ char *os_ctime(char *result, size_t result_len)
return os_ctime_r(&rawtime, result, result_len);
}
+/// Portable version of POSIX strptime()
+///
+/// @param str[in] string to convert
+/// @param format[in] format to parse "str"
+/// @param tm[out] time representation of "str"
+/// @return Pointer to first unprocessed character or NULL
+char *os_strptime(const char *str, const char *format, struct tm *tm)
+ FUNC_ATTR_NONNULL_ALL
+{
+#ifdef HAVE_STRPTIME
+ return strptime(str, format, tm);
+#else
+ return NULL;
+#endif
+}
+
/// Obtains the current Unix timestamp.
///
/// @return Seconds since epoch.
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 68abf57413..32c9750628 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -398,7 +398,7 @@ void pum_redraw(void)
char_u *p = NULL;
int totwidth, width, w;
int thumb_pos = 0;
- int thumb_heigth = 1;
+ int thumb_height = 1;
int round;
int n;
@@ -449,11 +449,11 @@ void pum_redraw(void)
}
if (pum_scrollbar) {
- thumb_heigth = pum_height * pum_height / pum_size;
- if (thumb_heigth == 0) {
- thumb_heigth = 1;
+ thumb_height = pum_height * pum_height / pum_size;
+ if (thumb_height == 0) {
+ thumb_height = 1;
}
- thumb_pos = (pum_first * (pum_height - thumb_heigth)
+ thumb_pos = (pum_first * (pum_height - thumb_height)
+ (pum_size - pum_height) / 2)
/ (pum_size - pum_height);
}
@@ -616,11 +616,11 @@ void pum_redraw(void)
if (pum_scrollbar > 0) {
if (pum_rl) {
grid_putchar(&pum_grid, ' ', row, col_off - pum_width,
- i >= thumb_pos && i < thumb_pos + thumb_heigth
+ i >= thumb_pos && i < thumb_pos + thumb_height
? attr_thumb : attr_scroll);
} else {
grid_putchar(&pum_grid, ' ', row, col_off + pum_width,
- i >= thumb_pos && i < thumb_pos + thumb_heigth
+ i >= thumb_pos && i < thumb_pos + thumb_height
? attr_thumb : attr_scroll);
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index dfd38a6eca..0785fa703d 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3617,6 +3617,15 @@ static int qf_open_new_cwindow(qf_info_T *qi, int height)
if (win_split(height, flags) == FAIL) {
return FAIL; // not enough room for window
}
+
+ // User autocommands may have invalidated the previous window after calling
+ // win_split, so add a check to ensure that the win is still here
+ if (IS_LL_STACK(qi) && !win_valid(win)) {
+ // close the window that was supposed to be for the loclist
+ win_close(curwin, false);
+ return FAIL;
+ }
+
RESET_BINDING(curwin);
if (IS_LL_STACK(qi)) {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index a2589ac431..d7693c7a6f 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -5895,7 +5895,7 @@ static void regdump(char_u *pattern, bt_regprog_T *r)
fprintf(f, " count %" PRId64, (int64_t)OPERAND_MIN(s));
s += 4;
} else if (op == RE_LNUM || op == RE_COL || op == RE_VCOL) {
- /* one int plus comperator */
+ // one int plus comparator
fprintf(f, " count %" PRId64, (int64_t)OPERAND_MIN(s));
s += 5;
}
@@ -7139,6 +7139,7 @@ list_T *reg_submatch_list(int no)
tv_list_append_string(list, s, (const char *)rsm.sm_match->endp[no] - s);
}
+ tv_list_ref(list);
return list;
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 8b5ee59d40..b6bcee3fda 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -559,7 +559,9 @@ static char_u *nfa_get_match_text(nfa_state_T *start)
*/
static void realloc_post_list(void)
{
- size_t new_max = (post_end - post_start) + 1000;
+ // For weird patterns the number of states can be very high. Increasing by
+ // 50% seems a reasonable compromise between memory use and speed.
+ const size_t new_max = (post_end - post_start) * 3 / 2;
int *new_start = xrealloc(post_start, new_max * sizeof(int));
post_ptr = new_start + (post_ptr - post_start);
post_end = new_start + new_max;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 095c020fe4..5bf5a471c1 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2082,6 +2082,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
int change_start = MAXCOL; // first col of changed area
int change_end = -1; // last col of changed area
colnr_T trailcol = MAXCOL; // start of trailing spaces
+ colnr_T leadcol = 0; // start of leading spaces
bool need_showbreak = false; // overlong line, skip first x chars
int line_attr = 0; // attribute for the whole line
int line_attr_lowprio = 0; // low-priority attribute for the line
@@ -2322,7 +2323,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL);
}
// do at least one character; happens when past end of line
- if (fromcol == tocol) {
+ if (fromcol == tocol && search_match_endcol) {
tocol = fromcol + 1;
}
area_highlighting = true;
@@ -2427,6 +2428,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (wp->w_p_list && !has_fold) {
if (wp->w_p_lcs_chars.space
|| wp->w_p_lcs_chars.trail
+ || wp->w_p_lcs_chars.lead
|| wp->w_p_lcs_chars.nbsp) {
extra_check = true;
}
@@ -2438,6 +2440,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
trailcol += (colnr_T) (ptr - line);
}
+ // find end of leading whitespace
+ if (wp->w_p_lcs_chars.lead) {
+ leadcol = 0;
+ while (ascii_iswhite(ptr[leadcol])) {
+ leadcol++;
+ }
+ if (ptr[leadcol] == NUL) {
+ // in a line full of spaces all of them are treated as trailing
+ leadcol = (colnr_T)0;
+ } else {
+ // keep track of the first column not filled with spaces
+ leadcol += (colnr_T)(ptr - line) + 1;
+ }
+ }
}
/*
@@ -3138,6 +3154,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
mb_utf8 = false;
}
} else {
+ assert(p_extra != NULL);
c = *p_extra;
mb_c = c;
// If the UTF-8 character is more than one byte:
@@ -3441,8 +3458,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// TODO: is passing p for start of the line OK?
n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1;
if (c == TAB && n_extra + col > grid->Columns) {
- n_extra = (int)wp->w_buffer->b_p_ts
- - vcol % (int)wp->w_buffer->b_p_ts - 1;
+ n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array) - 1;
}
c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
c_final = NUL;
@@ -3462,6 +3479,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|| (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
&& curwin->w_p_lcs_chars.nbsp)
|| (c == ' ' && curwin->w_p_lcs_chars.space
+ && ptr - line >= leadcol
&& ptr - line <= trailcol))) {
c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
n_attr = 1;
@@ -3477,8 +3495,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') {
- c = wp->w_p_lcs_chars.trail;
+ if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
+ || (leadcol != 0 && ptr < line + leadcol && c == ' ')) {
+ c = (ptr > line + trailcol) ? wp->w_p_lcs_chars.trail
+ : wp->w_p_lcs_chars.lead;
n_attr = 1;
extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
@@ -3508,8 +3528,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
}
// tab amount depends on current column
- tab_len = (int)wp->w_buffer->b_p_ts
- - vcol_adjusted % (int)wp->w_buffer->b_p_ts - 1;
+ tab_len = tabstop_padding(vcol_adjusted,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array) - 1;
if (!wp->w_p_lbr || !wp->w_p_list) {
n_extra = tab_len;
@@ -3542,6 +3563,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
xfree(p_extra_free);
p_extra_free = p;
for (i = 0; i < tab_len; i++) {
+ if (*p == NUL) {
+ tab_len = i;
+ break;
+ }
int lcs = wp->w_p_lcs_chars.tab2;
// if tab3 is given, need to change the char
@@ -7585,8 +7610,9 @@ void win_new_shellsize(void)
static long old_Columns = 0;
if (old_Rows != Rows) {
- // if 'window' uses the whole screen, keep it using that */
- if (p_window == old_Rows - 1 || old_Rows == 0) {
+ // If 'window' uses the whole screen, keep it using that.
+ // Don't change it when set with "-w size" on the command line.
+ if (p_window == old_Rows - 1 || (old_Rows == 0 && p_window == 0)) {
p_window = Rows - 1;
}
old_Rows = Rows;
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index e52fd888bd..4641408069 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -31,20 +31,11 @@ endif
SCRIPTS ?= $(SCRIPTS_DEFAULT)
# Tests using runtest.vim.
-NEW_TESTS_ALOT := test_alot_utf8 test_alot
+NEW_TESTS_ALOT := test_alot_utf8 test_alot test_alot_latin
NEW_TESTS_IN_ALOT := $(shell sed -n '/^source/ s/^source //; s/\.vim$$//p' $(addsuffix .vim,$(NEW_TESTS_ALOT)))
-NEW_TESTS_IN_ALOT_LATIN := $(shell sed -n '/^source/ s/^source //; s/\.vim$$//p' test_alot_latin.vim)
# Ignored tests.
-# test_alot_latin: Nvim does not allow setting encoding.
-# test_autochdir: ported to Lua, but kept for easier merging.
-# test_eval_func: used as include in old-style test (test_eval.in).
-# test_listlbr: Nvim does not allow setting encoding.
# test_largefile: uses too much resources to run on CI.
NEW_TESTS_IGNORE := \
- test_alot_latin $(NEW_TESTS_IN_ALOT_LATIN) \
- test_autochdir \
- test_eval_func \
- test_listlbr \
test_largefile \
NEW_TESTS := $(sort $(basename $(notdir $(wildcard test_*.vim))))
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index a47d20a265..71af3eead7 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -33,6 +33,7 @@ source test_move.vim
source test_partial.vim
source test_popup.vim
source test_put.vim
+source test_rename.vim
source test_scroll_opt.vim
source test_sort.vim
source test_sha256.vim
diff --git a/src/nvim/testdir/test_alot_latin.vim b/src/nvim/testdir/test_alot_latin.vim
index ebb3bde4ce..23a404cac1 100644
--- a/src/nvim/testdir/test_alot_latin.vim
+++ b/src/nvim/testdir/test_alot_latin.vim
@@ -4,7 +4,4 @@
" These tests use latin1 'encoding'. Setting 'encoding' is in the individual
" files, so that they can be run by themselves.
-" Nvim does not allow setting 'encoding', so skip this test group.
-finish
-
source test_regexp_latin.vim
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index b4f7478807..1d114221dc 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -52,6 +52,37 @@ func Test_assert_fails_in_try_block()
endtry
endfunc
+func Test_assert_inrange()
+ call assert_equal(0, assert_inrange(7, 7, 7))
+ call assert_equal(0, assert_inrange(5, 7, 5))
+ call assert_equal(0, assert_inrange(5, 7, 6))
+ call assert_equal(0, assert_inrange(5, 7, 7))
+ call assert_equal(1, assert_inrange(5, 7, 4))
+ call assert_match("Expected range 5 - 7, but got 4", v:errors[0])
+ call remove(v:errors, 0)
+ call assert_equal(1, assert_inrange(5, 7, 8))
+ call assert_match("Expected range 5 - 7, but got 8", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_fails('call assert_inrange(1, 1)', 'E119:')
+
+ if has('float')
+ call assert_equal(0, assert_inrange(7.0, 7, 7))
+ call assert_equal(0, assert_inrange(7, 7.0, 7))
+ call assert_equal(0, assert_inrange(7, 7, 7.0))
+ call assert_equal(0, assert_inrange(5, 7, 5.0))
+ call assert_equal(0, assert_inrange(5, 7, 6.0))
+ call assert_equal(0, assert_inrange(5, 7, 7.0))
+
+ call assert_equal(1, assert_inrange(5, 7, 4.0))
+ call assert_match("Expected range 5.0 - 7.0, but got 4.0", v:errors[0])
+ call remove(v:errors, 0)
+ call assert_equal(1, assert_inrange(5, 7, 8.0))
+ call assert_match("Expected range 5.0 - 7.0, but got 8.0", v:errors[0])
+ call remove(v:errors, 0)
+ endif
+endfunc
+
" Must be last.
func Test_zz_quit_detected()
" Verify that if a test function ends Vim the test script detects this.
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 67c537b407..d071f4b325 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -1,10 +1,10 @@
" Test 'autochdir' behavior
-if !exists("+autochdir")
- throw 'Skipped: autochdir feature missing'
-endif
+source check.vim
+CheckOption autochdir
func Test_set_filename()
+ CheckFunction test_autochdir
let cwd = getcwd()
call test_autochdir()
set acd
@@ -17,3 +17,5 @@ func Test_set_filename()
exe 'cd ' . cwd
call delete('samples/Xtest')
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 3401e791c9..5e99edf233 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -76,7 +76,7 @@ if has('timers')
endfunc
func Test_OptionSet_modeline()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
au! OptionSet
augroup set_tabstop
@@ -507,7 +507,7 @@ func s:AutoCommandOptionSet(match)
endfunc
func Test_OptionSet()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !has("eval") || !exists("+autochdir")
return
endif
@@ -648,7 +648,7 @@ func Test_OptionSet()
endfunc
func Test_OptionSet_diffmode()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
" 18: Changing an option when entering diff mode
new
@@ -682,7 +682,7 @@ func Test_OptionSet_diffmode()
endfunc
func Test_OptionSet_diffmode_close()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
call test_override('starting', 1)
" 19: Try to close the current window when entering diff mode
" should not segfault
@@ -1285,9 +1285,9 @@ func Test_autocommand_all_events()
endfunc
" Test TextChangedI and TextChangedP
+" See test/functional/viml/completion_spec.lua'
func Test_ChangedP()
- " Nvim does not support test_override().
- throw 'skipped: see test/functional/viml/completion_spec.lua'
+ CheckFunction test_override
new
call setline(1, ['foo', 'bar', 'foobar'])
call test_override("char_avail", 1)
@@ -1350,7 +1350,7 @@ func SetLineOne()
endfunc
func Test_TextChangedI_with_setline()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
new
call test_override('char_avail', 1)
autocmd TextChangedI <buffer> call SetLineOne()
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index d53acb77d7..ff5029b889 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -12,56 +12,88 @@ source view_util.vim
let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
-function s:screen_lines(lnum, width) abort
+func s:screen_lines(lnum, width) abort
return ScreenLines([a:lnum, a:lnum + 2], a:width)
-endfunction
+endfunc
-function! s:compare_lines(expect, actual)
+func! s:compare_lines(expect, actual)
call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
-endfunction
+endfunc
-function s:test_windows(...)
+func s:test_windows(...)
call NewWindow(10, 20)
setl ts=4 sw=4 sts=4 breakindent
put =s:input
exe get(a:000, 0, '')
-endfunction
+endfunc
-function s:close_windows(...)
+func s:close_windows(...)
call CloseWindow()
exe get(a:000, 0, '')
-endfunction
+endfunc
-function Test_breakindent01()
+func Test_breakindent01()
" simple breakindent test
call s:test_windows('setl briopt=min:0')
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ " abcd",
-\ " qrst",
-\ " GHIJ",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrst",
+ \ " GHIJ",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
-function Test_breakindent02()
+func Test_breakindent01_vartabs()
+ " like 01 but with vartabs feature
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrst",
+ \ " GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent02()
" simple breakindent test with showbreak set
call s:test_windows('setl briopt=min:0 sbr=>>')
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ " abcd",
-\ " >>qr",
-\ " >>EF",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " >>qr",
+ \ " >>EF",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set sbr=')
-endfunction
+endfunc
+
+func Test_breakindent02_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " simple breakindent test with showbreak set
+ call s:test_windows('setl briopt=min:0 sbr=>> vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " >>qr",
+ \ " >>EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
-function Test_breakindent03()
+func Test_breakindent03()
" simple breakindent test with showbreak set and briopt including sbr
call s:test_windows('setl briopt=sbr,min:0 sbr=++')
- let lines=s:screen_lines(line('.'),8)
+ let lines = s:screen_lines(line('.'),8)
let expect=[
\ " abcd",
\ "++ qrst",
@@ -70,77 +102,177 @@ function Test_breakindent03()
call s:compare_lines(expect, lines)
" clean up
call s:close_windows('set sbr=')
-endfunction
+endfunc
-function Test_breakindent04()
+func Test_breakindent03_vartabs()
+ " simple breakindent test with showbreak set and briopt including sbr
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=sbr,min:0 sbr=++ vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ "++ qrst",
+ \ "++ GHIJ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent04()
" breakindent set with min width 18
call s:test_windows('setl sbr= briopt=min:18')
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ " abcd",
-\ " qrstuv",
-\ " IJKLMN",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstuv",
+ \ " IJKLMN",
+ \ ]
call s:compare_lines(expect, lines)
" clean up
call s:close_windows('set sbr=')
-endfunction
+endfunc
+
+func Test_breakindent04_vartabs()
+ " breakindent set with min width 18
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl sbr= briopt=min:18 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstuv",
+ \ " IJKLMN",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
-function Test_breakindent05()
+func Test_breakindent05()
" breakindent set and shift by 2
call s:test_windows('setl briopt=shift:2,min:0')
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ " abcd",
-\ " qr",
-\ " EF",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qr",
+ \ " EF",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
-function Test_breakindent06()
+func Test_breakindent05_vartabs()
+ " breakindent set and shift by 2
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=shift:2,min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qr",
+ \ " EF",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
+
+func Test_breakindent06()
" breakindent set and shift by -1
call s:test_windows('setl briopt=shift:-1,min:0')
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ " abcd",
-\ " qrstu",
-\ " HIJKL",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstu",
+ \ " HIJKL",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
+
+func Test_breakindent06_vartabs()
+ " breakindent set and shift by -1
+ if !has("vartabs")
+ return
+ endif
+ call s:test_windows('setl briopt=shift:-1,min:0 vts=4')
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ " abcd",
+ \ " qrstu",
+ \ " HIJKL",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
-function Test_breakindent07()
+func Test_breakindent07()
" breakindent set and shift by 1, Number set sbr=? and briopt:sbr
call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n')
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ab",
-\ "? m",
-\ "? x",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "? m",
+ \ "? x",
+ \ ]
call s:compare_lines(expect, lines)
" clean up
call s:close_windows('set sbr= cpo-=n')
-endfunction
+endfunc
+
+func Test_breakindent07_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 cpo+=n vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "? m",
+ \ "? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
-function Test_breakindent07a()
+func Test_breakindent07a()
" breakindent set and shift by 1, Number set sbr=? and briopt:sbr
call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4')
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ab",
-\ " ? m",
-\ " ? x",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ " ? m",
+ \ " ? x",
+ \ ]
call s:compare_lines(expect, lines)
" clean up
call s:close_windows('set sbr=')
-endfunction
+endfunc
+
+func Test_breakindent07a_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number set sbr=? and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ " ? m",
+ \ " ? x",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " clean up
+ call s:close_windows('set sbr= vts&')
+endfunc
-function Test_breakindent08()
+func Test_breakindent08()
" breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4')
" make sure, cache is invalidated!
@@ -148,43 +280,96 @@ function Test_breakindent08()
redraw!
set ts=4
redraw!
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ^Iabcd",
-\ "# opq",
-\ "# BCD",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ "# opq",
+ \ "# BCD",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set sbr= cpo-=n')
-endfunction
+endfunc
+
+func Test_breakindent08_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list cpo+=n ts=4 vts=4')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ "# opq",
+ \ "# BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
-function Test_breakindent08a()
+func Test_breakindent08a()
" breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list')
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ^Iabcd",
-\ " # opq",
-\ " # BCD",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " # opq",
+ \ " # BCD",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set sbr=')
-endfunction
+endfunc
-function Test_breakindent09()
+func Test_breakindent08a_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=# and briopt:sbr
+ call s:test_windows('setl briopt=shift:1,sbr,min:0 nu nuw=4 sbr=# list vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " # opq",
+ \ " # BCD",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
+
+func Test_breakindent09()
" breakindent set and shift by 1, Number and list set sbr=#
call s:test_windows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list')
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ^Iabcd",
-\ " #op",
-\ " #AB",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " #op",
+ \ " #AB",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set sbr=')
-endfunction
+endfunc
+
+func Test_breakindent09_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set and shift by 1, Number and list set sbr=#
+ call s:test_windows('setl briopt=shift:1,min:0 nu nuw=4 sbr=# list vts=4')
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ^Iabcd",
+ \ " #op",
+ \ " #AB",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= vts&')
+endfunc
-function Test_breakindent10()
+func Test_breakindent10()
" breakindent set, Number set sbr=~
call s:test_windows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0')
" make sure, cache is invalidated!
@@ -192,41 +377,91 @@ function Test_breakindent10()
redraw!
set ts=4
redraw!
- let lines=s:screen_lines(line('.'),10)
- let expect=[
-\ " 2 ab",
-\ "~ mn",
-\ "~ yz",
-\ ]
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "~ mn",
+ \ "~ yz",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set sbr= cpo-=n')
-endfunction
+endfunc
+
+func Test_breakindent10_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " breakindent set, Number set sbr=~
+ call s:test_windows('setl cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0 vts=4')
+ " make sure, cache is invalidated!
+ set ts=8
+ redraw!
+ set ts=4
+ redraw!
+ let lines = s:screen_lines(line('.'),10)
+ let expect = [
+ \ " 2 ab",
+ \ "~ mn",
+ \ "~ yz",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set sbr= cpo-=n vts&')
+endfunc
-function Test_breakindent11()
+func Test_breakindent11()
" test strdisplaywidth()
call s:test_windows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4')
let text=getline(2)
let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times
call assert_equal(width, strdisplaywidth(text))
call s:close_windows('set sbr=')
-endfunction
+endfunc
+
+func Test_breakindent11_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " test strdisplaywidth()
+ call s:test_windows('setl cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4 vts=4')
+ let text = getline(2)
+ let width = strlen(text[1:])+indent(2)+strlen(&sbr)*3 " text wraps 3 times
+ call assert_equal(width, strdisplaywidth(text))
+ call s:close_windows('set sbr= vts&')
+endfunc
-function Test_breakindent12()
+func Test_breakindent12()
" test breakindent with long indent
let s:input="\t\t\t\t\t{"
call s:test_windows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>-')
- let lines=s:screen_lines(2,16)
- let expect=[
-\ " 2 >--->--->--->",
-\ " ---{ ",
-\ "~ ",
-\ ]
+ let lines = s:screen_lines(2,16)
+ let expect = [
+ \ " 2 >--->--->--->",
+ \ " ---{ ",
+ \ "~ ",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows('set nuw=4 listchars=')
-endfunction
+endfunc
+
+func Test_breakindent12_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " test breakindent with long indent
+ let s:input = "\t\t\t\t\t{"
+ call s:test_windows('setl breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4 list listchars=tab:>- vts=4')
+ let lines = s:screen_lines(2,16)
+ let expect = [
+ \ " 2 >--->--->--->",
+ \ " ---{ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set nuw=4 listchars= vts&')
+endfunc
-function Test_breakindent13()
- let s:input=""
+func Test_breakindent13()
+ let s:input = ""
call s:test_windows('setl breakindent briopt=min:10 ts=8')
vert resize 20
call setline(1, [" a\tb\tc\td\te", " z y x w v"])
@@ -237,65 +472,149 @@ function Test_breakindent13()
call assert_equal('d', @a)
call assert_equal('w', @b)
call s:close_windows()
-endfunction
+endfunc
+
+func Test_breakindent13_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:10 ts=8 vts=8')
+ vert resize 20
+ call setline(1, [" a\tb\tc\td\te", " z y x w v"])
+ 1
+ norm! fbgj"ayl
+ 2
+ norm! fygj"byl
+ call assert_equal('d', @a)
+ call assert_equal('w', @b)
+ call s:close_windows('set vts&')
+endfunc
-function Test_breakindent14()
- let s:input=""
+func Test_breakindent14()
+ let s:input = ""
call s:test_windows('setl breakindent briopt= ts=8')
vert resize 30
norm! 3a1234567890
norm! a abcde
exec "norm! 0\<C-V>tex"
- let lines=s:screen_lines(line('.'),8)
- let expect=[
-\ "e ",
-\ "~ ",
-\ "~ ",
-\ ]
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ "e ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
+
+func Test_breakindent14_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8 vts=8')
+ vert resize 30
+ norm! 3a1234567890
+ norm! a abcde
+ exec "norm! 0\<C-V>tex"
+ let lines = s:screen_lines(line('.'),8)
+ let expect = [
+ \ "e ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
-function Test_breakindent15()
- let s:input=""
+func Test_breakindent15()
+ let s:input = ""
call s:test_windows('setl breakindent briopt= ts=8 sw=8')
vert resize 30
norm! 4a1234567890
exe "normal! >>\<C-V>3f0x"
- let lines=s:screen_lines(line('.'),20)
- let expect=[
-\ " 1234567890 ",
-\ "~ ",
-\ "~ ",
-\ ]
+ let lines = s:screen_lines(line('.'),20)
+ let expect = [
+ \ " 1234567890 ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
+
+func Test_breakindent15_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt= ts=8 sw=8 vts=8')
+ vert resize 30
+ norm! 4a1234567890
+ exe "normal! >>\<C-V>3f0x"
+ let lines = s:screen_lines(line('.'),20)
+ let expect = [
+ \ " 1234567890 ",
+ \ "~ ",
+ \ "~ ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
-function Test_breakindent16()
+func Test_breakindent16()
" Check that overlong lines are indented correctly.
- let s:input=""
+ let s:input = ""
call s:test_windows('setl breakindent briopt=min:0 ts=4')
call setline(1, "\t".repeat("1234567890", 10))
resize 6
norm! 1gg$
redraw!
- let lines=s:screen_lines(1,10)
- let expect=[
-\ " 789012",
-\ " 345678",
-\ " 901234",
-\ ]
+ let lines = s:screen_lines(1,10)
+ let expect = [
+ \ " 789012",
+ \ " 345678",
+ \ " 901234",
+ \ ]
call s:compare_lines(expect, lines)
- let lines=s:screen_lines(4,10)
- let expect=[
-\ " 567890",
-\ " 123456",
-\ " 7890 ",
-\ ]
+ let lines = s:screen_lines(4,10)
+ let expect = [
+ \ " 567890",
+ \ " 123456",
+ \ " 7890 ",
+ \ ]
call s:compare_lines(expect, lines)
call s:close_windows()
-endfunction
+endfunc
+
+func Test_breakindent16_vartabs()
+ if !has("vartabs")
+ return
+ endif
+ " Check that overlong lines are indented correctly.
+ let s:input = ""
+ call s:test_windows('setl breakindent briopt=min:0 ts=4 vts=4')
+ call setline(1, "\t".repeat("1234567890", 10))
+ resize 6
+ norm! 1gg$
+ redraw!
+ let lines = s:screen_lines(1,10)
+ let expect = [
+ \ " 789012",
+ \ " 345678",
+ \ " 901234",
+ \ ]
+ call s:compare_lines(expect, lines)
+ let lines = s:screen_lines(4,10)
+ let expect = [
+ \ " 567890",
+ \ " 123456",
+ \ " 7890 ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set vts&')
+endfunc
func Test_breakindent17_vartabs()
if !has("vartabs")
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index ff50d53d86..73b57f302e 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -24,7 +24,7 @@ endfunc
func Test_for_invalid()
call assert_fails("for x in 99", 'E714:')
- call assert_fails("for x in 'asdf'", 'E714:')
+ call assert_fails("for x in function('winnr')", 'E714:')
call assert_fails("for x in {'a': 9}", 'E714:')
if 0
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 5dae8d681a..555f549743 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1,5 +1,7 @@
" Tests for various functions.
+
source shared.vim
+source check.vim
" Must be done first, since the alternate buffer must be unset.
func Test_00_bufexists()
@@ -171,9 +173,8 @@ func Test_str2nr()
endfunc
func Test_strftime()
- if !exists('*strftime')
- return
- endif
+ CheckFunction strftime
+
" Format of strftime() depends on system. We assume
" that basic formats tested here are available and
" identical on all systems which support strftime().
@@ -214,6 +215,33 @@ func Test_strftime()
endif
endfunc
+func Test_strptime()
+ CheckFunction strptime
+ CheckNotMSWindows
+
+ if exists('$TZ')
+ let tz = $TZ
+ endif
+ let $TZ = 'UTC'
+
+ call assert_equal(1484653763, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23'))
+
+ " Force DST and check that it's considered
+ let $TZ = 'WINTER0SUMMER,J1,J365'
+ call assert_equal(1484653763 - 3600, strptime('%Y-%m-%d %T', '2017-01-17 11:49:23'))
+
+ call assert_fails('call strptime()', 'E119:')
+ call assert_fails('call strptime("xxx")', 'E119:')
+ call assert_equal(0, strptime("%Y", ''))
+ call assert_equal(0, strptime("%Y", "xxx"))
+
+ if exists('tz')
+ let $TZ = tz
+ else
+ unlet $TZ
+ endif
+endfunc
+
func Test_resolve_unix()
if !has('unix')
return
diff --git a/src/nvim/testdir/test_gn.vim b/src/nvim/testdir/test_gn.vim
index 9acec51913..d09b25b0e7 100644
--- a/src/nvim/testdir/test_gn.vim
+++ b/src/nvim/testdir/test_gn.vim
@@ -1,9 +1,8 @@
" Test for gn command
func Test_gn_command()
- set belloff=all
noautocmd new
- " replace a single char by itsself quoted:
+ " replace a single char by itself quoted:
call setline('.', 'abc x def x ghi x jkl')
let @/ = 'x'
exe "norm! cgn'x'\<esc>.."
@@ -157,7 +156,6 @@ func Test_gn_command()
sil! %d _
set wrapscan&vim
- set belloff&vim
endfunc
func Test_gN_repeat()
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index dcc588120c..4cb609aaf0 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -110,6 +110,35 @@ func Test_listchars()
\ '.....h>-$',
\ 'iii<<<<><<$', '$'], l)
+ " Test lead and trail
+ normal ggdG
+ set listchars=eol:$
+ set listchars+=lead:>,trail:<,space:x
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' gg',
+ \ 'h ',
+ \ ' ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ '>>>>ffff<<<<$',
+ \ '>>>>>>>>>>gg$',
+ \ 'h<<<<<<<<<<<$',
+ \ '<<<<<<<<<<<<$',
+ \ '>>>>0xx0<<<<$',
+ \ '$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
" test nbsp
normal ggdG
diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim
index d619ac0eb5..e0518de3c2 100644
--- a/src/nvim/testdir/test_listlbr.vim
+++ b/src/nvim/testdir/test_listlbr.vim
@@ -1,9 +1,5 @@
" Test for linebreak and list option (non-utf8)
-" Nvim does not allow setting 'encoding', so skip this test.
-finish
-
-set encoding=latin1
scriptencoding latin1
if !exists("+linebreak") || !has("conceal")
@@ -46,6 +42,7 @@ func Test_set_linebreak()
endfunc
func Test_linebreak_with_list()
+ throw 'skipped: Nvim does not support enc=latin1'
call s:test_windows('setl ts=4 sbr=+ list listchars=')
call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
let lines = s:screen_lines([1, 4], winwidth(0))
@@ -217,6 +214,7 @@ func Test_norm_after_block_visual()
endfunc
func Test_block_replace_after_wrapping()
+ throw 'skipped: Nvim does not support enc=latin1'
call s:test_windows()
call setline(1, repeat("a", 150))
exe "norm! 0yypk147|\<C-V>jr0"
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index c4807797ff..0191dbf33e 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -427,6 +427,30 @@ func Test_error_in_map_expr()
exe buf .. 'bwipe!'
endfunc
+func Test_expr_map_gets_cursor()
+ new
+ call setline(1, ['one', 'some w!rd'])
+ func StoreColumn()
+ let g:exprLine = line('.')
+ let g:exprCol = col('.')
+ return 'x'
+ endfunc
+ nnoremap <expr> x StoreColumn()
+ 2
+ nmap ! f!<Ignore>x
+ call feedkeys("!", 'xt')
+ call assert_equal('some wrd', getline(2))
+ call assert_equal(2, g:exprLine)
+ call assert_equal(7, g:exprCol)
+
+ bwipe!
+ unlet g:exprLine
+ unlet g:exprCol
+ delfunc StoreColumn
+ nunmap x
+ nunmap !
+endfunc
+
" Test for mapping errors
func Test_map_error()
call assert_fails('unmap', 'E474:')
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 3ebd048f46..08586dffe1 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -1,5 +1,6 @@
" Tests for :messages, :echomsg, :echoerr
+source check.vim
source shared.vim
func Test_messages()
@@ -77,7 +78,7 @@ func Test_echomsg()
endfunc
func Test_echoerr()
- throw 'skipped: Nvim does not support test_ignore_error()'
+ CheckFunction test_ignore_error
call test_ignore_error('IgNoRe')
call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"'))
call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"'))
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 07e2481f95..5aef33cb09 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -448,6 +448,36 @@ func Test_backupskip()
endif
endfor
+ " Duplicates from environment variables should be filtered out (option has
+ " P_NODUP). Run this in a separate instance and write v:errors in a file,
+ " so that we see what happens on startup.
+ let after =<< trim [CODE]
+ let bsklist = split(&backupskip, ',')
+ call assert_equal(uniq(copy(bsklist)), bsklist)
+ call writefile(['errors:'] + v:errors, 'Xtestout')
+ qall
+ [CODE]
+ call writefile(after, 'Xafter')
+ " let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
+ let cmd = GetVimProg() . ' -S Xafter --cmd "set enc=utf8"'
+
+ let saveenv = {}
+ for var in ['TMPDIR', 'TMP', 'TEMP']
+ let saveenv[var] = getenv(var)
+ call setenv(var, '/duplicate/path')
+ endfor
+
+ exe 'silent !' . cmd
+ call assert_equal(['errors:'], readfile('Xtestout'))
+
+ " restore environment variables
+ for var in ['TMPDIR', 'TMP', 'TEMP']
+ call setenv(var, saveenv[var])
+ endfor
+
+ call delete('Xtestout')
+ call delete('Xafter')
+
" Duplicates should be filtered out (option has P_NODUP)
let backupskip = &backupskip
set backupskip=
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 4ee16558a0..9443958984 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -871,7 +871,7 @@ func Test_popup_complete_backwards_ctrl_p()
endfunc
fun! Test_complete_o_tab()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
let s:o_char_pressed = 0
fun! s:act_on_text_changed()
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 704fdacdcd..da949f5940 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -2660,7 +2660,7 @@ endfunc
" Test for incsearch highlighting of the :vimgrep pattern
" This test used to cause "E315: ml_get: invalid lnum" errors.
func Test_vimgrep_incsearch()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
enew
set incsearch
call test_override("char_avail", 1)
diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim
index 77a5153a81..6e6f91362b 100644
--- a/src/nvim/testdir/test_quotestar.vim
+++ b/src/nvim/testdir/test_quotestar.vim
@@ -97,7 +97,7 @@ func Do_test_quotestar_for_x11()
if has('unix') && has('gui') && !has('gui_running')
let @* = ''
- " Running in a terminal and the GUI is avaiable: Tell the server to open
+ " Running in a terminal and the GUI is available: Tell the server to open
" the GUI and check that the remote command still works.
" Need to wait for the GUI to start up, otherwise the send hangs in trying
" to send to the terminal window.
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index 1bb2ee53de..cacdd68d10 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -1,5 +1,5 @@
" Tests for regexp in latin1 encoding
-set encoding=latin1
+" set encoding=latin1
scriptencoding latin1
func s:equivalence_test()
@@ -22,11 +22,13 @@ func s:equivalence_test()
endfunc
func Test_equivalence_re1()
+ throw 'skipped: Nvim does not support enc=latin1'
set re=1
call s:equivalence_test()
endfunc
func Test_equivalence_re2()
+ throw 'skipped: Nvim does not support enc=latin1'
set re=2
call s:equivalence_test()
endfunc
@@ -39,6 +41,17 @@ func Test_range_with_newline()
bwipe!
endfunc
+func Test_pattern_compile_speed()
+ if !exists('+spellcapcheck') || !has('reltime')
+ return
+ endif
+ let start = reltime()
+ " this used to be very slow, not it should be about a second
+ set spc=\\v(((((Nxxxxxxx&&xxxx){179})+)+)+){179}
+ call assert_inrange(0.01, 10.0, reltimefloat(reltime(start)))
+ set spc=
+endfunc
+
func Test_get_equi_class()
new
" Incomplete equivalence class caused invalid memory access
@@ -87,6 +100,7 @@ func Test_multi_failure()
endfunc
func Test_recursive_addstate()
+ throw 'skipped: TODO: '
" This will call addstate() recursively until it runs into the limit.
let lnum = search('\v((){328}){389}')
call assert_equal(0, lnum)
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 8d2a768ba0..53069b3d31 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -109,6 +109,8 @@ func Test_recording_esc_sequence()
bwipe!
if exists('save_F2')
let &t_F2 = save_F2
+ else
+ set t_F2=
endif
endfunc
diff --git a/src/nvim/testdir/test_rename.vim b/src/nvim/testdir/test_rename.vim
new file mode 100644
index 0000000000..e4228188bd
--- /dev/null
+++ b/src/nvim/testdir/test_rename.vim
@@ -0,0 +1,119 @@
+" Test rename()
+
+func Test_rename_file_to_file()
+ call writefile(['foo'], 'Xrename1')
+
+ call assert_equal(0, rename('Xrename1', 'Xrename2'))
+
+ call assert_equal('', glob('Xrename1'))
+ call assert_equal(['foo'], readfile('Xrename2'))
+
+ " When the destination file already exists, it should be overwritten.
+ call writefile(['foo'], 'Xrename1')
+ call writefile(['bar'], 'Xrename2')
+
+ call assert_equal(0, rename('Xrename1', 'Xrename2'))
+ call assert_equal('', glob('Xrename1'))
+ call assert_equal(['foo'], readfile('Xrename2'))
+
+ call delete('Xrename2')
+endfunc
+
+func Test_rename_file_ignore_case()
+ " With 'fileignorecase', renaming file will go through a temp file
+ " when the source and destination file only differ by case.
+ set fileignorecase
+ call writefile(['foo'], 'Xrename')
+
+ call assert_equal(0, rename('Xrename', 'XRENAME'))
+
+ call assert_equal(['foo'], readfile('XRENAME'))
+
+ set fileignorecase&
+ call delete('XRENAME')
+endfunc
+
+func Test_rename_same_file()
+ call writefile(['foo'], 'Xrename')
+
+ " When the source and destination are the same file, nothing
+ " should be done. The source file should not be deleted.
+ call assert_equal(0, rename('Xrename', 'Xrename'))
+ call assert_equal(['foo'], readfile('Xrename'))
+
+ call assert_equal(0, rename('./Xrename', 'Xrename'))
+ call assert_equal(['foo'], readfile('Xrename'))
+
+ call delete('Xrename')
+endfunc
+
+func Test_rename_dir_to_dir()
+ call mkdir('Xrenamedir1')
+ call writefile(['foo'], 'Xrenamedir1/Xrenamefile')
+
+ call assert_equal(0, rename('Xrenamedir1', 'Xrenamedir2'))
+
+ call assert_equal('', glob('Xrenamedir1'))
+ call assert_equal(['foo'], readfile('Xrenamedir2/Xrenamefile'))
+
+ call delete('Xrenamedir2/Xrenamefile')
+ call delete('Xrenamedir2', 'd')
+endfunc
+
+func Test_rename_same_dir()
+ call mkdir('Xrenamedir')
+ call writefile(['foo'], 'Xrenamedir/Xrenamefile')
+
+ call assert_equal(0, rename('Xrenamedir', 'Xrenamedir'))
+
+ call assert_equal(['foo'], readfile('Xrenamedir/Xrenamefile'))
+
+ call delete('Xrenamedir/Xrenamefile')
+ call delete('Xrenamedir', 'd')
+endfunc
+
+func Test_rename_copy()
+ " Check that when original file can't be deleted, rename()
+ " still succeeds but copies the file.
+ call mkdir('Xrenamedir')
+ call writefile(['foo'], 'Xrenamedir/Xrenamefile')
+ call setfperm('Xrenamedir', 'r-xr-xr-x')
+
+ call assert_equal(0, rename('Xrenamedir/Xrenamefile', 'Xrenamefile'))
+
+ if !has('win32')
+ " On Windows, the source file is removed despite
+ " its directory being made not writable.
+ call assert_equal(['foo'], readfile('Xrenamedir/Xrenamefile'))
+ endif
+ call assert_equal(['foo'], readfile('Xrenamefile'))
+
+ call setfperm('Xrenamedir', 'rwxrwxrwx')
+ call delete('Xrenamedir/Xrenamefile')
+ call delete('Xrenamedir', 'd')
+ call delete('Xrenamefile')
+endfunc
+
+func Test_rename_fails()
+ throw 'skipped: TODO: '
+ call writefile(['foo'], 'Xrenamefile')
+
+ " Can't rename into a non-existing directory.
+ call assert_notequal(0, rename('Xrenamefile', 'Xdoesnotexist/Xrenamefile'))
+
+ " Can't rename a non-existing file.
+ call assert_notequal(0, rename('Xdoesnotexist', 'Xrenamefile2'))
+ call assert_equal('', glob('Xrenamefile2'))
+
+ " When rename() fails, the destination file should not be deleted.
+ call assert_notequal(0, rename('Xdoesnotexist', 'Xrenamefile'))
+ call assert_equal(['foo'], readfile('Xrenamefile'))
+
+ " Can't rename to en empty file name.
+ call assert_notequal(0, rename('Xrenamefile', ''))
+
+ call assert_fails('call rename("Xrenamefile", [])', 'E730')
+ call assert_fails('call rename(0z, "Xrenamefile")', 'E976')
+
+ call delete('Xrenamefile')
+endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 0703a6b141..d4d529e4b9 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -2,10 +2,11 @@
source shared.vim
source screendump.vim
+source check.vim
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -202,9 +203,9 @@ func Test_search_cmdline()
bw!
endfunc
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline2()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -351,7 +352,7 @@ func Test_searchc()
endfunc
func Cmdline3_prep()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
" need to disable char_avail,
" so that expansion of commandline works
call test_override("char_avail", 1)
@@ -361,14 +362,13 @@ func Cmdline3_prep()
endfunc
func Incsearch_cleanup()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
set noincsearch
call test_override("char_avail", 0)
bw!
endfunc
func Test_search_cmdline3()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -382,7 +382,6 @@ func Test_search_cmdline3()
endfunc
func Test_search_cmdline3s()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -409,7 +408,6 @@ func Test_search_cmdline3s()
endfunc
func Test_search_cmdline3g()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -433,7 +431,6 @@ func Test_search_cmdline3g()
endfunc
func Test_search_cmdline3v()
- throw 'skipped: Nvim does not support test_override()'
if !exists('+incsearch')
return
endif
@@ -450,9 +447,9 @@ func Test_search_cmdline3v()
call Incsearch_cleanup()
endfunc
+" See test/functional/legacy/search_spec.lua
func Test_search_cmdline4()
- " See test/functional/legacy/search_spec.lua
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -507,7 +504,7 @@ func Test_search_cmdline5()
endfunc
func Test_search_cmdline7()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
" Test that pressing <c-g> in an empty command line
" does not move the cursor
if !exists('+incsearch')
@@ -798,7 +795,7 @@ func Test_incsearch_vimgrep_dump()
endfunc
func Test_keep_last_search_pattern()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -820,7 +817,7 @@ func Test_keep_last_search_pattern()
endfunc
func Test_word_under_cursor_after_match()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -840,7 +837,7 @@ func Test_word_under_cursor_after_match()
endfunc
func Test_subst_word_under_cursor()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -882,7 +879,7 @@ func Test_incsearch_with_change()
endfunc
func Test_incsearch_cmdline_modifier()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -960,7 +957,7 @@ func Test_incsearch_search_dump()
endfunc
func Test_incsearch_substitute()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -982,7 +979,7 @@ func Test_incsearch_substitute()
endfunc
func Test_incsearch_substitute_long_line()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
new
call test_override("char_avail", 1)
set incsearch
@@ -1104,7 +1101,7 @@ func Test_one_error_msg()
endfunc
func Test_incsearch_add_char_under_cursor()
- throw 'skipped: Nvim does not support test_override()'
+ CheckFunction test_override
if !exists('+incsearch')
return
endif
@@ -1192,4 +1189,40 @@ func Test_search_smartcase_utf8()
close!
endfunc
+func Test_zzzz_incsearch_highlighting_newline()
+ CheckRunVimInTerminal
+ CheckOption incsearch
+ CheckScreendump
+ new
+ call test_override("char_avail", 1)
+
+ let commands =<< trim [CODE]
+ set incsearch nohls
+ call setline(1, ['test', 'xxx'])
+ [CODE]
+ call writefile(commands, 'Xincsearch_nl')
+ let buf = RunVimInTerminal('-S Xincsearch_nl', {'rows': 5, 'cols': 10})
+ " Need to send one key at a time to force a redraw
+ call term_sendkeys(buf, '/test')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline1', {})
+ call term_sendkeys(buf, '\n')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline2', {})
+ call term_sendkeys(buf, 'x')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline3', {})
+ call term_sendkeys(buf, 'x')
+ call VerifyScreenDump(buf, 'Test_incsearch_newline4', {})
+ call term_sendkeys(buf, "\<CR>")
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_newline5', {})
+ call StopVimInTerminal(buf)
+
+ " clean up
+ call delete('Xincsearch_nl')
+ call test_override("char_avail", 0)
+ bw
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 4bbd722fdb..9c3a5636ce 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -1,8 +1,7 @@
" Test for signs
-if !has('signs')
- finish
-endif
+source check.vim
+CheckFeature signs
source screendump.vim
@@ -1541,7 +1540,7 @@ endfunc
" Tests for memory allocation failures in sign functions
func Test_sign_memfailures()
- throw 'skipped: Nvim does not support test_alloc_fail()'
+ CheckFunction test_alloc_fail
call writefile(repeat(["Sun is shining"], 30), "Xsign")
edit Xsign
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 4d1ad10c23..e0dc0e0075 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -814,6 +814,34 @@ func Test_v_argv()
call assert_equal(['arg1', '--cmd', 'echo v:argv', '--cmd', 'q'']'], list[idx:])
endfunc
+" Test for the '-t' option to jump to a tag
+func Test_t_arg()
+ let before =<< trim [CODE]
+ set tags=Xtags
+ [CODE]
+ let after =<< trim [CODE]
+ let s = bufname('') .. ':L' .. line('.') .. 'C' .. col('.')
+ call writefile([s], "Xtestout")
+ qall
+ [CODE]
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "first\tXfile1\t/^ \\zsfirst$/",
+ \ "second\tXfile1\t/^ \\zssecond$/",
+ \ "third\tXfile1\t/^ \\zsthird$/"],
+ \ 'Xtags')
+ call writefile([' first', ' second', ' third'], 'Xfile1')
+
+ for t_arg in ['-t second', '-tsecond']
+ if RunVim(before, after, '-t second')
+ call assert_equal(['Xfile1:L2C5'], readfile('Xtestout'), t_arg)
+ call delete('Xtestout')
+ endif
+ endfor
+
+ call delete('Xtags')
+ call delete('Xfile1')
+endfunc
+
" Test the '-T' argument which sets the 'term' option.
func Test_T_arg()
throw 'skipped: Nvim does not support "-T" argument'
@@ -862,6 +890,66 @@ func Test_x_arg()
call delete('Xtest_x_arg')
endfunc
+" Test for --not-a-term avoiding escape codes.
+func Test_not_a_term()
+ CheckUnix
+ CheckNotGui
+
+ if &shellredir =~ '%s'
+ let redir = printf(&shellredir, 'Xvimout')
+ else
+ let redir = &shellredir .. ' Xvimout'
+ endif
+
+ " Without --not-a-term there are a few escape sequences.
+ " This will take 2 seconds because of the missing --not-a-term
+ let cmd = GetVimProg() .. ' --cmd quit ' .. redir
+ exe "silent !" . cmd
+ " call assert_match("\<Esc>", readfile('Xvimout')->join())
+ call assert_match("\<Esc>", join(readfile('Xvimout')))
+ call delete('Xvimout')
+
+ " With --not-a-term there are no escape sequences.
+ let cmd = GetVimProg() .. ' --not-a-term --cmd quit ' .. redir
+ exe "silent !" . cmd
+ " call assert_notmatch("\<Esc>", readfile('Xvimout')->join())
+ call assert_notmatch("\<Esc>", join(readfile('Xvimout')))
+ call delete('Xvimout')
+endfunc
+
+
+" Test for the "-w scriptout" argument
+func Test_w_arg()
+ " Can't catch the output of gvim.
+ CheckNotGui
+
+ call writefile(["iVim Editor\<Esc>:q!\<CR>"], 'Xscriptin', 'b')
+ if RunVim([], [], '-s Xscriptin -w Xscriptout')
+ call assert_equal(["iVim Editor\e:q!\r"], readfile('Xscriptout'))
+ call delete('Xscriptout')
+ endif
+ call delete('Xscriptin')
+
+ " Test for failing to open the script output file. This test works only when
+ " the language is English.
+ if !has('win32') && (v:lang == "C" || v:lang =~ '^[Ee]n')
+ call mkdir("Xdir")
+ let m = system(GetVimCommand() .. " -w Xdir")
+ call assert_equal("Cannot open for script output: \"Xdir\"\n", m)
+ call delete("Xdir", 'rf')
+ endif
+
+ " A number argument sets the 'window' option
+ call writefile(["iwindow \<C-R>=&window\<CR>\<Esc>:wq! Xresult\<CR>"], 'Xscriptin', 'b')
+ for w_arg in ['-w 17', '-w17']
+ if RunVim([], [], '-s Xscriptin ' .. w_arg)
+ call assert_equal(["window 17"], readfile('Xresult'), w_arg)
+ call delete('Xresult')
+ endif
+ endfor
+ call delete('Xscriptin')
+endfunc
+
" Test starting vim with various names: vim, ex, view, evim, etc.
func Test_progname()
CheckUnix
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index ce2ef4dcd8..48b7b4f2f1 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -440,6 +440,27 @@ func Test_statusline_removed_group()
call delete('XTest_statusline')
endfunc
+func Test_statusline_using_mode()
+ CheckScreendump
+
+ let lines =<< trim END
+ set laststatus=2
+ let &statusline = '-%{mode()}-'
+ END
+ call writefile(lines, 'XTest_statusline')
+
+ let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 5, 'cols': 50})
+ call VerifyScreenDump(buf, 'Test_statusline_mode_1', {})
+
+ call term_sendkeys(buf, ":")
+ call VerifyScreenDump(buf, 'Test_statusline_mode_2', {})
+
+ " clean up
+ call term_sendkeys(buf, "\<CR>")
+ call StopVimInTerminal(buf)
+ call delete('XTest_statusline')
+endfunc
+
func Test_statusline_after_split_vsplit()
only
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 2a27f7a3a1..cc3bfe9f7f 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -746,3 +746,12 @@ func Test_sub_beyond_end()
call assert_equal('#', getline(1))
bwipe!
endfunc
+
+func Test_submatch_list_concatenate()
+ let pat = 'A\(.\)'
+ let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
+ " call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
+ call assert_equal(substitute('A1', pat, Rep, ''), "[['A1'], ['1']]")
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 4cf0e983b0..66cb0bbe22 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -30,7 +30,7 @@ func Test_syn_iskeyword()
\ 'CREATE TABLE FOOBAR(',
\ ' DLTD_BY VARCHAR2(100)',
\ ');',
- \ ''])
+ \ ''])
syntax on
set ft=sql
@@ -521,7 +521,7 @@ func Test_synstack_synIDtrans()
norm f/
call assert_equal(['cComment', 'cCommentStart'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
- call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+ call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
norm fA
call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 9cf8690d57..6bbe714d19 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -93,7 +93,6 @@ function! Test_system_exmode()
endfunc
func Test_system_with_shell_quote()
- throw 'skipped: enable after porting method patches'
CheckMSWindows
call mkdir('Xdir with spaces', 'p')
@@ -122,7 +121,8 @@ func Test_system_with_shell_quote()
let msg = printf('shell=%s shellxquote=%s', &shell, &shellxquote)
try
- let out = 'echo 123'->system()
+ " let out = 'echo 123'->system()
+ let out = system('echo 123')
catch
call assert_report(printf('%s: %s', msg, v:exception))
continue
diff --git a/src/nvim/testdir/test_tab.vim b/src/nvim/testdir/test_tab.vim
index b847dbd962..b8e8dfe062 100644
--- a/src/nvim/testdir/test_tab.vim
+++ b/src/nvim/testdir/test_tab.vim
@@ -1,3 +1,4 @@
+" Various tests for inserting a Tab.
" Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set.
" Also test that dv_ works correctly
@@ -43,3 +44,47 @@ func Test_smarttab()
enew!
set expandtab& smartindent& copyindent& ts& sw& sts&
endfunc
+
+func Test_softtabstop()
+ new
+ set sts=0 sw=0
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x\tx", getline(1))
+
+ call setline(1, '')
+ set sts=4
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, '')
+ set sts=-1 sw=4
+ exe "normal ix\<Tab>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=0 sw=0 backspace=start
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=4
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x ')
+ set sts=-1 sw=4
+ exe "normal A\<BS>x\<Esc>"
+ call assert_equal("x x", getline(1))
+
+ call setline(1, 'x')
+ set sts=-1 sw=0 smarttab
+ exe "normal I\<Tab>\<Esc>"
+ call assert_equal("\tx", getline(1))
+
+ call setline(1, 'x')
+ exe "normal I\<Tab>\<BS>\<Esc>"
+ call assert_equal("x", getline(1))
+
+ set sts=0 sw=0 backspace& nosmarttab
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 2b6a89647e..b261b96c3b 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -142,9 +142,6 @@ endfunc
" Test autocommands
function Test_tabpage_with_autocmd()
- if !has('autocmd')
- return
- endif
command -nargs=1 -bar C :call add(s:li, '=== ' . <q-args> . ' ===')|<args>
augroup TestTabpageGroup
au!
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 13971a918d..ceaa5de92b 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -317,8 +317,8 @@ endfunc
" Test that the garbage collector isn't triggered if a timer callback invokes
" vgetc().
func Test_nocatch_garbage_collect()
- " skipped: Nvim does not support test_garbagecollect_soon(), test_override()
- return
+ CheckFunction test_garbagecollect_soon
+ CheckFunction test_override
" 'uptimetime. must be bigger than the timer timeout
set ut=200
call test_garbagecollect_soon()
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 3b66071d6d..54caed3983 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -3,6 +3,8 @@
" undo-able pieces. Do that by setting 'undolevels'.
" Also tests :earlier and :later.
+source check.vim
+
func Test_undotree()
new
@@ -135,7 +137,7 @@ func BackOne(expected)
endfunc
func Test_undo_del_chars()
- throw 'skipped: Nvim does not support test_settime()'
+ CheckFunction test_settime
" Setup a buffer without creating undo entries
new
@@ -330,7 +332,7 @@ func Test_insert_expr()
endfunc
func Test_undofile_earlier()
- throw 'skipped: Nvim does not support test_settime()'
+ CheckFunction test_settime
let t0 = localtime() - 43200
call test_settime(t0)
diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim
new file mode 100644
index 0000000000..2fbf130345
--- /dev/null
+++ b/src/nvim/testdir/test_vartabs.vim
@@ -0,0 +1,381 @@
+" Test for variable tabstops
+
+if !has("vartabs")
+ finish
+endif
+
+source view_util.vim
+
+func s:compare_lines(expect, actual)
+ call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
+endfunc
+
+func Test_vartabs()
+ new
+ %d
+
+ " Test normal operation of tabstops ...
+ set ts=4
+ call setline(1, join(split('aaaaa', '\zs'), "\t"))
+ retab 8
+ let expect = "a a\<tab>a a\<tab>a"
+ call assert_equal(expect, getline(1))
+
+ " ... and softtabstops
+ set ts=8 sts=6
+ exe "norm! Sb\<tab>b\<tab>b\<tab>b\<tab>b"
+ let expect = "b b\<tab> b\<tab> b\<tab>b"
+ call assert_equal(expect, getline(1))
+
+ " Test variable tabstops.
+ set sts=0 vts=4,8,4,8
+ exe "norm! Sc\<tab>c\<tab>c\<tab>c\<tab>c\<tab>c"
+ retab 8
+ let expect = "c c\<tab> c\<tab>c\<tab>c\<tab>c"
+ call assert_equal(expect, getline(1))
+
+ set et vts=4,8,4,8
+ exe "norm! Sd\<tab>d\<tab>d\<tab>d\<tab>d\<tab>d"
+ let expect = "d d d d d d"
+ call assert_equal(expect, getline(1))
+
+ " Changing ts should have no effect if vts is in use.
+ call cursor(1, 1)
+ set ts=6
+ exe "norm! Se\<tab>e\<tab>e\<tab>e\<tab>e\<tab>e"
+ let expect = "e e e e e e"
+ call assert_equal(expect, getline(1))
+
+ " Clearing vts should revert to using ts.
+ set vts=
+ exe "norm! Sf\<tab>f\<tab>f\<tab>f\<tab>f\<tab>f"
+ let expect = "f f f f f f"
+ call assert_equal(expect, getline(1))
+
+ " Test variable softtabstops.
+ set noet ts=8 vsts=12,2,6
+ exe "norm! Sg\<tab>g\<tab>g\<tab>g\<tab>g\<tab>g"
+ let expect = "g\<tab> g g\<tab> g\<tab> g\<tab>g"
+ call assert_equal(expect, getline(1))
+
+ " Variable tabstops and softtabstops combined.
+ set vsts=6,12,8 vts=4,6,8
+ exe "norm! Sh\<tab>h\<tab>h\<tab>h\<tab>h"
+ let expect = "h\<tab> h\<tab>\<tab>h\<tab>h\<tab>h"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, not using vts.
+ set ts=8 sts=0 vts= vsts=
+ exe "norm! Si\<tab>i\<tab>i\<tab>i\<tab>i"
+ retab 4
+ let expect = "i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sj\<tab>j\<tab>j\<tab>j\<tab>j"
+ retab 4
+ let expect = "j\<tab> j\<tab>\<tab>j\<tab> j\<tab>\<tab>j"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, not using vts.
+ set ts=6 sts=0 vts= vsts=
+ exe "norm! Sk\<tab>k\<tab>k\<tab>k\<tab>k\<tab>k"
+ retab 4,8
+ let expect = "k\<tab> k\<tab>k k\<tab> k\<tab> k"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sl\<tab>l\<tab>l\<tab>l\<tab>l\<tab>l"
+ retab 4,8
+ let expect = "l\<tab> l\<tab>l l\<tab> l\<tab> l"
+ call assert_equal(expect, getline(1))
+
+ " Check that global and local values are set.
+ set ts=4 vts=6 sts=8 vsts=10
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that local values only are set.
+ setlocal ts=5 vts=7 sts=9 vsts=11
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that global values only are set.
+ setglobal ts=6 vts=8 sts=10 vsts=12
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 6)
+ call assert_equal(&vts, '8')
+ call assert_equal(&sts, 10)
+ call assert_equal(&vsts, '12')
+ bwipeout!
+
+ set ts& vts& sts& vsts& et&
+ bwipeout!
+endfunc
+
+func! Test_vartabs_breakindent()
+ if !exists("+breakindent")
+ return
+ endif
+ new
+ %d
+
+ " Test normal operation of tabstops ...
+ set ts=4
+ call setline(1, join(split('aaaaa', '\zs'), "\t"))
+ retab 8
+ let expect = "a a\<tab>a a\<tab>a"
+ call assert_equal(expect, getline(1))
+
+ " ... and softtabstops
+ set ts=8 sts=6
+ exe "norm! Sb\<tab>b\<tab>b\<tab>b\<tab>b"
+ let expect = "b b\<tab> b\<tab> b\<tab>b"
+ call assert_equal(expect, getline(1))
+
+ " Test variable tabstops.
+ set sts=0 vts=4,8,4,8
+ exe "norm! Sc\<tab>c\<tab>c\<tab>c\<tab>c\<tab>c"
+ retab 8
+ let expect = "c c\<tab> c\<tab>c\<tab>c\<tab>c"
+ call assert_equal(expect, getline(1))
+
+ set et vts=4,8,4,8
+ exe "norm! Sd\<tab>d\<tab>d\<tab>d\<tab>d\<tab>d"
+ let expect = "d d d d d d"
+ call assert_equal(expect, getline(1))
+
+ " Changing ts should have no effect if vts is in use.
+ call cursor(1, 1)
+ set ts=6
+ exe "norm! Se\<tab>e\<tab>e\<tab>e\<tab>e\<tab>e"
+ let expect = "e e e e e e"
+ call assert_equal(expect, getline(1))
+
+ " Clearing vts should revert to using ts.
+ set vts=
+ exe "norm! Sf\<tab>f\<tab>f\<tab>f\<tab>f\<tab>f"
+ let expect = "f f f f f f"
+ call assert_equal(expect, getline(1))
+
+ " Test variable softtabstops.
+ set noet ts=8 vsts=12,2,6
+ exe "norm! Sg\<tab>g\<tab>g\<tab>g\<tab>g\<tab>g"
+ let expect = "g\<tab> g g\<tab> g\<tab> g\<tab>g"
+ call assert_equal(expect, getline(1))
+
+ " Variable tabstops and softtabstops combined.
+ set vsts=6,12,8 vts=4,6,8
+ exe "norm! Sh\<tab>h\<tab>h\<tab>h\<tab>h"
+ let expect = "h\<tab> h\<tab>\<tab>h\<tab>h\<tab>h"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, not using vts.
+ set ts=8 sts=0 vts= vsts=
+ exe "norm! Si\<tab>i\<tab>i\<tab>i\<tab>i"
+ retab 4
+ let expect = "i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i\<tab>\<tab>i"
+ call assert_equal(expect, getline(1))
+
+ " Retab with a single value, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sj\<tab>j\<tab>j\<tab>j\<tab>j"
+ retab 4
+ let expect = "j\<tab> j\<tab>\<tab>j\<tab> j\<tab>\<tab>j"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, not using vts.
+ set ts=6 sts=0 vts= vsts=
+ exe "norm! Sk\<tab>k\<tab>k\<tab>k\<tab>k\<tab>k"
+ retab 4,8
+ let expect = "k\<tab> k\<tab>k k\<tab> k\<tab> k"
+ call assert_equal(expect, getline(1))
+
+ " Retab with multiple values, using vts.
+ set ts=8 sts=0 vts=6 vsts=
+ exe "norm! Sl\<tab>l\<tab>l\<tab>l\<tab>l\<tab>l"
+ retab 4,8
+ let expect = "l\<tab> l\<tab>l l\<tab> l\<tab> l"
+ call assert_equal(expect, getline(1))
+
+ " Check that global and local values are set.
+ set ts=4 vts=6 sts=8 vsts=10
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that local values only are set.
+ setlocal ts=5 vts=7 sts=9 vsts=11
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 4)
+ call assert_equal(&vts, '6')
+ call assert_equal(&sts, 8)
+ call assert_equal(&vsts, '10')
+ bwipeout!
+
+ " Check that global values only are set.
+ setglobal ts=6 vts=8 sts=10 vsts=12
+ call assert_equal(&ts, 5)
+ call assert_equal(&vts, '7')
+ call assert_equal(&sts, 9)
+ call assert_equal(&vsts, '11')
+ new
+ call assert_equal(&ts, 6)
+ call assert_equal(&vts, '8')
+ call assert_equal(&sts, 10)
+ call assert_equal(&vsts, '12')
+ bwipeout!
+
+ bwipeout!
+endfunc
+
+func Test_vartabs_linebreak()
+ if winwidth(0) < 40
+ return
+ endif
+ new
+ 40vnew
+ %d
+ setl linebreak vartabstop=10,20,30,40
+ call setline(1, "\tx\tx\tx\tx")
+
+ let expect = [' x ',
+ \ 'x x ',
+ \ 'x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect, lines)
+ setl list listchars=tab:>-
+ let expect = ['>---------x>------------------ ',
+ \ 'x>------------------x>------------------',
+ \ 'x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect, lines)
+ setl linebreak vartabstop=40
+ let expect = ['>---------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x>--------------------------------------',
+ \ 'x ']
+ let lines = ScreenLines([1, 5], winwidth(0))
+ call s:compare_lines(expect, lines)
+
+ " cleanup
+ bw!
+ bw!
+ set nolist listchars&vim
+endfunc
+
+func Test_vartabs_shiftwidth()
+ "return
+ if winwidth(0) < 40
+ return
+ endif
+ new
+ 40vnew
+ %d
+" setl varsofttabstop=10,20,30,40
+ setl shiftwidth=0 vartabstop=10,20,30,40
+ call setline(1, "x")
+
+ " Check without any change.
+ let expect = ['x ']
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect, lines)
+ " Test 1:
+ " shiftwidth depends on the indent, first check with cursor at the end of the
+ " line (which is the same as the start of the line, since there is only one
+ " character).
+ norm! $>>
+ let expect1 = [' x ']
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect1, lines)
+ call assert_equal(10, shiftwidth())
+ call assert_equal(10, shiftwidth(1))
+ call assert_equal(20, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect2 = [' x ', '~ ']
+ let lines = ScreenLines([1, 2], winwidth(0))
+ call s:compare_lines(expect2, lines)
+ call assert_equal(20, shiftwidth(virtcol('.')-2))
+ call assert_equal(30, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect3 = [' ', ' x ', '~ ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect3, lines)
+ call assert_equal(30, shiftwidth(virtcol('.')-2))
+ call assert_equal(40, shiftwidth(virtcol('.')))
+ norm! $>>
+ let expect4 = [' ', ' ', ' x ']
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call assert_equal(40, shiftwidth(virtcol('.')))
+ call s:compare_lines(expect4, lines)
+
+ " Test 2: Put the cursor at the first column, result should be the same
+ call setline(1, "x")
+ norm! 0>>
+ let lines = ScreenLines(1, winwidth(0))
+ call s:compare_lines(expect1, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 2], winwidth(0))
+ call s:compare_lines(expect2, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect3, lines)
+ norm! 0>>
+ let lines = ScreenLines([1, 3], winwidth(0))
+ call s:compare_lines(expect4, lines)
+
+ " cleanup
+ bw!
+ bw!
+endfunc
+
+func Test_vartabs_failures()
+ call assert_fails('set vts=8,')
+ call assert_fails('set vsts=8,')
+ call assert_fails('set vts=8,,8')
+ call assert_fails('set vsts=8,,8')
+ call assert_fails('set vts=8,,8,')
+ call assert_fails('set vsts=8,,8,')
+ call assert_fails('set vts=,8')
+ call assert_fails('set vsts=,8')
+endfunc
+
+func Test_vartabs_reset()
+ set vts=8
+ set all&
+ call assert_equal('', &vts)
+endfunc
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 7f50894f66..73c7960579 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -255,7 +255,6 @@ func TriggerTheProblem()
endfunc
func Test_visual_mode_reset()
- set belloff=all
enew
let g:msg = "Everything's fine."
enew
@@ -268,7 +267,6 @@ func Test_visual_mode_reset()
exe "normal! GV:call TriggerTheProblem()\<CR>"
call assert_equal("Everything's fine.", g:msg)
- set belloff&
endfunc
func Test_Visual_word_textobject()
diff --git a/src/nvim/window.c b/src/nvim/window.c
index fd7af108b7..859f4353b3 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1301,6 +1301,10 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
p_wh = i;
}
+ if (!win_valid(oldwin)) {
+ return FAIL;
+ }
+
// Send the window positions to the UI
oldwin->w_pos_changed = true;