diff options
31 files changed, 487 insertions, 457 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 827d0318ab..be42b7c14e 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -348,7 +348,7 @@ callbacks. These callbacks are called frequently in various contexts; |nvim_buf_attach()| will take keyword args for the callbacks. "on_lines" will receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline}, -{new_lastline}, {old_byte_size}[, {old_utf32_size}, {old_utf16_size}]). +{new_lastline}, {old_byte_size} [, {old_utf32_size}, {old_utf16_size}]). Unlike remote channel events the text contents are not passed. The new text can be accessed inside the callback as diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 61d04c6660..f0f47cddf4 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -5311,7 +5311,7 @@ mode([expr]) Return a string that indicates the current mode. niV Normal using |i_CTRL-O| in |Virtual-Replace-mode| nt Normal in |terminal-emulator| (insert goes to Terminal mode) - ntT Normal using |t_CTRL-\_CTRL-O| in |terminal-mode| + ntT Normal using |t_CTRL-\_CTRL-O| in |Terminal-mode| v Visual by character vs Visual by character using |v_CTRL-O| in Select mode V Visual by line diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index c9505429c6..4062a35735 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -704,7 +704,7 @@ regex:match_str({str}) *regex:match_str()* As any integer is truth-y, `regex:match()` can be directly used as a condition in an if-statement. -regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()* +regex:match_line({bufnr}, {line_idx} [, {start}, {end}]) *regex:match_line()* Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and {end} are supplied, match only this byte index range. Otherwise see |regex:match_str()|. If {start} is used, then the returned byte @@ -855,13 +855,13 @@ vim.empty_dict() *vim.empty_dict()* Note: If numeric keys are present in the table, Nvim ignores the metatable marker and converts the dict to a list/array anyway. -vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()* +vim.rpcnotify({channel}, {method} [, {args}...]) *vim.rpcnotify()* Sends {event} to {channel} via |RPC| and returns immediately. If {channel} is 0, the event is broadcast to all channels. This function also works in a fast callback |lua-loop-callbacks|. -vim.rpcrequest({channel}, {method}[, {args}...]) *vim.rpcrequest()* +vim.rpcrequest({channel}, {method} [, {args}...]) *vim.rpcrequest()* Sends a request to {channel} to invoke {method} via |RPC| and blocks until a response is received. @@ -873,7 +873,7 @@ vim.stricmp({a}, {b}) *vim.stricmp()* are equal, {a} is greater than {b} or {a} is lesser than {b}, respectively. -vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()* +vim.str_utfindex({str} [, {index}]) *vim.str_utfindex()* Convert byte index to UTF-32 and UTF-16 indices. If {index} is not supplied, the length of the string is used. All indices are zero-based. Returns two values: the UTF-32 and UTF-16 indices respectively. @@ -883,7 +883,7 @@ vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()* point each. An {index} in the middle of a UTF-8 sequence is rounded upwards to the end of that sequence. -vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()* +vim.str_byteindex({str}, {index} [, {use_utf16}]) *vim.str_byteindex()* Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not supplied, it defaults to false (use UTF-32). Returns the byte index. @@ -1315,7 +1315,7 @@ cmd({command}) *vim.cmd()* vim.cmd('write! myfile.txt') vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true } vim.cmd.write { args = { "myfile.txt" }, bang = true } - vim.cmd.write {"myfile.txt", bang = true }) + vim.cmd.write { "myfile.txt", bang = true } -- Ex command :colorscheme blue vim.cmd('colorscheme blue') @@ -2229,7 +2229,8 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* • remap: (boolean) Make the mapping recursive. This is the inverse of the "noremap" option from |nvim_set_keymap()|. Default `false`. - • replace_keycodes: (boolean) defaults to true. + • replace_keycodes: (boolean) defaults to true if + "expr" is true. See also: ~ |nvim_set_keymap()| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index ffeed6f977..9d03397821 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4210,7 +4210,7 @@ A jump table for the options with a short description can be found at |Q_op|. The 'mousemodel' option is set by the |:behave| command. - *'mousescroll'* + *'mousescroll'* 'mousescroll' string (default "ver:3,hor:6") global This option controls the number of lines / columns to scroll by when diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 094fb2f909..b8a7f71145 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -312,7 +312,7 @@ end --- vim.cmd('write! myfile.txt') --- vim.cmd { cmd = 'write', args = { "myfile.txt" }, bang = true } --- vim.cmd.write { args = { "myfile.txt" }, bang = true } ---- vim.cmd.write {"myfile.txt", bang = true }) +--- vim.cmd.write { "myfile.txt", bang = true } --- --- -- Ex command :colorscheme blue --- vim.cmd('colorscheme blue') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 0549f63180..7265beb56b 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -43,7 +43,7 @@ local keymap = {} --- - remap: (boolean) Make the mapping recursive. This is the --- inverse of the "noremap" option from |nvim_set_keymap()|. --- Default `false`. ---- - replace_keycodes: (boolean) defaults to true. +--- - replace_keycodes: (boolean) defaults to true if "expr" is true. ---@see |nvim_set_keymap()| function keymap.set(mode, lhs, rhs, opts) vim.validate({ diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 33efa6b326..04242932c9 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -505,6 +505,11 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error OBJ_TO_BOOL(cmdinfo.magic.file, magic.file, ea.argt & EX_XFILE, "'magic.file'"); OBJ_TO_BOOL(cmdinfo.magic.bar, magic.bar, ea.argt & EX_TRLBAR, "'magic.bar'"); + if (cmdinfo.magic.file) { + ea.argt |= EX_XFILE; + } else { + ea.argt &= ~EX_XFILE; + } } else { cmdinfo.magic.file = ea.argt & EX_XFILE; cmdinfo.magic.bar = ea.argt & EX_TRLBAR; @@ -939,7 +944,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, cmd_addr_T addr_type_arg = ADDR_NONE; int compl = EXPAND_NOTHING; char *compl_arg = NULL; - char *rep = NULL; + const char *rep = NULL; LuaRef luaref = LUA_NOREF; LuaRef compl_luaref = LUA_NOREF; LuaRef preview_luaref = LUA_NOREF; @@ -1111,8 +1116,7 @@ void create_user_command(String name, Object command, Dict(user_command) *opts, if (opts->desc.type == kObjectTypeString) { rep = opts->desc.data.string.data; } else { - snprintf((char *)IObuff, IOSIZE, "<Lua function %d>", luaref); - rep = (char *)IObuff; + rep = ""; } break; case kObjectTypeString: diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index aa7bed1132..6239e414a7 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -27,7 +27,7 @@ typedef struct { uint64_t channel_id; #define UI_BUF_SIZE 4096 ///< total buffer size for pending msgpack data. - /// guranteed size available for each new event (so packing of simple events + /// guaranteed size available for each new event (so packing of simple events /// and the header of grid_line will never fail) #define EVENT_BUF_SIZE 256 char buf[UI_BUF_SIZE]; ///< buffer of packed but not yet sent msgpack data @@ -43,7 +43,7 @@ typedef struct { // We start packing the two outermost msgpack arrays before knowing the total // number of elements. Thus track the location where array size will need - // to be written in the msgpack buffer, once the specifc array is finished. + // to be written in the msgpack buffer, once the specific array is finished. char *nevents_pos; char *ncalls_pos; uint32_t nevents; ///< number of distinct events (top-level args to "redraw" diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 2b4c9c5b9c..bbb044fba3 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -196,9 +196,16 @@ static void aupat_show(AutoPat *ap, event_T event, int previous_group) if (ac->desc != NULL) { size_t msglen = 100; char *msg = (char *)xmallocz(msglen); - snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc); + if (ac->exec.type == CALLABLE_CB) { + msg_puts_attr(exec_to_string, HL_ATTR(HLF_8)); + snprintf(msg, msglen, " [%s]", ac->desc); + } else { + snprintf(msg, msglen, "%s [%s]", exec_to_string, ac->desc); + } msg_outtrans(msg); XFREE_CLEAR(msg); + } else if (ac->exec.type == CALLABLE_CB) { + msg_puts_attr(exec_to_string, HL_ATTR(HLF_8)); } else { msg_outtrans(exec_to_string); } diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c index 62cf60e03b..9c33b1a806 100644 --- a/src/nvim/cursor_shape.c +++ b/src/nvim/cursor_shape.c @@ -43,7 +43,7 @@ cursorentry_T shape_table[SHAPE_IDX_COUNT] = }; /// Converts cursor_shapes into an Array of Dictionaries -/// @param arena initialized arena where memory will be alocated +/// @param arena initialized arena where memory will be allocated /// /// @return Array of the form {[ "cursor_shape": ... ], ...} Array mode_style_array(Arena *arena) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index fd57b45e86..ff1808ed91 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1657,13 +1657,14 @@ void callback_copy(Callback *dest, Callback *src) /// Generate a string description of a callback char *callback_to_string(Callback *cb) { - size_t msglen = 100; + if (cb->type == kCallbackLua) { + return nlua_funcref_str(cb->data.luaref); + } + + const size_t msglen = 100; char *msg = (char *)xmallocz(msglen); switch (cb->type) { - case kCallbackLua: - snprintf(msg, msglen, "<lua: %d>", cb->data.luaref); - break; case kCallbackFuncref: // TODO(tjdevries): Is this enough space for this? snprintf(msg, msglen, "<vim function: %s>", cb->data.funcref); @@ -1672,7 +1673,7 @@ char *callback_to_string(Callback *cb) snprintf(msg, msglen, "<vim partial: %s>", cb->data.partial->pt_name); break; default: - snprintf(msg, msglen, "%s", ""); + *msg = '\0'; break; } return msg; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 5ff1a9dd47..23e7660606 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -5054,7 +5054,7 @@ int find_help_tags(const char *arg, int *num_matches, char ***matches, bool keep int i; // Specific tags that either have a specific replacement or won't go - // throught the generic rules. + // through the generic rules. static char *(except_tbl[][2]) = { { "*", "star" }, { "g*", "gstar" }, diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 052926fa1f..e80e47bcff 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -37,34 +37,34 @@ // 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and // long name of the command. -#define EX_RANGE 0x001 // allow a linespecs -#define EX_BANG 0x002 // allow a ! after the command name -#define EX_EXTRA 0x004 // allow extra args after command name -#define EX_XFILE 0x008 // expand wildcards in extra part -#define EX_NOSPC 0x010 // no spaces allowed in the extra part -#define EX_DFLALL 0x020 // default file range is 1,$ -#define EX_WHOLEFOLD 0x040 // extend range to include whole fold also - // when less than two numbers given -#define EX_NEEDARG 0x080 // argument required -#define EX_TRLBAR 0x100 // check for trailing vertical bar -#define EX_REGSTR 0x200 // allow "x for register designation -#define EX_COUNT 0x400 // allow count in argument, after command -#define EX_NOTRLCOM 0x800 // no trailing comment allowed -#define EX_ZEROR 0x1000 // zero line number allowed -#define EX_CTRLV 0x2000 // do not remove CTRL-V from argument -#define EX_CMDARG 0x4000 // allow "+command" argument -#define EX_BUFNAME 0x8000 // accepts buffer name -#define EX_BUFUNL 0x10000 // accepts unlisted buffer too -#define EX_ARGOPT 0x20000 // allow "++opt=val" argument -#define EX_SBOXOK 0x40000 // allowed in the sandbox -#define EX_CMDWIN 0x80000 // allowed in cmdline window -#define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer -#define EX_FLAGS 0x200000 // allow flags after count in argument -#define EX_LOCK_OK 0x1000000 // command can be executed when textlock is - // set; when missing disallows editing another - // buffer when current buffer is locked -#define EX_KEEPSCRIPT 0x4000000 // keep sctx of where command was invoked -#define EX_PREVIEW 0x8000000 // allow incremental command preview +#define EX_RANGE 0x001u // allow a linespecs +#define EX_BANG 0x002u // allow a ! after the command name +#define EX_EXTRA 0x004u // allow extra args after command name +#define EX_XFILE 0x008u // expand wildcards in extra part +#define EX_NOSPC 0x010u // no spaces allowed in the extra part +#define EX_DFLALL 0x020u // default file range is 1,$ +#define EX_WHOLEFOLD 0x040u // extend range to include whole fold also + // when less than two numbers given +#define EX_NEEDARG 0x080u // argument required +#define EX_TRLBAR 0x100u // check for trailing vertical bar +#define EX_REGSTR 0x200u // allow "x for register designation +#define EX_COUNT 0x400u // allow count in argument, after command +#define EX_NOTRLCOM 0x800u // no trailing comment allowed +#define EX_ZEROR 0x1000u // zero line number allowed +#define EX_CTRLV 0x2000u // do not remove CTRL-V from argument +#define EX_CMDARG 0x4000u // allow "+command" argument +#define EX_BUFNAME 0x8000u // accepts buffer name +#define EX_BUFUNL 0x10000u // accepts unlisted buffer too +#define EX_ARGOPT 0x20000u // allow "++opt=val" argument +#define EX_SBOXOK 0x40000u // allowed in the sandbox +#define EX_CMDWIN 0x80000u // allowed in cmdline window +#define EX_MODIFY 0x100000u // forbidden in non-'modifiable' buffer +#define EX_FLAGS 0x200000u // allow flags after count in argument +#define EX_LOCK_OK 0x1000000u // command can be executed when textlock is + // set; when missing disallows editing another + // buffer when current buffer is locked +#define EX_KEEPSCRIPT 0x4000000u // keep sctx of where command was invoked +#define EX_PREVIEW 0x8000000u // allow incremental command preview #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file #define EX_WORD1 (EX_EXTRA | EX_NOSPC) // one extra word allowed diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a7d91a47d7..e3d61ef7e2 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1563,69 +1563,12 @@ err: return false; } -/// Execute an Ex command using parsed command line information. -/// Does not do any validation of the Ex command arguments. -/// -/// @param eap Ex-command arguments -/// @param cmdinfo Command parse information -/// @param preview Execute command preview callback instead of actual command -int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) +static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview) { - char *errormsg = NULL; - int retv = 0; - -#define ERROR(msg) \ - do { \ - errormsg = msg; \ - goto end; \ - } while (0) - - cmdmod_T save_cmdmod = cmdmod; - cmdmod = cmdinfo->cmdmod; - - // Apply command modifiers - apply_cmdmod(&cmdmod); - - if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) - // allow :put in terminals - && !(curbuf->terminal && eap->cmdidx == CMD_put)) { - ERROR(_(e_modifiable)); - } - if (!IS_USER_CMDIDX(eap->cmdidx)) { - if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) { - // Command not allowed in the command line window - ERROR(_(e_cmdwin)); - } - if (text_locked() && !(eap->argt & EX_LOCK_OK)) { - // Command not allowed when text is locked - ERROR(_(get_text_locked_msg())); - } - } - // Disallow editing another buffer when "curbuf->b_ro_locked" is set. - // Do allow ":checktime" (it is postponed). - // Do allow ":edit" (check for an argument later). - // Do allow ":file" with no arguments - if (!(eap->argt & EX_CMDWIN) - && eap->cmdidx != CMD_checktime - && eap->cmdidx != CMD_edit - && !(eap->cmdidx == CMD_file && *eap->arg == NUL) - && !IS_USER_CMDIDX(eap->cmdidx) - && curbuf_locked()) { - ERROR(_(e_cannot_edit_other_buf)); - } - - if (((eap->argt & EX_WHOLEFOLD) || eap->addr_count >= 2) && !global_busy - && eap->addr_type == ADDR_LINES) { - // Put the first line at the start of a closed fold, put the last line - // at the end of a closed fold. - (void)hasFolding(eap->line1, &eap->line1, NULL); - (void)hasFolding(eap->line2, NULL, &eap->line2); - } - // If filename expansion is enabled, expand filenames - if (cmdinfo->magic.file) { - if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) { - goto end; + if (eap->argt & EX_XFILE) { + if (expand_filename(eap, eap->cmdlinep, errormsg) == FAIL) { + return FAIL; } } @@ -1670,29 +1613,104 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) eap->arg = eap->args[0]; } if (eap->line2 < 0) { // failed - goto end; + return FAIL; } } + // The :try command saves the emsg_silent flag, reset it here when + // ":silent! try" was used, it should only apply to :try itself. + if (eap->cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) { + emsg_silent -= cmdmod.cmod_did_esilent; + if (emsg_silent < 0) { + emsg_silent = 0; + } + cmdmod.cmod_did_esilent = 0; + } + // Execute the command if (IS_USER_CMDIDX(eap->cmdidx)) { // Execute a user-defined command. - retv = do_ucmd(eap, preview); + *retv = do_ucmd(eap, preview); } else { // Call the function to execute the command or the preview callback. eap->errmsg = NULL; if (preview) { - retv = (cmdnames[eap->cmdidx].cmd_preview_func)(eap, cmdpreview_get_ns(), - cmdpreview_get_bufnr()); + *retv = (cmdnames[eap->cmdidx].cmd_preview_func)(eap, cmdpreview_get_ns(), + cmdpreview_get_bufnr()); } else { (cmdnames[eap->cmdidx].cmd_func)(eap); } if (eap->errmsg != NULL) { - errormsg = _(eap->errmsg); + *errormsg = _(eap->errmsg); } } + return OK; +} + +/// Execute an Ex command using parsed command line information. +/// Does not do any validation of the Ex command arguments. +/// +/// @param eap Ex-command arguments +/// @param cmdinfo Command parse information +/// @param preview Execute command preview callback instead of actual command +int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) +{ + char *errormsg = NULL; + int retv = 0; + +#define ERROR(msg) \ + do { \ + errormsg = msg; \ + goto end; \ + } while (0) + + cmdmod_T save_cmdmod = cmdmod; + cmdmod = cmdinfo->cmdmod; + + // Apply command modifiers + apply_cmdmod(&cmdmod); + + if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) + // allow :put in terminals + && !(curbuf->terminal && eap->cmdidx == CMD_put)) { + ERROR(_(e_modifiable)); + } + if (!IS_USER_CMDIDX(eap->cmdidx)) { + if (cmdwin_type != 0 && !(eap->argt & EX_CMDWIN)) { + // Command not allowed in the command line window + ERROR(_(e_cmdwin)); + } + if (text_locked() && !(eap->argt & EX_LOCK_OK)) { + // Command not allowed when text is locked + ERROR(_(get_text_locked_msg())); + } + } + // Disallow editing another buffer when "curbuf->b_ro_locked" is set. + // Do allow ":checktime" (it is postponed). + // Do allow ":edit" (check for an argument later). + // Do allow ":file" with no arguments + if (!(eap->argt & EX_CMDWIN) + && eap->cmdidx != CMD_checktime + && eap->cmdidx != CMD_edit + && !(eap->cmdidx == CMD_file && *eap->arg == NUL) + && !IS_USER_CMDIDX(eap->cmdidx) + && curbuf_locked()) { + ERROR(_(e_cannot_edit_other_buf)); + } + + if (((eap->argt & EX_WHOLEFOLD) || eap->addr_count >= 2) && !global_busy + && eap->addr_type == ADDR_LINES) { + // Put the first line at the start of a closed fold, put the last line + // at the end of a closed fold. + (void)hasFolding(eap->line1, &eap->line1, NULL); + (void)hasFolding(eap->line2, NULL, &eap->line2); + } + + // Execute the command + execute_cmd0(&retv, eap, &errormsg, preview); + end: if (errormsg != NULL && *errormsg != NUL) { emsg(errormsg); @@ -1704,6 +1722,142 @@ end: #undef ERROR } +static void profile_cmd(const exarg_T *eap, cstack_T *cstack, LineGetter fgetline, void *cookie) +{ + // Count this line for profiling if skip is TRUE. + if (do_profiling == PROF_YES + && (!eap->skip || cstack->cs_idx == 0 + || (cstack->cs_idx > 0 + && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))) { + int skip = did_emsg || got_int || current_exception; + + if (eap->cmdidx == CMD_catch) { + skip = !skip && !(cstack->cs_idx >= 0 + && (cstack->cs_flags[cstack->cs_idx] & CSF_THROWN) + && !(cstack->cs_flags[cstack->cs_idx] & CSF_CAUGHT)); + } else if (eap->cmdidx == CMD_else || eap->cmdidx == CMD_elseif) { + skip = skip || !(cstack->cs_idx >= 0 + && !(cstack->cs_flags[cstack->cs_idx] + & (CSF_ACTIVE | CSF_TRUE))); + } else if (eap->cmdidx == CMD_finally) { + skip = false; + } else if (eap->cmdidx != CMD_endif + && eap->cmdidx != CMD_endfor + && eap->cmdidx != CMD_endtry + && eap->cmdidx != CMD_endwhile) { + skip = eap->skip; + } + + if (!skip) { + if (getline_equal(fgetline, cookie, get_func_line)) { + func_line_exec(getline_cookie(fgetline, cookie)); + } else if (getline_equal(fgetline, cookie, getsourceline)) { + script_line_exec(); + } + } + } +} + +static bool skip_cmd(const exarg_T *eap) +{ + // Skip the command when it's not going to be executed. + // The commands like :if, :endif, etc. always need to be executed. + // Also make an exception for commands that handle a trailing command + // themselves. + if (eap->skip) { + switch (eap->cmdidx) { + // commands that need evaluation + case CMD_while: + case CMD_endwhile: + case CMD_for: + case CMD_endfor: + case CMD_if: + case CMD_elseif: + case CMD_else: + case CMD_endif: + case CMD_try: + case CMD_catch: + case CMD_finally: + case CMD_endtry: + case CMD_function: + break; + + // Commands that handle '|' themselves. Check: A command should + // either have the EX_TRLBAR flag, appear in this list or appear in + // the list at ":help :bar". + case CMD_aboveleft: + case CMD_and: + case CMD_belowright: + case CMD_botright: + case CMD_browse: + case CMD_call: + case CMD_confirm: + case CMD_const: + case CMD_delfunction: + case CMD_djump: + case CMD_dlist: + case CMD_dsearch: + case CMD_dsplit: + case CMD_echo: + case CMD_echoerr: + case CMD_echomsg: + case CMD_echon: + case CMD_eval: + case CMD_execute: + case CMD_filter: + case CMD_help: + case CMD_hide: + case CMD_ijump: + case CMD_ilist: + case CMD_isearch: + case CMD_isplit: + case CMD_keepalt: + case CMD_keepjumps: + case CMD_keepmarks: + case CMD_keeppatterns: + case CMD_leftabove: + case CMD_let: + case CMD_lockmarks: + case CMD_lockvar: + case CMD_lua: + case CMD_match: + case CMD_mzscheme: + case CMD_noautocmd: + case CMD_noswapfile: + case CMD_perl: + case CMD_psearch: + case CMD_python: + case CMD_py3: + case CMD_python3: + case CMD_pythonx: + case CMD_pyx: + case CMD_return: + case CMD_rightbelow: + case CMD_ruby: + case CMD_silent: + case CMD_smagic: + case CMD_snomagic: + case CMD_substitute: + case CMD_syntax: + case CMD_tab: + case CMD_tcl: + case CMD_throw: + case CMD_tilde: + case CMD_topleft: + case CMD_unlet: + case CMD_unlockvar: + case CMD_verbose: + case CMD_vertical: + case CMD_wincmd: + break; + + default: + return true; + } + } + return false; +} + /// Execute one Ex command. /// /// If 'sourcing' is TRUE, the command will be included in the error message. @@ -1724,16 +1878,11 @@ end: static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline, void *cookie) { - char *p; - linenr_T lnum; char *errormsg = NULL; // error message - char *after_modifier = NULL; - exarg_T ea; - cmdmod_T save_cmdmod; const int save_reg_executing = reg_executing; const bool save_pending_end_reg_executing = pending_end_reg_executing; - char *cmd; + exarg_T ea; memset(&ea, 0, sizeof(ea)); ea.line1 = 1; ea.line2 = 1; @@ -1749,11 +1898,9 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter --quitmore; } - /* - * Reset browse, confirm, etc.. They are restored when returning, for - * recursive calls. - */ - save_cmdmod = cmdmod; + // Reset browse, confirm, etc.. They are restored when returning, for + // recursive calls. + cmdmod_T save_cmdmod = cmdmod; // "#!anything" is handled like a comment. if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') { @@ -1775,7 +1922,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter } apply_cmdmod(&cmdmod); - after_modifier = ea.cmd; + char *after_modifier = ea.cmd; ea.skip = (did_emsg || got_int @@ -1786,45 +1933,14 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // 3. Skip over the range to find the command. Let "p" point to after it. // // We need the command to know what kind of range it uses. - cmd = ea.cmd; + char *cmd = ea.cmd; ea.cmd = skip_range(ea.cmd, NULL); if (*ea.cmd == '*') { ea.cmd = skipwhite(ea.cmd + 1); } - p = find_ex_command(&ea, NULL); - - // Count this line for profiling if skip is TRUE. - if (do_profiling == PROF_YES - && (!ea.skip || cstack->cs_idx == 0 - || (cstack->cs_idx > 0 - && (cstack->cs_flags[cstack->cs_idx - 1] & CSF_ACTIVE)))) { - int skip = did_emsg || got_int || current_exception; - - if (ea.cmdidx == CMD_catch) { - skip = !skip && !(cstack->cs_idx >= 0 - && (cstack->cs_flags[cstack->cs_idx] & CSF_THROWN) - && !(cstack->cs_flags[cstack->cs_idx] & CSF_CAUGHT)); - } else if (ea.cmdidx == CMD_else || ea.cmdidx == CMD_elseif) { - skip = skip || !(cstack->cs_idx >= 0 - && !(cstack->cs_flags[cstack->cs_idx] - & (CSF_ACTIVE | CSF_TRUE))); - } else if (ea.cmdidx == CMD_finally) { - skip = false; - } else if (ea.cmdidx != CMD_endif - && ea.cmdidx != CMD_endfor - && ea.cmdidx != CMD_endtry - && ea.cmdidx != CMD_endwhile) { - skip = ea.skip; - } + char *p = find_ex_command(&ea, NULL); - if (!skip) { - if (getline_equal(fgetline, cookie, get_func_line)) { - func_line_exec(getline_cookie(fgetline, cookie)); - } else if (getline_equal(fgetline, cookie, getsourceline)) { - script_line_exec(); - } - } - } + profile_cmd(&ea, cstack, fgetline, cookie); // May go to debug mode. If this happens and the ">quit" debug command is // used, throw an interrupt exception and skip the next command. @@ -1855,19 +1971,13 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter goto doend; } - /* - * 5. Parse the command. - */ + // 5. Parse the command. - /* - * Skip ':' and any white space - */ + // Skip ':' and any white space ea.cmd = skip_colon_white(ea.cmd, true); - /* - * If we got a line, but no command, then go to the line. - * If we find a '|' or '\n' we set ea.nextcmd. - */ + // If we got a line, but no command, then go to the line. + // If we find a '|' or '\n' we set ea.nextcmd. if (*ea.cmd == NUL || *ea.cmd == '"' || (ea.nextcmd = (char *)check_nextcmd((char_u *)ea.cmd)) != NULL) { // strange vi behaviour: @@ -1947,12 +2057,12 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter const int ni = is_cmd_ni(ea.cmdidx); // Forced commands. - if (*p == '!' && ea.cmdidx != CMD_substitute - && ea.cmdidx != CMD_smagic && ea.cmdidx != CMD_snomagic) { + ea.forceit = *p == '!' + && ea.cmdidx != CMD_substitute + && ea.cmdidx != CMD_smagic + && ea.cmdidx != CMD_snomagic; + if (ea.forceit) { p++; - ea.forceit = true; - } else { - ea.forceit = false; } // 6. Parse arguments. Then check for errors. @@ -2012,10 +2122,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter goto doend; } - /* - * Don't complain about the range if it is not used - * (could happen if line_count is accidentally set to 0). - */ + // Don't complain about the range if it is not used + // (could happen if line_count is accidentally set to 0). if (!ea.skip && !ni && (ea.argt & EX_RANGE)) { // If the range is backwards, ask for confirmation and, if given, swap // ea.line1 & ea.line2 so it's forwards again. @@ -2030,7 +2138,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter goto doend; } } - lnum = ea.line1; + linenr_T lnum = ea.line1; ea.line1 = ea.line2; ea.line2 = lnum; } @@ -2054,34 +2162,24 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter (void)hasFolding(ea.line2, NULL, &ea.line2); } - /* - * For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' - * option here, so things like % get expanded. - */ + // For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' + // option here, so things like % get expanded. p = replace_makeprg(&ea, p, cmdlinep); if (p == NULL) { goto doend; } - /* - * Skip to start of argument. - * Don't do this for the ":!" command, because ":!! -l" needs the space. - */ - if (ea.cmdidx == CMD_bang) { - ea.arg = p; - } else { - ea.arg = skipwhite(p); - } + // Skip to start of argument. + // Don't do this for the ":!" command, because ":!! -l" needs the space. + ea.arg = ea.cmdidx == CMD_bang ? p : skipwhite(p); // ":file" cannot be run with an argument when "curbuf->b_ro_locked" is set if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked()) { goto doend; } - /* - * Check for "++opt=val" argument. - * Must be first, allow ":w ++enc=utf8 !cmd" - */ + // Check for "++opt=val" argument. + // Must be first, allow ":w ++enc=utf8 !cmd" if (ea.argt & EX_ARGOPT) { while (ea.arg[0] == '+' && ea.arg[1] == '+') { if (getargopt(&ea) == FAIL && !ni) { @@ -2103,9 +2201,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter ++ea.arg; ea.usefilter = TRUE; } - } - - if (ea.cmdidx == CMD_read) { + } else if (ea.cmdidx == CMD_read) { if (ea.forceit) { ea.usefilter = TRUE; // :r! filter if ea.forceit ea.forceit = FALSE; @@ -2113,9 +2209,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter ++ea.arg; ea.usefilter = TRUE; } - } - - if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { + } else if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { ea.amount = 1; while (*ea.arg == *ea.cmd) { // count number of '>' or '<' ea.arg++; @@ -2124,18 +2218,14 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter ea.arg = skipwhite(ea.arg); } - /* - * Check for "+command" argument, before checking for next command. - * Don't do this for ":read !cmd" and ":write !cmd". - */ + // Check for "+command" argument, before checking for next command. + // Don't do this for ":read !cmd" and ":write !cmd". if ((ea.argt & EX_CMDARG) && !ea.usefilter) { ea.do_ecmd_cmd = getargcmd(&ea.arg); } - /* - * Check for '|' to separate commands and '"' to start comments. - * Don't do this for ":read !cmd" and ":write !cmd". - */ + // Check for '|' to separate commands and '"' to start comments. + // Don't do this for ":read !cmd" and ":write !cmd". if ((ea.argt & EX_TRLBAR) && !ea.usefilter) { separate_nextcmd(&ea); } else if (ea.cmdidx == CMD_bang @@ -2146,18 +2236,18 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // Check for <newline> to end a shell command. // Also do this for ":read !cmd", ":write !cmd" and ":global". // Any others? - for (p = ea.arg; *p; p++) { + for (char *s = ea.arg; *s; s++) { // Remove one backslash before a newline, so that it's possible to // pass a newline to the shell and also a newline that is preceded // with a backslash. This makes it impossible to end a shell // command in a backslash, but that doesn't appear useful. // Halving the number of backslashes is incompatible with previous // versions. - if (*p == '\\' && p[1] == '\n') { - STRMOVE(p, p + 1); - } else if (*p == '\n') { - ea.nextcmd = p + 1; - *p = NUL; + if (*s == '\\' && s[1] == '\n') { + STRMOVE(s, s + 1); + } else if (*s == '\n') { + ea.nextcmd = s + 1; + *s = NUL; break; } } @@ -2173,9 +2263,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter goto doend; } - /* - * Check for flags: 'l', 'p' and '#'. - */ + // Check for flags: 'l', 'p' and '#'. if (ea.argt & EX_FLAGS) { get_flags(&ea); } @@ -2191,173 +2279,21 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter goto doend; } - /* - * Skip the command when it's not going to be executed. - * The commands like :if, :endif, etc. always need to be executed. - * Also make an exception for commands that handle a trailing command - * themselves. - */ - if (ea.skip) { - switch (ea.cmdidx) { - // commands that need evaluation - case CMD_while: - case CMD_endwhile: - case CMD_for: - case CMD_endfor: - case CMD_if: - case CMD_elseif: - case CMD_else: - case CMD_endif: - case CMD_try: - case CMD_catch: - case CMD_finally: - case CMD_endtry: - case CMD_function: - break; - - // Commands that handle '|' themselves. Check: A command should - // either have the EX_TRLBAR flag, appear in this list or appear in - // the list at ":help :bar". - case CMD_aboveleft: - case CMD_and: - case CMD_belowright: - case CMD_botright: - case CMD_browse: - case CMD_call: - case CMD_confirm: - case CMD_const: - case CMD_delfunction: - case CMD_djump: - case CMD_dlist: - case CMD_dsearch: - case CMD_dsplit: - case CMD_echo: - case CMD_echoerr: - case CMD_echomsg: - case CMD_echon: - case CMD_eval: - case CMD_execute: - case CMD_filter: - case CMD_help: - case CMD_hide: - case CMD_ijump: - case CMD_ilist: - case CMD_isearch: - case CMD_isplit: - case CMD_keepalt: - case CMD_keepjumps: - case CMD_keepmarks: - case CMD_keeppatterns: - case CMD_leftabove: - case CMD_let: - case CMD_lockmarks: - case CMD_lockvar: - case CMD_lua: - case CMD_match: - case CMD_mzscheme: - case CMD_noautocmd: - case CMD_noswapfile: - case CMD_perl: - case CMD_psearch: - case CMD_python: - case CMD_py3: - case CMD_python3: - case CMD_pythonx: - case CMD_pyx: - case CMD_return: - case CMD_rightbelow: - case CMD_ruby: - case CMD_silent: - case CMD_smagic: - case CMD_snomagic: - case CMD_substitute: - case CMD_syntax: - case CMD_tab: - case CMD_tcl: - case CMD_throw: - case CMD_tilde: - case CMD_topleft: - case CMD_unlet: - case CMD_unlockvar: - case CMD_verbose: - case CMD_vertical: - case CMD_wincmd: - break; - - default: - goto doend; - } - } - - if (ea.argt & EX_XFILE) { - if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL) { - goto doend; - } - } - - /* - * Accept buffer name. Cannot be used at the same time with a buffer - * number. Don't do this for a user command. - */ - if ((ea.argt & EX_BUFNAME) && *ea.arg != NUL && ea.addr_count == 0 - && !IS_USER_CMDIDX(ea.cmdidx)) { - /* - * :bdelete, :bwipeout and :bunload take several arguments, separated - * by spaces: find next space (skipping over escaped characters). - * The others take one argument: ignore trailing spaces. - */ - if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout - || ea.cmdidx == CMD_bunload) { - p = skiptowhite_esc(ea.arg); - } else { - p = ea.arg + STRLEN(ea.arg); - while (p > ea.arg && ascii_iswhite(p[-1])) { - p--; - } - } - ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & EX_BUFUNL) != 0, - false, false); - if (ea.line2 < 0) { // failed - goto doend; - } - ea.addr_count = 1; - ea.arg = skipwhite(p); - } - - // The :try command saves the emsg_silent flag, reset it here when - // ":silent! try" was used, it should only apply to :try itself. - if (ea.cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) { - emsg_silent -= cmdmod.cmod_did_esilent; - if (emsg_silent < 0) { - emsg_silent = 0; - } - cmdmod.cmod_did_esilent = 0; + if (skip_cmd(&ea)) { + goto doend; } // 7. Execute the command. - if (IS_USER_CMDIDX(ea.cmdidx)) { - /* - * Execute a user-defined command. - */ - do_ucmd(&ea, false); - } else { - /* - * Call the function to execute the command. - */ - ea.errmsg = NULL; - (cmdnames[ea.cmdidx].cmd_func)(&ea); - if (ea.errmsg != NULL) { - errormsg = _(ea.errmsg); - } + int retv = 0; + if (execute_cmd0(&retv, &ea, &errormsg, false) == FAIL) { + goto doend; } - /* - * If the command just executed called do_cmdline(), any throw or ":return" - * or ":finish" encountered there must also check the cstack of the still - * active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught - * exception, or reanimate a returned function or finished script file and - * return or finish it again. - */ + // If the command just executed called do_cmdline(), any throw or ":return" + // or ":finish" encountered there must also check the cstack of the still + // active do_cmdline() that called this do_one_cmd(). Rethrow an uncaught + // exception, or reanimate a returned function or finished script file and + // return or finish it again. if (need_rethrow) { do_throw(cstack); } else if (check_cstack) { @@ -2383,7 +2319,7 @@ doend: STRCPY(IObuff, errormsg); errormsg = (char *)IObuff; } - append_command(*cmdlinep); + append_command(*ea.cmdlinep); } emsg(errormsg); } @@ -5504,7 +5440,7 @@ char *uc_validate_name(char *name) /// This function takes ownership of compl_arg, compl_luaref, and luaref. /// /// @return OK if the command is created, FAIL otherwise. -int uc_add_command(char *name, size_t name_len, char *rep, uint32_t argt, long def, int flags, +int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, long def, int flags, int compl, char *compl_arg, LuaRef compl_luaref, LuaRef preview_luaref, cmd_addr_T addr_type, LuaRef luaref, bool force) FUNC_ATTR_NONNULL_ARG(1, 3) @@ -5826,6 +5762,16 @@ static void uc_list(char *name, size_t name_len) IObuff[len] = '\0'; msg_outtrans((char *)IObuff); + if (cmd->uc_luaref != LUA_NOREF) { + char *fn = nlua_funcref_str(cmd->uc_luaref); + msg_puts_attr(fn, HL_ATTR(HLF_8)); + xfree(fn); + // put the description on a new line + if (*cmd->uc_rep != NUL) { + msg_puts("\n "); + } + } + msg_outtrans_special(cmd->uc_rep, false, name_len == 0 ? Columns - 47 : 0); if (p_verbose > 0) { diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 4a5841ca6e..28ff0cbd59 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1737,7 +1737,7 @@ static bool at_ins_compl_key(void) || ((compl_cont_status & CONT_LOCAL) && (c == Ctrl_N || c == Ctrl_P)); } -/// Check if typebuf.tb_buf[] contains a modifer plus key that can be changed +/// Check if typebuf.tb_buf[] contains a modifier plus key that can be changed /// into just a key, apply that. /// Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off + "max_offset"]. /// @return the length of the replaced bytes, 0 if nothing changed, -1 for error. diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index b89ab19226..c5e030ce25 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -2002,7 +2002,7 @@ int get_c_indent(void) } // #defines and so on go at the left when included in 'cinkeys', - // exluding pragmas when customized in 'cinoptions' + // excluding pragmas when customized in 'cinoptions' if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', true))) { const char_u *const directive = (char_u *)skipwhite((char *)theline + 1); if (curbuf->b_ind_pragma == 0 || STRNCMP(directive, "pragma", 6) != 0) { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 2fc8f1dadc..a64d8e8f00 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -825,7 +825,6 @@ static void ins_compl_longest_match(compl_T *match) /// Add an array of matches to the list of matches. /// Frees matches[]. static void ins_compl_add_matches(int num_matches, char **matches, int icase) - FUNC_ATTR_NONNULL_ALL { int add_r = OK; Direction dir = compl_direction; diff --git a/src/nvim/keycodes.h b/src/nvim/keycodes.h index f6c576f6ee..c4d984ee17 100644 --- a/src/nvim/keycodes.h +++ b/src/nvim/keycodes.h @@ -7,10 +7,8 @@ // // Any special key code sequences are replaced by these codes. -// -// For MS-DOS some keys produce codes larger than 0xff. They are split into two -// chars, the first one is K_NUL. -// +/// For MS-DOS some keys produce codes larger than 0xff. They are split into two +/// chars, the first one is K_NUL. #define K_NUL (0xce) // for MS-DOS: special key follows /// K_SPECIAL is the first byte of a special key code and is always followed by @@ -59,13 +57,13 @@ #define KS_SELECT 245 #define K_SELECT_STRING (char_u *)"\200\365X" -// Used a termcap entry that produces a normal character. +/// Used a termcap entry that produces a normal character. #define KS_KEY 242 -// Used for click in a tab pages label. +/// Used for click in a tab pages label. #define KS_TABLINE 240 -// Used for menu in a tab pages line. +/// Used for menu in a tab pages line. #define KS_TABMENU 239 /// Filler used after KS_SPECIAL and others @@ -89,18 +87,19 @@ #define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \ KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b)) -// Codes for keys that do not have a termcap name. -// The numbers are fixed to make sure that recorded key sequences remain valid. -// Add new entries at the end, not halfway. -// -// K_SPECIAL KS_EXTRA KE_xxx -// -// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL). +/// Codes for keys that do not have a termcap name. +/// The numbers are fixed to make sure that recorded key sequences remain valid. +/// Add new entries at the end, not halfway. +/// +/// K_SPECIAL KS_EXTRA KE_xxx +/// +/// Entries must be in the range 0x02-0x7f (see comment at K_SPECIAL). enum key_extra { KE_S_UP = 4, // shift-up - KE_S_DOWN = 5, // shift-down + KE_S_DOWN = 5, // shift-down - KE_S_F1 = 6, // shifted function keys + // shifted function keys + KE_S_F1 = 6, KE_S_F2 = 7, KE_S_F3 = 8, KE_S_F4 = 9, @@ -141,7 +140,7 @@ enum key_extra { KE_S_F36 = 41, KE_S_F37 = 42, - KE_MOUSE = 43, // mouse event start + KE_MOUSE = 43, // mouse event start // Symbols for pseudo keys which are translated from the real key symbols // above. @@ -153,14 +152,14 @@ enum key_extra { KE_MIDDLERELEASE = 49, // Middle mouse button release KE_RIGHTMOUSE = 50, // Right mouse button click KE_RIGHTDRAG = 51, // Drag with right mouse button down - KE_RIGHTRELEASE = 52, // Right mouse button release + KE_RIGHTRELEASE = 52, // Right mouse button release - KE_IGNORE = 53, // Ignored mouse drag/release + KE_IGNORE = 53, // Ignored mouse drag/release KE_TAB = 54, // unshifted TAB key - KE_S_TAB_OLD = 55, // shifted TAB key (no longer used) + KE_S_TAB_OLD = 55, // shifted TAB key (no longer used) - // , KE_SNIFF_UNUSED = 56 // obsolete + // KE_SNIFF_UNUSED = 56, // obsolete KE_XF1 = 57, // extra vt100 function keys for xterm KE_XF2 = 58, KE_XF3 = 59, @@ -175,7 +174,7 @@ enum key_extra { KE_XRIGHT = 68, KE_LEFTMOUSE_NM = 69, // non-mappable Left mouse button click - KE_LEFTRELEASE_NM = 70, // non-mappable left mouse button release + KE_LEFTRELEASE_NM = 70, // non-mappable left mouse button release KE_S_XF1 = 71, // vt100 shifted function keys for xterm KE_S_XF2 = 72, @@ -188,20 +187,20 @@ enum key_extra { KE_MOUSEDOWN = 75, // scroll wheel pseudo-button Down KE_MOUSEUP = 76, // scroll wheel pseudo-button Up KE_MOUSELEFT = 77, // scroll wheel pseudo-button Left - KE_MOUSERIGHT = 78, // scroll wheel pseudo-button Right + KE_MOUSERIGHT = 78, // scroll wheel pseudo-button Right KE_KINS = 79, // keypad Insert key - KE_KDEL = 80, // keypad Delete key + KE_KDEL = 80, // keypad Delete key // KE_CSI = 81, // Nvim doesn't need escaping CSI KE_SNR = 82, // <SNR> KE_PLUG = 83, // <Plug> - KE_CMDWIN = 84, // open command-line window from Command-line Mode + KE_CMDWIN = 84, // open command-line window from Command-line Mode KE_C_LEFT = 85, // control-left KE_C_RIGHT = 86, // control-right KE_C_HOME = 87, // control-home - KE_C_END = 88, // control-end + KE_C_END = 88, // control-end KE_X1MOUSE = 89, // X1/X2 mouse-buttons KE_X1DRAG = 90, @@ -210,16 +209,16 @@ enum key_extra { KE_X2DRAG = 93, KE_X2RELEASE = 94, - KE_DROP = 95, // DnD data is available - // , KE_CURSORHOLD = 96 // CursorHold event - KE_NOP = 97, // no-op: does nothing - // , KE_FOCUSGAINED = 98 // focus gained - // , KE_FOCUSLOST = 99 // focus lost - KE_MOUSEMOVE = 100, // mouse moved with no button down - // , KE_CANCEL = 101 // return from vgetc + KE_DROP = 95, // DnD data is available + // KE_CURSORHOLD = 96, // CursorHold event + KE_NOP = 97, // no-op: does nothing + // KE_FOCUSGAINED = 98, // focus gained + // KE_FOCUSLOST = 99, // focus lost + KE_MOUSEMOVE = 100, // mouse moved with no button down + // KE_CANCEL = 101, // return from vgetc() KE_EVENT = 102, // event - KE_LUA = 103, // lua special key - KE_COMMAND = 104, // <Cmd> special key + KE_LUA = 103, // Lua special key + KE_COMMAND = 104, // <Cmd> special key }; // the three byte codes are replaced with the following int when using vgetc() @@ -259,7 +258,8 @@ enum key_extra { #define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT) #define K_XRIGHT TERMCAP2KEY(KS_EXTRA, KE_XRIGHT) -#define K_F1 TERMCAP2KEY('k', '1') // function keys +// function keys +#define K_F1 TERMCAP2KEY('k', '1') #define K_F2 TERMCAP2KEY('k', '2') #define K_F3 TERMCAP2KEY('k', '3') #define K_F4 TERMCAP2KEY('k', '4') @@ -463,13 +463,13 @@ enum key_extra { /// Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and '>'). #define MAX_KEY_NAME_LEN 32 -// Maximum length of a special key event as tokens. This includes modifiers. -// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the -// following string of tokens: -// -// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>. -// -// This is a total of 6 tokens, and is currently the longest one possible. +/// Maximum length of a special key event as tokens. This includes modifiers. +/// The longest event is something like <M-C-S-T-4-LeftDrag> which would be the +/// following string of tokens: +/// +/// <K_SPECIAL> <KS_MODIFIER> bitmask <K_SPECIAL> <KS_EXTRA> <KE_LEFTDRAG>. +/// +/// This is a total of 6 tokens, and is currently the longest one possible. #define MAX_KEY_CODE_LEN 6 #define FLAG_CPO_BSLASH 0x01 @@ -477,7 +477,7 @@ enum key_extra { ? 0 \ : FLAG_CPO_BSLASH) -// Flags for replace_termcodes() +/// Flags for replace_termcodes() enum { REPTERM_FROM_PART = 1, REPTERM_DO_LT = 2, @@ -485,7 +485,7 @@ enum { REPTERM_NO_SIMPLIFY = 8, }; -// Flags for find_special_key() +/// Flags for find_special_key() enum { FSK_KEYCODE = 0x01, ///< prefer key code, e.g. K_DEL in place of DEL FSK_KEEP_X_KEY = 0x02, ///< don’t translate xHome to Home key diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 17157ccdc2..197a209e97 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -2076,3 +2076,34 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview) return retv; } + +/// String representation of a Lua function reference +/// +/// @return Allocated string +char *nlua_funcref_str(LuaRef ref) +{ + lua_State *const lstate = global_lstate; + StringBuilder str = KV_INITIAL_VALUE; + kv_resize(str, 16); + + if (!lua_checkstack(lstate, 1)) { + goto plain; + } + nlua_pushref(lstate, ref); + if (!lua_isfunction(lstate, -1)) { + lua_pop(lstate, 1); + goto plain; + } + + lua_Debug ar; + if (lua_getinfo(lstate, ">S", &ar) && *ar.source == '@' && ar.linedefined >= 0) { + char *src = home_replace_save(NULL, ar.source + 1); + kv_printf(str, "<Lua %d: %s:%d>", ref, src, ar.linedefined); + xfree(src); + return str.items; + } + +plain: + kv_printf(str, "<Lua %d>", ref); + return str.items; +} diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 520a91491a..342b1b0d47 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -196,9 +196,9 @@ static void showmap(mapblock_T *mp, bool local) // Use false below if we only want things like <Up> to show up as such on // the rhs, and not M-x etc, true gets both -- webb if (mp->m_luaref != LUA_NOREF) { - char msg[100]; - snprintf(msg, sizeof(msg), "<Lua function %d>", mp->m_luaref); - msg_puts_attr(msg, HL_ATTR(HLF_8)); + char *str = nlua_funcref_str(mp->m_luaref); + msg_puts_attr(str, HL_ATTR(HLF_8)); + xfree(str); } else if (mp->m_str[0] == NUL) { msg_puts_attr("<Nop>", HL_ATTR(HLF_8)); } else { @@ -235,7 +235,7 @@ static void showmap(mapblock_T *mp, bool local) /// @param[in] orig_lhs Original mapping LHS, with characters to replace. /// @param[in] orig_lhs_len `strlen` of orig_lhs. /// @param[in] orig_rhs Original mapping RHS, with characters to replace. -/// @param[in] rhs_lua Lua reference for Lua maps. +/// @param[in] rhs_lua Lua reference for Lua mappings. /// @param[in] orig_rhs_len `strlen` of orig_rhs. /// @param[in] cpo_flags See param docs for @ref replace_termcodes. /// @param[out] mapargs MapArguments struct holding the replaced strings. @@ -1633,7 +1633,7 @@ int makemap(FILE *fd, buf_T *buf) continue; } - // skip lua mappings and mappings that contain a <SNR> (script-local thing), + // skip Lua mappings and mappings that contain a <SNR> (script-local thing), // they probably don't work when loaded again if (mp->m_luaref != LUA_NOREF) { continue; @@ -2110,10 +2110,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) rettv->vval.v_string = str2special_save((char *)rhs, false, false); } } else if (rhs_lua != LUA_NOREF) { - size_t msglen = 100; - char *msg = (char *)xmalloc(msglen); - snprintf(msg, msglen, "<Lua function %d>", mp->m_luaref); - rettv->vval.v_string = msg; + rettv->vval.v_string = nlua_funcref_str(mp->m_luaref); } } else { tv_dict_alloc_ret(rettv); @@ -2601,7 +2598,7 @@ fail_and_free: /// /// @param mode The abbreviation for the mode /// @param buf The buffer to get the mapping array. NULL for global -/// @param from_lua Whether it is called from internal lua api. +/// @param from_lua Whether it is called from internal Lua api. /// @returns Array of maparg()-like dictionaries describing mappings ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua) { diff --git a/src/nvim/memory.c b/src/nvim/memory.c index a74fcf6137..5ae7f7bbe3 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -546,7 +546,7 @@ void arena_start(Arena *arena, ArenaMem *reuse_blk) /// Finnish the allocations in an arena. /// -/// This does not immedately free the memory, but leaves existing allocated +/// This does not immediately free the memory, but leaves existing allocated /// objects valid, and returns an opaque ArenaMem handle, which can be used to /// free the allocations using `arena_mem_free`, when the objects allocated /// from the arena are not needed anymore. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 660902b10b..53612be697 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4889,7 +4889,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) linenr_T amount = Prenum1; // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the - // buffer is not completly updated yet. Postpone updating folds until before + // buffer is not completely updated yet. Postpone updating folds until before // the call to changed_lines(). disable_fold_update++; diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 9c93057fe7..eaa56ffe63 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -1143,7 +1143,7 @@ size_t home_replace(const buf_T *const buf, const char *src, char *const dst, si /// Like home_replace, store the replaced string in allocated memory. /// @param buf When not NULL, check for help files /// @param src Input file name -char *home_replace_save(buf_T *buf, char *src) +char *home_replace_save(buf_T *buf, const char *src) FUNC_ATTR_NONNULL_RET { size_t len = 3; // space for "~/" and trailing NUL diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index 6407ac172e..2f718e9c2e 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -156,7 +156,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) /// Use instead of rbuffer_consumed to use rbuffer in a linear, non-cyclic fashion. /// -/// This is generally usefull if we can guarantee to parse all input +/// This is generally useful if we can guarantee to parse all input /// except some small incomplete token, like when parsing msgpack. void rbuffer_consumed_compact(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index c2a9c90dda..fbbf904f8b 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -1649,7 +1649,7 @@ static void clear_submatch_list(staticList10_T *sl) /// vim_regexec_multi() match. /// /// If "flags" has REGSUB_COPY really copy into "dest[destlen]". -/// Oterwise nothing is copied, only compue the length of the result. +/// Otherwise nothing is copied, only compute the length of the result. /// /// If "flags" has REGSUB_MAGIC then behave like 'magic' is set. /// diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index 09e971f03f..a586fec3bf 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -53,7 +53,7 @@ UIClientHandler ui_client_get_redraw_handler(const char *name, size_t name_len, /// Placeholder for _sync_ requests with 'redraw' method name /// /// async 'redraw' events, which are expected when nvim acts as an ui client. -/// get handled in msgpack_rpc/unpacker.c and directy dispatched to handlers +/// get handled in msgpack_rpc/unpacker.c and directly dispatched to handlers /// of specific ui events, like ui_client_event_grid_resize and so on. Object handle_ui_client_redraw(uint64_t channel_id, Array args, Error *error) { diff --git a/src/nvim/window.c b/src/nvim/window.c index c7f038850e..b737215616 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5518,6 +5518,7 @@ void win_setheight_win(int height, win_T *win) msg_row = row; msg_col = 0; redraw_all_later(NOT_VALID); + redraw_cmdline = true; } } diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index eb2a467a8b..a93a4544ff 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -822,7 +822,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] assert.truthy(string.match(exec_lua[[return vim.api.nvim_exec(':nmap asdf', true)]], - "^\nn asdf <Lua function %d+>")) + "^\nn asdf <Lua %d+>")) end) it ('mapcheck() returns lua mapping correctly', function() @@ -830,7 +830,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] assert.truthy(string.match(funcs.mapcheck('asdf', 'n'), - "^<Lua function %d+>")) + "^<Lua %d+>")) end) it ('maparg() returns lua mapping correctly', function() @@ -838,7 +838,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function() vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] assert.truthy(string.match(funcs.maparg('asdf', 'n'), - "^<Lua function %d+>")) + "^<Lua %d+>")) local mapargs = funcs.maparg('asdf', 'n', false, true) assert(type(mapargs.callback) == 'number', 'callback is not luaref number') mapargs.callback = nil diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index e27da0947f..6cdac3c079 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -1253,4 +1253,10 @@ describe('completion', function() feed('ifoo#<C-X><C-U>') assert_alive() end) + + it('does not crash when using i_CTRL-X_CTRL-V to complete non-existent colorscheme', function() + feed('icolorscheme NOSUCHCOLORSCHEME<C-X><C-V>') + expect('colorscheme NOSUCHCOLORSCHEME') + assert_alive() + end) end) diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index 7dd0b9f154..849a02c28b 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -59,7 +59,7 @@ describe('tabpage', function() screen:set_default_attr_ids({ [0] = {bold = true, foreground = Screen.colors.Blue}, [1] = {bold = true, reverse = true}, -- StatusLine - [2] = {reverse = true}, -- StatusLineNC, TabLineFill + [2] = {reverse = true}, -- TabLineFill [3] = {bold = true}, -- TabLineSel [4] = {background = Screen.colors.LightGrey, underline = true}, -- TabLine [5] = {bold = true, foreground = Screen.colors.Magenta}, diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 69a2d2f4ed..f3735c8e4c 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -407,3 +407,40 @@ it('statusline does not crash if it has Arabic characters #19447', function() command('redraw!') assert_alive() end) + +it('statusline is redrawn with :resize from <Cmd> mapping #19629', function() + clear() + local screen = Screen.new(40, 8) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, reverse = true}, -- StatusLine + }) + screen:attach() + exec([[ + set laststatus=2 + nnoremap <Up> <cmd>resize -1<CR> + nnoremap <Down> <cmd>resize +1<CR> + ]]) + feed('<Up>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1:[No Name] }| + | + | + ]]) + feed('<Down>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1:[No Name] }| + | + ]]) +end) |