aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/extmark.c26
-rw-r--r--src/nvim/api/keysets.lua1
-rw-r--r--src/nvim/api/vim.c5
-rw-r--r--src/nvim/autocmd.c5
-rw-r--r--src/nvim/charset.h4
-rw-r--r--src/nvim/cursor.c1
-rw-r--r--src/nvim/edit.c40
-rw-r--r--src/nvim/eval.c216
-rw-r--r--src/nvim/eval.h7
-rw-r--r--src/nvim/eval.lua188
-rw-r--r--src/nvim/eval/decode.c10
-rw-r--r--src/nvim/eval/funcs.c3
-rw-r--r--src/nvim/ex_cmds.c41
-rw-r--r--src/nvim/ex_docmd.c12
-rw-r--r--src/nvim/ex_eval.c43
-rw-r--r--src/nvim/ex_eval.h4
-rw-r--r--src/nvim/ex_getln.c18
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/fold.h8
-rw-r--r--src/nvim/getchar.c851
-rw-r--r--src/nvim/globals.h6
-rw-r--r--src/nvim/hardcopy.c59
-rw-r--r--src/nvim/if_cscope.c47
-rw-r--r--src/nvim/lua/executor.c3
-rw-r--r--src/nvim/message.c14
-rw-r--r--src/nvim/normal.c843
-rw-r--r--src/nvim/ops.c794
-rw-r--r--src/nvim/option.c148
-rw-r--r--src/nvim/regexp.c32
-rw-r--r--src/nvim/screen.c10
-rw-r--r--src/nvim/tag.c6
-rw-r--r--src/nvim/terminal.c5
-rw-r--r--src/nvim/testdir/runtest.vim5
-rw-r--r--src/nvim/testdir/test_autocmd.vim525
-rw-r--r--src/nvim/testdir/test_breakindent.vim2
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim5
-rw-r--r--src/nvim/testdir/test_cd.vim2
-rw-r--r--src/nvim/testdir/test_charsearch.vim2
-rw-r--r--src/nvim/testdir/test_clientserver.vim2
-rw-r--r--src/nvim/testdir/test_cmdline.vim2
-rw-r--r--src/nvim/testdir/test_compiler.vim10
-rw-r--r--src/nvim/testdir/test_cursor_func.vim6
-rw-r--r--src/nvim/testdir/test_diffmode.vim2
-rw-r--r--src/nvim/testdir/test_environ.vim2
-rw-r--r--src/nvim/testdir/test_execute_func.vim2
-rw-r--r--src/nvim/testdir/test_expr.vim6
-rw-r--r--src/nvim/testdir/test_filetype.vim3
-rw-r--r--src/nvim/testdir/test_fold.vim3
-rw-r--r--src/nvim/testdir/test_functions.vim37
-rw-r--r--src/nvim/testdir/test_listchars.vim2
-rw-r--r--src/nvim/testdir/test_marks.vim4
-rw-r--r--src/nvim/testdir/test_matchadd_conceal_utf8.vim2
-rw-r--r--src/nvim/testdir/test_messages.vim2
-rw-r--r--src/nvim/testdir/test_mksession.vim3
-rw-r--r--src/nvim/testdir/test_options.vim3
-rw-r--r--src/nvim/testdir/test_prompt_buffer.vim84
-rw-r--r--src/nvim/testdir/test_put.vim2
-rw-r--r--src/nvim/testdir/test_quickfix.vim4
-rw-r--r--src/nvim/testdir/test_ruby.vim2
-rw-r--r--src/nvim/testdir/test_search.vim37
-rw-r--r--src/nvim/testdir/test_sha256.vim10
-rw-r--r--src/nvim/testdir/test_signs.vim19
-rw-r--r--src/nvim/testdir/test_spell.vim6
-rw-r--r--src/nvim/testdir/test_spell_utf8.vim6
-rw-r--r--src/nvim/testdir/test_startup.vim6
-rw-r--r--src/nvim/testdir/test_substitute.vim5
-rw-r--r--src/nvim/testdir/test_swap.vim4
-rw-r--r--src/nvim/testdir/test_syntax.vim20
-rw-r--r--src/nvim/testdir/test_system.vim3
-rw-r--r--src/nvim/testdir/test_tabpage.vim4
-rw-r--r--src/nvim/testdir/test_tagjump.vim2
-rw-r--r--src/nvim/testdir/test_taglist.vim2
-rw-r--r--src/nvim/testdir/test_timers.vim10
-rw-r--r--src/nvim/testdir/test_undo.vim2
-rw-r--r--src/nvim/testdir/test_utf8.vim4
-rw-r--r--src/nvim/testdir/test_vartabs.vim2
-rw-r--r--src/nvim/testdir/test_window_cmd.vim29
-rw-r--r--src/nvim/testdir/test_window_id.vim17
-rw-r--r--src/nvim/window.c65
79 files changed, 2594 insertions, 1835 deletions
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 6e25e627b9..742b953c2a 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -339,7 +339,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// @param col Column where to place the mark, 0-based. |api-indexing|
/// @param opts Optional parameters.
/// - id : id of the extmark to edit.
-/// - end_line : ending line of the mark, 0-based inclusive.
+/// - end_row : ending line of the mark, 0-based inclusive.
/// - end_col : ending col of the mark, 0-based exclusive.
/// - hl_group : name of the highlight group used to highlight
/// this mark.
@@ -431,16 +431,26 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
int line2 = -1;
- if (opts->end_line.type == kObjectTypeInteger) {
- Integer val = opts->end_line.data.integer;
+
+ // For backward compatibility we support "end_line" as an alias for "end_row"
+ if (HAS_KEY(opts->end_line)) {
+ if (HAS_KEY(opts->end_row)) {
+ api_set_error(err, kErrorTypeValidation, "cannot use both end_row and end_line");
+ goto error;
+ }
+ opts->end_row = opts->end_line;
+ }
+
+ if (opts->end_row.type == kObjectTypeInteger) {
+ Integer val = opts->end_row.data.integer;
if (val < 0 || val > buf->b_ml.ml_line_count) {
- api_set_error(err, kErrorTypeValidation, "end_line value outside range");
+ api_set_error(err, kErrorTypeValidation, "end_row value outside range");
goto error;
} else {
line2 = (int)val;
}
- } else if (HAS_KEY(opts->end_line)) {
- api_set_error(err, kErrorTypeValidation, "end_line is not an integer");
+ } else if (HAS_KEY(opts->end_row)) {
+ api_set_error(err, kErrorTypeValidation, "end_row is not an integer");
goto error;
}
@@ -571,10 +581,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
OPTION_TO_BOOL(right_gravity, right_gravity, true);
// Only error out if they try to set end_right_gravity without
- // setting end_col or end_line
+ // setting end_col or end_row
if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) {
api_set_error(err, kErrorTypeValidation,
- "cannot set end_right_gravity without setting end_line or end_col");
+ "cannot set end_right_gravity without setting end_row or end_col");
goto error;
}
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index e956a54dbc..f3e7f2f1dc 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -5,6 +5,7 @@ return {
set_extmark = {
"id";
"end_line";
+ "end_row";
"end_col";
"hl_group";
"virt_text";
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 36179b1fab..4f7c320129 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -842,7 +842,7 @@ void nvim_echo(Array chunks, Boolean history, Dictionary opts, Error *err)
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i);
msg_multiline_attr((const char *)chunk.text.data, chunk.attr,
- false, &need_clear);
+ true, &need_clear);
}
if (history) {
msg_ext_set_kind("echomsg");
@@ -1842,6 +1842,9 @@ static void write_msg(String message, bool to_err)
++no_wait_return;
for (uint32_t i = 0; i < message.size; i++) {
+ if (got_int) {
+ break;
+ }
if (to_err) {
PUSH_CHAR(i, err_pos, err_line_buf, emsg);
} else {
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 490fe5a0ac..9044657358 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -1213,10 +1213,13 @@ win_found:
// Hmm, original window disappeared. Just use the first one.
curwin = firstwin;
}
+ curbuf = curwin->w_buffer;
+ // May need to restore insert mode for a prompt buffer.
+ entering_window(curwin);
+
prevwin = win_find_by_handle(aco->save_prevwin_handle);
vars_clear(&aucmd_win->w_vars->dv_hashtab); // free all w: variables
hash_init(&aucmd_win->w_vars->dv_hashtab); // re-use the hashtab
- curbuf = curwin->w_buffer;
xfree(globaldir);
globaldir = aco->globaldir;
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index 47d89717e8..c4e5d9522b 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -14,8 +14,8 @@
/// @return Folded variant.
#define CH_FOLD(c) \
utf_fold((sizeof(c) == sizeof(char)) \
- ?((int)(uint8_t)(c)) \
- :((int)(c)))
+ ? ((int)(uint8_t)(c)) \
+ : ((int)(c)))
/// Flags for vim_str2nr()
typedef enum {
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index e334fd166e..4e1d7f9d78 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -108,6 +108,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a
int head = 0;
one_more = (State & INSERT)
+ || (State & TERM_FOCUS)
|| restart_edit != NUL
|| (VIsual_active && *p_sel != 'o')
|| ((ve_flags & VE_ONEMORE) && wcol < MAXCOL);
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 7d2ce04743..9bfb8a9d4a 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -227,6 +227,7 @@ typedef struct insert_state {
cmdarg_T *ca;
int mincol;
int cmdchar;
+ int cmdchar_todo; // cmdchar to handle once in init_prompt
int startln;
long count;
int c;
@@ -290,6 +291,7 @@ static void insert_enter(InsertState *s)
s->did_backspace = true;
s->old_topfill = -1;
s->replaceState = REPLACE;
+ s->cmdchar_todo = s->cmdchar;
// Remember whether editing was restarted after CTRL-O
did_restart_edit = restart_edit;
// sleep before redrawing, needed for "CTRL-O :" that results in an
@@ -585,7 +587,8 @@ static int insert_check(VimState *state)
}
if (bt_prompt(curbuf)) {
- init_prompt(s->cmdchar);
+ init_prompt(s->cmdchar_todo);
+ s->cmdchar_todo = NUL;
}
// If we inserted a character at the last position of the last line in the
@@ -655,10 +658,17 @@ static int insert_check(VimState *state)
static int insert_execute(VimState *state, int key)
{
+ InsertState *const s = (InsertState *)state;
+ if (stop_insert_mode) {
+ // Insert mode ended, possibly from a callback.
+ s->count = 0;
+ s->nomove = true;
+ return 0;
+ }
+
if (key == K_IGNORE || key == K_NOP) {
return -1; // get another key
}
- InsertState *s = (InsertState *)state;
s->c = key;
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
@@ -984,6 +994,15 @@ static int insert_handle_key(InsertState *s)
break;
case Ctrl_W: // delete word before the cursor
+ if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) {
+ // In a prompt window CTRL-W is used for window commands.
+ // Use Shift-CTRL-W to delete a word.
+ stuffcharReadbuff(Ctrl_W);
+ restart_edit = 'A';
+ s->nomove = true;
+ s->count = 0;
+ return 0;
+ }
s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space);
auto_format(false, true);
break;
@@ -1653,10 +1672,21 @@ static void init_prompt(int cmdchar_todo)
coladvance(MAXCOL);
changed_bytes(curbuf->b_ml.ml_line_count, 0);
}
+
+ // Insert always starts after the prompt, allow editing text after it.
+ if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) {
+ Insstart.lnum = curwin->w_cursor.lnum;
+ Insstart.col = STRLEN(prompt);
+ Insstart_orig = Insstart;
+ Insstart_textlen = Insstart.col;
+ Insstart_blank_vcol = MAXCOL;
+ arrow_used = false;
+ }
+
if (cmdchar_todo == 'A') {
coladvance(MAXCOL);
}
- if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) {
+ if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) {
curwin->w_cursor.col = STRLEN(prompt);
}
// Make sure the cursor is in a valid position.
@@ -5241,7 +5271,7 @@ static int ins_complete(int c, bool enable_pum)
funcname = get_complete_funcname(ctrl_x_mode);
if (*funcname == NUL) {
semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
- ? "completefunc" : "omnifunc");
+ ? "completefunc" : "omnifunc");
// restore did_ai, so that adding comment leader works
did_ai = save_did_ai;
return FAIL;
@@ -8241,7 +8271,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
|| (!revins_on
&& ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
|| (!can_bs(BS_START)
- && (arrow_used
+ && ((arrow_used && !bt_prompt(curbuf))
|| (curwin->w_cursor.lnum == Insstart_orig.lnum
&& curwin->w_cursor.col <= Insstart_orig.col)))
|| (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 2faae08fc8..85e81ee975 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -134,13 +134,15 @@ typedef struct {
.vv_flags = flags, \
}
+#define VIMVAR_KEY_LEN 16 // Maximum length of the key of v:variables
+
// Array to hold the value of v: variables.
// The value is in a dictitem, so that it can also be used in the v: scope.
// The reason to use this table anyway is for very quick access to the
// variables with the VV_ defines.
static struct vimvar {
char *vv_name; ///< Name of the variable, without v:.
- TV_DICTITEM_STRUCT(17) vv_di; ///< Value and name for key (max 16 chars).
+ TV_DICTITEM_STRUCT(VIMVAR_KEY_LEN + 1) vv_di; ///< Value and name for key (max 16 chars).
char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
} vimvars[] =
{
@@ -150,100 +152,103 @@ static struct vimvar {
// VV_SEND_SERVER "servername"
// VV_REG "register"
// VV_OP "operator"
- VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
- VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
- VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
- VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
- VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
- VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
- VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
- VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
- VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT+VV_RO),
- VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
- VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
- VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
- VV(VV_LANG, "lang", VAR_STRING, VV_RO),
- VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
- VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
- VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
- VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
- VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
- VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
- VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
- VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
- VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
- VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
- VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
- VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
- VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
- VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
- VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
- VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
- VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
- VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
- VV(VV_REG, "register", VAR_STRING, VV_RO),
- VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
- VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
- VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
- VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
- VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
- VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
- VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
- VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
- VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
- VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
- VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
- VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
- VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
- VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
- VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
- VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
- VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
- VV(VV_CHAR, "char", VAR_STRING, 0),
- VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
- VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
- VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
- VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
- VV(VV_OP, "operator", VAR_STRING, VV_RO),
- VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
- VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
- VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
- VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
- VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
- VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, VV_RO),
- VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
- VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
- VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
- VV(VV_ERRORS, "errors", VAR_LIST, 0),
- VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
- VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
- VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
- VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
- VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
- VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
- VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
- VV(VV_TESTING, "testing", VAR_NUMBER, 0),
- VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
- VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
- VV(VV_EVENT, "event", VAR_DICT, VV_RO),
- VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
- VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
- VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
- VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
+ VV(VV_COUNT, "count", VAR_NUMBER, VV_RO),
+ VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
+ VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
+ VV(VV_ERRMSG, "errmsg", VAR_STRING, 0),
+ VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
+ VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
+ VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_RO),
+ VV(VV_THIS_SESSION, "this_session", VAR_STRING, 0),
+ VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT+VV_RO),
+ VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO),
+ VV(VV_FNAME, "fname", VAR_STRING, VV_RO),
+ VV(VV_LANG, "lang", VAR_STRING, VV_RO),
+ VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO),
+ VV(VV_CTYPE, "ctype", VAR_STRING, VV_RO),
+ VV(VV_CC_FROM, "charconvert_from", VAR_STRING, VV_RO),
+ VV(VV_CC_TO, "charconvert_to", VAR_STRING, VV_RO),
+ VV(VV_FNAME_IN, "fname_in", VAR_STRING, VV_RO),
+ VV(VV_FNAME_OUT, "fname_out", VAR_STRING, VV_RO),
+ VV(VV_FNAME_NEW, "fname_new", VAR_STRING, VV_RO),
+ VV(VV_FNAME_DIFF, "fname_diff", VAR_STRING, VV_RO),
+ VV(VV_CMDARG, "cmdarg", VAR_STRING, VV_RO),
+ VV(VV_FOLDSTART, "foldstart", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_FOLDEND, "foldend", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_FOLDDASHES, "folddashes", VAR_STRING, VV_RO_SBX),
+ VV(VV_FOLDLEVEL, "foldlevel", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_PROGNAME, "progname", VAR_STRING, VV_RO),
+ VV(VV_SEND_SERVER, "servername", VAR_STRING, VV_RO),
+ VV(VV_DYING, "dying", VAR_NUMBER, VV_RO),
+ VV(VV_EXCEPTION, "exception", VAR_STRING, VV_RO),
+ VV(VV_THROWPOINT, "throwpoint", VAR_STRING, VV_RO),
+ VV(VV_REG, "register", VAR_STRING, VV_RO),
+ VV(VV_CMDBANG, "cmdbang", VAR_NUMBER, VV_RO),
+ VV(VV_INSERTMODE, "insertmode", VAR_STRING, VV_RO),
+ VV(VV_VAL, "val", VAR_UNKNOWN, VV_RO),
+ VV(VV_KEY, "key", VAR_UNKNOWN, VV_RO),
+ VV(VV_PROFILING, "profiling", VAR_NUMBER, VV_RO),
+ VV(VV_FCS_REASON, "fcs_reason", VAR_STRING, VV_RO),
+ VV(VV_FCS_CHOICE, "fcs_choice", VAR_STRING, 0),
+ VV(VV_BEVAL_BUFNR, "beval_bufnr", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_WINNR, "beval_winnr", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_WINID, "beval_winid", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_LNUM, "beval_lnum", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_COL, "beval_col", VAR_NUMBER, VV_RO),
+ VV(VV_BEVAL_TEXT, "beval_text", VAR_STRING, VV_RO),
+ VV(VV_SCROLLSTART, "scrollstart", VAR_STRING, 0),
+ VV(VV_SWAPNAME, "swapname", VAR_STRING, VV_RO),
+ VV(VV_SWAPCHOICE, "swapchoice", VAR_STRING, 0),
+ VV(VV_SWAPCOMMAND, "swapcommand", VAR_STRING, VV_RO),
+ VV(VV_CHAR, "char", VAR_STRING, 0),
+ VV(VV_MOUSE_WIN, "mouse_win", VAR_NUMBER, 0),
+ VV(VV_MOUSE_WINID, "mouse_winid", VAR_NUMBER, 0),
+ VV(VV_MOUSE_LNUM, "mouse_lnum", VAR_NUMBER, 0),
+ VV(VV_MOUSE_COL, "mouse_col", VAR_NUMBER, 0),
+ VV(VV_OP, "operator", VAR_STRING, VV_RO),
+ VV(VV_SEARCHFORWARD, "searchforward", VAR_NUMBER, 0),
+ VV(VV_HLSEARCH, "hlsearch", VAR_NUMBER, 0),
+ VV(VV_OLDFILES, "oldfiles", VAR_LIST, 0),
+ VV(VV_WINDOWID, "windowid", VAR_NUMBER, VV_RO_SBX),
+ VV(VV_PROGPATH, "progpath", VAR_STRING, VV_RO),
+ VV(VV_COMPLETED_ITEM, "completed_item", VAR_DICT, VV_RO),
+ VV(VV_OPTION_NEW, "option_new", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLD, "option_old", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLDLOCAL, "option_oldlocal", VAR_STRING, VV_RO),
+ VV(VV_OPTION_OLDGLOBAL, "option_oldglobal", VAR_STRING, VV_RO),
+ VV(VV_OPTION_COMMAND, "option_command", VAR_STRING, VV_RO),
+ VV(VV_OPTION_TYPE, "option_type", VAR_STRING, VV_RO),
+ VV(VV_ERRORS, "errors", VAR_LIST, 0),
+ VV(VV_FALSE, "false", VAR_BOOL, VV_RO),
+ VV(VV_TRUE, "true", VAR_BOOL, VV_RO),
+ VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
+ VV(VV_NUMBERMAX, "numbermax", VAR_NUMBER, VV_RO),
+ VV(VV_NUMBERMIN, "numbermin", VAR_NUMBER, VV_RO),
+ VV(VV_NUMBERSIZE, "numbersize", VAR_NUMBER, VV_RO),
+ VV(VV_VIM_DID_ENTER, "vim_did_enter", VAR_NUMBER, VV_RO),
+ VV(VV_TESTING, "testing", VAR_NUMBER, 0),
+ VV(VV_TYPE_NUMBER, "t_number", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_STRING, "t_string", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_FUNC, "t_func", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_LIST, "t_list", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
+ VV(VV_EVENT, "event", VAR_DICT, VV_RO),
+ VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
+ VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
+ VV(VV_COLLATE, "collate", VAR_STRING, VV_RO),
+ VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
// Neovim
- VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
- VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
- VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
- VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
- VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
- VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
- VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
+ VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
+ VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
+ VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
+ VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
+ VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
+ VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
+ VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
};
#undef VV
@@ -344,7 +349,7 @@ void eval_init(void)
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
p = &vimvars[i];
- assert(STRLEN(p->vv_name) <= 16);
+ assert(STRLEN(p->vv_name) <= VIMVAR_KEY_LEN);
STRCPY(p->vv_di.di_key, p->vv_name);
if (p->vv_flags & VV_RO) {
p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
@@ -4523,7 +4528,7 @@ static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose)
* dict.name
*/
key = *arg + 1;
- for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len) {
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {
}
if (len == 0) {
return FAIL;
@@ -6603,8 +6608,9 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr
: (const char *)s));
// Don't check an autoload name for existence here.
} else if (trans_name != NULL
- && (is_funcref ? find_func(trans_name) == NULL
- : !translated_function_exists((const char *)trans_name))) {
+ && (is_funcref
+ ? find_func(trans_name) == NULL
+ : !translated_function_exists((const char *)trans_name))) {
semsg(_("E700: Unknown function: %s"), s);
} else {
int dict_idx = 0;
@@ -9649,8 +9655,8 @@ bool var_check_func_name(const char *const name, const bool new_var)
{
// Allow for w: b: s: and t:.
if (!(vim_strchr((char_u *)"wbst", name[0]) != NULL && name[1] == ':')
- && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':') ? name[2]
- : name[0])) {
+ && !ASCII_ISUPPER((name[0] != NUL && name[1] == ':')
+ ? name[2] : name[0])) {
semsg(_("E704: Funcref variable name must start with a capital: %s"), name);
return false;
}
@@ -10446,11 +10452,15 @@ void option_last_set_msg(LastSet last_set)
}
}
-// reset v:option_new, v:option_old and v:option_type
+// reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
+// v:option_type, and v:option_command.
void reset_v_option_vars(void)
{
- set_vim_var_string(VV_OPTION_NEW, NULL, -1);
- set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_NEW, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
+ set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
}
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index d34348a274..3b3a68bd29 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -138,6 +138,9 @@ typedef enum {
VV_COMPLETED_ITEM,
VV_OPTION_NEW,
VV_OPTION_OLD,
+ VV_OPTION_OLDLOCAL,
+ VV_OPTION_OLDGLOBAL,
+ VV_OPTION_COMMAND,
VV_OPTION_TYPE,
VV_ERRORS,
VV_FALSE,
@@ -209,8 +212,8 @@ typedef enum {
/// flags for find_name_end()
#define FNE_INCL_BR 1 // find_name_end(): include [] in name
-#define FNE_CHECK_START 2 /* find_name_end(): check name starts with
- valid character */
+#define FNE_CHECK_START 2 // find_name_end(): check name starts with
+ // valid character
typedef struct {
TimeWatcher tw;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index dfc51d80af..9a76b67de6 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -17,7 +17,7 @@ end
-- Usable with the base key: use the last function argument as the method base.
-- Value is from funcs.h file. "BASE_" prefix is omitted.
-local LAST = "BASE_LAST"
+-- local LAST = "BASE_LAST" (currently unused after port of v8.2.1168)
return {
funcs={
@@ -26,14 +26,14 @@ return {
add={args=2, base=1},
['and']={args=2, base=1},
api_info={},
- append={args=2, base=LAST},
- appendbufline={args=3, base=LAST},
+ append={args=2, base=2},
+ appendbufline={args=3, base=3},
argc={args={0, 1}},
argidx={},
arglistid={args={0, 2}},
argv={args={0, 2}},
asin={args=1, base=1, func="float_op_wrapper", data="&asin"}, -- WJMc
- assert_beeps={args={1}, base=1},
+ assert_beeps={args=1, base=1},
assert_equal={args={2, 3}, base=2},
assert_equalfile={args={2, 3}, base=1},
assert_exception={args={1, 2}},
@@ -41,7 +41,7 @@ return {
assert_false={args={1, 2}, base=1},
assert_inrange={args={3, 4}, base=3},
assert_match={args={2, 3}, base=2},
- assert_nobeep={args={1}},
+ assert_nobeep={args=1, base=1},
assert_notequal={args={2, 3}, base=2},
assert_notmatch={args={2, 3}, base=2},
assert_report={args=1, base=1},
@@ -53,8 +53,8 @@ return {
bufadd={args=1, base=1},
bufexists={args=1, base=1},
buffer_exists={args=1, base=1, func='f_bufexists'}, -- obsolete
- buffer_name={args={0, 1}, func='f_bufname'}, -- obsolete
- buffer_number={args={0, 1}, func='f_bufnr'}, -- obsolete
+ buffer_name={args={0, 1}, base=1, func='f_bufname'}, -- obsolete
+ buffer_number={args={0, 1}, base=1, func='f_bufnr'}, -- obsolete
buflisted={args=1, base=1},
bufload={args=1, base=1},
bufloaded={args=1, base=1},
@@ -71,7 +71,7 @@ return {
chanclose={args={1, 2}},
chansend={args=2},
char2nr={args={1, 2}, base=1},
- charidx={args={2, 3}},
+ charidx={args={2, 3}, base=1},
chdir={args=1, base=1},
cindent={args=1, base=1},
clearmatches={args={0, 1}, base=1},
@@ -121,7 +121,7 @@ return {
filter={args=2, base=1},
finddir={args={1, 3}, base=1},
findfile={args={1, 3}, base=1},
- flatten={args={1, 2}},
+ flatten={args={1, 2}, base=1},
float2nr={args=1, base=1},
floor={args=1, base=1, func="float_op_wrapper", data="&floor"},
fmod={args=2, base=1},
@@ -137,7 +137,7 @@ return {
['function']={args={1, 3}, base=1},
garbagecollect={args={0, 1}},
get={args={2, 3}, base=1},
- getbufinfo={args={0, 1}},
+ getbufinfo={args={0, 1}, base=1},
getbufline={args={2, 3}, base=1},
getbufvar={args={2, 3}, base=1},
getchangelist={args={0, 1}, base=1},
@@ -152,7 +152,7 @@ return {
getcompletion={args={2, 3}, base=1},
getcurpos={},
getcwd={args={0, 2}, base=1},
- getenv={args={1}, base=1},
+ getenv={args=1, base=1},
getfontname={args={0, 1}},
getfperm={args=1, base=1},
getfsize={args=1, base=1},
@@ -161,7 +161,7 @@ return {
getjumplist={args={0, 2}, base=1},
getline={args={1, 2}, base=1},
getloclist={args={1, 2}},
- getmarklist={args={0, 1}},
+ getmarklist={args={0, 1}, base=1},
getmatches={args={0, 1}},
getmousepos={},
getpid={},
@@ -262,7 +262,7 @@ return {
pow={args=2, base=1},
prevnonblank={args=1, base=1},
printf={args=varargs(1), base=2},
- prompt_getprompt={args=1},
+ prompt_getprompt={args=1, base=1},
prompt_setcallback={args={2, 2}, base=1},
prompt_setinterrupt={args={2, 2}, base=1},
prompt_setprompt={args={2, 2}, base=1},
@@ -291,82 +291,82 @@ return {
rpcstart={args={1, 2}},
rpcstop={args=1},
rubyeval={args=1, base=1},
- screenattr={args=2},
- screenchar={args=2},
- screenchars={args=2},
+ screenattr={args=2, base=1},
+ screenchar={args=2, base=1},
+ screenchars={args=2, base=1},
screencol={},
- screenpos={args=3},
+ screenpos={args=3, base=1},
screenrow={},
- screenstring={args=2},
- search={args={1, 4}},
- searchcount={args={0,1}},
- searchdecl={args={1, 3}},
+ screenstring={args=2, base=1},
+ search={args={1, 4}, base=1},
+ searchcount={args={0, 1}, base=1},
+ searchdecl={args={1, 3}, base=1},
searchpair={args={3, 7}},
searchpairpos={args={3, 7}},
- searchpos={args={1, 4}},
+ searchpos={args={1, 4}, base=1},
serverlist={},
serverstart={args={0, 1}},
serverstop={args=1},
- setbufline={args=3},
- setbufvar={args=3},
- setcharsearch={args=1},
- setcmdpos={args=1},
- setenv={args=2},
+ setbufline={args=3, base=3},
+ setbufvar={args=3, base=3},
+ setcharsearch={args=1, base=1},
+ setcmdpos={args=1, base=1},
+ setenv={args=2, base=2},
setfperm={args=2, base=1},
- setline={args=2},
- setloclist={args={2, 4}},
- setmatches={args={1, 2}},
- setpos={args=2},
- setqflist={args={1, 3}},
- setreg={args={2, 3}},
- settabvar={args=3},
- settabwinvar={args=4},
- settagstack={args={2, 3}},
- setwinvar={args=3},
- sha256={args=1},
- shellescape={args={1, 2}},
- shiftwidth={args={0, 1}},
- sign_define={args={1, 2}},
- sign_getdefined={args={0, 1}},
- sign_getplaced={args={0, 2}},
- sign_jump={args={3, 3}},
- sign_place={args={4, 5}},
- sign_placelist={args={1}},
- sign_undefine={args={0, 1}},
- sign_unplace={args={1, 2}},
- sign_unplacelist={args={1}},
- simplify={args=1},
+ setline={args=2, base=2},
+ setloclist={args={2, 4}, base=2},
+ setmatches={args={1, 2}, base=1},
+ setpos={args=2, base=2},
+ setqflist={args={1, 3}, base=1},
+ setreg={args={2, 3}, base=2},
+ settabvar={args=3, base=3},
+ settabwinvar={args=4, base=4},
+ settagstack={args={2, 3}, base=2},
+ setwinvar={args=3, base=3},
+ sha256={args=1, base=1},
+ shellescape={args={1, 2}, base=1},
+ shiftwidth={args={0, 1}, base=1},
+ sign_define={args={1, 2}, base=1},
+ sign_getdefined={args={0, 1}, base=1},
+ sign_getplaced={args={0, 2}, base=1},
+ sign_jump={args=3, base=1},
+ sign_place={args={4, 5}, base=1},
+ sign_placelist={args=1, base=1},
+ sign_undefine={args={0, 1}, base=1},
+ sign_unplace={args={1, 2}, base=1},
+ sign_unplacelist={args=1, base=1},
+ simplify={args=1, base=1},
sin={args=1, base=1, func="float_op_wrapper", data="&sin"},
sinh={args=1, base=1, func="float_op_wrapper", data="&sinh"},
sockconnect={args={2,3}},
sort={args={1, 3}, base=1},
- soundfold={args=1},
+ soundfold={args=1, base=1},
stdioopen={args=1},
- spellbadword={args={0, 1}},
- spellsuggest={args={1, 3}},
+ spellbadword={args={0, 1}, base=1},
+ spellsuggest={args={1, 3}, base=1},
split={args={1, 3}, base=1},
sqrt={args=1, base=1, func="float_op_wrapper", data="&sqrt"},
stdpath={args=1},
str2float={args=1, base=1},
str2list={args={1, 2}, base=1},
- str2nr={args={1, 3}},
- strcharpart={args={2, 3}},
- strchars={args={1,2}},
- strdisplaywidth={args={1, 2}},
- strftime={args={1, 2}},
- strgetchar={args={2, 2}},
- stridx={args={2, 3}},
+ str2nr={args={1, 3}, base=1},
+ strcharpart={args={2, 3}, base=1},
+ strchars={args={1, 2}, base=1},
+ strdisplaywidth={args={1, 2}, base=1},
+ strftime={args={1, 2}, base=1},
+ strgetchar={args=2, base=1},
+ stridx={args={2, 3}, base=1},
string={args=1, base=1},
strlen={args=1, base=1},
- strpart={args={2, 4}},
- strptime={args=2},
- strridx={args={2, 3}},
+ strpart={args={2, 4}, base=1},
+ strptime={args=2, base=1},
+ strridx={args={2, 3}, base=1},
strtrans={args=1, base=1},
strwidth={args=1, base=1},
- submatch={args={1, 2}},
+ submatch={args={1, 2}, base=1},
substitute={args=4, base=1},
- swapinfo={args={1}},
- swapname={args={1}},
+ swapinfo={args=1, base=1},
+ swapname={args=1, base=1},
synID={args=3},
synIDattr={args={2, 3}, base=1},
synIDtrans={args=1, base=1},
@@ -374,58 +374,58 @@ return {
synstack={args=2},
system={args={1, 2}, base=1},
systemlist={args={1, 3}, base=1},
- tabpagebuflist={args={0, 1}},
+ tabpagebuflist={args={0, 1}, base=1},
tabpagenr={args={0, 1}},
- tabpagewinnr={args={1, 2}},
+ tabpagewinnr={args={1, 2}, base=1},
tagfiles={},
- taglist={args={1, 2}},
+ taglist={args={1, 2}, base=1},
tan={args=1, base=1, func="float_op_wrapper", data="&tan"},
tanh={args=1, base=1, func="float_op_wrapper", data="&tanh"},
tempname={},
termopen={args={1, 2}},
test_garbagecollect_now={},
test_write_list_log={args=1},
- timer_info={args={0,1}},
- timer_pause={args=2},
- timer_start={args={2,3}},
- timer_stop={args=1},
+ timer_info={args={0, 1}, base=1},
+ timer_pause={args=2, base=1},
+ timer_start={args={2, 3}, base=1},
+ timer_stop={args=1, base=1},
timer_stopall={args=0},
- tolower={args=1},
- toupper={args=1},
- tr={args=3},
- trim={args={1,3}},
+ tolower={args=1, base=1},
+ toupper={args=1, base=1},
+ tr={args=3, base=1},
+ trim={args={1, 3}, base=1},
trunc={args=1, base=1, func="float_op_wrapper", data="&trunc"},
type={args=1, base=1},
- undofile={args=1},
+ undofile={args=1, base=1},
undotree={},
uniq={args={1, 3}, base=1},
values={args=1, base=1},
- virtcol={args=1},
+ virtcol={args=1, base=1},
visualmode={args={0, 1}},
wait={args={2,3}},
wildmenumode={},
- win_execute={args={2, 3}},
- win_findbuf={args=1},
- win_getid={args={0,2}},
- win_gettype={args={0,1}},
- win_gotoid={args=1},
- win_id2tabwin={args=1},
- win_id2win={args=1},
- win_screenpos={args=1},
- win_splitmove={args={2, 3}},
+ win_execute={args={2, 3}, base=2},
+ win_findbuf={args=1, base=1},
+ win_getid={args={0, 2}, base=1},
+ win_gettype={args={0, 1}, base=1},
+ win_gotoid={args=1, base=1},
+ win_id2tabwin={args=1, base=1},
+ win_id2win={args=1, base=1},
+ win_screenpos={args=1, base=1},
+ win_splitmove={args={2, 3}, base=1},
winbufnr={args=1, base=1},
wincol={},
windowsversion={},
- winheight={args=1},
- winlayout={args={0, 1}},
+ winheight={args=1, base=1},
+ winlayout={args={0, 1}, base=1},
winline={},
- winnr={args={0, 1}},
+ winnr={args={0, 1}, base=1},
winrestcmd={},
- winrestview={args=1},
+ winrestview={args=1, base=1},
winsaveview={},
- winwidth={args=1},
+ winwidth={args=1, base=1},
wordcount={},
- writefile={args={2, 3}},
+ writefile={args={2, 3}, base=1},
xor={args=2, base=1},
},
}
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 5008945f09..797420c150 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -726,11 +726,11 @@ json_decode_string_cycle_start:
semsg(_("E474: Using comma in place of colon: %.*s"), LENP(p, e));
goto json_decode_string_fail;
} else if (last_container.special_val == NULL
- ? (last_container.container.v_type == VAR_DICT
- ? (DICT_LEN(last_container.container.vval.v_dict) == 0)
- : (tv_list_len(last_container.container.vval.v_list)
- == 0))
- : (tv_list_len(last_container.special_val) == 0)) {
+ ? (last_container.container.v_type == VAR_DICT
+ ? (DICT_LEN(last_container.container.vval.v_dict) == 0)
+ : (tv_list_len(last_container.container.vval.v_list)
+ == 0))
+ : (tv_list_len(last_container.special_val) == 0)) {
semsg(_("E474: Leading comma: %.*s"), LENP(p, e));
goto json_decode_string_fail;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index dfadd28ebe..33ca4016cf 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -11551,6 +11551,9 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dict_T *dict;
rettv->vval.v_number = -1;
+ if (check_secure()) {
+ return;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
if (argvars[2].v_type != VAR_DICT
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 77944851d2..f95fe84f69 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -305,9 +305,8 @@ void ex_align(exarg_T *eap)
*/
do {
(void)set_indent(++new_indent, 0);
- }
- while (linelen(NULL) <= width);
- --new_indent;
+ } while (linelen(NULL) <= width);
+ new_indent--;
break;
}
--new_indent;
@@ -1457,7 +1456,7 @@ error:
filterend:
if (curbuf != old_curbuf) {
- --no_wait_return;
+ no_wait_return--;
emsg(_("E135: *Filter* Autocommands must not change current buffer"));
}
if (itmp != NULL) {
@@ -2094,7 +2093,7 @@ void do_wqall(exarg_T *eap)
}
if (buf->b_ffname == NULL) {
semsg(_("E141: No file name for buffer %" PRId64), (int64_t)buf->b_fnum);
- ++error;
+ error++;
} else if (check_readonly(&eap->forceit, buf)
|| check_overwrite(eap, buf, buf->b_fname, buf->b_ffname,
FALSE) == FAIL) {
@@ -2120,17 +2119,15 @@ void do_wqall(exarg_T *eap)
}
}
-/*
- * Check the 'write' option.
- * Return TRUE and give a message when it's not st.
- */
-int not_writing(void)
+// Check the 'write' option.
+// Return true and give a message when it's not st.
+bool not_writing(void)
{
if (p_write) {
- return FALSE;
+ return false;
}
emsg(_("E142: File not written: Writing is disabled by 'write' option"));
- return TRUE;
+ return true;
}
/*
@@ -2945,7 +2942,7 @@ void ex_append(exarg_T *eap)
}
for (;;) {
- msg_scroll = TRUE;
+ msg_scroll = true;
need_wait_return = false;
if (curbuf->b_p_ai) {
if (append_indent >= 0) {
@@ -3131,7 +3128,7 @@ void ex_z(exarg_T *eap)
// the number of '-' and '+' multiplies the distance
if (*kind == '-' || *kind == '+') {
- for (x = kind + 1; *x == *kind; ++x) {
+ for (x = kind + 1; *x == *kind; x++) {
}
}
@@ -3214,26 +3211,24 @@ void ex_z(exarg_T *eap)
ex_no_reprint = true;
}
-/*
- * Check if the secure flag is set (.exrc or .vimrc in current directory).
- * If so, give an error message and return TRUE.
- * Otherwise, return FALSE.
- */
-int check_secure(void)
+// Check if the secure flag is set (.exrc or .vimrc in current directory).
+// If so, give an error message and return true.
+// Otherwise, return false.
+bool check_secure(void)
{
if (secure) {
secure = 2;
emsg(_(e_curdir));
- return TRUE;
+ return true;
}
// In the sandbox more things are not allowed, including the things
// disallowed in secure mode.
if (sandbox != 0) {
emsg(_(e_sandbox));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/// Previous substitute replacement string
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 024eb0a904..77cd50ecb7 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -435,7 +435,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
&& cstack.cs_idx < 0
&& !(getline_is_func
&& func_has_abort(real_cookie))) {
- did_emsg = FALSE;
+ did_emsg = false;
}
/*
@@ -2717,7 +2717,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *
*/
gap = &curbuf->b_ucmds;
for (;;) {
- for (j = 0; j < gap->ga_len; ++j) {
+ for (j = 0; j < gap->ga_len; j++) {
uc = USER_CMD_GA(gap, j);
cp = eap->cmd;
np = uc->uc_name;
@@ -5328,7 +5328,7 @@ static void uc_list(char_u *name, size_t name_len)
? &prevwin->w_buffer->b_ucmds
: &curbuf->b_ucmds;
for (;;) {
- for (i = 0; i < gap->ga_len; ++i) {
+ for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
a = cmd->uc_argt;
@@ -5715,7 +5715,7 @@ static void ex_delcommand(exarg_T *eap)
gap = &curbuf->b_ucmds;
for (;;) {
- for (i = 0; i < gap->ga_len; ++i) {
+ for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
cmp = STRCMP(eap->arg, cmd->uc_name);
if (cmp <= 0) {
@@ -8338,9 +8338,7 @@ static void ex_redir(exarg_T *eap)
if (var_redir_start(skipwhite(arg), append) == OK) {
redir_vname = 1;
}
- }
- // TODO: redirect to a buffer
- else {
+ } else { // TODO(vim): redirect to a buffer
semsg(_(e_invarg2), eap->arg);
}
}
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index f60f0ebe98..b1c59a607c 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -437,7 +437,7 @@ char *get_exception_string(void *value, except_type_T type, char_u *cmdname, int
}
}
} else {
- *should_free = FALSE;
+ *should_free = false;
ret = value;
}
@@ -888,11 +888,10 @@ void ex_endif(exarg_T *eap)
*/
void ex_else(exarg_T *eap)
{
- int skip;
int result;
cstack_T *const cstack = eap->cstack;
- skip = CHECK_SKIP;
+ bool skip = CHECK_SKIP;
if (cstack->cs_idx < 0
|| (cstack->cs_flags[cstack->cs_idx]
@@ -902,14 +901,14 @@ void ex_else(exarg_T *eap)
return;
}
eap->errmsg = N_("E582: :elseif without :if");
- skip = TRUE;
+ skip = true;
} else if (cstack->cs_flags[cstack->cs_idx] & CSF_ELSE) {
if (eap->cmdidx == CMD_else) {
eap->errmsg = N_("E583: multiple :else");
return;
}
eap->errmsg = N_("E584: :elseif after :else");
- skip = TRUE;
+ skip = true;
}
// if skipping or the ":if" was TRUE, reset ACTIVE, otherwise set it
@@ -917,7 +916,7 @@ void ex_else(exarg_T *eap)
if (eap->errmsg == NULL) {
cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
}
- skip = TRUE; // don't evaluate an ":elseif"
+ skip = true; // don't evaluate an ":elseif"
} else {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE;
}
@@ -932,7 +931,7 @@ void ex_else(exarg_T *eap)
// later on.
if (!skip && dbg_check_skipped(eap) && got_int) {
(void)do_intthrow(cstack);
- skip = TRUE;
+ skip = true;
}
if (eap->cmdidx == CMD_elseif) {
@@ -1322,9 +1321,9 @@ void ex_try(exarg_T *eap)
void ex_catch(exarg_T *eap)
{
int idx = 0;
- int give_up = FALSE;
- int skip = FALSE;
- int caught = FALSE;
+ bool give_up = false;
+ bool skip = false;
+ bool caught = false;
char_u *end;
char_u save_char = 0;
char_u *save_cpo;
@@ -1335,13 +1334,13 @@ void ex_catch(exarg_T *eap)
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = N_("E603: :catch without :try");
- give_up = TRUE;
+ give_up = true;
} else {
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
// Report what's missing if the matching ":try" is not in its
// finally clause.
eap->errmsg = get_end_emsg(cstack);
- skip = TRUE;
+ skip = true;
}
for (idx = cstack->cs_idx; idx > 0; --idx) {
if (cstack->cs_flags[idx] & CSF_TRY) {
@@ -1352,7 +1351,7 @@ void ex_catch(exarg_T *eap)
// Give up for a ":catch" after ":finally" and ignore it.
// Just parse.
eap->errmsg = N_("E604: :catch after :finally");
- give_up = TRUE;
+ give_up = true;
} else {
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
&cstack->cs_looplevel);
@@ -1425,7 +1424,7 @@ void ex_catch(exarg_T *eap)
// CTRL-C while matching should abort it.
//
prev_got_int = got_int;
- got_int = FALSE;
+ got_int = false;
caught = vim_regexec_nl(&regmatch, (char_u *)current_exception->value,
(colnr_T)0);
got_int |= prev_got_int;
@@ -1602,8 +1601,7 @@ void ex_finally(exarg_T *eap)
void ex_endtry(exarg_T *eap)
{
int idx;
- int skip;
- int rethrow = FALSE;
+ bool rethrow = false;
int pending = CSTP_NONE;
void *rettv = NULL;
cstack_T *const cstack = eap->cstack;
@@ -1621,20 +1619,19 @@ void ex_endtry(exarg_T *eap)
// made inactive by a ":continue", ":break", ":return", or ":finish" in
// the finally clause. The latter case need not be tested since then
// anything pending has already been discarded.
- skip = (did_emsg || got_int || current_exception
- || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE));
+ bool skip = did_emsg || got_int || current_exception
+ || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
// Find the matching ":try" and report what's missing.
idx = cstack->cs_idx;
do {
- --idx;
- }
- while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
+ idx--;
+ } while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
&cstack->cs_looplevel);
- skip = TRUE;
+ skip = true;
/*
* If an exception is being thrown, discard it to prevent it from
@@ -1677,7 +1674,7 @@ void ex_endtry(exarg_T *eap)
// before the ":endtry". That is, throw an interrupt exception and
// set "skip" and "rethrow".
if (got_int) {
- skip = TRUE;
+ skip = true;
(void)do_intthrow(cstack);
// The do_intthrow() call may have reset current_exception or
// cstack->cs_pending[idx].
diff --git a/src/nvim/ex_eval.h b/src/nvim/ex_eval.h
index 25b30b2805..15da4b2d60 100644
--- a/src/nvim/ex_eval.h
+++ b/src/nvim/ex_eval.h
@@ -17,8 +17,8 @@
#define CSF_THROWN 0x0400 // exception thrown to this try conditional
#define CSF_CAUGHT 0x0800 // exception caught by this try conditional
#define CSF_SILENT 0x1000 // "emsg_silent" reset by ":try"
-/* Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
- * (an ":if"), and CSF_SILENT is only used when CSF_TRY is set. */
+// Note that CSF_ELSE is only used when CSF_TRY and CSF_WHILE are unset
+// (an ":if"), and CSF_SILENT is only used when CSF_TRY is set.
/*
* What's pending for being reactivated at the ":endtry" of this try
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 9cf39802de..475f22d061 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2491,27 +2491,25 @@ char *get_text_locked_msg(void)
}
/// Check if "curbuf->b_ro_locked" or "allbuf_lock" is set and
-/// return TRUE when it is and give an error message.
-int curbuf_locked(void)
+/// return true when it is and give an error message.
+bool curbuf_locked(void)
{
if (curbuf->b_ro_locked > 0) {
emsg(_("E788: Not allowed to edit another buffer now"));
- return TRUE;
+ return true;
}
return allbuf_locked();
}
-/*
- * Check if "allbuf_lock" is set and return TRUE when it is and give an error
- * message.
- */
-int allbuf_locked(void)
+// Check if "allbuf_lock" is set and return true when it is and give an error
+// message.
+bool allbuf_locked(void)
{
if (allbuf_lock > 0) {
emsg(_("E811: Not allowed to change buffer information now"));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int cmdline_charsize(int idx)
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index c90115d796..24428c2d9a 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1851,7 +1851,7 @@ failed:
msg_scrolled_ign = true;
if (!read_stdin && !read_buffer) {
- p = (char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0);
+ p = (char_u *)msg_trunc_attr((char *)IObuff, false, 0);
}
if (read_stdin || read_buffer || restart_edit != 0
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index a96ea8a039..6b29214760 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -14,10 +14,10 @@
*/
typedef struct foldinfo {
linenr_T fi_lnum; // line number where fold starts
- int fi_level; /* level of the fold; when this is zero the
- other fields are invalid */
- int fi_low_level; /* lowest fold level that starts in the same
- line */
+ int fi_level; // level of the fold; when this is zero the
+ // other fields are invalid
+ int fi_low_level; // lowest fold level that starts in the same
+ // line
long fi_lines;
} foldinfo_T;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 2f4b59837a..27e8cb36af 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1680,6 +1680,325 @@ int char_avail(void)
return retval != NUL;
}
+typedef enum {
+ map_result_fail, // failed, break loop
+ map_result_get, // get a character from typeahead
+ map_result_retry, // try to map again
+ map_result_nomatch // no matching mapping, get char
+} map_result_T;
+
+/// Handle mappings in the typeahead buffer.
+/// - When something was mapped, return map_result_retry for recursive mappings.
+/// - When nothing mapped and typeahead has a character: return map_result_get.
+/// - When there is no match yet, return map_result_nomatch, need to get more
+/// typeahead.
+static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
+{
+ mapblock_T *mp = NULL;
+ mapblock_T *mp2;
+ mapblock_T *mp_match;
+ int mp_match_len = 0;
+ int max_mlen = 0;
+ int tb_c1;
+ int mlen;
+ int nolmaplen;
+ int keylen = *keylenp;
+ int i;
+ int local_State = get_real_state();
+
+ // Check for a mappable key sequence.
+ // Walk through one maphash[] list until we find an entry that matches.
+ //
+ // Don't look for mappings if:
+ // - no_mapping set: mapping disabled (e.g. for CTRL-V)
+ // - maphash_valid not set: no mappings present.
+ // - typebuf.tb_buf[typebuf.tb_off] should not be remapped
+ // - in insert or cmdline mode and 'paste' option set
+ // - waiting for "hit return to continue" and CR or SPACE typed
+ // - waiting for a char with --more--
+ // - in Ctrl-X mode, and we get a valid char for that mode
+ tb_c1 = typebuf.tb_buf[typebuf.tb_off];
+ if (no_mapping == 0 && maphash_valid
+ && (no_zero_mapping == 0 || tb_c1 != '0')
+ && (typebuf.tb_maplen == 0
+ || (p_remap
+ && !(typebuf.tb_noremap[typebuf.tb_off] & (RM_NONE|RM_ABBR))))
+ && !(p_paste && (State & (INSERT + CMDLINE)))
+ && !(State == HITRETURN && (tb_c1 == CAR || tb_c1 == ' '))
+ && State != ASKMORE
+ && State != CONFIRM
+ && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(tb_c1))
+ || ((compl_cont_status & CONT_LOCAL)
+ && (tb_c1 == Ctrl_N || tb_c1 == Ctrl_P)))) {
+ if (tb_c1 == K_SPECIAL) {
+ nolmaplen = 2;
+ } else {
+ LANGMAP_ADJUST(tb_c1, !(State & (CMDLINE | INSERT)) && get_real_state() != SELECTMODE);
+ nolmaplen = 0;
+ }
+ // First try buffer-local mappings.
+ mp = curbuf->b_maphash[MAP_HASH(local_State, tb_c1)];
+ mp2 = maphash[MAP_HASH(local_State, tb_c1)];
+ if (mp == NULL) {
+ // There are no buffer-local mappings.
+ mp = mp2;
+ mp2 = NULL;
+ }
+ // Loop until a partly matching mapping is found or all (local)
+ // mappings have been checked.
+ // The longest full match is remembered in "mp_match".
+ // A full match is only accepted if there is no partly match, so "aa"
+ // and "aaa" can both be mapped.
+ mp_match = NULL;
+ mp_match_len = 0;
+ for (; mp != NULL; mp->m_next == NULL ? (mp = mp2, mp2 = NULL) : (mp = mp->m_next)) {
+ // Only consider an entry if the first character matches and it is
+ // for the current state.
+ // Skip ":lmap" mappings if keys were mapped.
+ if (mp->m_keys[0] == tb_c1 && (mp->m_mode & local_State)
+ && ((mp->m_mode & LANGMAP) == 0 || typebuf.tb_maplen == 0)) {
+ int nomap = nolmaplen;
+ int c2;
+ // 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--;
+ } else if (c2 == K_SPECIAL) {
+ nomap = 2;
+ } else {
+ LANGMAP_ADJUST(c2, true);
+ }
+ if (mp->m_keys[mlen] != c2) {
+ break;
+ }
+ }
+
+ // Don't allow mapping the first byte(s) of a multi-byte char.
+ // Happens when mapping <M-a> and then changing 'encoding'.
+ // Beware that 0x80 is escaped.
+ char_u *p1 = mp->m_keys;
+ char_u *p2 = (char_u *)mb_unescape((const char **)&p1);
+
+ if (p2 != NULL && MB_BYTE2LEN(tb_c1) > utfc_ptr2len(p2)) {
+ mlen = 0;
+ }
+
+ // Check an entry whether it matches.
+ // - Full match: mlen == keylen
+ // - Partly match: mlen == typebuf.tb_len
+ keylen = mp->m_keylen;
+ if (mlen == keylen || (mlen == typebuf.tb_len && typebuf.tb_len < keylen)) {
+ char_u *s;
+ int n;
+
+ // If only script-local mappings are allowed, check if the
+ // mapping starts with K_SNR.
+ s = typebuf.tb_noremap + typebuf.tb_off;
+ if (*s == RM_SCRIPT
+ && (mp->m_keys[0] != K_SPECIAL
+ || mp->m_keys[1] != KS_EXTRA
+ || mp->m_keys[2] != KE_SNR)) {
+ continue;
+ }
+
+ // If one of the typed keys cannot be remapped, skip the entry.
+ for (n = mlen; --n >= 0;) {
+ if (*s++ & (RM_NONE|RM_ABBR)) {
+ break;
+ }
+ }
+ if (n >= 0) {
+ continue;
+ }
+
+ if (keylen > typebuf.tb_len) {
+ if (!*timedout && !(mp_match != NULL && mp_match->m_nowait)) {
+ // break at a partly match
+ keylen = KEYLEN_PART_MAP;
+ break;
+ }
+ } else if (keylen > mp_match_len
+ || (keylen == mp_match_len
+ && mp_match != NULL
+ && (mp_match->m_mode & LANGMAP) == 0
+ && (mp->m_mode & LANGMAP) != 0)) {
+ // found a longer match
+ mp_match = mp;
+ mp_match_len = keylen;
+ }
+ } else {
+ // No match; may have to check for termcode at next character.
+ if (max_mlen < mlen) {
+ max_mlen = mlen;
+ }
+ }
+ }
+ }
+
+ // If no partly match found, use the longest full match.
+ if (keylen != KEYLEN_PART_MAP) {
+ mp = mp_match;
+ keylen = mp_match_len;
+ }
+ }
+
+ // Check for match with 'pastetoggle'
+ if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) {
+ bool match = typebuf_match_len(p_pt, &mlen);
+ if (match) {
+ // write chars to script file(s)
+ if (mlen > typebuf.tb_maplen) {
+ gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
+ (size_t)(mlen - typebuf.tb_maplen));
+ }
+
+ del_typebuf(mlen, 0); // remove the chars
+ set_option_value("paste", !p_paste, NULL, 0);
+ if (!(State & INSERT)) {
+ msg_col = 0;
+ msg_row = Rows - 1;
+ msg_clr_eos(); // clear ruler
+ }
+ status_redraw_all();
+ redraw_statuslines();
+ showmode();
+ setcursor();
+ *keylenp = keylen;
+ return map_result_retry;
+ }
+ // 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
+ max_mlen = mlen + 1;
+ }
+ }
+
+ if ((mp == NULL || max_mlen >= mp_match_len) && keylen != KEYLEN_PART_MAP) {
+ // No matching mapping found or found a non-matching mapping that
+ // matches at least what the matching mapping matched
+ keylen = 0;
+ (void)keylen; // suppress clang/dead assignment
+ // If there was no mapping, use the character from the typeahead
+ // buffer right here. Otherwise, use the mapping (loop around).
+ if (mp == NULL) {
+ *keylenp = keylen;
+ return map_result_get; // got character, break for loop
+ } else {
+ keylen = mp_match_len;
+ }
+ }
+
+ // complete match
+ if (keylen >= 0 && keylen <= typebuf.tb_len) {
+ char_u *map_str;
+ int save_m_expr;
+ int save_m_noremap;
+ int save_m_silent;
+
+ // Write chars to script file(s).
+ // Note: :lmap mappings are written *after* being applied. #5658
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) == 0) {
+ gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
+ (size_t)(keylen - typebuf.tb_maplen));
+ }
+
+ cmd_silent = (typebuf.tb_silent > 0);
+ del_typebuf(keylen, 0); // remove the mapped keys
+
+ // Put the replacement string in front of mapstr.
+ // The depth check catches ":map x y" and ":map y x".
+ if (++*mapdepth >= p_mmd) {
+ emsg(_("E223: recursive mapping"));
+ if (State & CMDLINE) {
+ redrawcmdline();
+ } else {
+ setcursor();
+ }
+ flush_buffers(FLUSH_MINIMAL);
+ *mapdepth = 0; // for next one
+ *keylenp = keylen;
+ return map_result_fail;
+ }
+
+ // In Select mode and a Visual mode mapping is used: Switch to Visual
+ // mode temporarily. Append K_SELECT to switch back to Select mode.
+ if (VIsual_active && VIsual_select && (mp->m_mode & VISUAL)) {
+ VIsual_select = false;
+ (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, 0, true, false);
+ }
+
+ // Copy the values from *mp that are used, because evaluating the
+ // expression may invoke a function that redefines the mapping, thereby
+ // making *mp invalid.
+ save_m_expr = mp->m_expr;
+ save_m_noremap = mp->m_noremap;
+ save_m_silent = mp->m_silent;
+ 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
+ // expression. Also save and restore the command line
+ // for "normal :".
+ if (mp->m_expr) {
+ int save_vgetc_busy = vgetc_busy;
+ const bool save_may_garbage_collect = may_garbage_collect;
+
+ vgetc_busy = 0;
+ may_garbage_collect = false;
+
+ save_m_keys = vim_strsave(mp->m_keys);
+ save_m_str = vim_strsave(mp->m_str);
+ map_str = eval_map_expr(save_m_str, NUL);
+ vgetc_busy = save_vgetc_busy;
+ may_garbage_collect = save_may_garbage_collect;
+ } else {
+ map_str = mp->m_str;
+ }
+
+ // Insert the 'to' part in the typebuf.tb_buf.
+ // If 'from' field is the same as the start of the 'to' field, don't
+ // remap the first character (but do allow abbreviations).
+ // If m_noremap is set, don't remap the whole 'to' part.
+ if (map_str == NULL) {
+ i = FAIL;
+ } else {
+ int noremap;
+
+ // If this is a LANGMAP mapping, then we didn't record the keys
+ // at the start of the function and have to record them now.
+ if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) != 0) {
+ gotchars(map_str, STRLEN(map_str));
+ }
+
+ if (save_m_noremap != REMAP_YES) {
+ noremap = save_m_noremap;
+ } else if (STRNCMP(map_str, save_m_keys != NULL ? save_m_keys : mp->m_keys,
+ (size_t)keylen) != 0) {
+ noremap = REMAP_YES;
+ } else {
+ noremap = REMAP_SKIP;
+ }
+ i = ins_typebuf(map_str, noremap, 0, true, cmd_silent || save_m_silent);
+ if (save_m_expr) {
+ xfree(map_str);
+ }
+ }
+ xfree(save_m_keys);
+ xfree(save_m_str);
+ *keylenp = keylen;
+ if (i == FAIL) {
+ return map_result_fail;
+ }
+ return map_result_retry;
+ }
+
+ *keylenp = keylen;
+ return map_result_nomatch;
+}
+
// unget one character (can only be done once!)
void vungetc(int c)
{
@@ -1715,44 +2034,27 @@ void vungetc(int c)
static int vgetorpeek(bool advance)
{
int c, c1;
- int keylen;
- char_u *s;
- mapblock_T *mp;
- mapblock_T *mp2;
- mapblock_T *mp_match;
- int mp_match_len = 0;
- bool timedout = false; // waited for more than 1 second
- // for mapping to complete
+ 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;
- int i;
int new_wcol, new_wrow;
int n;
- int nolmaplen;
int old_wcol, old_wrow;
int wait_tb_len;
- /*
- * This function doesn't work very well when called recursively. This may
- * happen though, because of:
- * 1. The call to add_to_showcmd(). char_avail() is then used to check if
- * there is a character available, which calls this function. In that
- * case we must return NUL, to indicate no character is available.
- * 2. A GUI callback function writes to the screen, causing a
- * wait_return().
- * Using ":normal" can also do this, but it saves the typeahead buffer,
- * thus it should be OK. But don't get a key from the user then.
- */
- if (vgetc_busy > 0
- && ex_normal_busy == 0) {
+ // This function doesn't work very well when called recursively. This may
+ // happen though, because of:
+ // 1. The call to add_to_showcmd(). char_avail() is then used to check if
+ // there is a character available, which calls this function. In that
+ // case we must return NUL, to indicate no character is available.
+ // 2. A GUI callback function writes to the screen, causing a
+ // wait_return().
+ // Using ":normal" can also do this, but it saves the typeahead buffer,
+ // thus it should be OK. But don't get a key from the user then.
+ if (vgetc_busy > 0 && ex_normal_busy == 0) {
return NUL;
}
- local_State = get_real_state();
-
++vgetc_busy;
if (advance) {
@@ -1765,9 +2067,7 @@ static int vgetorpeek(bool advance)
reg_executing = 0;
}
do {
- /*
- * get a character: 1. from the stuffbuffer
- */
+ // get a character: 1. from the stuffbuffer
if (typeahead_char != 0) {
c = typeahead_char;
if (advance) {
@@ -1784,30 +2084,27 @@ static int vgetorpeek(bool advance)
KeyStuffed = true;
}
if (typebuf.tb_no_abbr_cnt == 0) {
- typebuf.tb_no_abbr_cnt = 1; // no abbreviations now
+ typebuf.tb_no_abbr_cnt = 1; // no abbreviations now
}
} else {
- /*
- * Loop until we either find a matching mapped key, or we
- * are sure that it is not a mapped key.
- * If a mapped key sequence is found we go back to the start to
- * try re-mapping.
- */
+ // Loop until we either find a matching mapped key, or we
+ // are sure that it is not a mapped key.
+ // If a mapped key sequence is found we go back to the start to
+ // try re-mapping.
for (;;) {
- /*
- * os_breakcheck() is slow, don't use it too often when
- * inside a mapping. But call it each time for typed
- * characters.
- */
+ // os_breakcheck() is slow, don't use it too often when
+ // inside a mapping. But call it each time for typed
+ // characters.
if (typebuf.tb_maplen) {
line_breakcheck();
} else {
- os_breakcheck(); // check for CTRL-C
+ os_breakcheck(); // check for CTRL-C
}
- keylen = 0;
+ int keylen = 0;
if (got_int) {
// flush all input
c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L);
+
// If inchar() returns TRUE (script file was active) or we
// are inside a mapping, get out of Insert mode.
// Otherwise we behave like having gotten a CTRL-C.
@@ -1831,361 +2128,49 @@ static int vgetorpeek(bool advance)
break;
} else if (typebuf.tb_len > 0) {
- /*
- * Check for a mappable key sequence.
- * Walk through one maphash[] list until we find an
- * entry that matches.
- *
- * Don't look for mappings if:
- * - no_mapping set: mapping disabled (e.g. for CTRL-V)
- * - maphash_valid not set: no mappings present.
- * - typebuf.tb_buf[typebuf.tb_off] should not be remapped
- * - in insert or cmdline mode and 'paste' option set
- * - waiting for "hit return to continue" and CR or SPACE
- * typed
- * - waiting for a char with --more--
- * - in Ctrl-X mode, and we get a valid char for that mode
- */
- mp = NULL;
- max_mlen = 0;
- c1 = typebuf.tb_buf[typebuf.tb_off];
- if (no_mapping == 0 && maphash_valid
- && (no_zero_mapping == 0 || c1 != '0')
- && (typebuf.tb_maplen == 0
- || (p_remap
- && (typebuf.tb_noremap[typebuf.tb_off]
- & (RM_NONE|RM_ABBR)) == 0))
- && !(p_paste && (State & (INSERT + CMDLINE)))
- && !(State == HITRETURN && (c1 == CAR || c1 == ' '))
- && State != ASKMORE
- && State != CONFIRM
- && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c1))
- || ((compl_cont_status & CONT_LOCAL)
- && (c1 == Ctrl_N
- || c1 == Ctrl_P)))) {
- if (c1 == K_SPECIAL) {
- nolmaplen = 2;
- } else {
- LANGMAP_ADJUST(c1, (State & (CMDLINE | INSERT)) == 0
- && get_real_state() != SELECTMODE);
- nolmaplen = 0;
- }
- // 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.
- mp = mp2;
- mp2 = NULL;
- }
- /*
- * Loop until a partly matching mapping is found or
- * all (local) mappings have been checked.
- * The longest full match is remembered in "mp_match".
- * A full match is only accepted if there is no partly
- * match, so "aa" and "aaa" can both be mapped.
- */
- mp_match = NULL;
- mp_match_len = 0;
- for (; mp != NULL;
- mp->m_next == NULL ? (mp = mp2, mp2 = NULL) :
- (mp = mp->m_next)) {
- /*
- * Only consider an entry if the first character
- * matches and it is for the current state.
- * Skip ":lmap" mappings if keys were mapped.
- */
- if (mp->m_keys[0] == c1
- && (mp->m_mode & local_State)
- && ((mp->m_mode & LANGMAP) == 0
- || typebuf.tb_maplen == 0)) {
- int nomap = nolmaplen;
- int c2;
- // 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;
- } else if (c2 == K_SPECIAL) {
- nomap = 2;
- } else {
- LANGMAP_ADJUST(c2, TRUE);
- }
- if (mp->m_keys[mlen] != c2) {
- break;
- }
- }
+ // Check for a mapping in "typebuf".
+ map_result_T result = (map_result_T)handle_mapping(&keylen, &timedout, &mapdepth);
- /* Don't allow mapping the first byte(s) of a
- * multi-byte char. Happens when mapping
- * <M-a> and then changing 'encoding'. Beware
- * that 0x80 is escaped. */
- char_u *p1 = mp->m_keys;
- char_u *p2 = (char_u *)mb_unescape((const char **)&p1);
-
- if (p2 != NULL && MB_BYTE2LEN(c1) > utfc_ptr2len(p2)) {
- mlen = 0;
- }
-
- // Check an entry whether it matches.
- // - Full match: mlen == keylen
- // - Partly match: mlen == typebuf.tb_len
- keylen = mp->m_keylen;
- if (mlen == keylen
- || (mlen == typebuf.tb_len
- && typebuf.tb_len < keylen)) {
- /*
- * If only script-local mappings are
- * allowed, check if the mapping starts
- * with K_SNR.
- */
- s = typebuf.tb_noremap + typebuf.tb_off;
- if (*s == RM_SCRIPT
- && (mp->m_keys[0] != K_SPECIAL
- || mp->m_keys[1] != KS_EXTRA
- || mp->m_keys[2]
- != KE_SNR)) {
- continue;
- }
- /*
- * If one of the typed keys cannot be
- * remapped, skip the entry.
- */
- for (n = mlen; --n >= 0;) {
- if (*s++ & (RM_NONE|RM_ABBR)) {
- break;
- }
- }
- if (n >= 0) {
- continue;
- }
-
- if (keylen > typebuf.tb_len) {
- if (!timedout && !(mp_match != NULL
- && mp_match->m_nowait)) {
- // break at a partly match
- keylen = KEYLEN_PART_MAP;
- break;
- }
- } else if (keylen > mp_match_len
- || (keylen == mp_match_len
- && mp_match != NULL
- && (mp_match->m_mode & LANGMAP) == 0
- && (mp->m_mode & LANGMAP) != 0)) {
- // found a longer match
- mp_match = mp;
- mp_match_len = keylen;
- }
- } else {
- // No match; may have to check for termcode at next character.
- if (max_mlen < mlen) {
- max_mlen = mlen;
- }
- }
- }
- }
-
- /* If no partly match found, use the longest full
- * match. */
- if (keylen != KEYLEN_PART_MAP) {
- mp = mp_match;
- keylen = mp_match_len;
- }
- }
-
- if (*p_pt != NUL && mp == NULL && (State & (INSERT|NORMAL))) {
- bool match = typebuf_match_len(p_pt, &mlen);
- if (match) {
- // write chars to script file(s)
- if (mlen > typebuf.tb_maplen) {
- gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
- (size_t)(mlen - typebuf.tb_maplen));
- }
-
- del_typebuf(mlen, 0); // Remove the chars.
- set_option_value("paste", !p_paste, NULL, 0);
- if (!(State & INSERT)) {
- msg_col = 0;
- msg_row = Rows - 1;
- msg_clr_eos(); // clear ruler
- }
- status_redraw_all();
- redraw_statuslines();
- showmode();
- setcursor();
- continue;
- }
- // 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
- max_mlen = mlen + 1;
- }
+ if (result == map_result_retry) {
+ // try mapping again
+ continue;
}
- if ((mp == NULL || max_mlen >= mp_match_len)
- && keylen != KEYLEN_PART_MAP) {
- // No matching mapping found or found a non-matching mapping that
- // matches at least what the matching mapping matched
- keylen = 0;
- (void)keylen; // suppress clang/dead assignment
- // If there was no mapping, use the character from the typeahead
- // buffer right here. Otherwise, use the mapping (loop around).
- if (mp == NULL) {
- // get a character: 2. from the typeahead buffer
- c = typebuf.tb_buf[typebuf.tb_off] & 255;
- if (advance) { // remove chars from tb_buf
- cmd_silent = (typebuf.tb_silent > 0);
- if (typebuf.tb_maplen > 0) {
- KeyTyped = false;
- } else {
- KeyTyped = true;
- // write char to script file(s)
- gotchars(typebuf.tb_buf + typebuf.tb_off, 1);
- }
- KeyNoremap = typebuf.tb_noremap[typebuf.tb_off];
- del_typebuf(1, 0);
- }
- break; // got character, break for loop
- } else {
- keylen = mp_match_len;
- }
+ if (result == map_result_fail) {
+ // failed, use the outer loop
+ c = -1;
+ break;
}
- // complete match
- if (keylen >= 0 && keylen <= typebuf.tb_len) {
- int save_m_expr;
- int save_m_noremap;
- int save_m_silent;
-
- // Write chars to script file(s)
- // Note: :lmap mappings are written *after* being applied. #5658
- if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) == 0) {
- gotchars(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_maplen,
- (size_t)(keylen - typebuf.tb_maplen));
- }
-
- cmd_silent = (typebuf.tb_silent > 0);
- del_typebuf(keylen, 0); // remove the mapped keys
-
- /*
- * Put the replacement string in front of mapstr.
- * The depth check catches ":map x y" and ":map y x".
- */
- if (++mapdepth >= p_mmd) {
- emsg(_("E223: recursive mapping"));
- if (State & CMDLINE) {
- redrawcmdline();
+ if (result == map_result_get) {
+ // get a character: 2. from the typeahead buffer
+ c = typebuf.tb_buf[typebuf.tb_off] & 255;
+ if (advance) { // remove chars from tb_buf
+ cmd_silent = (typebuf.tb_silent > 0);
+ if (typebuf.tb_maplen > 0) {
+ KeyTyped = false;
} else {
- setcursor();
+ KeyTyped = true;
+ // write char to script file(s)
+ gotchars(typebuf.tb_buf + typebuf.tb_off, 1);
}
- flush_buffers(FLUSH_MINIMAL);
- mapdepth = 0; // for next one
- c = -1;
- break;
- }
-
- /*
- * In Select mode and a Visual mode mapping is used:
- * Switch to Visual mode temporarily. Append K_SELECT
- * to switch back to Select mode.
- */
- if (VIsual_active && VIsual_select
- && (mp->m_mode & VISUAL)) {
- VIsual_select = false;
- (void)ins_typebuf(K_SELECT_STRING, REMAP_NONE, 0, true, false);
- }
-
- /* Copy the values from *mp that are used, because
- * evaluating the expression may invoke a function
- * that redefines the mapping, thereby making *mp
- * invalid. */
- save_m_expr = mp->m_expr;
- save_m_noremap = mp->m_noremap;
- save_m_silent = mp->m_silent;
- 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
- * expression. Also save and restore the command line
- * for "normal :".
- */
- if (mp->m_expr) {
- int save_vgetc_busy = vgetc_busy;
- const bool save_may_garbage_collect = may_garbage_collect;
-
- vgetc_busy = 0;
- may_garbage_collect = false;
-
- save_m_keys = vim_strsave(mp->m_keys);
- save_m_str = vim_strsave(mp->m_str);
- s = eval_map_expr(save_m_str, NUL);
- vgetc_busy = save_vgetc_busy;
- may_garbage_collect = save_may_garbage_collect;
- } else {
- s = mp->m_str;
+ KeyNoremap = typebuf.tb_noremap[typebuf.tb_off];
+ del_typebuf(1, 0);
}
-
- /*
- * Insert the 'to' part in the typebuf.tb_buf.
- * If 'from' field is the same as the start of the
- * 'to' field, don't remap the first character (but do
- * allow abbreviations).
- * If m_noremap is set, don't remap the whole 'to'
- * part.
- */
- if (s == NULL) {
- i = FAIL;
- } else {
- int noremap;
-
- // If this is a LANGMAP mapping, then we didn't record the keys
- // at the start of the function and have to record them now.
- if (keylen > typebuf.tb_maplen && (mp->m_mode & LANGMAP) != 0) {
- gotchars(s, STRLEN(s));
- }
-
- if (save_m_noremap != REMAP_YES) {
- noremap = save_m_noremap;
- } else if (
- STRNCMP(s, save_m_keys != NULL
- ? save_m_keys : mp->m_keys,
- (size_t)keylen)
- != 0) {
- noremap = REMAP_YES;
- } else {
- noremap = REMAP_SKIP;
- }
- i = ins_typebuf(s, noremap,
- 0, TRUE, cmd_silent || save_m_silent);
- if (save_m_expr) {
- xfree(s);
- }
- }
- xfree(save_m_keys);
- xfree(save_m_str);
- if (i == FAIL) {
- c = -1;
- break;
- }
- continue;
+ break;
}
+
+ // not enough characters, get more
}
- /*
- * get a character: 3. from the user - handle <Esc> in Insert mode
- */
- /*
- * special case: if we get an <ESC> in insert mode and there
- * are no more characters at once, we pretend to go out of
- * insert mode. This prevents the one second delay after
- * typing an <ESC>. If we get something after all, we may
- * have to redisplay the mode. That the cursor is in the wrong
- * place does not matter.
- */
+ // get a character: 3. from the user - handle <Esc> in Insert mode
+
+ // special case: if we get an <ESC> in insert mode and there
+ // are no more characters at once, we pretend to go out of
+ // insert mode. This prevents the one second delay after
+ // typing an <ESC>. If we get something after all, we may
+ // have to redisplay the mode. That the cursor is in the wrong
+ // place does not matter.
c = 0;
new_wcol = curwin->w_wcol;
new_wrow = curwin->w_wrow;
@@ -2196,10 +2181,8 @@ static int vgetorpeek(bool advance)
&& ex_normal_busy == 0
&& typebuf.tb_maplen == 0
&& (State & INSERT)
- && (p_timeout
- || (keylen == KEYLEN_PART_KEY && p_ttimeout))
- && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
- 3, 25L)) == 0) {
+ && (p_timeout || (keylen == KEYLEN_PART_KEY && p_ttimeout))
+ && (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, 3, 25L)) == 0) {
colnr_T col = 0, vcol;
char_u *ptr;
@@ -2215,11 +2198,9 @@ static int vgetorpeek(bool advance)
if (curwin->w_cursor.col != 0) {
if (curwin->w_wcol > 0) {
if (did_ai) {
- /*
- * We are expecting to truncate the trailing
- * white-space, so find the last non-white
- * character -- webb
- */
+ // We are expecting to truncate the trailing
+ // white-space, so find the last non-white
+ // character -- webb
col = vcol = curwin->w_wcol = 0;
ptr = get_cursor_line_ptr();
while (col < curwin->w_cursor.col) {
@@ -2233,7 +2214,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;
@@ -2261,7 +2242,7 @@ static int vgetorpeek(bool advance)
curwin->w_wrow = old_wrow;
}
if (c < 0) {
- continue; // end of input script reached
+ continue; // end of input script reached
}
// Allow mapping for just typed characters. When we get here c
@@ -2307,9 +2288,8 @@ static int vgetorpeek(bool advance)
break;
}
- /*
- * get a character: 3. from the user - update display
- */
+ // get a character: 3. from the user - update display
+
// In insert mode a screen update is skipped when characters
// are still available. But when those available characters
// are part of a mapping, and we are going to do a blocking
@@ -2320,26 +2300,21 @@ 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
}
- /*
- * If we have a partial match (and are going to wait for more
- * input from the user), show the partially matched characters
- * to the user with showcmd.
- */
- i = 0;
+ // If we have a partial match (and are going to wait for more
+ // input from the user), show the partially matched characters
+ // to the user with showcmd.
+ int showcmd_idx = 0;
c1 = 0;
if (typebuf.tb_len > 0 && advance && !exmode_active) {
- if (((State & (NORMAL | INSERT)) || State == LANGMAP)
- && State != HITRETURN) {
+ if (((State & (NORMAL | INSERT)) || State == LANGMAP) && State != HITRETURN) {
// 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
+ && 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
c1 = 1;
}
// need to use the col and row from above here
@@ -2349,11 +2324,10 @@ static int vgetorpeek(bool advance)
curwin->w_wrow = new_wrow;
push_showcmd();
if (typebuf.tb_len > SHOWCMD_COLS) {
- i = typebuf.tb_len - SHOWCMD_COLS;
+ showcmd_idx = typebuf.tb_len - SHOWCMD_COLS;
}
- while (i < typebuf.tb_len) {
- (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off
- + i++]);
+ while (showcmd_idx < typebuf.tb_len) {
+ (void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off + showcmd_idx++]);
}
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
@@ -2369,9 +2343,7 @@ static int vgetorpeek(bool advance)
}
}
- /*
- * get a character: 3. from the user - get it
- */
+ // get a character: 3. from the user - get it
if (typebuf.tb_len == 0) {
// timedout may have been set while waiting for a mapping
// that has a <Nop> RHS.
@@ -2381,8 +2353,7 @@ static int vgetorpeek(bool advance)
long wait_time = 0;
if (advance) {
- if (typebuf.tb_len == 0
- || !(p_timeout || (p_ttimeout && keylen == KEYLEN_PART_KEY))) {
+ if (typebuf.tb_len == 0 || !(p_timeout || (p_ttimeout && keylen == KEYLEN_PART_KEY))) {
// blocking wait
wait_time = -1L;
} else if (keylen == KEYLEN_PART_KEY && p_ttm >= 0) {
@@ -2397,7 +2368,7 @@ static int vgetorpeek(bool advance)
typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
wait_time);
- if (i != 0) {
+ if (showcmd_idx != 0) {
pop_showcmd();
}
if (c1 == 1) {
@@ -2407,47 +2378,45 @@ static int vgetorpeek(bool advance)
if (State & CMDLINE) {
unputcmdline();
} else {
- setcursor(); // put cursor back where it belongs
+ setcursor(); // put cursor back where it belongs
}
}
if (c < 0) {
- continue; // end of input script reached
+ continue; // end of input script reached
}
- if (c == NUL) { // no character available
+ if (c == NUL) { // no character available
if (!advance) {
break;
}
- if (wait_tb_len > 0) { // timed out
+ if (wait_tb_len > 0) { // timed out
timedout = true;
continue;
}
- } else { // allow mapping for just typed characters
+ } 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));
- /*
- * The "INSERT" message is taken care of here:
- * if we return an ESC to exit insert mode, the message is deleted
- * if we don't return an ESC but deleted the message before, redisplay it
- */
+ // The "INSERT" message is taken care of here:
+ // if we return an ESC to exit insert mode, the message is deleted
+ // if we don't return an ESC but deleted the message before, redisplay it
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
+ 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
+ redraw_cmdline = true; // show mode later
} else {
showmode();
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 7ae7b65702..b2422fd531 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <stdbool.h>
+#include "nvim/ascii.h"
#include "nvim/event/loop.h"
#include "nvim/ex_eval.h"
#include "nvim/iconv.h"
@@ -533,6 +534,11 @@ EXTERN int VIsual_mode INIT(= 'v');
/// true when redoing Visual.
EXTERN int redo_VIsual_busy INIT(= false);
+// The Visual area is remembered for reselection.
+EXTERN int resel_VIsual_mode INIT(= NUL); // 'v', 'V', or Ctrl-V
+EXTERN linenr_T resel_VIsual_line_count; // number of lines
+EXTERN colnr_T resel_VIsual_vcol; // nr of cols or end col
+
/// When pasting text with the middle mouse button in visual mode with
/// restart_edit set, remember where it started so we can set Insstart.
EXTERN pos_T where_paste_started;
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 93fcdc55a6..6fc70144ac 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -1253,7 +1253,7 @@ static struct prt_dsc_comment_S prt_dsc_table[] =
* Variables for the output PostScript file.
*/
static FILE *prt_ps_fd;
-static int prt_file_error;
+static bool prt_file_error;
static char_u *prt_ps_file_name = NULL;
/*
@@ -1329,7 +1329,7 @@ static void prt_write_file_raw_len(char_u *buffer, size_t bytes)
if (!prt_file_error
&& fwrite(buffer, sizeof(char_u), bytes, prt_ps_fd) != bytes) {
emsg(_("E455: Error writing to PostScript output file"));
- prt_file_error = TRUE;
+ prt_file_error = true;
}
}
@@ -1981,7 +1981,7 @@ void mch_print_cleanup(void)
if (prt_ps_fd != NULL) {
fclose(prt_ps_fd);
prt_ps_fd = NULL;
- prt_file_error = FALSE;
+ prt_file_error = false;
}
if (prt_ps_file_name != NULL) {
XFREE_CLEAR(prt_ps_file_name);
@@ -2203,7 +2203,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
// Check encoding and character set are compatible
if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0) {
emsg(_("E673: Incompatible multi-byte encoding and character set."));
- return FALSE;
+ return false;
}
// Add charset name if not empty
@@ -2215,7 +2215,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
// Add custom CMap character set name
if (*p_pmcs == NUL) {
emsg(_("E674: printmbcharset cannot be empty with multi-byte encoding."));
- return FALSE;
+ return false;
}
STRLCPY(prt_cmap, p_pmcs, sizeof(prt_cmap) - 2);
STRCAT(prt_cmap, "-");
@@ -2231,7 +2231,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
if (!mbfont_opts[OPT_MBFONT_REGULAR].present) {
emsg(_("E675: No default font specified for multi-byte printing."));
- return FALSE;
+ return false;
}
// Derive CID font names with fallbacks if not defined
@@ -2425,12 +2425,12 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
prt_need_bgcol = false;
prt_need_underline = false;
- prt_file_error = FALSE;
+ prt_file_error = false;
return OK;
}
-static int prt_add_resource(struct prt_ps_resource_S *resource)
+static bool prt_add_resource(struct prt_ps_resource_S *resource)
{
FILE *fd_resource;
char_u resource_buffer[512];
@@ -2439,7 +2439,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
fd_resource = os_fopen((char *)resource->filename, READBIN);
if (fd_resource == NULL) {
semsg(_("E456: Can't open file \"%s\""), resource->filename);
- return FALSE;
+ return false;
}
switch (resource->type) {
case PRT_RESOURCE_TYPE_PROCSET:
@@ -2449,7 +2449,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
(char *)resource->title);
break;
default:
- return FALSE;
+ return false;
}
prt_dsc_textline("BeginDocument", (char *)resource->filename);
@@ -2461,7 +2461,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
semsg(_("E457: Can't read PostScript resource file \"%s\""),
resource->filename);
fclose(fd_resource);
- return FALSE;
+ return false;
}
if (bytes_read == 0) {
break;
@@ -2469,7 +2469,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
prt_write_file_raw_len(resource_buffer, bytes_read);
if (prt_file_error) {
fclose(fd_resource);
- return FALSE;
+ return false;
}
}
fclose(fd_resource);
@@ -2478,10 +2478,10 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
prt_dsc_noarg("EndResource");
- return TRUE;
+ return true;
}
-int mch_print_begin(prt_settings_T *psettings)
+bool mch_print_begin(prt_settings_T *psettings)
{
int bbox[4];
double left;
@@ -2495,7 +2495,6 @@ int mch_print_begin(prt_settings_T *psettings)
char_u *p;
struct prt_ps_resource_S res_cidfont;
struct prt_ps_resource_S res_cmap;
- int retval = FALSE;
/*
* PS DSC Header comments - no PS code!
@@ -2567,25 +2566,25 @@ int mch_print_begin(prt_settings_T *psettings)
// Search for external resources VIM supplies
if (!prt_find_resource("prolog", &res_prolog)) {
emsg(_("E456: Can't find PostScript resource file \"prolog.ps\""));
- return FALSE;
+ return false;
}
if (!prt_open_resource(&res_prolog)) {
- return FALSE;
+ return false;
}
if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION)) {
- return FALSE;
+ return false;
}
if (prt_out_mbyte) {
// Look for required version of multi-byte printing procset
if (!prt_find_resource("cidfont", &res_cidfont)) {
emsg(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
- return FALSE;
+ return false;
}
if (!prt_open_resource(&res_cidfont)) {
- return FALSE;
+ return false;
}
if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION)) {
- return FALSE;
+ return false;
}
}
@@ -2610,12 +2609,12 @@ int mch_print_begin(prt_settings_T *psettings)
if (!prt_find_resource(p_encoding, &res_encoding)) {
semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
p_encoding);
- return FALSE;
+ return false;
}
}
}
if (!prt_open_resource(&res_encoding)) {
- return FALSE;
+ return false;
}
// For the moment there are no checks on encoding resource files to
// perform
@@ -2629,10 +2628,10 @@ int mch_print_begin(prt_settings_T *psettings)
if (!prt_find_resource(prt_ascii_encoding, &res_encoding)) {
semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
prt_ascii_encoding);
- return FALSE;
+ return false;
}
if (!prt_open_resource(&res_encoding)) {
- return FALSE;
+ return false;
}
// For the moment there are no checks on encoding resource files to
// perform
@@ -2655,10 +2654,10 @@ int mch_print_begin(prt_settings_T *psettings)
if (!prt_find_resource(prt_cmap, &res_cmap)) {
semsg(_("E456: Can't find PostScript resource file \"%s.ps\""),
prt_cmap);
- return FALSE;
+ return false;
}
if (!prt_open_resource(&res_cmap)) {
- return FALSE;
+ return false;
}
}
@@ -2736,7 +2735,7 @@ int mch_print_begin(prt_settings_T *psettings)
// There will be only one Roman font encoding to be included in the PS
// file.
if (!prt_add_resource(&res_encoding)) {
- return FALSE;
+ return false;
}
}
@@ -2846,9 +2845,7 @@ int mch_print_begin(prt_settings_T *psettings)
prt_dsc_noarg("EndSetup");
// Fail if any problems writing out to the PS file
- retval = !prt_file_error;
-
- return retval;
+ return !prt_file_error;
}
void mch_print_end(prt_settings_T *psettings)
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 6f02ebfb48..daef8db267 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -223,9 +223,9 @@ void ex_cstag(exarg_T *eap)
switch (p_csto) {
case 0:
if (cs_check_for_connections()) {
- ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
- if (ret == FALSE) {
+ ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, false,
+ false, *eap->cmdlinep);
+ if (ret == false) {
cs_free_tags();
if (msg_col) {
msg_putchar('\n');
@@ -249,16 +249,16 @@ void ex_cstag(exarg_T *eap)
if (cs_check_for_connections()) {
ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
- FALSE, FALSE, *eap->cmdlinep);
- if (ret == FALSE) {
+ false, false, *eap->cmdlinep);
+ if (ret == false) {
cs_free_tags();
}
}
}
} else if (cs_check_for_connections()) {
- ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
- if (ret == FALSE) {
+ ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, false,
+ false, *eap->cmdlinep);
+ if (ret == false) {
cs_free_tags();
}
}
@@ -520,7 +520,7 @@ add_err:
}
-static int cs_check_for_connections(void)
+static bool cs_check_for_connections(void)
{
return cs_cnt_connections() > 0;
}
@@ -887,20 +887,20 @@ static int cs_find(exarg_T *eap)
{
char *opt, *pat;
- if (cs_check_for_connections() == FALSE) {
+ if (cs_check_for_connections() == false) {
(void)emsg(_("E567: no cscope connections"));
- return FALSE;
+ return false;
}
if ((opt = strtok((char *)NULL, (const char *)" ")) == NULL) {
cs_usage_msg(Find);
- return FALSE;
+ return false;
}
pat = opt + strlen(opt) + 1;
if (pat >= (char *)eap->arg + eap_arg_len) {
cs_usage_msg(Find);
- return FALSE;
+ return false;
}
/*
@@ -919,8 +919,8 @@ static int cs_find(exarg_T *eap)
/// Common code for cscope find, shared by cs_find() and ex_cstag().
-static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int use_ll,
- char_u *cmdline)
+static bool cs_find_common(char *opt, char *pat, int forceit, int verbose,
+ bool use_ll, char_u *cmdline)
{
char *cmd;
int *nummatches;
@@ -967,7 +967,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
// next symbol must be + or -
if (strchr(CSQF_FLAGS, *qfpos) == NULL) {
(void)semsg(_("E469: invalid cscopequickfix flag %c for %c"), *qfpos, *(qfpos - 1));
- return FALSE;
+ return false;
}
if (*qfpos != '0'
@@ -982,7 +982,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
// create the actual command to send to cscope
cmd = cs_create_cmd(opt, pat);
if (cmd == NULL) {
- return FALSE;
+ return false;
}
nummatches = xmalloc(sizeof(int) * csinfo_size);
@@ -1019,7 +1019,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
(void)semsg(_("E259: no matches found for cscope query %s of %s"), opt, pat);
}
xfree(nummatches);
- return FALSE;
+ return false;
}
if (qfpos != NULL && *qfpos != '0') {
@@ -1064,7 +1064,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
os_remove((char *)tmp);
xfree(tmp);
xfree(nummatches);
- return TRUE;
+ return true;
} else {
char **matches = NULL, **contexts = NULL;
size_t matched = 0;
@@ -1073,7 +1073,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
cs_fill_results(pat, totmatches, nummatches, &matches, &contexts, &matched);
xfree(nummatches);
if (matches == NULL) {
- return FALSE;
+ return false;
}
(void)cs_manage_matches(matches, contexts, matched, Store);
@@ -1499,12 +1499,13 @@ static void cs_file_results(FILE *f, int *nummatches_a)
continue;
}
- context = xmalloc(strlen(cntx) + 5);
+ size_t context_len = strlen(cntx) + 5;
+ context = xmalloc(context_len);
if (strcmp(cntx, "<global>") == 0) {
- strcpy(context, "<<global>>");
+ xstrlcpy(context, "<<global>>", context_len);
} else {
- sprintf(context, "<<%s>>", cntx);
+ snprintf(context, context_len, "<<%s>>", cntx);
}
if (search == NULL) {
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 6a8b70a158..a899ca63ac 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -521,6 +521,9 @@ static void nlua_print_event(void **argv)
const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL
for (size_t i = 0; i < len;) {
+ if (got_int) {
+ break;
+ }
const size_t start = i;
while (i < len) {
switch (str[i]) {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index d698cfbeda..eaf7e2622a 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -839,13 +839,11 @@ void msg_schedule_semsg(const char *const fmt, ...)
multiqueue_put(main_loop.events, msg_semsg_event, 1, s);
}
-/*
- * Like msg(), but truncate to a single line if p_shm contains 't', or when
- * "force" is TRUE. This truncates in another way as for normal messages.
- * Careful: The string may be changed by msg_may_trunc()!
- * Returns a pointer to the printed message, if wait_return() not called.
- */
-char *msg_trunc_attr(char *s, int force, int attr)
+// Like msg(), but truncate to a single line if p_shm contains 't', or when
+// "force" is true. This truncates in another way as for normal messages.
+// Careful: The string may be changed by msg_may_trunc()!
+// Returns a pointer to the printed message, if wait_return() not called.
+char *msg_trunc_attr(char *s, bool force, int attr)
{
int n;
@@ -869,7 +867,7 @@ char *msg_trunc_attr(char *s, int force, int attr)
* Return a pointer to where the truncated message starts.
* Note: May change the message by replacing a character with '<'.
*/
-char_u *msg_may_trunc(int force, char_u *s)
+char_u *msg_may_trunc(bool force, char_u *s)
{
int room;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index f2b272a13f..9332c55b5f 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -31,8 +31,8 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/indent.h"
-#include "nvim/indent_c.h"
#include "nvim/keymap.h"
#include "nvim/log.h"
#include "nvim/main.h"
@@ -84,12 +84,6 @@ typedef struct normal_state {
pos_T old_pos;
} NormalState;
-/*
- * The Visual area is remembered for reselection.
- */
-static int resel_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
-static linenr_T resel_VIsual_line_count; // number of lines
-static colnr_T resel_VIsual_vcol; // nr of cols or end col
static int VIsual_mode_orig = NUL; // saved Visual mode
@@ -1455,758 +1449,6 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount)
*set_prevcount = false; // only set v:prevcount once
}
-// Handle an operator after Visual mode or when the movement is finished.
-// "gui_yank" is true when yanking text for the clipboard.
-void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
-{
- oparg_T *oap = cap->oap;
- pos_T old_cursor;
- bool empty_region_error;
- int restart_edit_save;
- int lbr_saved = curwin->w_p_lbr;
-
-
- // The visual area is remembered for redo
- static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
- static linenr_T redo_VIsual_line_count; // number of lines
- static colnr_T redo_VIsual_vcol; // number of cols or end column
- static long redo_VIsual_count; // count for Visual operator
- static int redo_VIsual_arg; // extra argument
- bool include_line_break = false;
-
- old_cursor = curwin->w_cursor;
-
- /*
- * If an operation is pending, handle it...
- */
- if ((finish_op
- || VIsual_active)
- && oap->op_type != OP_NOP) {
- // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
- // for the clipboard.
- const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
-
- // Avoid a problem with unwanted linebreaks in block mode
- if (curwin->w_p_lbr) {
- curwin->w_valid &= ~VALID_VIRTCOL;
- }
- curwin->w_p_lbr = false;
- oap->is_VIsual = VIsual_active;
- if (oap->motion_force == 'V') {
- oap->motion_type = kMTLineWise;
- } else if (oap->motion_force == 'v') {
- // If the motion was linewise, "inclusive" will not have been set.
- // Use "exclusive" to be consistent. Makes "dvj" work nice.
- if (oap->motion_type == kMTLineWise) {
- oap->inclusive = false;
- } else if (oap->motion_type == kMTCharWise) {
- // If the motion already was charwise, toggle "inclusive"
- oap->inclusive = !oap->inclusive;
- }
- oap->motion_type = kMTCharWise;
- } else if (oap->motion_force == Ctrl_V) {
- // Change line- or charwise motion into Visual block mode.
- if (!VIsual_active) {
- VIsual_active = true;
- VIsual = oap->start;
- }
- VIsual_mode = Ctrl_V;
- VIsual_select = false;
- VIsual_reselect = false;
- }
-
- // Only redo yank when 'y' flag is in 'cpoptions'.
- // Never redo "zf" (define fold).
- if ((redo_yank || oap->op_type != OP_YANK)
- && ((!VIsual_active || oap->motion_force)
- // Also redo Operator-pending Visual mode mappings.
- || ((cap->cmdchar == ':' || cap->cmdchar == K_COMMAND)
- && oap->op_type != OP_COLON))
- && cap->cmdchar != 'D'
- && oap->op_type != OP_FOLD
- && oap->op_type != OP_FOLDOPEN
- && oap->op_type != OP_FOLDOPENREC
- && oap->op_type != OP_FOLDCLOSE
- && oap->op_type != OP_FOLDCLOSEREC
- && oap->op_type != OP_FOLDDEL
- && oap->op_type != OP_FOLDDELREC) {
- prep_redo(oap->regname, cap->count0,
- get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
- oap->motion_force, cap->cmdchar, cap->nchar);
- if (cap->cmdchar == '/' || cap->cmdchar == '?') { // was a search
- /*
- * If 'cpoptions' does not contain 'r', insert the search
- * pattern to really repeat the same command.
- */
- if (vim_strchr(p_cpo, CPO_REDO) == NULL) {
- AppendToRedobuffLit(cap->searchbuf, -1);
- }
- AppendToRedobuff(NL_STR);
- } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) {
- // do_cmdline() has stored the first typed line in
- // "repeat_cmdline". When several lines are typed repeating
- // won't be possible.
- if (repeat_cmdline == NULL) {
- ResetRedobuff();
- } else {
- AppendToRedobuffLit(repeat_cmdline, -1);
- AppendToRedobuff(NL_STR);
- XFREE_CLEAR(repeat_cmdline);
- }
- }
- }
-
- if (redo_VIsual_busy) {
- /* Redo of an operation on a Visual area. Use the same size from
- * redo_VIsual_line_count and redo_VIsual_vcol. */
- oap->start = curwin->w_cursor;
- curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
- curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- }
- VIsual_mode = redo_VIsual_mode;
- if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') {
- if (VIsual_mode == 'v') {
- if (redo_VIsual_line_count <= 1) {
- validate_virtcol();
- curwin->w_curswant =
- curwin->w_virtcol + redo_VIsual_vcol - 1;
- } else {
- curwin->w_curswant = redo_VIsual_vcol;
- }
- } else {
- curwin->w_curswant = MAXCOL;
- }
- coladvance(curwin->w_curswant);
- }
- cap->count0 = redo_VIsual_count;
- cap->count1 = (cap->count0 == 0 ? 1 : cap->count0);
- } else if (VIsual_active) {
- if (!gui_yank) {
- // Save the current VIsual area for '< and '> marks, and "gv"
- curbuf->b_visual.vi_start = VIsual;
- curbuf->b_visual.vi_end = curwin->w_cursor;
- curbuf->b_visual.vi_mode = VIsual_mode;
- if (VIsual_mode_orig != NUL) {
- curbuf->b_visual.vi_mode = VIsual_mode_orig;
- VIsual_mode_orig = NUL;
- }
- curbuf->b_visual.vi_curswant = curwin->w_curswant;
- curbuf->b_visual_mode_eval = VIsual_mode;
- }
-
- // In Select mode, a linewise selection is operated upon like a
- // charwise selection.
- // Special case: gH<Del> deletes the last line.
- if (VIsual_select && VIsual_mode == 'V'
- && cap->oap->op_type != OP_DELETE) {
- if (lt(VIsual, curwin->w_cursor)) {
- VIsual.col = 0;
- curwin->w_cursor.col =
- (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum));
- } else {
- curwin->w_cursor.col = 0;
- VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum));
- }
- VIsual_mode = 'v';
- }
- /* If 'selection' is "exclusive", backup one character for
- * charwise selections. */
- else if (VIsual_mode == 'v') {
- include_line_break =
- unadjust_for_sel();
- }
-
- oap->start = VIsual;
- if (VIsual_mode == 'V') {
- oap->start.col = 0;
- oap->start.coladd = 0;
- }
- }
-
- /*
- * Set oap->start to the first position of the operated text, oap->end
- * to the end of the operated text. w_cursor is equal to oap->start.
- */
- if (lt(oap->start, curwin->w_cursor)) {
- // Include folded lines completely.
- if (!VIsual_active) {
- if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) {
- oap->start.col = 0;
- }
- if ((curwin->w_cursor.col > 0
- || oap->inclusive
- || oap->motion_type == kMTLineWise)
- && hasFolding(curwin->w_cursor.lnum, NULL,
- &curwin->w_cursor.lnum)) {
- curwin->w_cursor.col = (colnr_T)STRLEN(get_cursor_line_ptr());
- }
- }
- oap->end = curwin->w_cursor;
- curwin->w_cursor = oap->start;
-
- /* w_virtcol may have been updated; if the cursor goes back to its
- * previous position w_virtcol becomes invalid and isn't updated
- * automatically. */
- curwin->w_valid &= ~VALID_VIRTCOL;
- } else {
- // Include folded lines completely.
- if (!VIsual_active && oap->motion_type == kMTLineWise) {
- if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum,
- NULL)) {
- curwin->w_cursor.col = 0;
- }
- if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) {
- oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum));
- }
- }
- oap->end = oap->start;
- oap->start = curwin->w_cursor;
- }
-
- // Just in case lines were deleted that make the position invalid.
- check_pos(curwin->w_buffer, &oap->end);
- oap->line_count = oap->end.lnum - oap->start.lnum + 1;
-
- // Set "virtual_op" before resetting VIsual_active.
- virtual_op = virtual_active();
-
- if (VIsual_active || redo_VIsual_busy) {
- get_op_vcol(oap, redo_VIsual_vcol, true);
-
- if (!redo_VIsual_busy && !gui_yank) {
- /*
- * Prepare to reselect and redo Visual: this is based on the
- * size of the Visual text
- */
- resel_VIsual_mode = VIsual_mode;
- if (curwin->w_curswant == MAXCOL) {
- resel_VIsual_vcol = MAXCOL;
- } else {
- if (VIsual_mode != Ctrl_V) {
- getvvcol(curwin, &(oap->end),
- NULL, NULL, &oap->end_vcol);
- }
- if (VIsual_mode == Ctrl_V || oap->line_count <= 1) {
- if (VIsual_mode != Ctrl_V) {
- getvvcol(curwin, &(oap->start),
- &oap->start_vcol, NULL, NULL);
- }
- resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1;
- } else {
- resel_VIsual_vcol = oap->end_vcol;
- }
- }
- resel_VIsual_line_count = oap->line_count;
- }
-
- // can't redo yank (unless 'y' is in 'cpoptions') and ":"
- if ((redo_yank || oap->op_type != OP_YANK)
- && oap->op_type != OP_COLON
- && oap->op_type != OP_FOLD
- && oap->op_type != OP_FOLDOPEN
- && oap->op_type != OP_FOLDOPENREC
- && oap->op_type != OP_FOLDCLOSE
- && oap->op_type != OP_FOLDCLOSEREC
- && oap->op_type != OP_FOLDDEL
- && oap->op_type != OP_FOLDDELREC
- && oap->motion_force == NUL) {
- /* Prepare for redoing. Only use the nchar field for "r",
- * otherwise it might be the second char of the operator. */
- if (cap->cmdchar == 'g' && (cap->nchar == 'n'
- || cap->nchar == 'N')) {
- prep_redo(oap->regname, cap->count0,
- get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
- oap->motion_force, cap->cmdchar, cap->nchar);
- } else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND) {
- int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
-
- // reverse what nv_replace() did
- if (nchar == REPLACE_CR_NCHAR) {
- nchar = CAR;
- } else if (nchar == REPLACE_NL_NCHAR) {
- nchar = NL;
- }
- prep_redo(oap->regname, 0L, NUL, 'v', get_op_char(oap->op_type),
- get_extra_op_char(oap->op_type), nchar);
- }
- if (!redo_VIsual_busy) {
- redo_VIsual_mode = resel_VIsual_mode;
- redo_VIsual_vcol = resel_VIsual_vcol;
- redo_VIsual_line_count = resel_VIsual_line_count;
- redo_VIsual_count = cap->count0;
- redo_VIsual_arg = cap->arg;
- }
- }
-
- // oap->inclusive defaults to true.
- // If oap->end is on a NUL (empty line) oap->inclusive becomes
- // false. This makes "d}P" and "v}dP" work the same.
- if (oap->motion_force == NUL || oap->motion_type == kMTLineWise) {
- oap->inclusive = true;
- }
- if (VIsual_mode == 'V') {
- oap->motion_type = kMTLineWise;
- } else if (VIsual_mode == 'v') {
- oap->motion_type = kMTCharWise;
- if (*ml_get_pos(&(oap->end)) == NUL
- && (include_line_break || !virtual_op)) {
- oap->inclusive = false;
- // Try to include the newline, unless it's an operator
- // that works on lines only.
- if (*p_sel != 'o'
- && !op_on_lines(oap->op_type)
- && oap->end.lnum < curbuf->b_ml.ml_line_count) {
- oap->end.lnum++;
- oap->end.col = 0;
- oap->end.coladd = 0;
- oap->line_count++;
- }
- }
- }
-
- redo_VIsual_busy = false;
-
- /*
- * Switch Visual off now, so screen updating does
- * not show inverted text when the screen is redrawn.
- * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
- * no screen redraw, so it is done here to remove the inverted
- * part.
- */
- if (!gui_yank) {
- VIsual_active = false;
- setmouse();
- mouse_dragging = 0;
- may_clear_cmdline();
- if ((oap->op_type == OP_YANK
- || oap->op_type == OP_COLON
- || oap->op_type == OP_FUNCTION
- || oap->op_type == OP_FILTER)
- && oap->motion_force == NUL) {
- // Make sure redrawing is correct.
- curwin->w_p_lbr = lbr_saved;
- redraw_curbuf_later(INVERTED);
- }
- }
- }
-
- // Include the trailing byte of a multi-byte char.
- if (oap->inclusive) {
- const int l = utfc_ptr2len(ml_get_pos(&oap->end));
- if (l > 1) {
- oap->end.col += l - 1;
- }
- }
- curwin->w_set_curswant = true;
-
- /*
- * oap->empty is set when start and end are the same. The inclusive
- * flag affects this too, unless yanking and the end is on a NUL.
- */
- oap->empty = (oap->motion_type != kMTLineWise
- && (!oap->inclusive
- || (oap->op_type == OP_YANK
- && gchar_pos(&oap->end) == NUL))
- && equalpos(oap->start, oap->end)
- && !(virtual_op && oap->start.coladd != oap->end.coladd)
- );
- /*
- * For delete, change and yank, it's an error to operate on an
- * empty region, when 'E' included in 'cpoptions' (Vi compatible).
- */
- empty_region_error = (oap->empty
- && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
-
- /* Force a redraw when operating on an empty Visual region, when
- * 'modifiable is off or creating a fold. */
- if (oap->is_VIsual && (oap->empty || !MODIFIABLE(curbuf)
- || oap->op_type == OP_FOLD
- )) {
- curwin->w_p_lbr = lbr_saved;
- redraw_curbuf_later(INVERTED);
- }
-
- /*
- * If the end of an operator is in column one while oap->motion_type
- * is kMTCharWise and oap->inclusive is false, we put op_end after the last
- * character in the previous line. If op_start is on or before the
- * first non-blank in the line, the operator becomes linewise
- * (strange, but that's the way vi does it).
- */
- if (oap->motion_type == kMTCharWise
- && oap->inclusive == false
- && !(cap->retval & CA_NO_ADJ_OP_END)
- && oap->end.col == 0
- && (!oap->is_VIsual || *p_sel == 'o')
- && oap->line_count > 1) {
- oap->end_adjusted = true; // remember that we did this
- oap->line_count--;
- oap->end.lnum--;
- if (inindent(0)) {
- oap->motion_type = kMTLineWise;
- } else {
- oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
- if (oap->end.col) {
- --oap->end.col;
- oap->inclusive = true;
- }
- }
- } else {
- oap->end_adjusted = false;
- }
-
- switch (oap->op_type) {
- case OP_LSHIFT:
- case OP_RSHIFT:
- op_shift(oap, true,
- oap->is_VIsual ? (int)cap->count1 :
- 1);
- auto_format(false, true);
- break;
-
- case OP_JOIN_NS:
- case OP_JOIN:
- if (oap->line_count < 2) {
- oap->line_count = 2;
- }
- if (curwin->w_cursor.lnum + oap->line_count - 1 >
- curbuf->b_ml.ml_line_count) {
- beep_flush();
- } else {
- do_join((size_t)oap->line_count, oap->op_type == OP_JOIN,
- true, true, true);
- auto_format(false, true);
- }
- break;
-
- case OP_DELETE:
- VIsual_reselect = false; // don't reselect now
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- (void)op_delete(oap);
- // save cursor line for undo if it wasn't saved yet
- if (oap->motion_type == kMTLineWise
- && has_format_option(FO_AUTO)
- && u_save_cursor() == OK) {
- auto_format(false, true);
- }
- }
- break;
-
- case OP_YANK:
- if (empty_region_error) {
- if (!gui_yank) {
- vim_beep(BO_OPER);
- CancelRedo();
- }
- } else {
- curwin->w_p_lbr = lbr_saved;
- oap->excl_tr_ws = cap->cmdchar == 'z';
- (void)op_yank(oap, !gui_yank, false);
- }
- check_cursor_col();
- break;
-
- case OP_CHANGE:
- VIsual_reselect = false; // don't reselect now
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- /* This is a new edit command, not a restart. Need to
- * remember it to make 'insertmode' work with mappings for
- * Visual mode. But do this only once and not when typed and
- * 'insertmode' isn't set. */
- if (p_im || !KeyTyped) {
- restart_edit_save = restart_edit;
- } else {
- restart_edit_save = 0;
- }
- restart_edit = 0;
-
- // Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
-
- // Reset finish_op now, don't want it set inside edit().
- finish_op = false;
- if (op_change(oap)) { // will call edit()
- cap->retval |= CA_COMMAND_BUSY;
- }
- if (restart_edit == 0) {
- restart_edit = restart_edit_save;
- }
- }
- break;
-
- case OP_FILTER:
- if (vim_strchr(p_cpo, CPO_FILTER) != NULL) {
- AppendToRedobuff("!\r"); // Use any last used !cmd.
- } else {
- bangredo = true; // do_bang() will put cmd in redo buffer.
- }
- FALLTHROUGH;
-
- case OP_INDENT:
- case OP_COLON:
-
- /*
- * If 'equalprg' is empty, do the indenting internally.
- */
- if (oap->op_type == OP_INDENT && *get_equalprg() == NUL) {
- if (curbuf->b_p_lisp) {
- op_reindent(oap, get_lisp_indent);
- break;
- }
- op_reindent(oap,
- *curbuf->b_p_inde != NUL ? get_expr_indent :
- get_c_indent);
- break;
- }
-
- op_colon(oap);
- break;
-
- case OP_TILDE:
- case OP_UPPER:
- case OP_LOWER:
- case OP_ROT13:
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- op_tilde(oap);
- }
- check_cursor_col();
- break;
-
- case OP_FORMAT:
- if (*curbuf->b_p_fex != NUL) {
- op_formatexpr(oap); // use expression
- } else {
- if (*p_fp != NUL || *curbuf->b_p_fp != NUL) {
- op_colon(oap); // use external command
- } else {
- op_format(oap, false); // use internal function
- }
- }
- break;
-
- case OP_FORMAT2:
- op_format(oap, true); // use internal function
- break;
-
- case OP_FUNCTION:
- // Restore linebreak, so that when the user edits it looks as
- // before.
- curwin->w_p_lbr = lbr_saved;
- op_function(oap); // call 'operatorfunc'
- break;
-
- case OP_INSERT:
- case OP_APPEND:
- VIsual_reselect = false; // don't reselect now
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- /* This is a new edit command, not a restart. Need to
- * remember it to make 'insertmode' work with mappings for
- * Visual mode. But do this only once. */
- restart_edit_save = restart_edit;
- restart_edit = 0;
-
- // Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
-
- op_insert(oap, cap->count1);
-
- // Reset linebreak, so that formatting works correctly.
- curwin->w_p_lbr = false;
-
- /* TODO: when inserting in several lines, should format all
- * the lines. */
- auto_format(false, true);
-
- if (restart_edit == 0) {
- restart_edit = restart_edit_save;
- } else {
- cap->retval |= CA_COMMAND_BUSY;
- }
- }
- break;
-
- case OP_REPLACE:
- VIsual_reselect = false; // don't reselect now
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- // Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
-
- op_replace(oap, cap->nchar);
- }
- break;
-
- case OP_FOLD:
- VIsual_reselect = false; // don't reselect now
- foldCreate(curwin, oap->start, oap->end);
- break;
-
- case OP_FOLDOPEN:
- case OP_FOLDOPENREC:
- case OP_FOLDCLOSE:
- case OP_FOLDCLOSEREC:
- VIsual_reselect = false; // don't reselect now
- opFoldRange(oap->start, oap->end,
- oap->op_type == OP_FOLDOPEN
- || oap->op_type == OP_FOLDOPENREC,
- oap->op_type == OP_FOLDOPENREC
- || oap->op_type == OP_FOLDCLOSEREC,
- oap->is_VIsual);
- break;
-
- case OP_FOLDDEL:
- case OP_FOLDDELREC:
- VIsual_reselect = false; // don't reselect now
- deleteFold(curwin, oap->start.lnum, oap->end.lnum,
- oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
- break;
-
- case OP_NR_ADD:
- case OP_NR_SUB:
- if (empty_region_error) {
- vim_beep(BO_OPER);
- CancelRedo();
- } else {
- VIsual_active = true;
- curwin->w_p_lbr = lbr_saved;
- op_addsub(oap, cap->count1, redo_VIsual_arg);
- VIsual_active = false;
- }
- check_cursor_col();
- break;
- default:
- clearopbeep(oap);
- }
- virtual_op = kNone;
- if (!gui_yank) {
- /*
- * if 'sol' not set, go back to old column for some commands
- */
- if (!p_sol && oap->motion_type == kMTLineWise && !oap->end_adjusted
- && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
- || oap->op_type == OP_DELETE)) {
- curwin->w_p_lbr = false;
- coladvance(curwin->w_curswant = old_col);
- }
- } else {
- curwin->w_cursor = old_cursor;
- }
- clearop(oap);
- motion_force = NUL;
- }
- curwin->w_p_lbr = lbr_saved;
-}
-
-/*
- * Handle indent and format operators and visual mode ":".
- */
-static void op_colon(oparg_T *oap)
-{
- stuffcharReadbuff(':');
- if (oap->is_VIsual) {
- stuffReadbuff("'<,'>");
- } else {
- // Make the range look nice, so it can be repeated.
- if (oap->start.lnum == curwin->w_cursor.lnum) {
- stuffcharReadbuff('.');
- } else {
- stuffnumReadbuff((long)oap->start.lnum);
- }
- if (oap->end.lnum != oap->start.lnum) {
- stuffcharReadbuff(',');
- if (oap->end.lnum == curwin->w_cursor.lnum) {
- stuffcharReadbuff('.');
- } else if (oap->end.lnum == curbuf->b_ml.ml_line_count) {
- stuffcharReadbuff('$');
- } else if (oap->start.lnum == curwin->w_cursor.lnum) {
- stuffReadbuff(".+");
- stuffnumReadbuff(oap->line_count - 1);
- } else {
- stuffnumReadbuff((long)oap->end.lnum);
- }
- }
- }
- if (oap->op_type != OP_COLON) {
- stuffReadbuff("!");
- }
- if (oap->op_type == OP_INDENT) {
- stuffReadbuff((const char *)get_equalprg());
- stuffReadbuff("\n");
- } else if (oap->op_type == OP_FORMAT) {
- if (*curbuf->b_p_fp != NUL) {
- stuffReadbuff((const char *)curbuf->b_p_fp);
- } else if (*p_fp != NUL) {
- stuffReadbuff((const char *)p_fp);
- } else {
- stuffReadbuff("fmt");
- }
- stuffReadbuff("\n']");
- }
-
- /*
- * do_cmdline() does the rest
- */
-}
-
-/*
- * Handle the "g@" operator: call 'operatorfunc'.
- */
-static void op_function(const oparg_T *oap)
- FUNC_ATTR_NONNULL_ALL
-{
- const TriState save_virtual_op = virtual_op;
- const bool save_finish_op = finish_op;
-
- if (*p_opfunc == NUL) {
- emsg(_("E774: 'operatorfunc' is empty"));
- } else {
- // Set '[ and '] marks to text to be operated on.
- curbuf->b_op_start = oap->start;
- curbuf->b_op_end = oap->end;
- if (oap->motion_type != kMTLineWise && !oap->inclusive) {
- // Exclude the end position.
- decl(&curbuf->b_op_end);
- }
-
- typval_T argv[2];
- argv[0].v_type = VAR_STRING;
- argv[1].v_type = VAR_UNKNOWN;
- argv[0].vval.v_string =
- (char_u *)(((const char *const[]) {
- [kMTBlockWise] = "block",
- [kMTLineWise] = "line",
- [kMTCharWise] = "char",
- })[oap->motion_type]);
-
- // Reset virtual_op so that 'virtualedit' can be changed in the
- // function.
- virtual_op = kNone;
-
- // Reset finish_op so that mode() returns the right value.
- finish_op = false;
-
- (void)call_func_retnr(p_opfunc, 1, argv);
-
- virtual_op = save_virtual_op;
- finish_op = save_finish_op;
- }
-}
-
// Move the current tab to tab in same column as mouse or to end of the
// tabline if there is no tab there.
static void move_tab_to_mouse(void)
@@ -3096,6 +2338,14 @@ void reset_VIsual(void)
}
}
+void restore_visual_mode(void)
+{
+ if (VIsual_mode_orig != NUL) {
+ curbuf->b_visual.vi_mode = VIsual_mode_orig;
+ VIsual_mode_orig = NUL;
+ }
+}
+
// Check for a balloon-eval special item to include when searching for an
// identifier. When "dir" is BACKWARD "ptr[-1]" must be valid!
// Returns true if the character at "*ptr" should be included.
@@ -3274,7 +2524,7 @@ static void prep_redo_cmd(cmdarg_T *cap)
* Prepare for redo of any command.
* Note that only the last argument can be a multi-byte char.
*/
-static void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5)
+void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5)
{
ResetRedobuff();
if (regname != 0) { // yank from specified buffer
@@ -3331,7 +2581,7 @@ static bool checkclearopq(oparg_T *oap)
return true;
}
-static void clearop(oparg_T *oap)
+void clearop(oparg_T *oap)
{
oap->op_type = OP_NOP;
oap->regname = 0;
@@ -3340,7 +2590,7 @@ static void clearop(oparg_T *oap)
motion_force = NUL;
}
-static void clearopbeep(oparg_T *oap)
+void clearopbeep(oparg_T *oap)
{
clearop(oap);
beep_flush();
@@ -3370,7 +2620,7 @@ static void unshift_special(cmdarg_T *cap)
/// If the mode is currently displayed clear the command line or update the
/// command displayed.
-static void may_clear_cmdline(void)
+void may_clear_cmdline(void)
{
if (mode_displayed) {
// unshow visual mode later
@@ -7738,7 +6988,7 @@ static void adjust_for_sel(cmdarg_T *cap)
* Should check VIsual_mode before calling this.
* Returns true when backed up to the previous line.
*/
-static bool unadjust_for_sel(void)
+bool unadjust_for_sel(void)
{
pos_T *pp;
@@ -8328,71 +7578,6 @@ static void nv_open(cmdarg_T *cap)
}
}
-/// Calculate start/end virtual columns for operating in block mode.
-///
-/// @param initial when true: adjust position for 'selectmode'
-static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial)
-{
- colnr_T start;
- colnr_T end;
-
- if (VIsual_mode != Ctrl_V
- || (!initial && oap->end.col < curwin->w_width_inner)) {
- return;
- }
-
- oap->motion_type = kMTBlockWise;
-
- // prevent from moving onto a trail byte
- mark_mb_adjustpos(curwin->w_buffer, &oap->end);
-
- getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
- if (!redo_VIsual_busy) {
- getvvcol(curwin, &(oap->end), &start, NULL, &end);
-
- if (start < oap->start_vcol) {
- oap->start_vcol = start;
- }
- if (end > oap->end_vcol) {
- if (initial && *p_sel == 'e'
- && start >= 1
- && start - 1 >= oap->end_vcol) {
- oap->end_vcol = start - 1;
- } else {
- oap->end_vcol = end;
- }
- }
- }
-
- // if '$' was used, get oap->end_vcol from longest line
- if (curwin->w_curswant == MAXCOL) {
- curwin->w_cursor.col = MAXCOL;
- oap->end_vcol = 0;
- for (curwin->w_cursor.lnum = oap->start.lnum;
- curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) {
- getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
- if (end > oap->end_vcol) {
- oap->end_vcol = end;
- }
- }
- } else if (redo_VIsual_busy) {
- oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
- }
-
- // Correct oap->end.col and oap->start.col to be the
- // upper-left and lower-right corner of the block area.
- //
- // (Actually, this does convert column positions into character
- // positions)
- curwin->w_cursor.lnum = oap->end.lnum;
- coladvance(oap->end_vcol);
- oap->end = curwin->w_cursor;
-
- curwin->w_cursor = oap->start;
- coladvance(oap->start_vcol);
- oap->start = curwin->w_cursor;
-}
-
// Handle an arbitrary event in normal mode
static void nv_event(cmdarg_T *cap)
{
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 38de24b8ad..52c382028e 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -27,7 +27,9 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/indent.h"
+#include "nvim/indent_c.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/macros.h"
@@ -37,6 +39,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
+#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
@@ -1768,7 +1771,7 @@ static void replace_character(int c)
/*
* Replace a whole area with one character.
*/
-int op_replace(oparg_T *oap, int c)
+static int op_replace(oparg_T *oap, int c)
{
int n, numc;
int num_chars;
@@ -4177,7 +4180,7 @@ static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, in
/// Implementation of the format operator 'gq'.
///
/// @param keep_cursor keep cursor on same text char
-void op_format(oparg_T *oap, int keep_cursor)
+static void op_format(oparg_T *oap, int keep_cursor)
{
long old_line_count = curbuf->b_ml.ml_line_count;
@@ -4245,7 +4248,7 @@ void op_format(oparg_T *oap, int keep_cursor)
/*
* Implementation of the format operator 'gq' for when using 'formatexpr'.
*/
-void op_formatexpr(oparg_T *oap)
+static void op_formatexpr(oparg_T *oap)
{
if (oap->is_VIsual) {
// When there is no change: need to remove the Visual selection
@@ -5936,6 +5939,791 @@ void cursor_pos_info(dict_T *dict)
}
}
+// Handle indent and format operators and visual mode ":".
+static void op_colon(oparg_T *oap)
+{
+ stuffcharReadbuff(':');
+ if (oap->is_VIsual) {
+ stuffReadbuff("'<,'>");
+ } else {
+ // Make the range look nice, so it can be repeated.
+ if (oap->start.lnum == curwin->w_cursor.lnum) {
+ stuffcharReadbuff('.');
+ } else {
+ stuffnumReadbuff((long)oap->start.lnum);
+ }
+ if (oap->end.lnum != oap->start.lnum) {
+ stuffcharReadbuff(',');
+ if (oap->end.lnum == curwin->w_cursor.lnum) {
+ stuffcharReadbuff('.');
+ } else if (oap->end.lnum == curbuf->b_ml.ml_line_count) {
+ stuffcharReadbuff('$');
+ } else if (oap->start.lnum == curwin->w_cursor.lnum) {
+ stuffReadbuff(".+");
+ stuffnumReadbuff(oap->line_count - 1);
+ } else {
+ stuffnumReadbuff((long)oap->end.lnum);
+ }
+ }
+ }
+ if (oap->op_type != OP_COLON) {
+ stuffReadbuff("!");
+ }
+ if (oap->op_type == OP_INDENT) {
+ stuffReadbuff((const char *)get_equalprg());
+ stuffReadbuff("\n");
+ } else if (oap->op_type == OP_FORMAT) {
+ if (*curbuf->b_p_fp != NUL) {
+ stuffReadbuff((const char *)curbuf->b_p_fp);
+ } else if (*p_fp != NUL) {
+ stuffReadbuff((const char *)p_fp);
+ } else {
+ stuffReadbuff("fmt");
+ }
+ stuffReadbuff("\n']");
+ }
+
+ // do_cmdline() does the rest
+}
+
+// Handle the "g@" operator: call 'operatorfunc'.
+static void op_function(const oparg_T *oap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const TriState save_virtual_op = virtual_op;
+ const bool save_finish_op = finish_op;
+
+ if (*p_opfunc == NUL) {
+ emsg(_("E774: 'operatorfunc' is empty"));
+ } else {
+ // Set '[ and '] marks to text to be operated on.
+ curbuf->b_op_start = oap->start;
+ curbuf->b_op_end = oap->end;
+ if (oap->motion_type != kMTLineWise && !oap->inclusive) {
+ // Exclude the end position.
+ decl(&curbuf->b_op_end);
+ }
+
+ typval_T argv[2];
+ argv[0].v_type = VAR_STRING;
+ argv[1].v_type = VAR_UNKNOWN;
+ argv[0].vval.v_string =
+ (char_u *)(((const char *const[]) {
+ [kMTBlockWise] = "block",
+ [kMTLineWise] = "line",
+ [kMTCharWise] = "char",
+ })[oap->motion_type]);
+
+ // Reset virtual_op so that 'virtualedit' can be changed in the
+ // function.
+ virtual_op = kNone;
+
+ // Reset finish_op so that mode() returns the right value.
+ finish_op = false;
+
+ (void)call_func_retnr(p_opfunc, 1, argv);
+
+ virtual_op = save_virtual_op;
+ finish_op = save_finish_op;
+ }
+}
+
+/// Calculate start/end virtual columns for operating in block mode.
+///
+/// @param initial when true: adjust position for 'selectmode'
+static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial)
+{
+ colnr_T start;
+ colnr_T end;
+
+ if (VIsual_mode != Ctrl_V
+ || (!initial && oap->end.col < curwin->w_width_inner)) {
+ return;
+ }
+
+ oap->motion_type = kMTBlockWise;
+
+ // prevent from moving onto a trail byte
+ mark_mb_adjustpos(curwin->w_buffer, &oap->end);
+
+ getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
+ if (!redo_VIsual_busy) {
+ getvvcol(curwin, &(oap->end), &start, NULL, &end);
+
+ if (start < oap->start_vcol) {
+ oap->start_vcol = start;
+ }
+ if (end > oap->end_vcol) {
+ if (initial && *p_sel == 'e'
+ && start >= 1
+ && start - 1 >= oap->end_vcol) {
+ oap->end_vcol = start - 1;
+ } else {
+ oap->end_vcol = end;
+ }
+ }
+ }
+
+ // if '$' was used, get oap->end_vcol from longest line
+ if (curwin->w_curswant == MAXCOL) {
+ curwin->w_cursor.col = MAXCOL;
+ oap->end_vcol = 0;
+ for (curwin->w_cursor.lnum = oap->start.lnum;
+ curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) {
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
+ if (end > oap->end_vcol) {
+ oap->end_vcol = end;
+ }
+ }
+ } else if (redo_VIsual_busy) {
+ oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
+ }
+
+ // Correct oap->end.col and oap->start.col to be the
+ // upper-left and lower-right corner of the block area.
+ //
+ // (Actually, this does convert column positions into character
+ // positions)
+ curwin->w_cursor.lnum = oap->end.lnum;
+ coladvance(oap->end_vcol);
+ oap->end = curwin->w_cursor;
+
+ curwin->w_cursor = oap->start;
+ coladvance(oap->start_vcol);
+ oap->start = curwin->w_cursor;
+}
+
+// Handle an operator after Visual mode or when the movement is finished.
+// "gui_yank" is true when yanking text for the clipboard.
+void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
+{
+ oparg_T *oap = cap->oap;
+ pos_T old_cursor;
+ bool empty_region_error;
+ int restart_edit_save;
+ int lbr_saved = curwin->w_p_lbr;
+
+
+ // The visual area is remembered for redo
+ static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
+ static linenr_T redo_VIsual_line_count; // number of lines
+ static colnr_T redo_VIsual_vcol; // number of cols or end column
+ static long redo_VIsual_count; // count for Visual operator
+ static int redo_VIsual_arg; // extra argument
+ bool include_line_break = false;
+
+ old_cursor = curwin->w_cursor;
+
+ // If an operation is pending, handle it...
+ if ((finish_op
+ || VIsual_active)
+ && oap->op_type != OP_NOP) {
+ // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
+ // for the clipboard.
+ const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
+
+ // Avoid a problem with unwanted linebreaks in block mode
+ if (curwin->w_p_lbr) {
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ }
+ curwin->w_p_lbr = false;
+ oap->is_VIsual = VIsual_active;
+ if (oap->motion_force == 'V') {
+ oap->motion_type = kMTLineWise;
+ } else if (oap->motion_force == 'v') {
+ // If the motion was linewise, "inclusive" will not have been set.
+ // Use "exclusive" to be consistent. Makes "dvj" work nice.
+ if (oap->motion_type == kMTLineWise) {
+ oap->inclusive = false;
+ } else if (oap->motion_type == kMTCharWise) {
+ // If the motion already was charwise, toggle "inclusive"
+ oap->inclusive = !oap->inclusive;
+ }
+ oap->motion_type = kMTCharWise;
+ } else if (oap->motion_force == Ctrl_V) {
+ // Change line- or charwise motion into Visual block mode.
+ if (!VIsual_active) {
+ VIsual_active = true;
+ VIsual = oap->start;
+ }
+ VIsual_mode = Ctrl_V;
+ VIsual_select = false;
+ VIsual_reselect = false;
+ }
+
+ // Only redo yank when 'y' flag is in 'cpoptions'.
+ // Never redo "zf" (define fold).
+ if ((redo_yank || oap->op_type != OP_YANK)
+ && ((!VIsual_active || oap->motion_force)
+ // Also redo Operator-pending Visual mode mappings.
+ || ((cap->cmdchar == ':' || cap->cmdchar == K_COMMAND)
+ && oap->op_type != OP_COLON))
+ && cap->cmdchar != 'D'
+ && oap->op_type != OP_FOLD
+ && oap->op_type != OP_FOLDOPEN
+ && oap->op_type != OP_FOLDOPENREC
+ && oap->op_type != OP_FOLDCLOSE
+ && oap->op_type != OP_FOLDCLOSEREC
+ && oap->op_type != OP_FOLDDEL
+ && oap->op_type != OP_FOLDDELREC) {
+ prep_redo(oap->regname, cap->count0,
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ if (cap->cmdchar == '/' || cap->cmdchar == '?') { // was a search
+ // If 'cpoptions' does not contain 'r', insert the search
+ // pattern to really repeat the same command.
+ if (vim_strchr(p_cpo, CPO_REDO) == NULL) {
+ AppendToRedobuffLit(cap->searchbuf, -1);
+ }
+ AppendToRedobuff(NL_STR);
+ } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) {
+ // do_cmdline() has stored the first typed line in
+ // "repeat_cmdline". When several lines are typed repeating
+ // won't be possible.
+ if (repeat_cmdline == NULL) {
+ ResetRedobuff();
+ } else {
+ AppendToRedobuffLit(repeat_cmdline, -1);
+ AppendToRedobuff(NL_STR);
+ XFREE_CLEAR(repeat_cmdline);
+ }
+ }
+ }
+
+ if (redo_VIsual_busy) {
+ // Redo of an operation on a Visual area. Use the same size from
+ // redo_VIsual_line_count and redo_VIsual_vcol.
+ oap->start = curwin->w_cursor;
+ curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
+ curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
+ VIsual_mode = redo_VIsual_mode;
+ if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') {
+ if (VIsual_mode == 'v') {
+ if (redo_VIsual_line_count <= 1) {
+ validate_virtcol();
+ curwin->w_curswant =
+ curwin->w_virtcol + redo_VIsual_vcol - 1;
+ } else {
+ curwin->w_curswant = redo_VIsual_vcol;
+ }
+ } else {
+ curwin->w_curswant = MAXCOL;
+ }
+ coladvance(curwin->w_curswant);
+ }
+ cap->count0 = redo_VIsual_count;
+ cap->count1 = (cap->count0 == 0 ? 1 : cap->count0);
+ } else if (VIsual_active) {
+ if (!gui_yank) {
+ // Save the current VIsual area for '< and '> marks, and "gv"
+ curbuf->b_visual.vi_start = VIsual;
+ curbuf->b_visual.vi_end = curwin->w_cursor;
+ curbuf->b_visual.vi_mode = VIsual_mode;
+ restore_visual_mode();
+ curbuf->b_visual.vi_curswant = curwin->w_curswant;
+ curbuf->b_visual_mode_eval = VIsual_mode;
+ }
+
+ // In Select mode, a linewise selection is operated upon like a
+ // charwise selection.
+ // Special case: gH<Del> deletes the last line.
+ if (VIsual_select && VIsual_mode == 'V'
+ && cap->oap->op_type != OP_DELETE) {
+ if (lt(VIsual, curwin->w_cursor)) {
+ VIsual.col = 0;
+ curwin->w_cursor.col =
+ (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum));
+ } else {
+ curwin->w_cursor.col = 0;
+ VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum));
+ }
+ VIsual_mode = 'v';
+ } else if (VIsual_mode == 'v') {
+ // If 'selection' is "exclusive", backup one character for
+ // charwise selections.
+ include_line_break =
+ unadjust_for_sel();
+ }
+
+ oap->start = VIsual;
+ if (VIsual_mode == 'V') {
+ oap->start.col = 0;
+ oap->start.coladd = 0;
+ }
+ }
+
+ // Set oap->start to the first position of the operated text, oap->end
+ // to the end of the operated text. w_cursor is equal to oap->start.
+ if (lt(oap->start, curwin->w_cursor)) {
+ // Include folded lines completely.
+ if (!VIsual_active) {
+ if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) {
+ oap->start.col = 0;
+ }
+ if ((curwin->w_cursor.col > 0
+ || oap->inclusive
+ || oap->motion_type == kMTLineWise)
+ && hasFolding(curwin->w_cursor.lnum, NULL,
+ &curwin->w_cursor.lnum)) {
+ curwin->w_cursor.col = (colnr_T)STRLEN(get_cursor_line_ptr());
+ }
+ }
+ oap->end = curwin->w_cursor;
+ curwin->w_cursor = oap->start;
+
+ // w_virtcol may have been updated; if the cursor goes back to its
+ // previous position w_virtcol becomes invalid and isn't updated
+ // automatically.
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ } else {
+ // Include folded lines completely.
+ if (!VIsual_active && oap->motion_type == kMTLineWise) {
+ if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum,
+ NULL)) {
+ curwin->w_cursor.col = 0;
+ }
+ if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) {
+ oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum));
+ }
+ }
+ oap->end = oap->start;
+ oap->start = curwin->w_cursor;
+ }
+
+ // Just in case lines were deleted that make the position invalid.
+ check_pos(curwin->w_buffer, &oap->end);
+ oap->line_count = oap->end.lnum - oap->start.lnum + 1;
+
+ // Set "virtual_op" before resetting VIsual_active.
+ virtual_op = virtual_active();
+
+ if (VIsual_active || redo_VIsual_busy) {
+ get_op_vcol(oap, redo_VIsual_vcol, true);
+
+ if (!redo_VIsual_busy && !gui_yank) {
+ // Prepare to reselect and redo Visual: this is based on the
+ // size of the Visual text
+ resel_VIsual_mode = VIsual_mode;
+ if (curwin->w_curswant == MAXCOL) {
+ resel_VIsual_vcol = MAXCOL;
+ } else {
+ if (VIsual_mode != Ctrl_V) {
+ getvvcol(curwin, &(oap->end),
+ NULL, NULL, &oap->end_vcol);
+ }
+ if (VIsual_mode == Ctrl_V || oap->line_count <= 1) {
+ if (VIsual_mode != Ctrl_V) {
+ getvvcol(curwin, &(oap->start),
+ &oap->start_vcol, NULL, NULL);
+ }
+ resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1;
+ } else {
+ resel_VIsual_vcol = oap->end_vcol;
+ }
+ }
+ resel_VIsual_line_count = oap->line_count;
+ }
+
+ // can't redo yank (unless 'y' is in 'cpoptions') and ":"
+ if ((redo_yank || oap->op_type != OP_YANK)
+ && oap->op_type != OP_COLON
+ && oap->op_type != OP_FOLD
+ && oap->op_type != OP_FOLDOPEN
+ && oap->op_type != OP_FOLDOPENREC
+ && oap->op_type != OP_FOLDCLOSE
+ && oap->op_type != OP_FOLDCLOSEREC
+ && oap->op_type != OP_FOLDDEL
+ && oap->op_type != OP_FOLDDELREC
+ && oap->motion_force == NUL) {
+ // Prepare for redoing. Only use the nchar field for "r",
+ // otherwise it might be the second char of the operator.
+ if (cap->cmdchar == 'g' && (cap->nchar == 'n'
+ || cap->nchar == 'N')) {
+ prep_redo(oap->regname, cap->count0,
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ } else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND) {
+ int nchar = oap->op_type == OP_REPLACE ? cap->nchar : NUL;
+
+ // reverse what nv_replace() did
+ if (nchar == REPLACE_CR_NCHAR) {
+ nchar = CAR;
+ } else if (nchar == REPLACE_NL_NCHAR) {
+ nchar = NL;
+ }
+ prep_redo(oap->regname, 0L, NUL, 'v', get_op_char(oap->op_type),
+ get_extra_op_char(oap->op_type), nchar);
+ }
+ if (!redo_VIsual_busy) {
+ redo_VIsual_mode = resel_VIsual_mode;
+ redo_VIsual_vcol = resel_VIsual_vcol;
+ redo_VIsual_line_count = resel_VIsual_line_count;
+ redo_VIsual_count = cap->count0;
+ redo_VIsual_arg = cap->arg;
+ }
+ }
+
+ // oap->inclusive defaults to true.
+ // If oap->end is on a NUL (empty line) oap->inclusive becomes
+ // false. This makes "d}P" and "v}dP" work the same.
+ if (oap->motion_force == NUL || oap->motion_type == kMTLineWise) {
+ oap->inclusive = true;
+ }
+ if (VIsual_mode == 'V') {
+ oap->motion_type = kMTLineWise;
+ } else if (VIsual_mode == 'v') {
+ oap->motion_type = kMTCharWise;
+ if (*ml_get_pos(&(oap->end)) == NUL
+ && (include_line_break || !virtual_op)) {
+ oap->inclusive = false;
+ // Try to include the newline, unless it's an operator
+ // that works on lines only.
+ if (*p_sel != 'o'
+ && !op_on_lines(oap->op_type)
+ && oap->end.lnum < curbuf->b_ml.ml_line_count) {
+ oap->end.lnum++;
+ oap->end.col = 0;
+ oap->end.coladd = 0;
+ oap->line_count++;
+ }
+ }
+ }
+
+ redo_VIsual_busy = false;
+
+ // Switch Visual off now, so screen updating does
+ // not show inverted text when the screen is redrawn.
+ // With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
+ // no screen redraw, so it is done here to remove the inverted
+ // part.
+ if (!gui_yank) {
+ VIsual_active = false;
+ setmouse();
+ mouse_dragging = 0;
+ may_clear_cmdline();
+ if ((oap->op_type == OP_YANK
+ || oap->op_type == OP_COLON
+ || oap->op_type == OP_FUNCTION
+ || oap->op_type == OP_FILTER)
+ && oap->motion_force == NUL) {
+ // Make sure redrawing is correct.
+ curwin->w_p_lbr = lbr_saved;
+ redraw_curbuf_later(INVERTED);
+ }
+ }
+ }
+
+ // Include the trailing byte of a multi-byte char.
+ if (oap->inclusive) {
+ const int l = utfc_ptr2len(ml_get_pos(&oap->end));
+ if (l > 1) {
+ oap->end.col += l - 1;
+ }
+ }
+ curwin->w_set_curswant = true;
+
+ // oap->empty is set when start and end are the same. The inclusive
+ // flag affects this too, unless yanking and the end is on a NUL.
+ oap->empty = (oap->motion_type != kMTLineWise
+ && (!oap->inclusive
+ || (oap->op_type == OP_YANK
+ && gchar_pos(&oap->end) == NUL))
+ && equalpos(oap->start, oap->end)
+ && !(virtual_op && oap->start.coladd != oap->end.coladd));
+ // For delete, change and yank, it's an error to operate on an
+ // empty region, when 'E' included in 'cpoptions' (Vi compatible).
+ empty_region_error = (oap->empty
+ && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
+
+ // Force a redraw when operating on an empty Visual region, when
+ // 'modifiable is off or creating a fold.
+ if (oap->is_VIsual && (oap->empty || !MODIFIABLE(curbuf)
+ || oap->op_type == OP_FOLD)) {
+ curwin->w_p_lbr = lbr_saved;
+ redraw_curbuf_later(INVERTED);
+ }
+
+ // If the end of an operator is in column one while oap->motion_type
+ // is kMTCharWise and oap->inclusive is false, we put op_end after the last
+ // character in the previous line. If op_start is on or before the
+ // first non-blank in the line, the operator becomes linewise
+ // (strange, but that's the way vi does it).
+ if (oap->motion_type == kMTCharWise
+ && oap->inclusive == false
+ && !(cap->retval & CA_NO_ADJ_OP_END)
+ && oap->end.col == 0
+ && (!oap->is_VIsual || *p_sel == 'o')
+ && oap->line_count > 1) {
+ oap->end_adjusted = true; // remember that we did this
+ oap->line_count--;
+ oap->end.lnum--;
+ if (inindent(0)) {
+ oap->motion_type = kMTLineWise;
+ } else {
+ oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col) {
+ oap->end.col--;
+ oap->inclusive = true;
+ }
+ }
+ } else {
+ oap->end_adjusted = false;
+ }
+
+ switch (oap->op_type) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ op_shift(oap, true,
+ oap->is_VIsual ? (int)cap->count1 :
+ 1);
+ auto_format(false, true);
+ break;
+
+ case OP_JOIN_NS:
+ case OP_JOIN:
+ if (oap->line_count < 2) {
+ oap->line_count = 2;
+ }
+ if (curwin->w_cursor.lnum + oap->line_count - 1 >
+ curbuf->b_ml.ml_line_count) {
+ beep_flush();
+ } else {
+ do_join((size_t)oap->line_count, oap->op_type == OP_JOIN,
+ true, true, true);
+ auto_format(false, true);
+ }
+ break;
+
+ case OP_DELETE:
+ VIsual_reselect = false; // don't reselect now
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ (void)op_delete(oap);
+ // save cursor line for undo if it wasn't saved yet
+ if (oap->motion_type == kMTLineWise
+ && has_format_option(FO_AUTO)
+ && u_save_cursor() == OK) {
+ auto_format(false, true);
+ }
+ }
+ break;
+
+ case OP_YANK:
+ if (empty_region_error) {
+ if (!gui_yank) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ } else {
+ curwin->w_p_lbr = lbr_saved;
+ oap->excl_tr_ws = cap->cmdchar == 'z';
+ (void)op_yank(oap, !gui_yank, false);
+ }
+ check_cursor_col();
+ break;
+
+ case OP_CHANGE:
+ VIsual_reselect = false; // don't reselect now
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ // This is a new edit command, not a restart. Need to
+ // remember it to make 'insertmode' work with mappings for
+ // Visual mode. But do this only once and not when typed and
+ // 'insertmode' isn't set.
+ if (p_im || !KeyTyped) {
+ restart_edit_save = restart_edit;
+ } else {
+ restart_edit_save = 0;
+ }
+ restart_edit = 0;
+
+ // Restore linebreak, so that when the user edits it looks as before.
+ curwin->w_p_lbr = lbr_saved;
+
+ // Reset finish_op now, don't want it set inside edit().
+ finish_op = false;
+ if (op_change(oap)) { // will call edit()
+ cap->retval |= CA_COMMAND_BUSY;
+ }
+ if (restart_edit == 0) {
+ restart_edit = restart_edit_save;
+ }
+ }
+ break;
+
+ case OP_FILTER:
+ if (vim_strchr(p_cpo, CPO_FILTER) != NULL) {
+ AppendToRedobuff("!\r"); // Use any last used !cmd.
+ } else {
+ bangredo = true; // do_bang() will put cmd in redo buffer.
+ }
+ FALLTHROUGH;
+
+ case OP_INDENT:
+ case OP_COLON:
+
+ // If 'equalprg' is empty, do the indenting internally.
+ if (oap->op_type == OP_INDENT && *get_equalprg() == NUL) {
+ if (curbuf->b_p_lisp) {
+ op_reindent(oap, get_lisp_indent);
+ break;
+ }
+ op_reindent(oap,
+ *curbuf->b_p_inde != NUL ? get_expr_indent :
+ get_c_indent);
+ break;
+ }
+
+ op_colon(oap);
+ break;
+
+ case OP_TILDE:
+ case OP_UPPER:
+ case OP_LOWER:
+ case OP_ROT13:
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ op_tilde(oap);
+ }
+ check_cursor_col();
+ break;
+
+ case OP_FORMAT:
+ if (*curbuf->b_p_fex != NUL) {
+ op_formatexpr(oap); // use expression
+ } else {
+ if (*p_fp != NUL || *curbuf->b_p_fp != NUL) {
+ op_colon(oap); // use external command
+ } else {
+ op_format(oap, false); // use internal function
+ }
+ }
+ break;
+
+ case OP_FORMAT2:
+ op_format(oap, true); // use internal function
+ break;
+
+ case OP_FUNCTION:
+ // Restore linebreak, so that when the user edits it looks as
+ // before.
+ curwin->w_p_lbr = lbr_saved;
+ op_function(oap); // call 'operatorfunc'
+ break;
+
+ case OP_INSERT:
+ case OP_APPEND:
+ VIsual_reselect = false; // don't reselect now
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ // This is a new edit command, not a restart. Need to
+ // remember it to make 'insertmode' work with mappings for
+ // Visual mode. But do this only once.
+ restart_edit_save = restart_edit;
+ restart_edit = 0;
+
+ // Restore linebreak, so that when the user edits it looks as before.
+ curwin->w_p_lbr = lbr_saved;
+
+ op_insert(oap, cap->count1);
+
+ // Reset linebreak, so that formatting works correctly.
+ curwin->w_p_lbr = false;
+
+ // TODO(brammool): when inserting in several lines, should format all
+ // the lines.
+ auto_format(false, true);
+
+ if (restart_edit == 0) {
+ restart_edit = restart_edit_save;
+ } else {
+ cap->retval |= CA_COMMAND_BUSY;
+ }
+ }
+ break;
+
+ case OP_REPLACE:
+ VIsual_reselect = false; // don't reselect now
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ // Restore linebreak, so that when the user edits it looks as before.
+ curwin->w_p_lbr = lbr_saved;
+
+ op_replace(oap, cap->nchar);
+ }
+ break;
+
+ case OP_FOLD:
+ VIsual_reselect = false; // don't reselect now
+ foldCreate(curwin, oap->start, oap->end);
+ break;
+
+ case OP_FOLDOPEN:
+ case OP_FOLDOPENREC:
+ case OP_FOLDCLOSE:
+ case OP_FOLDCLOSEREC:
+ VIsual_reselect = false; // don't reselect now
+ opFoldRange(oap->start, oap->end,
+ oap->op_type == OP_FOLDOPEN
+ || oap->op_type == OP_FOLDOPENREC,
+ oap->op_type == OP_FOLDOPENREC
+ || oap->op_type == OP_FOLDCLOSEREC,
+ oap->is_VIsual);
+ break;
+
+ case OP_FOLDDEL:
+ case OP_FOLDDELREC:
+ VIsual_reselect = false; // don't reselect now
+ deleteFold(curwin, oap->start.lnum, oap->end.lnum,
+ oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
+ break;
+
+ case OP_NR_ADD:
+ case OP_NR_SUB:
+ if (empty_region_error) {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ } else {
+ VIsual_active = true;
+ curwin->w_p_lbr = lbr_saved;
+ op_addsub(oap, cap->count1, redo_VIsual_arg);
+ VIsual_active = false;
+ }
+ check_cursor_col();
+ break;
+ default:
+ clearopbeep(oap);
+ }
+ virtual_op = kNone;
+ if (!gui_yank) {
+ // if 'sol' not set, go back to old column for some commands
+ if (!p_sol && oap->motion_type == kMTLineWise && !oap->end_adjusted
+ && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
+ || oap->op_type == OP_DELETE)) {
+ curwin->w_p_lbr = false;
+ coladvance(curwin->w_curswant = old_col);
+ }
+ } else {
+ curwin->w_cursor = old_cursor;
+ }
+ clearop(oap);
+ motion_force = NUL;
+ }
+ curwin->w_p_lbr = lbr_saved;
+}
+
/// Check if the default register (used in an unnamed paste) should be a
/// clipboard register. This happens when `clipboard=unnamed[plus]` is set
/// and a provider is available.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index ee5f62d826..1fe2e1d04c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1301,7 +1301,11 @@ int do_set(char_u *arg, int opt_flags)
char_u *oldval = NULL; // previous value if *varp
char_u *newval;
char_u *origval = NULL;
+ char_u *origval_l = NULL;
+ char_u *origval_g = NULL;
char *saved_origval = NULL;
+ char *saved_origval_l = NULL;
+ char *saved_origval_g = NULL;
char *saved_newval = NULL;
unsigned newlen;
int comma;
@@ -1319,10 +1323,21 @@ int do_set(char_u *arg, int opt_flags)
// new value is valid.
oldval = *(char_u **)varp;
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ origval_l = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
+ origval_g = *(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+
+ // A global-local string option might have an empty
+ // option as value to indicate that the global
+ // value should be used.
+ if (((int)options[opt_idx].indir & PV_BOTH) && origval_l == empty_option) {
+ origval_l = origval_g;
+ }
+ }
+
// When setting the local value of a global
// option, the old value may be the global value.
- if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags
- & OPT_LOCAL)) {
+ if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL)) {
origval = *(char_u **)get_varp(&options[opt_idx]);
} else {
origval = oldval;
@@ -1388,6 +1403,12 @@ int do_set(char_u *arg, int opt_flags)
if (origval == oldval) {
origval = *(char_u **)varp;
}
+ if (origval_l == oldval) {
+ origval_l = *(char_u **)varp;
+ }
+ if (origval_g == oldval) {
+ origval_g = *(char_u **)varp;
+ }
oldval = *(char_u **)varp;
}
/*
@@ -1596,6 +1617,8 @@ int do_set(char_u *arg, int opt_flags)
// origval may be freed by
// did_set_string_option(), make a copy.
saved_origval = (origval != NULL) ? xstrdup((char *)origval) : 0;
+ saved_origval_l = (origval_l != NULL) ? xstrdup((char *)origval_l) : 0;
+ saved_origval_g = (origval_g != NULL) ? xstrdup((char *)origval_g) : 0;
// newval (and varp) may become invalid if the
// buffer is closed by autocommands.
@@ -1630,8 +1653,8 @@ int do_set(char_u *arg, int opt_flags)
if (errmsg == NULL) {
if (!starting) {
- trigger_optionsset_string(opt_idx, opt_flags, saved_origval,
- saved_newval);
+ trigger_optionsset_string(opt_idx, opt_flags, saved_origval, saved_origval_l,
+ saved_origval_g, saved_newval);
}
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
@@ -1639,6 +1662,8 @@ int do_set(char_u *arg, int opt_flags)
}
}
xfree(saved_origval);
+ xfree(saved_origval_l);
+ xfree(saved_origval_g);
xfree(saved_newval);
// If error detected, print the error message.
@@ -2233,9 +2258,19 @@ static char *set_string_option(const int opt_idx, const char *const value, const
? OPT_GLOBAL : OPT_LOCAL)
: opt_flags));
char *const oldval = *varp;
+ char *oldval_l = NULL;
+ char *oldval_g = NULL;
+
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ oldval_l = *(char **)get_varp_scope(&(options[opt_idx]), OPT_LOCAL);
+ oldval_g = *(char **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+ }
+
*varp = s;
char *const saved_oldval = xstrdup(oldval);
+ char *const saved_oldval_l = (oldval_l != NULL) ? xstrdup((char *)oldval_l) : 0;
+ char *const saved_oldval_g = (oldval_g != NULL) ? xstrdup((char *)oldval_g) : 0;
char *const saved_newval = xstrdup(s);
int value_checked = false;
@@ -2249,7 +2284,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const
// call autocommand after handling side effects
if (r == NULL) {
if (!starting) {
- trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_newval);
+ trigger_optionsset_string(opt_idx, opt_flags, saved_oldval, saved_oldval_l, saved_oldval_g,
+ saved_newval);
}
if (options[opt_idx].flags & P_UI_OPTION) {
ui_call_option_set(cstr_as_string(options[opt_idx].fullname),
@@ -2257,6 +2293,8 @@ static char *set_string_option(const int opt_idx, const char *const value, const
}
}
xfree(saved_oldval);
+ xfree(saved_oldval_l);
+ xfree(saved_oldval_g);
xfree(saved_newval);
return r;
@@ -3851,6 +3889,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
const int opt_flags)
{
int old_value = *(int *)varp;
+ int old_global_value = 0;
// Disallow changing some options from secure mode
if ((secure || sandbox != 0)
@@ -3858,6 +3897,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
return (char *)e_secure;
}
+ // Save the global value before changing anything. This is needed as for
+ // a global-only option setting the "local value" in fact sets the global
+ // value (since there is only one value).
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ old_global_value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+ }
+
*(int *)varp = value; // set the new value
// Remember where the option was set.
set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
@@ -4134,20 +4180,35 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, const int va
// Don't do this while starting up or recursively.
if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
char buf_old[2];
+ char buf_old_global[2];
char buf_new[2];
char buf_type[7];
- vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d",
- old_value ? true: false);
- vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d",
- value ? true: false);
+ vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d", old_value ? true : false);
+ vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%d", old_global_value ? true : false);
+ vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d", value ? true : false);
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global");
set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- apply_autocmds(EVENT_OPTIONSET,
- (char_u *)options[opt_idx].fullname,
- NULL, false, NULL);
+ if (opt_flags & OPT_LOCAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ }
+ if (opt_flags & OPT_GLOBAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1);
+ }
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ set_vim_var_string(VV_OPTION_COMMAND, "set", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1);
+ }
+ if (opt_flags & OPT_MODELINE) {
+ set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ }
+ apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL);
reset_v_option_vars();
}
@@ -4181,7 +4242,8 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
{
char *errmsg = NULL;
long old_value = *(long *)varp;
- long old_Rows = Rows; // remember old Rows
+ long old_global_value = 0; // only used when setting a local and global option
+ long old_Rows = Rows; // remember old Rows
long *pp = (long *)varp;
// Disallow changing some options from secure mode.
@@ -4190,6 +4252,13 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
return e_secure;
}
+ // Save the global value before changing anything. This is needed as for
+ // a global-only option setting the "local value" infact sets the global
+ // value (since there is only one value).
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ old_global_value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
+ }
+
// Many number options assume their value is in the signed int range.
if (value < INT_MIN || value > INT_MAX) {
return e_invarg;
@@ -4534,19 +4603,36 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
// Don't do this while starting up, failure or recursively.
if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) {
char buf_old[NUMBUFLEN];
+ char buf_old_global[NUMBUFLEN];
char buf_new[NUMBUFLEN];
char buf_type[7];
vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_value);
+ vim_snprintf(buf_old_global, ARRAY_SIZE(buf_old_global), "%ld", old_global_value);
vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%ld", value);
vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global");
set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- apply_autocmds(EVENT_OPTIONSET,
- (char_u *)options[opt_idx].fullname,
- NULL, false, NULL);
+ if (opt_flags & OPT_LOCAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ }
+ if (opt_flags & OPT_GLOBAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1);
+ }
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ set_vim_var_string(VV_OPTION_COMMAND, "set", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1);
+ }
+ if (opt_flags & OPT_MODELINE) {
+ set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1);
+ }
+ apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL);
reset_v_option_vars();
}
@@ -4565,7 +4651,15 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
return (char *)errmsg;
}
-static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *newval)
+/// Trigger the OptionSet autocommand.
+/// "opt_idx" is the index of the option being set.
+/// "opt_flags" can be OPT_LOCAL etc.
+/// "oldval" the old value
+/// "oldval_l" the old local value (only non-NULL if global and local value are set)
+/// "oldval_g" the old global value (only non-NULL if global and local value are set)
+/// "newval" the new value
+static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *oldval_l,
+ char *oldval_g, char *newval)
{
// Don't do this recursively.
if (oldval != NULL
@@ -4578,8 +4672,24 @@ static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval,
set_vim_var_string(VV_OPTION_OLD, oldval, -1);
set_vim_var_string(VV_OPTION_NEW, newval, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
- apply_autocmds(EVENT_OPTIONSET,
- (char_u *)options[opt_idx].fullname, NULL, false, NULL);
+ if (opt_flags & OPT_LOCAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setlocal", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
+ }
+ if (opt_flags & OPT_GLOBAL) {
+ set_vim_var_string(VV_OPTION_COMMAND, "setglobal", -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval, -1);
+ }
+ if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) {
+ set_vim_var_string(VV_OPTION_COMMAND, "set", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval_l, -1);
+ set_vim_var_string(VV_OPTION_OLDGLOBAL, oldval_g, -1);
+ }
+ if (opt_flags & OPT_MODELINE) {
+ set_vim_var_string(VV_OPTION_COMMAND, "modeline", -1);
+ set_vim_var_string(VV_OPTION_OLDLOCAL, oldval, -1);
+ }
+ apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, NULL, false, NULL);
reset_v_option_vars();
}
}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index bec3bc9648..e67efb8ea0 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -1760,13 +1760,14 @@ static char_u *regpiece(int *flagp)
break;
}
if (re_multi_type(peekchr()) != NOT_MULTI) {
- /* Can't have a multi follow a multi. */
- if (peekchr() == Magic('*'))
- sprintf((char *)IObuff, _("E61: Nested %s*"),
- reg_magic >= MAGIC_ON ? "" : "\\");
- else
- sprintf((char *)IObuff, _("E62: Nested %s%c"),
- reg_magic == MAGIC_ALL ? "" : "\\", no_Magic(peekchr()));
+ // Can't have a multi follow a multi.
+ if (peekchr() == Magic('*')) {
+ snprintf((char *)IObuff, IOSIZE, _("E61: Nested %s*"),
+ reg_magic >= MAGIC_ON ? "" : "\\");
+ } else {
+ snprintf((char *)IObuff, IOSIZE, _("E62: Nested %s%c"),
+ reg_magic == MAGIC_ALL ? "" : "\\", no_Magic(peekchr()));
+ }
EMSG_RET_NULL((char *)IObuff);
}
@@ -1926,11 +1927,11 @@ static char_u *regatom(int *flagp)
case Magic('{'):
case Magic('*'):
c = no_Magic(c);
- sprintf((char *)IObuff, _("E64: %s%c follows nothing"),
- (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL)
- ? "" : "\\", c);
+ snprintf((char *)IObuff, IOSIZE, _("E64: %s%c follows nothing"),
+ (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL)
+ ? "" : "\\", c);
EMSG_RET_NULL((char *)IObuff);
- /* NOTREACHED */
+ // NOTREACHED
case Magic('~'): /* previous substitute pattern */
if (reg_prev_sub != NULL) {
@@ -3152,8 +3153,8 @@ static int read_limits(long *minval, long *maxval)
regparse++; // Allow either \{...} or \{...\}
}
if (*regparse != '}') {
- sprintf((char *)IObuff, _("E554: Syntax error in %s{...}"),
- reg_magic == MAGIC_ALL ? "" : "\\");
+ snprintf((char *)IObuff, IOSIZE, _("E554: Syntax error in %s{...}"),
+ reg_magic == MAGIC_ALL ? "" : "\\");
EMSG_RET_FAIL((char *)IObuff);
}
@@ -7263,9 +7264,10 @@ regprog_T *vim_regcomp(char_u *expr_arg, int re_flags)
if (f) {
fprintf(f, "Syntax error in \"%s\"\n", expr);
fclose(f);
- } else
+ } else {
semsg("(NFA) Could not open \"%s\" to write !!!",
- BT_REGEXP_DEBUG_LOG_NAME);
+ BT_REGEXP_DEBUG_LOG_NAME);
+ }
}
#endif
// If the NFA engine failed, try the backtracking engine. The NFA engine
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 2ce2be0bfd..a666b9c8b0 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -451,9 +451,11 @@ int update_screen(int type)
// reset cmdline_row now (may have been changed temporarily)
compute_cmdrow();
+ bool hl_changed = false;
// Check for changed highlighting
if (need_highlight_changed) {
highlight_changed();
+ hl_changed = true;
}
if (type == CLEAR) { // first clear screen
@@ -554,7 +556,7 @@ int update_screen(int type)
* buffer. Each buffer must only be done once.
*/
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- update_window_hl(wp, type >= NOT_VALID);
+ update_window_hl(wp, type >= NOT_VALID || hl_changed);
buf_T *buf = wp->w_buffer;
if (buf->b_mod_set) {
@@ -1692,7 +1694,7 @@ static void win_update(win_T *wp, Providers *providers)
if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
j = win_get_fill(wp, wp->w_botline);
- if (j > 0 && !wp->w_botfill) {
+ if (j > 0 && !wp->w_botfill && row < wp->w_grid.Rows) {
// Display filler text below last line. win_line() will check
// for ml_line_count+1 and only draw filler lines
foldinfo_T info = FOLDINFO_INIT;
@@ -6930,7 +6932,7 @@ int showmode(void)
do_mode = ((p_smd && msg_silent == 0)
&& ((State & TERM_FOCUS)
|| (State & INSERT)
- || restart_edit
+ || restart_edit != NUL
|| VIsual_active));
if (do_mode || reg_recording != 0) {
// Don't show mode right now, when not redrawing or inside a mapping.
@@ -7010,7 +7012,7 @@ int showmode(void)
}
msg_puts_attr(_(" INSERT"), attr);
} else if (restart_edit == 'I' || restart_edit == 'i'
- || restart_edit == 'a') {
+ || restart_edit == 'a' || restart_edit == 'A') {
msg_puts_attr(_(" (insert)"), attr);
} else if (restart_edit == 'R') {
msg_puts_attr(_(" (replace)"), attr);
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 1f4d3adc92..483d2df778 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -141,12 +141,12 @@ static int tfu_in_use = false; // disallow recursive call of tagfunc
/// type == DT_LTAG: use location list for displaying tag matches
/// type == DT_FREE: free cached matches
///
-/// for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise
+/// for cscope, returns true if we jumped to tag or aborted, false otherwise
///
/// @param tag tag (pattern) to jump to
/// @param forceit :ta with !
/// @param verbose print "tag not found" message
-int do_tag(char_u *tag, int type, int count, int forceit, int verbose)
+bool do_tag(char_u *tag, int type, int count, int forceit, int verbose)
{
taggy_T *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
@@ -163,7 +163,7 @@ int do_tag(char_u *tag, int type, int count, int forceit, int verbose)
int error_cur_match = 0;
int save_pos = false;
fmark_T saved_fmark;
- int jumped_to_tag = false;
+ bool jumped_to_tag = false;
int new_num_matches;
char_u **new_matches;
int use_tagstack;
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 83ade74db1..afebda4948 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -46,6 +46,7 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
+#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/event/loop.h"
#include "nvim/event/time.h"
@@ -464,9 +465,7 @@ static void terminal_check_cursor(void)
row_to_linenr(term, term->cursor.row));
// Nudge cursor when returning to normal-mode.
int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1);
- curwin->w_cursor.col = MAX(0, term->cursor.col + win_col_off(curwin) + off);
- curwin->w_cursor.coladd = 0;
- mb_check_adjust_col(curwin);
+ coladvance(MAX(0, term->cursor.col + off));
}
// Function executed before each iteration of terminal mode.
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 49993c03aa..ab047fd2a8 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -197,7 +197,12 @@ func RunTheTest(test)
" Close any extra tab pages and windows and make the current one not modified.
while tabpagenr('$') > 1
+ let winid = win_getid()
quit!
+ if winid == win_getid()
+ echoerr 'Could not quit window'
+ break
+ endif
endwhile
while 1
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 49d56349a5..4e1a24af61 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -526,8 +526,7 @@ func Test_autocmd_blast_badd()
call writefile(content, 'XblastBall')
call system(GetVimCommand() .. ' --clean -S XblastBall')
- " call assert_match('OK', readfile('Xerrors')->join())
- call assert_match('OK', join(readfile('Xerrors')))
+ call assert_match('OK', readfile('Xerrors')->join())
call delete('XblastBall')
call delete('Xerrors')
@@ -580,9 +579,10 @@ func Test_empty_doau()
endfunc
func s:AutoCommandOptionSet(match)
+ let template = "Option: <%s>, OldVal: <%s>, OldValLocal: <%s>, OldValGlobal: <%s>, NewVal: <%s>, Scope: <%s>, Command: <%s>\n"
let item = remove(g:options, 0)
- let expected = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", item[0], item[1], item[2], item[3])
- let actual = printf("Option: <%s>, Oldval: <%s>, NewVal: <%s>, Scope: <%s>\n", a:match, v:option_old, v:option_new, v:option_type)
+ let expected = printf(template, item[0], item[1], item[2], item[3], item[4], item[5], item[6])
+ let actual = printf(template, a:match, v:option_old, v:option_oldlocal, v:option_oldglobal, v:option_new, v:option_type, v:option_command)
let g:opt = [expected, actual]
"call assert_equal(expected, actual)
endfunc
@@ -596,130 +596,593 @@ func Test_OptionSet()
au OptionSet * :call s:AutoCommandOptionSet(expand("<amatch>"))
" 1: Setting number option"
- let g:options = [['number', 0, 1, 'global']]
+ let g:options = [['number', 0, 0, 0, 1, 'global', 'set']]
set nu
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 2: Setting local number option"
- let g:options = [['number', 1, 0, 'local']]
+ let g:options = [['number', 1, 1, '', 0, 'local', 'setlocal']]
setlocal nonu
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 3: Setting global number option"
- let g:options = [['number', 1, 0, 'global']]
+ let g:options = [['number', 1, '', 1, 0, 'global', 'setglobal']]
setglobal nonu
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 4: Setting local autoindent option"
- let g:options = [['autoindent', 0, 1, 'local']]
+ let g:options = [['autoindent', 0, 0, '', 1, 'local', 'setlocal']]
setlocal ai
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 5: Setting global autoindent option"
- let g:options = [['autoindent', 0, 1, 'global']]
+ let g:options = [['autoindent', 0, '', 0, 1, 'global', 'setglobal']]
setglobal ai
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 6: Setting global autoindent option"
- let g:options = [['autoindent', 1, 0, 'global']]
+ let g:options = [['autoindent', 1, 1, 1, 0, 'global', 'set']]
+ set ai!
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 6a: Setting global autoindent option"
+ let g:options = [['autoindent', 1, 1, 0, 0, 'global', 'set']]
+ noa setlocal ai
+ noa setglobal noai
set ai!
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" Should not print anything, use :noa
" 7: don't trigger OptionSet"
- let g:options = [['invalid', 1, 1, 'invalid']]
+ let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
noa set nonu
- call assert_equal([['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 8: Setting several global list and number option"
- let g:options = [['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
+ let g:options = [['list', 0, 0, 0, 1, 'global', 'set'], ['number', 0, 0, 0, 1, 'global', 'set']]
set list nu
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 9: don't trigger OptionSet"
- let g:options = [['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']]
+ let g:options = [['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']]
noa set nolist nonu
- call assert_equal([['invalid', 1, 1, 'invalid'], ['invalid', 1, 1, 'invalid']], g:options)
+ call assert_equal([['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid'], ['invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid', 'invalid']], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 10: Setting global acd"
- let g:options = [['autochdir', 0, 1, 'local']]
+ let g:options = [['autochdir', 0, 0, '', 1, 'local', 'setlocal']]
setlocal acd
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 11: Setting global autoread (also sets local value)"
- let g:options = [['autoread', 0, 1, 'global']]
+ let g:options = [['autoread', 0, 0, 0, 1, 'global', 'set']]
set ar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 12: Setting local autoread"
- let g:options = [['autoread', 1, 1, 'local']]
+ let g:options = [['autoread', 1, 1, '', 1, 'local', 'setlocal']]
setlocal ar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 13: Setting global autoread"
- let g:options = [['autoread', 1, 0, 'global']]
+ let g:options = [['autoread', 1, '', 1, 0, 'global', 'setglobal']]
setglobal invar
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 14: Setting option backspace through :let"
- let g:options = [['backspace', '', 'eol,indent,start', 'global']]
+ let g:options = [['backspace', '', '', '', 'eol,indent,start', 'global', 'set']]
let &bs = "eol,indent,start"
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 15: Setting option backspace through setbufvar()"
- let g:options = [['backup', 0, 1, 'local']]
+ let g:options = [['backup', 0, 0, '', 1, 'local', 'setlocal']]
" try twice, first time, shouldn't trigger because option name is invalid,
" second time, it should trigger
- call assert_fails("call setbufvar(1, '&l:bk', 1)", "E355")
+ let bnum = bufnr('%')
+ call assert_fails("call setbufvar(bnum, '&l:bk', 1)", 'E355:')
" should trigger, use correct option name
- call setbufvar(1, '&backup', 1)
+ call setbufvar(bnum, '&backup', 1)
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 16: Setting number option using setwinvar"
- let g:options = [['number', 0, 1, 'local']]
+ let g:options = [['number', 0, 0, '', 1, 'local', 'setlocal']]
call setwinvar(0, '&number', 1)
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
" 17: Setting key option, shouldn't trigger"
- let g:options = [['key', 'invalid', 'invalid1', 'invalid']]
+ let g:options = [['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']]
setlocal key=blah
setlocal key=
- call assert_equal([['key', 'invalid', 'invalid1', 'invalid']], g:options)
+ call assert_equal([['key', 'invalid', 'invalid1', 'invalid2', 'invalid3', 'invalid4', 'invalid5']], g:options)
call assert_equal(g:opt[0], g:opt[1])
- " 18: Setting string option"
+
+ " 18a: Setting string global option"
+ let oldval = &backupext
+ let g:options = [['backupext', oldval, oldval, oldval, 'foo', 'global', 'set']]
+ set backupext=foo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18b: Resetting string global option"
+ let g:options = [['backupext', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
+ set backupext&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18c: Setting global string global option"
+ let g:options = [['backupext', oldval, '', oldval, 'bar', 'global', 'setglobal']]
+ setglobal backupext=bar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18d: Setting local string global option"
+ " As this is a global option this sets the global value even though
+ " :setlocal is used!
+ noa set backupext& " Reset global and local value (without triggering autocmd)
+ let g:options = [['backupext', oldval, oldval, '', 'baz', 'local', 'setlocal']]
+ setlocal backupext=baz
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 18e: Setting again string global option"
+ noa setglobal backupext=ext_global " Reset global and local value (without triggering autocmd)
+ noa setlocal backupext=ext_local " Sets the global(!) value!
+ let g:options = [['backupext', 'ext_local', 'ext_local', 'ext_local', 'fuu', 'global', 'set']]
+ set backupext=fuu
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 19a: Setting string global-local (to buffer) option"
let oldval = &tags
- let g:options = [['tags', oldval, 'tagpath', 'global']]
+ let g:options = [['tags', oldval, oldval, oldval, 'tagpath', 'global', 'set']]
set tags=tagpath
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
- " 1l: Resetting string option"
- let g:options = [['tags', 'tagpath', oldval, 'global']]
+ " 19b: Resetting string global-local (to buffer) option"
+ let g:options = [['tags', 'tagpath', 'tagpath', 'tagpath', oldval, 'global', 'set']]
set tags&
call assert_equal([], g:options)
call assert_equal(g:opt[0], g:opt[1])
+ " 19c: Setting global string global-local (to buffer) option "
+ let g:options = [['tags', oldval, '', oldval, 'tagpath1', 'global', 'setglobal']]
+ setglobal tags=tagpath1
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 19d: Setting local string global-local (to buffer) option"
+ let g:options = [['tags', 'tagpath1', 'tagpath1', '', 'tagpath2', 'local', 'setlocal']]
+ setlocal tags=tagpath2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 19e: Setting again string global-local (to buffer) option"
+ " Note: v:option_old is the old global value for global-local string options
+ " but the old local value for all other kinds of options.
+ noa setglobal tags=tag_global " Reset global and local value (without triggering autocmd)
+ noa setlocal tags=tag_local
+ let g:options = [['tags', 'tag_global', 'tag_local', 'tag_global', 'tagpath', 'global', 'set']]
+ set tags=tagpath
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 19f: Setting string global-local (to buffer) option to an empty string"
+ " Note: v:option_old is the old global value for global-local string options
+ " but the old local value for all other kinds of options.
+ noa set tags=tag_global " Reset global and local value (without triggering autocmd)
+ noa setlocal tags= " empty string
+ let g:options = [['tags', 'tag_global', '', 'tag_global', 'tagpath', 'global', 'set']]
+ set tags=tagpath
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 20a: Setting string local (to buffer) option"
+ let oldval = &spelllang
+ let g:options = [['spelllang', oldval, oldval, oldval, 'elvish,klingon', 'global', 'set']]
+ set spelllang=elvish,klingon
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 20b: Resetting string local (to buffer) option"
+ let g:options = [['spelllang', 'elvish,klingon', 'elvish,klingon', 'elvish,klingon', oldval, 'global', 'set']]
+ set spelllang&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 20c: Setting global string local (to buffer) option"
+ let g:options = [['spelllang', oldval, '', oldval, 'elvish', 'global', 'setglobal']]
+ setglobal spelllang=elvish
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 20d: Setting local string local (to buffer) option"
+ noa set spelllang& " Reset global and local value (without triggering autocmd)
+ let g:options = [['spelllang', oldval, oldval, '', 'klingon', 'local', 'setlocal']]
+ setlocal spelllang=klingon
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 20e: Setting again string local (to buffer) option"
+ " Note: v:option_old is the old global value for global-local string options
+ " but the old local value for all other kinds of options.
+ noa setglobal spelllang=spellglobal " Reset global and local value (without triggering autocmd)
+ noa setlocal spelllang=spelllocal
+ let g:options = [['spelllang', 'spelllocal', 'spelllocal', 'spellglobal', 'foo', 'global', 'set']]
+ set spelllang=foo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 21a: Setting string global-local (to window) option"
+ let oldval = &statusline
+ let g:options = [['statusline', oldval, oldval, oldval, 'foo', 'global', 'set']]
+ set statusline=foo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 21b: Resetting string global-local (to window) option"
+ " Note: v:option_old is the old global value for global-local string options
+ " but the old local value for all other kinds of options.
+ let g:options = [['statusline', 'foo', 'foo', 'foo', oldval, 'global', 'set']]
+ set statusline&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 21c: Setting global string global-local (to window) option"
+ let g:options = [['statusline', oldval, '', oldval, 'bar', 'global', 'setglobal']]
+ setglobal statusline=bar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 21d: Setting local string global-local (to window) option"
+ noa set statusline& " Reset global and local value (without triggering autocmd)
+ let g:options = [['statusline', oldval, oldval, '', 'baz', 'local', 'setlocal']]
+ setlocal statusline=baz
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 21e: Setting again string global-local (to window) option"
+ " Note: v:option_old is the old global value for global-local string options
+ " but the old local value for all other kinds of options.
+ noa setglobal statusline=bar " Reset global and local value (without triggering autocmd)
+ noa setlocal statusline=baz
+ let g:options = [['statusline', 'bar', 'baz', 'bar', 'foo', 'global', 'set']]
+ set statusline=foo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 22a: Setting string local (to window) option"
+ let oldval = &foldignore
+ let g:options = [['foldignore', oldval, oldval, oldval, 'fo', 'global', 'set']]
+ set foldignore=fo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 22b: Resetting string local (to window) option"
+ let g:options = [['foldignore', 'fo', 'fo', 'fo', oldval, 'global', 'set']]
+ set foldignore&
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 22c: Setting global string local (to window) option"
+ let g:options = [['foldignore', oldval, '', oldval, 'bar', 'global', 'setglobal']]
+ setglobal foldignore=bar
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 22d: Setting local string local (to window) option"
+ noa set foldignore& " Reset global and local value (without triggering autocmd)
+ let g:options = [['foldignore', oldval, oldval, '', 'baz', 'local', 'setlocal']]
+ setlocal foldignore=baz
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 22e: Setting again string local (to window) option"
+ noa setglobal foldignore=glob " Reset global and local value (without triggering autocmd)
+ noa setlocal foldignore=loc
+ let g:options = [['foldignore', 'loc', 'loc', 'glob', 'fo', 'global', 'set']]
+ set foldignore=fo
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 23a: Setting global number global option"
+ noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal cmdheight=1 " Sets the global(!) value!
+ let g:options = [['cmdheight', '1', '', '1', '2', 'global', 'setglobal']]
+ setglobal cmdheight=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 23b: Setting local number global option"
+ noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal cmdheight=1 " Sets the global(!) value!
+ let g:options = [['cmdheight', '1', '1', '', '2', 'local', 'setlocal']]
+ setlocal cmdheight=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 23c: Setting again number global option"
+ noa setglobal cmdheight=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal cmdheight=1 " Sets the global(!) value!
+ let g:options = [['cmdheight', '1', '1', '1', '2', 'global', 'set']]
+ set cmdheight=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 23d: Setting again number global option"
+ noa set cmdheight=8 " Reset global and local value (without triggering autocmd)
+ let g:options = [['cmdheight', '8', '8', '8', '2', 'global', 'set']]
+ set cmdheight=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 24a: Setting global number global-local (to buffer) option"
+ noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal undolevels=1
+ let g:options = [['undolevels', '8', '', '8', '2', 'global', 'setglobal']]
+ setglobal undolevels=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 24b: Setting local number global-local (to buffer) option"
+ noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal undolevels=1
+ let g:options = [['undolevels', '1', '1', '', '2', 'local', 'setlocal']]
+ setlocal undolevels=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 24c: Setting again number global-local (to buffer) option"
+ noa setglobal undolevels=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal undolevels=1
+ let g:options = [['undolevels', '1', '1', '8', '2', 'global', 'set']]
+ set undolevels=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 24d: Setting again global number global-local (to buffer) option"
+ noa set undolevels=8 " Reset global and local value (without triggering autocmd)
+ let g:options = [['undolevels', '8', '8', '8', '2', 'global', 'set']]
+ set undolevels=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 25a: Setting global number local (to buffer) option"
+ noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapmargin=1
+ let g:options = [['wrapmargin', '8', '', '8', '2', 'global', 'setglobal']]
+ setglobal wrapmargin=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 25b: Setting local number local (to buffer) option"
+ noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapmargin=1
+ let g:options = [['wrapmargin', '1', '1', '', '2', 'local', 'setlocal']]
+ setlocal wrapmargin=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 25c: Setting again number local (to buffer) option"
+ noa setglobal wrapmargin=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapmargin=1
+ let g:options = [['wrapmargin', '1', '1', '8', '2', 'global', 'set']]
+ set wrapmargin=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 25d: Setting again global number local (to buffer) option"
+ noa set wrapmargin=8 " Reset global and local value (without triggering autocmd)
+ let g:options = [['wrapmargin', '8', '8', '8', '2', 'global', 'set']]
+ set wrapmargin=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 26: Setting number global-local (to window) option.
+ " Such option does currently not exist.
+
+
+ " 27a: Setting global number local (to window) option"
+ noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal foldcolumn=1
+ let g:options = [['foldcolumn', '8', '', '8', '2', 'global', 'setglobal']]
+ setglobal foldcolumn=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 27b: Setting local number local (to window) option"
+ noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal foldcolumn=1
+ let g:options = [['foldcolumn', '1', '1', '', '2', 'local', 'setlocal']]
+ setlocal foldcolumn=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 27c: Setting again number local (to window) option"
+ noa setglobal foldcolumn=8 " Reset global and local value (without triggering autocmd)
+ noa setlocal foldcolumn=1
+ let g:options = [['foldcolumn', '1', '1', '8', '2', 'global', 'set']]
+ set foldcolumn=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 27d: Setting again global number local (to window) option"
+ noa set foldcolumn=8 " Reset global and local value (without triggering autocmd)
+ let g:options = [['foldcolumn', '8', '8', '8', '2', 'global', 'set']]
+ set foldcolumn=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 28a: Setting global boolean global option"
+ noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapscan " Sets the global(!) value!
+ let g:options = [['wrapscan', '1', '', '1', '0', 'global', 'setglobal']]
+ setglobal nowrapscan
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 28b: Setting local boolean global option"
+ noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapscan " Sets the global(!) value!
+ let g:options = [['wrapscan', '1', '1', '', '0', 'local', 'setlocal']]
+ setlocal nowrapscan
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 28c: Setting again boolean global option"
+ noa setglobal nowrapscan " Reset global and local value (without triggering autocmd)
+ noa setlocal wrapscan " Sets the global(!) value!
+ let g:options = [['wrapscan', '1', '1', '1', '0', 'global', 'set']]
+ set nowrapscan
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 28d: Setting again global boolean global option"
+ noa set nowrapscan " Reset global and local value (without triggering autocmd)
+ let g:options = [['wrapscan', '0', '0', '0', '1', 'global', 'set']]
+ set wrapscan
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 29a: Setting global boolean global-local (to buffer) option"
+ noa setglobal noautoread " Reset global and local value (without triggering autocmd)
+ noa setlocal autoread
+ let g:options = [['autoread', '0', '', '0', '1', 'global', 'setglobal']]
+ setglobal autoread
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 29b: Setting local boolean global-local (to buffer) option"
+ noa setglobal noautoread " Reset global and local value (without triggering autocmd)
+ noa setlocal autoread
+ let g:options = [['autoread', '1', '1', '', '0', 'local', 'setlocal']]
+ setlocal noautoread
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 29c: Setting again boolean global-local (to buffer) option"
+ noa setglobal noautoread " Reset global and local value (without triggering autocmd)
+ noa setlocal autoread
+ let g:options = [['autoread', '1', '1', '0', '1', 'global', 'set']]
+ set autoread
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 29d: Setting again global boolean global-local (to buffer) option"
+ noa set noautoread " Reset global and local value (without triggering autocmd)
+ let g:options = [['autoread', '0', '0', '0', '1', 'global', 'set']]
+ set autoread
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 30a: Setting global boolean local (to buffer) option"
+ noa setglobal nocindent " Reset global and local value (without triggering autocmd)
+ noa setlocal cindent
+ let g:options = [['cindent', '0', '', '0', '1', 'global', 'setglobal']]
+ setglobal cindent
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 30b: Setting local boolean local (to buffer) option"
+ noa setglobal nocindent " Reset global and local value (without triggering autocmd)
+ noa setlocal cindent
+ let g:options = [['cindent', '1', '1', '', '0', 'local', 'setlocal']]
+ setlocal nocindent
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 30c: Setting again boolean local (to buffer) option"
+ noa setglobal nocindent " Reset global and local value (without triggering autocmd)
+ noa setlocal cindent
+ let g:options = [['cindent', '1', '1', '0', '1', 'global', 'set']]
+ set cindent
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 30d: Setting again global boolean local (to buffer) option"
+ noa set nocindent " Reset global and local value (without triggering autocmd)
+ let g:options = [['cindent', '0', '0', '0', '1', 'global', 'set']]
+ set cindent
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 31: Setting boolean global-local (to window) option
+ " Currently no such option exists.
+
+
+ " 32a: Setting global boolean local (to window) option"
+ noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
+ noa setlocal cursorcolumn
+ let g:options = [['cursorcolumn', '0', '', '0', '1', 'global', 'setglobal']]
+ setglobal cursorcolumn
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 32b: Setting local boolean local (to window) option"
+ noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
+ noa setlocal cursorcolumn
+ let g:options = [['cursorcolumn', '1', '1', '', '0', 'local', 'setlocal']]
+ setlocal nocursorcolumn
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 32c: Setting again boolean local (to window) option"
+ noa setglobal nocursorcolumn " Reset global and local value (without triggering autocmd)
+ noa setlocal cursorcolumn
+ let g:options = [['cursorcolumn', '1', '1', '0', '1', 'global', 'set']]
+ set cursorcolumn
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+ " 32d: Setting again global boolean local (to window) option"
+ noa set nocursorcolumn " Reset global and local value (without triggering autocmd)
+ let g:options = [['cursorcolumn', '0', '0', '0', '1', 'global', 'set']]
+ set cursorcolumn
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
+ " 33: Test autocommands when an option value is converted internally.
+ noa set backspace=1 " Reset global and local value (without triggering autocmd)
+ let g:options = [['backspace', 'indent,eol', 'indent,eol', 'indent,eol', '2', 'global', 'set']]
+ set backspace=2
+ call assert_equal([], g:options)
+ call assert_equal(g:opt[0], g:opt[1])
+
+
" Cleanup
au! OptionSet
" set tags&
- for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'tags']
+ for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'backupext', 'tags', 'spelllang', 'statusline', 'foldignore', 'cmdheight', 'undolevels', 'wrapmargin', 'foldcolumn', 'wrapscan', 'autoread', 'cindent', 'cursorcolumn']
exe printf(":set %s&vim", opt)
endfor
call test_override('starting', 0)
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index 277050876e..8d592f21ea 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -432,7 +432,7 @@ func Test_breakindent11_vartabs()
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:]) + 2->indent() + strlen(&sbr) * 3 " text wraps 3 times
- call assert_equal(width, strdisplaywidth(text))
+ call assert_equal(width, text->strdisplaywidth())
call s:close_windows('set sbr= vts&')
endfunc
diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim
index c04c8fbf60..a6eb93b4be 100644
--- a/src/nvim/testdir/test_bufwintabinfo.vim
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -20,6 +20,9 @@ function Test_getbufwintabinfo()
call assert_equal('vim', l[0].variables.editor)
call assert_notequal(-1, index(l[0].windows, '%'->bufwinid()))
+ let l = '%'->getbufinfo()
+ call assert_equal(bufnr('%'), l[0].bufnr)
+
" Test for getbufinfo() with 'bufmodified'
call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
call setbufline('Xtestfile1', 1, ["Line1"])
@@ -48,7 +51,7 @@ function Test_getbufwintabinfo()
tabnew | let w3_id = win_getid()
new | let w4_id = win_getid()
vert new | let w5_id = win_getid()
- call setwinvar(0, 'signal', 'green')
+ eval 'green'->setwinvar(0, 'signal')
tabfirst
let winlist = getwininfo()
call assert_equal(5, len(winlist))
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index 57db0a2544..76a2620be0 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -101,7 +101,7 @@ func Test_chdir_func()
call assert_match('^\[global\] .*/Xdir$', trim(execute('verbose pwd')))
call chdir('..')
call assert_equal('y', fnamemodify(getcwd(1, 2), ':t'))
- call assert_equal('z', fnamemodify(getcwd(3, 2), ':t'))
+ call assert_equal('z', fnamemodify(3->getcwd(2), ':t'))
tabnext | wincmd t
call assert_match('^\[tabpage\] .*/y$', trim(execute('verbose pwd')))
call chdir('..')
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
index 17a49e02be..6f09e85a42 100644
--- a/src/nvim/testdir/test_charsearch.vim
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -20,7 +20,7 @@ func Test_charsearch()
" check that setcharsearch() changes the settings.
3
normal! ylfep
- call setcharsearch({'char': 'k'})
+ eval {'char': 'k'}->setcharsearch()
normal! ;p
call setcharsearch({'forward': 0})
normal! $;p
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index f3db472b03..922803438f 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -82,7 +82,7 @@ func Test_client_server()
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
call assert_equal('got it', g:myserverid->remote_read(2))
- call remote_send(name, ":call server2client(expand('<client>'), 'another')\<CR>", 'g:myserverid')
+ call remote_send(name, ":eval expand('<client>')->server2client('another')\<CR>", 'g:myserverid')
let peek_result = 'nothing'
let r = g:myserverid->remote_peek('peek_result')
" unpredictable whether the result is already available.
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 75e17b47b8..49a5386337 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -905,7 +905,7 @@ func Test_setcmdpos()
call assert_equal('"12ab', @:)
" setcmdpos() returns 1 when not editing the command line.
- call assert_equal(1, setcmdpos(3))
+ call assert_equal(1, 3->setcmdpos())
endfunc
func Test_cmdline_overstrike()
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index c3de7d0050..aaa2301bca 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -38,10 +38,9 @@ func Test_compiler()
endfunc
func GetCompilerNames()
- " return glob('$VIMRUNTIME/compiler/*.vim', 0, 1)
- " \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')})
- " \ ->sort()
- return sort(map(glob('$VIMRUNTIME/compiler/*.vim', 0, 1), {i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')}))
+ return glob('$VIMRUNTIME/compiler/*.vim', 0, 1)
+ \ ->map({i, v -> substitute(v, '.*[\\/]\([a-zA-Z0-9_\-]*\).vim', '\1', '')})
+ \ ->sort()
endfunc
func Test_compiler_without_arg()
@@ -54,8 +53,7 @@ func Test_compiler_without_arg()
endfunc
func Test_compiler_completion()
- " let clist = GetCompilerNames()->join(' ')
- let clist = join(GetCompilerNames(), ' ')
+ let clist = GetCompilerNames()->join(' ')
call feedkeys(":compiler \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('^"compiler ' .. clist .. '$', @:)
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 46847e0663..e8c4a952ee 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -37,7 +37,7 @@ endfunc
" Very short version of what matchparen does.
function s:Highlight_Matching_Pair()
let save_cursor = getcurpos()
- call setpos('.', save_cursor)
+ eval save_cursor->setpos('.')
endfunc
func Test_curswant_with_autocommand()
@@ -82,11 +82,11 @@ func Test_screenpos()
call assert_equal({'row': winrow,
\ 'col': wincol + 0,
\ 'curscol': wincol + 7,
- \ 'endcol': wincol + 7}, screenpos(winid, 1, 1))
+ \ 'endcol': wincol + 7}, winid->screenpos(1, 1))
call assert_equal({'row': winrow,
\ 'col': wincol + 13,
\ 'curscol': wincol + 13,
- \ 'endcol': wincol + 13}, screenpos(winid, 1, 7))
+ \ 'endcol': wincol + 13}, winid->screenpos(1, 7))
call assert_equal({'row': winrow + 2,
\ 'col': wincol + 1,
\ 'curscol': wincol + 1,
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 61da3cbcaa..3a0c615cf6 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -387,7 +387,7 @@ func Test_diffoff()
call setline(1, ['One', '', 'Two', 'Three'])
diffthis
redraw
- call assert_notequal(normattr, screenattr(1, 1))
+ call assert_notequal(normattr, 1->screenattr(1))
diffoff!
redraw
call assert_equal(normattr, screenattr(1, 1))
diff --git a/src/nvim/testdir/test_environ.vim b/src/nvim/testdir/test_environ.vim
index cc15b63824..dd34983ee5 100644
--- a/src/nvim/testdir/test_environ.vim
+++ b/src/nvim/testdir/test_environ.vim
@@ -22,7 +22,7 @@ endfunc
func Test_setenv()
unlet! $TESTENV
- call setenv('TEST ENV', 'foo')
+ eval 'foo'->setenv('TEST ENV')
call assert_equal('foo', getenv('TEST ENV'))
call setenv('TEST ENV', v:null)
call assert_equal(v:null, getenv('TEST ENV'))
diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim
index f2c7da0aa9..2cb6d73407 100644
--- a/src/nvim/testdir/test_execute_func.vim
+++ b/src/nvim/testdir/test_execute_func.vim
@@ -99,7 +99,7 @@ func Test_win_execute()
if has('textprop')
let popupwin = popup_create('the popup win', {'line': 2, 'col': 3})
redraw
- let line = win_execute(popupwin, 'echo getline(1)')
+ let line = 'echo getline(1)'->win_execute(popupwin)
call assert_match('the popup win', line)
call popup_close(popupwin)
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 6343c47fde..1d7fd3e385 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -56,7 +56,7 @@ endfunc
func Test_strgetchar()
call assert_equal(char2nr('a'), strgetchar('axb', 0))
- call assert_equal(char2nr('x'), strgetchar('axb', 1))
+ call assert_equal(char2nr('x'), 'axb'->strgetchar(1))
call assert_equal(char2nr('b'), strgetchar('axb', 2))
call assert_equal(-1, strgetchar('axb', -1))
@@ -66,7 +66,7 @@ endfunc
func Test_strcharpart()
call assert_equal('a', strcharpart('axb', 0, 1))
- call assert_equal('x', strcharpart('axb', 1, 1))
+ call assert_equal('x', 'axb'->strcharpart(1, 1))
call assert_equal('b', strcharpart('axb', 2, 1))
call assert_equal('xb', strcharpart('axb', 1))
@@ -493,7 +493,7 @@ func Test_setmatches()
let set[0]['conceal'] = 5
let exp[0]['conceal'] = '5'
endif
- call setmatches(set)
+ eval set->setmatches()
call assert_equal(exp, getmatches())
endfunc
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 69edbc227d..31052ce47d 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -502,7 +502,7 @@ let s:filename_checks = {
\ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'],
\ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'],
\ 'texmf': ['texmf.cnf'],
- \ 'text': ['file.text', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'],
+ \ 'text': ['file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'],
\ 'tf': ['file.tf', '.tfrc', 'tfrc'],
\ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'],
\ 'tilde': ['file.t.html'],
@@ -568,6 +568,7 @@ let s:filename_checks = {
\ 'yaml': ['file.yaml', 'file.yml'],
\ 'raml': ['file.raml'],
\ 'z8a': ['file.z8a'],
+ \ 'zig': ['file.zig'],
\ 'zimbu': ['file.zu'],
\ 'zimbutempl': ['file.zut'],
\ 'zsh': ['.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh', '.zcompdump', '.zlogin', '.zlogout', '.zshenv', '.zshrc', '.zcompdump-file', '.zlog', '.zlog-file', '.zsh', '.zsh-file', 'any/etc/zprofile', 'zlog', 'zlog-file', 'zsh', 'zsh-file'],
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 5586fe2151..6da1b3d4a0 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -809,8 +809,7 @@ func Test_undo_fold_deletion()
g/"/d
undo
redo
- " eval getline(1, '$')->assert_equal([''])
- eval assert_equal(getline(1, '$'), [''])
+ eval getline(1, '$')->assert_equal([''])
set fdm&vim
bwipe!
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 4a2ade5afa..0edbeb420a 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -143,7 +143,7 @@ func Test_str2nr()
call assert_equal(-123456789, str2nr('-123456789'))
call assert_equal(5, str2nr('101', 2))
- call assert_equal(5, str2nr('0b101', 2))
+ call assert_equal(5, '0b101'->str2nr(2))
call assert_equal(5, str2nr('0B101', 2))
call assert_equal(-5, str2nr('-101', 2))
call assert_equal(-5, str2nr('-0b101', 2))
@@ -200,7 +200,7 @@ func Test_strftime()
" of strftime() can be 17 or 18, depending on timezone.
call assert_match('^2017-01-1[78]$', strftime('%Y-%m-%d', 1484695512))
"
- call assert_match('^\d\d\d\d-\(0\d\|1[012]\)-\([012]\d\|3[01]\) \([01]\d\|2[0-3]\):[0-5]\d:\([0-5]\d\|60\)$', strftime('%Y-%m-%d %H:%M:%S'))
+ call assert_match('^\d\d\d\d-\(0\d\|1[012]\)-\([012]\d\|3[01]\) \([01]\d\|2[0-3]\):[0-5]\d:\([0-5]\d\|60\)$', '%Y-%m-%d %H:%M:%S'->strftime())
call assert_fails('call strftime([])', 'E730:')
call assert_fails('call strftime("%Y", [])', 'E745:')
@@ -307,13 +307,19 @@ func Test_resolve_unix()
call assert_equal('/', resolve('/'))
endfunc
+func s:normalize_fname(fname)
+ let ret = substitute(a:fname, '\', '/', 'g')
+ let ret = substitute(ret, '//', '/', 'g')
+ return ret->tolower()
+endfunc
+
func Test_simplify()
call assert_equal('', simplify(''))
call assert_equal('/', simplify('/'))
call assert_equal('/', simplify('/.'))
call assert_equal('/', simplify('/..'))
call assert_equal('/...', simplify('/...'))
- call assert_equal('./dir/file', simplify('./dir/file'))
+ call assert_equal('./dir/file', './dir/file'->simplify())
call assert_equal('./dir/file', simplify('.///dir//file'))
call assert_equal('./dir/file', simplify('./dir/./file'))
call assert_equal('./file', simplify('./dir/../file'))
@@ -346,7 +352,7 @@ func Test_setbufvar_options()
wincmd h
let wh = winheight(0)
let dummy_buf = bufnr('dummy_buf2', v:true)
- call setbufvar(dummy_buf, '&buftype', 'nofile')
+ eval 'nofile'->setbufvar(dummy_buf, '&buftype')
execute 'belowright vertical split #' . dummy_buf
call assert_equal(wh, winheight(0))
@@ -375,7 +381,7 @@ endfunc
func Test_strpart()
call assert_equal('de', strpart('abcdefg', 3, 2))
call assert_equal('ab', strpart('abcdefg', -2, 4))
- call assert_equal('abcdefg', strpart('abcdefg', -2))
+ call assert_equal('abcdefg', 'abcdefg'->strpart(-2))
call assert_equal('fg', strpart('abcdefg', 5, 4))
call assert_equal('defg', strpart('abcdefg', 3))
@@ -469,7 +475,7 @@ func Test_toupper()
\ toupper(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'))
" Test with a few lowercase diacritics.
- call assert_equal("AÀÁÂÃÄÅĀĂĄǍǞǠẢ", toupper("aàáâãäåāăąǎǟǡả"))
+ call assert_equal("AÀÁÂÃÄÅĀĂĄǍǞǠẢ", "aàáâãäåāăąǎǟǡả"->toupper())
call assert_equal("BḂḆ", toupper("bḃḇ"))
call assert_equal("CÇĆĈĊČ", toupper("cçćĉċč"))
call assert_equal("DĎĐḊḎḐ", toupper("dďđḋḏḑ"))
@@ -532,6 +538,11 @@ func Test_toupper()
call toupper("123\xC0\x80\xC0")
endfunc
+func Test_tr()
+ call assert_equal('foo', tr('bar', 'bar', 'foo'))
+ call assert_equal('zxy', 'cab'->tr('abc', 'xyz'))
+endfunc
+
" Tests for the mode() function
let current_modes = ''
func Save_mode()
@@ -809,11 +820,11 @@ endfunc
func Test_stridx()
call assert_equal(-1, stridx('', 'l'))
call assert_equal(0, stridx('', ''))
- call assert_equal(0, stridx('hello', ''))
+ call assert_equal(0, 'hello'->stridx(''))
call assert_equal(-1, stridx('hello', 'L'))
call assert_equal(2, stridx('hello', 'l', -1))
call assert_equal(2, stridx('hello', 'l', 0))
- call assert_equal(2, stridx('hello', 'l', 1))
+ call assert_equal(2, 'hello'->stridx('l', 1))
call assert_equal(3, stridx('hello', 'l', 3))
call assert_equal(-1, stridx('hello', 'l', 4))
call assert_equal(-1, stridx('hello', 'l', 10))
@@ -826,7 +837,7 @@ func Test_strridx()
call assert_equal(0, strridx('', ''))
call assert_equal(5, strridx('hello', ''))
call assert_equal(-1, strridx('hello', 'L'))
- call assert_equal(3, strridx('hello', 'l'))
+ call assert_equal(3, 'hello'->strridx('l'))
call assert_equal(3, strridx('hello', 'l', 10))
call assert_equal(3, strridx('hello', 'l', 3))
call assert_equal(2, strridx('hello', 'l', 2))
@@ -1219,7 +1230,7 @@ func Test_shellescape()
let save_shell = &shell
set shell=bash
call assert_equal("'text'", shellescape('text'))
- call assert_equal("'te\"xt'", shellescape('te"xt'))
+ call assert_equal("'te\"xt'", 'te"xt'->shellescape())
call assert_equal("'te'\\''xt'", shellescape("te'xt"))
call assert_equal("'te%xt'", shellescape("te%xt"))
@@ -1293,7 +1304,7 @@ endfunc
func Test_trim()
call assert_equal("Testing", trim(" \t\r\r\x0BTesting \t\n\r\n\t\x0B\x0B"))
- call assert_equal("Testing", trim(" \t \r\r\n\n\x0BTesting \t\n\r\n\t\x0B\x0B"))
+ call assert_equal("Testing", " \t \r\r\n\n\x0BTesting \t\n\r\n\t\x0B\x0B"->trim())
call assert_equal("RESERVE", trim("xyz \twwRESERVEzyww \t\t", " wxyz\t"))
call assert_equal("wRE \tSERVEzyww", trim("wRE \tSERVEzyww"))
call assert_equal("abcd\t xxxx tail", trim(" \tabcd\t xxxx tail"))
@@ -1330,7 +1341,7 @@ func Test_func_range_with_edit()
" is invalid in that buffer.
call writefile(['just one line'], 'Xfuncrange2')
new
- call setline(1, 10->range())
+ eval 10->range()->setline(1)
write Xfuncrange1
call assert_fails('5,8call EditAnotherFile()', 'E16:')
@@ -1560,7 +1571,7 @@ func Test_bufadd_bufload()
call assert_equal([''], getbufline(buf, 1, '$'))
let curbuf = bufnr('')
- call writefile(['some', 'text'], 'XotherName')
+ eval ['some', 'text']->writefile('XotherName')
let buf = 'XotherName'->bufadd()
call assert_notequal(0, buf)
eval 'XotherName'->bufexists()->assert_equal(1)
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index 9906b00222..f4ee539803 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -25,7 +25,7 @@ func Test_listchars()
redraw!
for i in range(1, 5)
call cursor(i, 1)
- call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ call assert_equal([expected[i - 1]], ScreenLines(i, '$'->virtcol()))
endfor
set listchars-=trail:<
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index 2fd82a4b6d..b3035d73ce 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -227,7 +227,7 @@ func Test_getmarklist()
call cursor(2, 2)
normal mr
call assert_equal({'mark' : "'r", 'pos' : [bufnr(), 2, 2, 0]},
- \ getmarklist(bufnr())[0])
- call assert_equal([], getmarklist({}))
+ \ bufnr()->getmarklist()[0])
+ call assert_equal([], {}->getmarklist())
close!
endfunc
diff --git a/src/nvim/testdir/test_matchadd_conceal_utf8.vim b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
index 34c8c49dd5..7bfac13ad8 100644
--- a/src/nvim/testdir/test_matchadd_conceal_utf8.vim
+++ b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
@@ -6,7 +6,7 @@ endif
function! s:screenline(lnum) abort
let line = []
for c in range(1, winwidth(0))
- call add(line, nr2char(screenchar(a:lnum, c)))
+ call add(line, nr2char(a:lnum->screenchar(c)))
endfor
return s:trim(join(line, ''))
endfunction
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 08586dffe1..2140fe21ea 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -87,7 +87,7 @@ func Test_echoerr()
if has('float')
call assert_equal("\n1.23 IgNoRe", execute(':echoerr 1.23 "IgNoRe"'))
endif
- call test_ignore_error('<lambda>')
+ eval '<lambda>'->test_ignore_error()
call assert_match("function('<lambda>\\d*')", execute(':echoerr {-> 1234}'))
call test_ignore_error('RESET')
endfunc
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index c96c6a9678..057895047d 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -156,8 +156,7 @@ func Test_mksession_zero_winheight()
wincmd _
mksession! Xtest_mks_zero
set winminheight&
- " let text = readfile('Xtest_mks_zero')->join()
- let text = join(readfile('Xtest_mks_zero'))
+ let text = readfile('Xtest_mks_zero')->join()
call delete('Xtest_mks_zero')
close
" check there is no divide by zero
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 41c689849b..7d9cada074 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -235,8 +235,7 @@ func Test_set_completion()
call feedkeys(":set filetype=sshdconfi\<Tab>\<C-B>\"\<CR>", 'xt')
call assert_equal('"set filetype=sshdconfig', @:)
call feedkeys(":set filetype=a\<C-A>\<C-B>\"\<CR>", 'xt')
- " call assert_equal('"set filetype=' .. getcompletion('a*', 'filetype')->join(), @:)
- call assert_equal('"set filetype=' .. join(getcompletion('a*', 'filetype')), @:)
+ call assert_equal('"set filetype=' .. getcompletion('a*', 'filetype')->join(), @:)
endfunc
func Test_set_errors()
diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim
index 3da46eb1a6..8f94a8572b 100644
--- a/src/nvim/testdir/test_prompt_buffer.vim
+++ b/src/nvim/testdir/test_prompt_buffer.vim
@@ -41,6 +41,10 @@ func WriteScript(name)
\ ' set nomodified',
\ 'endfunc',
\ '',
+ \ 'func SwitchWindows()',
+ \ ' call timer_start(0, {-> execute("wincmd p|wincmd p", "")})',
+ \ 'endfunc',
+ \ '',
\ 'call setline(1, "other buffer")',
\ 'set nomodified',
\ 'new',
@@ -89,9 +93,12 @@ func Test_prompt_editing()
call term_sendkeys(buf, left . left . left . bs . '-')
call WaitForAssert({-> assert_equal('cmd: -hel', term_getline(buf, 1))})
+ call term_sendkeys(buf, "\<C-O>lz")
+ call WaitForAssert({-> assert_equal('cmd: -hzel', term_getline(buf, 1))})
+
let end = "\<End>"
call term_sendkeys(buf, end . "x")
- call WaitForAssert({-> assert_equal('cmd: -helx', term_getline(buf, 1))})
+ call WaitForAssert({-> assert_equal('cmd: -hzelx', term_getline(buf, 1))})
call term_sendkeys(buf, "\<C-U>exit\<CR>")
call WaitForAssert({-> assert_equal('other buffer', term_getline(buf, 1))})
@@ -100,6 +107,28 @@ func Test_prompt_editing()
call delete(scriptName)
endfunc
+func Test_prompt_switch_windows()
+ throw 'skipped: TODO'
+ call CanTestPromptBuffer()
+ let scriptName = 'XpromptSwitchWindows'
+ call WriteScript(scriptName)
+
+ let buf = RunVimInTerminal('-S ' . scriptName, {'rows': 12})
+ call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
+ call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))})
+
+ call term_sendkeys(buf, "\<C-O>:call SwitchWindows()\<CR>")
+ call term_wait(buf, 50)
+ call WaitForAssert({-> assert_match('-- INSERT --', term_getline(buf, 12))})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call term_wait(buf, 50)
+ call WaitForAssert({-> assert_match('^ *$', term_getline(buf, 12))})
+
+ call StopVimInTerminal(buf)
+ call delete(scriptName)
+endfunc
+
func Test_prompt_garbage_collect()
func MyPromptCallback(x, text)
" NOP
@@ -126,6 +155,14 @@ func Test_prompt_garbage_collect()
bwipe!
endfunc
+func Test_prompt_backspace()
+ new
+ set buftype=prompt
+ call feedkeys("A123456\<Left>\<BS>\<Esc>", 'xt')
+ call assert_equal('% 12346', getline(1))
+ bwipe!
+endfunc
+
" Test for editing the prompt buffer
func Test_prompt_buffer_edit()
new
@@ -145,10 +182,9 @@ func Test_prompt_buffer_edit()
call assert_beeps("normal! \<C-X>")
" pressing CTRL-W in the prompt buffer should trigger the window commands
call assert_equal(1, winnr())
- " In Nvim, CTRL-W commands aren't usable from insert mode in a prompt buffer
- " exe "normal A\<C-W>\<C-W>"
- " call assert_equal(2, winnr())
- " wincmd w
+ exe "normal A\<C-W>\<C-W>"
+ call assert_equal(2, winnr())
+ wincmd w
close!
call assert_equal(0, prompt_setprompt([], ''))
endfunc
@@ -165,9 +201,7 @@ func Test_prompt_buffer_getbufinfo()
call assert_equal('This is a test: ', prompt_getprompt('%'))
call prompt_setprompt( bufnr( '%' ), '' )
- " Nvim doesn't support method call syntax yet.
- " call assert_equal('', '%'->prompt_getprompt())
- call assert_equal('', prompt_getprompt('%'))
+ call assert_equal('', '%'->prompt_getprompt())
call prompt_setprompt( bufnr( '%' ), 'Another: ' )
call assert_equal('Another: ', prompt_getprompt('%'))
@@ -189,4 +223,38 @@ func Test_prompt_buffer_getbufinfo()
%bwipe!
endfunc
+function! Test_prompt_while_writing_to_hidden_buffer()
+ throw 'skipped: TODO'
+ call CanTestPromptBuffer()
+ CheckUnix
+
+ " Make a job continuously write to a hidden buffer, check that the prompt
+ " buffer is not affected.
+ let scriptName = 'XpromptscriptHiddenBuf'
+ let script =<< trim END
+ set buftype=prompt
+ call prompt_setprompt( bufnr(), 'cmd:' )
+ let job = job_start(['/bin/sh', '-c',
+ \ 'while true;
+ \ do echo line;
+ \ sleep 0.1;
+ \ done'], #{out_io: 'buffer', out_name: ''})
+ startinsert
+ END
+ eval script->writefile(scriptName)
+
+ let buf = RunVimInTerminal('-S ' .. scriptName, {})
+ call WaitForAssert({-> assert_equal('cmd:', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, 'test')
+ call WaitForAssert({-> assert_equal('cmd:test', term_getline(buf, 1))})
+ call term_sendkeys(buf, 'test')
+ call WaitForAssert({-> assert_equal('cmd:testtest', term_getline(buf, 1))})
+ call term_sendkeys(buf, 'test')
+ call WaitForAssert({-> assert_equal('cmd:testtesttest', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+ call delete(scriptName)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index 8d8cc77025..f42b177c50 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -39,7 +39,7 @@ func Test_put_lines()
call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1, '$'))
" clean up
bw!
- call setreg('a', a[0], a[1])
+ eval a[0]->setreg('a', a[1])
endfunc
func Test_put_expr()
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index b38a59e98f..6db679c5f9 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -811,7 +811,7 @@ func Test_locationlist()
" NOTE: problem 1:
" intentionally not setting 'lnum' so that the quickfix entries are not
" valid
- call setloclist(0, qflist, ' ')
+ eval qflist->setloclist(0, ' ')
endfor
" Test A
@@ -1699,7 +1699,7 @@ endfunc
func Test_setqflist_invalid_nr()
" The following command used to crash Vim
- call setqflist([], ' ', {'nr' : $XXX_DOES_NOT_EXIST})
+ eval []->setqflist(' ', {'nr' : $XXX_DOES_NOT_EXIST})
endfunc
func Test_setqflist_user_sets_buftype()
diff --git a/src/nvim/testdir/test_ruby.vim b/src/nvim/testdir/test_ruby.vim
index 1a274d1fec..1fbf3392d9 100644
--- a/src/nvim/testdir/test_ruby.vim
+++ b/src/nvim/testdir/test_ruby.vim
@@ -60,7 +60,7 @@ func Test_ruby_set_cursor()
" Check that movement after setting cursor position keeps current column.
normal j
call assert_equal([2, 6], [line('.'), col('.')])
- call assert_equal([2, 5], rubyeval('$curwin.cursor'))
+ call assert_equal([2, 5], '$curwin.cursor'->rubyeval())
" call assert_fails('ruby $curwin.cursor = [1]',
" \ 'ArgumentError: array length must be 2')
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 7570049e7c..c796f1f676 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -1315,7 +1315,7 @@ func Test_search_match_at_curpos()
normal gg
- call search('foobar', 'c')
+ eval 'foobar'->search('c')
call assert_equal([1, 1], [line('.'), col('.')])
normal j
@@ -1354,6 +1354,41 @@ func Test_search_display_pattern()
endif
endfunc
+func Test_searchdecl()
+ let lines =<< trim END
+ int global;
+
+ func()
+ {
+ int global;
+ if (cond) {
+ int local;
+ }
+ int local;
+ // comment
+ }
+ END
+ new
+ call setline(1, lines)
+ 10
+ call assert_equal(0, searchdecl('local', 0, 0))
+ call assert_equal(7, getcurpos()[1])
+
+ 10
+ call assert_equal(0, 'local'->searchdecl(0, 1))
+ call assert_equal(9, getcurpos()[1])
+
+ 10
+ call assert_equal(0, searchdecl('global'))
+ call assert_equal(5, getcurpos()[1])
+
+ 10
+ call assert_equal(0, searchdecl('global', 1))
+ call assert_equal(1, getcurpos()[1])
+
+ bwipe!
+endfunc
+
func Test_search_special()
" this was causing illegal memory access and an endless loop
set t_PE=
diff --git a/src/nvim/testdir/test_sha256.vim b/src/nvim/testdir/test_sha256.vim
index dd4707977e..76d1306836 100644
--- a/src/nvim/testdir/test_sha256.vim
+++ b/src/nvim/testdir/test_sha256.vim
@@ -6,17 +6,17 @@ endif
function Test_sha256()
" test for empty string:
- call assert_equal(sha256(""), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
+ call assert_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', sha256(""))
"'test for 1 char:
- call assert_equal(sha256("a"), 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb')
+ call assert_equal('ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', sha256("a"))
"
"test for 3 chars:
- call assert_equal(sha256("abc"), 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad')
+ call assert_equal('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', "abc"->sha256())
" test for contains meta char:
- call assert_equal(sha256("foo\nbar"), '807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776')
+ call assert_equal('807eff6267f3f926a21d234f7b0cf867a86f47e07a532f15e8cc39ed110ca776', sha256("foo\nbar"))
" test for contains non-ascii char:
- call assert_equal(sha256("\xde\xad\xbe\xef"), '5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953')
+ call assert_equal('5f78c33274e43fa9de5659265c1d917e25c03722dcb0b8d27db8d5feaa813953', sha256("\xde\xad\xbe\xef"))
endfunction
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 9753100375..f287256396 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -393,7 +393,7 @@ func Test_sign_funcs()
" Tests for sign_define()
let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
- call assert_equal(0, sign_define("sign1", attr))
+ call assert_equal(0, "sign1"->sign_define(attr))
call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
\ 'linehl' : 'Search', 'text' : '=>'}], sign_getdefined())
@@ -404,13 +404,13 @@ func Test_sign_funcs()
call Sign_define_ignore_error("sign2", attr)
call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
\ 'linehl' : 'DiffAdd', 'text' : '!!', 'icon' : 'sign2.ico'}],
- \ sign_getdefined("sign2"))
+ \ "sign2"->sign_getdefined())
" Test for a sign name with digits
call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'}))
call assert_equal([{'name' : '2', 'linehl' : 'StatusLine'}],
\ sign_getdefined(0002))
- call sign_undefine(0002)
+ eval 0002->sign_undefine()
" Tests for invalid arguments to sign_define()
call assert_fails('call sign_define("sign4", {"text" : "===>"})', 'E239:')
@@ -434,7 +434,7 @@ func Test_sign_funcs()
call assert_equal([{'bufnr' : bufnr(''), 'signs' :
\ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
\ 'priority' : 10}]}],
- \ sign_getplaced('%', {'lnum' : 20}))
+ \ '%'->sign_getplaced({'lnum' : 20}))
call assert_equal([{'bufnr' : bufnr(''), 'signs' :
\ [{'id' : 10, 'group' : '', 'lnum' : 20, 'name' : 'sign1',
\ 'priority' : 10}]}],
@@ -490,10 +490,10 @@ func Test_sign_funcs()
\ 'E745:')
" Tests for sign_unplace()
- call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
+ eval 20->sign_place('', 'sign2', 'Xsign', {"lnum" : 30})
call assert_equal(0, sign_unplace('',
\ {'id' : 20, 'buffer' : 'Xsign'}))
- call assert_equal(-1, sign_unplace('',
+ call assert_equal(-1, ''->sign_unplace(
\ {'id' : 30, 'buffer' : 'Xsign'}))
call sign_place(20, '', 'sign2', 'Xsign', {"lnum" : 30})
call assert_fails("call sign_unplace('',
@@ -1693,7 +1693,7 @@ func Test_sign_jump_func()
let r = sign_jump(5, '', 'foo')
call assert_equal(2, r)
call assert_equal(2, line('.'))
- let r = sign_jump(6, 'g1', 'foo')
+ let r = 6->sign_jump('g1', 'foo')
call assert_equal(5, r)
call assert_equal(5, line('.'))
let r = sign_jump(5, '', 'bar')
@@ -1921,8 +1921,7 @@ func Test_sign_funcs_multi()
\ 'group' : 'g1', 'priority' : 10}], s[0].signs)
" Change an existing sign without specifying the group
- call assert_equal([5], sign_placelist([
- \ {'id' : 5, 'name' : 'sign1', 'buffer' : 'Xsign'}]))
+ call assert_equal([5], [{'id' : 5, 'name' : 'sign1', 'buffer' : 'Xsign'}]->sign_placelist())
let s = sign_getplaced('Xsign', {'id' : 5, 'group' : ''})
call assert_equal([{'id' : 5, 'name' : 'sign1', 'lnum' : 11,
\ 'group' : '', 'priority' : 10}], s[0].signs)
@@ -1955,7 +1954,7 @@ func Test_sign_funcs_multi()
\ {'id' : 1, 'group' : 'g1'}, {'id' : 1, 'group' : 'g2'}]))
" Invalid arguments
- call assert_equal([], sign_unplacelist([]))
+ call assert_equal([], []->sign_unplacelist())
call assert_fails('call sign_unplacelist({})', "E714:")
call assert_fails('call sign_unplacelist([[]])', "E715:")
call assert_fails('call sign_unplacelist(["abc"])', "E715:")
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index e525d06ea2..cf0faeee31 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -77,7 +77,7 @@ func Test_spellbadword()
set spell
call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
- call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence'))
+ call assert_equal(['another', 'caps'], 'A sentence. another sentence'->spellbadword())
call assert_equal(['TheCamelWord', 'bad'], spellbadword('TheCamelWord asdf'))
set spelloptions=camel
@@ -407,7 +407,7 @@ func Test_zz_basic()
\ )
call assert_equal("gebletegek", soundfold('goobledygoook'))
- call assert_equal("kepereneven", soundfold('kóopërÿnôven'))
+ call assert_equal("kepereneven", 'kóopërÿnôven'->soundfold())
call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
endfunc
@@ -711,7 +711,7 @@ func TestGoodBadBase()
break
endif
let prevbad = bad
- let lst = spellsuggest(bad, 3)
+ let lst = bad->spellsuggest(3)
normal mm
call add(result, [bad, lst])
diff --git a/src/nvim/testdir/test_spell_utf8.vim b/src/nvim/testdir/test_spell_utf8.vim
index cafdb97f28..3d159f3352 100644
--- a/src/nvim/testdir/test_spell_utf8.vim
+++ b/src/nvim/testdir/test_spell_utf8.vim
@@ -512,8 +512,7 @@ func TestGoodBadBase()
break
endif
let prevbad = bad
- " let lst = bad->spellsuggest(3)
- let lst = spellsuggest(bad, 3)
+ let lst = bad->spellsuggest(3)
normal mm
call add(result, [bad, lst])
@@ -552,8 +551,7 @@ func Test_spell_basic()
\ )
call assert_equal("gebletegek", soundfold('goobledygoook'))
- " call assert_equal("kepereneven", 'kóopërÿnôven'->soundfold())
- call assert_equal("kepereneven", soundfold('kóopërÿnôven'))
+ call assert_equal("kepereneven", 'kóopërÿnôven'->soundfold())
call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
endfunc
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index b140077111..d830f5216d 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -905,15 +905,13 @@ func Test_not_a_term()
" 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 assert_match("\<Esc>", readfile('Xvimout')->join())
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 assert_notmatch("\<Esc>", readfile('Xvimout')->join())
call delete('Xvimout')
endfunc
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index e7f9bb76f2..113c85acef 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -547,7 +547,7 @@ func Test_sub_replace_5()
\ substitute('A123456789',
\ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
\ '\=string([submatch(0, 1), submatch(9, 1), ' .
- \ 'submatch(8, 1), submatch(7, 1), submatch(6, 1), ' .
+ \ 'submatch(8, 1), 7->submatch(1), submatch(6, 1), ' .
\ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' .
\ 'submatch(2, 1), submatch(1, 1)])',
\ ''))
@@ -752,8 +752,7 @@ 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']]")
+ call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
endfunc
func Test_substitute_skipped_range()
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index e3101d4e44..b3018b2b0d 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -113,7 +113,7 @@ func Test_swapinfo()
w
let fname = s:swapname()
call assert_match('Xswapinfo', fname)
- let info = swapinfo(fname)
+ let info = fname->swapinfo()
let ver = printf('VIM %d.%d', v:version / 100, v:version % 100)
call assert_equal(ver, info.version)
@@ -155,7 +155,7 @@ func Test_swapname()
let buf = bufnr('%')
let expected = s:swapname()
wincmd p
- call assert_equal(expected, swapname(buf))
+ call assert_equal(expected, buf->swapname())
new Xtest3
setlocal noswapfile
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 914d9c2782..757866f5dc 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -30,23 +30,17 @@ func AssertHighlightGroups(lnum, startcol, expected, trans = 1, msg = "")
" If groups are provided as a string, each character is assumed to be a
" group and spaces represent no group, useful for visually describing tests.
let l:expectedGroups = type(a:expected) == v:t_string
- "\ ? a:expected->split('\zs')->map({_, v -> trim(v)})
- \ ? map(split(a:expected, '\zs'), {_, v -> trim(v)})
+ \ ? a:expected->split('\zs')->map({_, v -> trim(v)})
\ : a:expected
let l:errors = 0
- " let l:msg = (a:msg->empty() ? "" : a:msg .. ": ")
- let l:msg = (empty(a:msg) ? "" : a:msg .. ": ")
+ let l:msg = (a:msg->empty() ? "" : a:msg .. ": ")
\ .. "Wrong highlight group at " .. a:lnum .. ","
- " for l:i in range(a:startcol, a:startcol + l:expectedGroups->len() - 1)
- " let l:errors += synID(a:lnum, l:i, a:trans)
- " \ ->synIDattr("name")
- " \ ->assert_equal(l:expectedGroups[l:i - 1],
- for l:i in range(a:startcol, a:startcol + len(l:expectedGroups) - 1)
- let l:errors +=
- \ assert_equal(synIDattr(synID(a:lnum, l:i, a:trans), "name"),
- \ l:expectedGroups[l:i - 1],
- \ l:msg .. l:i)
+ for l:i in range(a:startcol, a:startcol + l:expectedGroups->len() - 1)
+ let l:errors += synID(a:lnum, l:i, a:trans)
+ \ ->synIDattr("name")
+ \ ->assert_equal(l:expectedGroups[l:i - 1],
+ \ l:msg .. l:i)
endfor
endfunc
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 7b8ee778cc..1858b48807 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -121,8 +121,7 @@ func Test_system_with_shell_quote()
let msg = printf('shell=%s shellxquote=%s', &shell, &shellxquote)
try
- " let out = 'echo 123'->system()
- let out = system('echo 123')
+ let out = 'echo 123'->system()
catch
call assert_report(printf('%s: %s', msg, v:exception))
continue
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index b261b96c3b..9869dc7590 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -35,7 +35,7 @@ function Test_tabpage()
tabnew
tabfirst
call settabvar(2, 'val_num', 100)
- call settabvar(2, 'val_str', 'SetTabVar test')
+ eval 'SetTabVar test'->settabvar(2, 'val_str')
call settabvar(2, 'val_list', ['red', 'blue', 'green'])
"
call assert_true(gettabvar(2, 'val_num') == 100 && gettabvar(2, 'val_str') == 'SetTabVar test' && gettabvar(2, 'val_list') == ['red', 'blue', 'green'])
@@ -184,7 +184,7 @@ function Test_tabpage_with_autocmd()
let s:li = split(join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')), '\s\+')
call assert_equal(['a', 'a'], s:li)
let s:li = []
- C call map(copy(winr), 'settabwinvar('.tabn.', v:val, ''a'', v:val*2)')
+ C call map(copy(winr), '(v:val*2)->settabwinvar(' .. tabn .. ', v:val, ''a'')')
let s:li = split(join(map(copy(winr), 'gettabwinvar('.tabn.', v:val, "a")')), '\s\+')
call assert_equal(['2', '4'], s:li)
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 15182893e9..2aa04df42a 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -351,7 +351,7 @@ func Test_getsettagstack()
" Try to set current index to invalid values
call settagstack(1, {'curidx' : -1})
call assert_equal(1, gettagstack().curidx)
- call settagstack(1, {'curidx' : 50})
+ eval {'curidx' : 50}->settagstack(1)
call assert_equal(4, gettagstack().curidx)
" Try pushing invalid items onto the stack
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index e830813081..e11815ff33 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -14,7 +14,7 @@ func Test_taglist()
split Xtext
call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo"), {i, v -> v.name}))
- call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xtext"), {i, v -> v.name}))
+ call assert_equal(['FFoo', 'BFoo'], map("Foo"->taglist("Xtext"), {i, v -> v.name}))
call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xfoo"), {i, v -> v.name}))
call assert_equal(['BFoo', 'FFoo'], map(taglist("Foo", "Xbar"), {i, v -> v.name}))
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index ceaa5de92b..5cc0da2586 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -77,7 +77,7 @@ endfunc
func Test_info()
let id = timer_start(1000, 'MyHandler')
- let info = timer_info(id)
+ let info = id->timer_info()
call assert_equal(id, info[0]['id'])
call assert_equal(1000, info[0]['time'])
call assert_equal("function('MyHandler')", string(info[0]['callback']))
@@ -113,7 +113,7 @@ func Test_paused()
let info = timer_info(id)
call assert_equal(0, info[0]['paused'])
- call timer_pause(id, 1)
+ eval id->timer_pause(1)
let info = timer_info(id)
call assert_equal(1, info[0]['paused'])
sleep 200m
@@ -148,7 +148,7 @@ func Test_delete_myself()
endfunc
func StopTimer1(timer)
- let g:timer2 = timer_start(10, 'StopTimer2')
+ let g:timer2 = 10->timer_start('StopTimer2')
" avoid maxfuncdepth error
call timer_pause(g:timer1, 1)
sleep 40m
@@ -239,7 +239,7 @@ func FeedAndPeek(timer)
endfunc
func Interrupt(timer)
- " call test_feedinput("\<C-C>")
+ " eval "\<C-C>"->test_feedinput()
call nvim_input("\<C-C>")
endfunc
@@ -251,7 +251,7 @@ func Test_peek_and_get_char()
let intr = timer_start(100, 'Interrupt')
let c = getchar()
call assert_equal(char2nr('a'), c)
- call timer_stop(intr)
+ eval intr->timer_stop()
endfunc
func Test_getchar_zero()
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index c7dcaa0f36..30e00e7ad4 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -490,7 +490,7 @@ funct Test_undofile()
call delete('Xundodir', 'd')
" Test undofile() with 'undodir' set to a non-existing directory.
- " call assert_equal('', undofile('Xundofoo'))
+ " call assert_equal('', 'Xundofoo'->undofile())
if isdirectory('/tmp')
set undodir=/tmp
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index da72da087f..0818c2e4b0 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -17,7 +17,7 @@ func Test_strchars()
let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
for i in range(len(inp))
call assert_equal(exp[i][0], strchars(inp[i]))
- call assert_equal(exp[i][1], strchars(inp[i], 0))
+ call assert_equal(exp[i][1], inp[i]->strchars(0))
call assert_equal(exp[i][2], strchars(inp[i], 1))
endfor
endfunc
@@ -69,7 +69,7 @@ func Test_screenchar_utf8()
call setline(1, ["ABC\u0308"])
redraw
call assert_equal([0x0041], screenchars(1, 1))
- call assert_equal([0x0042], screenchars(1, 2))
+ call assert_equal([0x0042], 1->screenchars(2))
call assert_equal([0x0043, 0x0308], screenchars(1, 3))
call assert_equal("A", screenstring(1, 1))
call assert_equal("B", screenstring(1, 2))
diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim
index 2fbf130345..46e0d62313 100644
--- a/src/nvim/testdir/test_vartabs.vim
+++ b/src/nvim/testdir/test_vartabs.vim
@@ -330,7 +330,7 @@ func Test_vartabs_shiftwidth()
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('.')))
+ call assert_equal(30, virtcol('.')->shiftwidth())
norm! $>>
let expect3 = [' ', ' x ', '~ ']
let lines = ScreenLines([1, 3], winwidth(0))
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 039de0c623..a200bf7d42 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -72,7 +72,7 @@ endfunc
func Test_window_quit()
e Xa
split Xb
- call assert_equal(2, winnr('$'))
+ call assert_equal(2, '$'->winnr())
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xa', bufname(winbufnr(2)))
@@ -88,7 +88,7 @@ func Test_window_horizontal_split()
3wincmd s
call assert_equal(2, winnr('$'))
call assert_equal(3, winheight(0))
- call assert_equal(winwidth(1), winwidth(2))
+ call assert_equal(winwidth(1), 2->winwidth())
call assert_fails('botright topleft wincmd s', 'E442:')
bw
@@ -267,7 +267,7 @@ func Test_window_height()
wincmd +
call assert_equal(wh1, winheight(1))
- call assert_equal(wh2, winheight(2))
+ call assert_equal(wh2, 2->winheight())
2wincmd _
call assert_equal(2, winheight(1))
@@ -452,7 +452,7 @@ func Test_window_newtab()
wincmd T
call assert_equal(2, tabpagenr('$'))
call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
- call assert_equal(['Xc' ], map(tabpagebuflist(2), 'bufname(v:val)'))
+ call assert_equal(['Xc' ], map(2->tabpagebuflist(), 'bufname(v:val)'))
%bw!
endfunc
@@ -577,8 +577,11 @@ endfunc
function! Fun_RenewFile()
" Need to wait a bit for the timestamp to be older.
- sleep 2
- silent execute '!echo "1" > tmp.txt'
+ let old_ftime = getftime("tmp.txt")
+ while getftime("tmp.txt") == old_ftime
+ sleep 100m
+ silent execute '!echo "1" > tmp.txt'
+ endwhile
sp
wincmd p
edit! tmp.txt
@@ -814,13 +817,25 @@ func Test_winnr()
tabnew
call assert_equal(8, tabpagewinnr(1, 'j'))
- call assert_equal(2, tabpagewinnr(1, 'k'))
+ call assert_equal(2, 1->tabpagewinnr('k'))
call assert_equal(4, tabpagewinnr(1, 'h'))
call assert_equal(6, tabpagewinnr(1, 'l'))
only | tabonly
endfunc
+func Test_winrestview()
+ split runtest.vim
+ normal 50%
+ let view = winsaveview()
+ close
+ split runtest.vim
+ eval view->winrestview()
+ call assert_equal(view, winsaveview())
+
+ bwipe!
+endfunc
+
func Test_win_splitmove()
edit a
leftabove split b
diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim
index d10d831650..8bf4ede350 100644
--- a/src/nvim/testdir/test_window_id.vim
+++ b/src/nvim/testdir/test_window_id.vim
@@ -67,7 +67,7 @@ func Test_win_getid()
call win_gotoid(id2)
call assert_equal("two", expand("%"))
- call win_gotoid(id4)
+ eval id4->win_gotoid()
call assert_equal("four", expand("%"))
call win_gotoid(id1)
call assert_equal("one", expand("%"))
@@ -75,17 +75,17 @@ func Test_win_getid()
call assert_equal("five", expand("%"))
call assert_equal(0, win_id2win(9999))
- call assert_equal(nr5, win_id2win(id5))
+ call assert_equal(nr5, id5->win_id2win())
call assert_equal(0, win_id2win(id1))
tabnext
call assert_equal(nr1, win_id2win(id1))
call assert_equal([0, 0], win_id2tabwin(9999))
- call assert_equal([1, nr2], win_id2tabwin(id2))
+ call assert_equal([1, nr2], id2->win_id2tabwin())
call assert_equal([2, nr4], win_id2tabwin(id4))
call assert_equal([], win_findbuf(9999))
- call assert_equal([id2], win_findbuf(bufnr2))
+ call assert_equal([id2], bufnr2->win_findbuf())
call win_gotoid(id5)
split
call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5)))
@@ -98,7 +98,7 @@ func Test_win_getid_curtab()
tabfirst
copen
only
- call assert_equal(win_getid(1), win_getid(1, 1))
+ call assert_equal(win_getid(1), 1->win_getid( 1))
tabclose!
endfunc
@@ -120,4 +120,11 @@ func Test_winlayout()
call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout())
only!
+
+ let w1 = win_getid()
+ call assert_equal(['leaf', w1], winlayout(1))
+ tabnew
+ let w2 = win_getid()
+ call assert_equal(['leaf', w2], 2->winlayout())
+ tabclose
endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 3e6e42dec2..be963d8374 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2229,6 +2229,54 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
}
}
+static void leaving_window(win_T *const win)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Only matters for a prompt window.
+ if (!bt_prompt(win->w_buffer)) {
+ return;
+ }
+
+ // When leaving a prompt window stop Insert mode and perhaps restart
+ // it when entering that window again.
+ win->w_buffer->b_prompt_insert = restart_edit;
+ if (restart_edit != NUL && mode_displayed) {
+ clear_cmdline = true; // unshow mode later
+ }
+ restart_edit = NUL;
+
+ // When leaving the window (or closing the window) was done from a
+ // callback we need to break out of the Insert mode loop and restart Insert
+ // mode when entering the window again.
+ if (State & INSERT) {
+ stop_insert_mode = true;
+ if (win->w_buffer->b_prompt_insert == NUL) {
+ win->w_buffer->b_prompt_insert = 'A';
+ }
+ }
+}
+
+void entering_window(win_T *const win)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Only matters for a prompt window.
+ if (!bt_prompt(win->w_buffer)) {
+ return;
+ }
+
+ // When switching to a prompt buffer that was in Insert mode, don't stop
+ // Insert mode, it may have been set in leaving_window().
+ if (win->w_buffer->b_prompt_insert != NUL) {
+ stop_insert_mode = false;
+ }
+
+ // When entering the prompt window restart Insert mode if we were in Insert
+ // mode when we left it and not already in Insert mode.
+ if ((State & INSERT) == 0) {
+ restart_edit = win->w_buffer->b_prompt_insert;
+ }
+}
+
/// Closes all windows for buffer `buf`.
///
/// @param keep_curwin don't close `curwin`
@@ -2367,6 +2415,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
shell_new_rows();
}
}
+ entering_window(curwin);
// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
// that now.
@@ -2434,10 +2483,10 @@ int win_close(win_T *win, bool free_buf)
}
if (win == curwin) {
- /*
- * Guess which window is going to be the new current window.
- * This may change because of the autocommands (sigh).
- */
+ leaving_window(curwin);
+
+ // Guess which window is going to be the new current window.
+ // This may change because of the autocommands (sigh).
if (!win->w_floating) {
wp = frame2win(win_altframe(win, NULL));
} else {
@@ -3801,6 +3850,8 @@ int win_new_tabpage(int after, char_u *filename)
lastused_tabpage = old_curtab;
+ entering_window(curwin);
+
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
@@ -3956,6 +4007,7 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds)
{
tabpage_T *tp = curtab;
+ leaving_window(curwin);
reset_VIsual_and_resel(); // stop Visual mode
if (trigger_leave_autocmds) {
if (new_curbuf != curbuf) {
@@ -4478,6 +4530,10 @@ static void win_enter_ext(win_T *const wp, const int flags)
return;
}
+ if (!curwin_invalid) {
+ leaving_window(curwin);
+ }
+
if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS)) {
// Be careful: If autocommands delete the window, return now.
if (wp->w_buffer != curbuf) {
@@ -4525,6 +4581,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
fix_current_dir();
+ entering_window(curwin);
// Careful: autocommands may close the window and make "wp" invalid
if (flags & WEE_TRIGGER_NEW_AUTOCMDS) {
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);