aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mpack/object.h2
-rw-r--r--src/nvim/CMakeLists.txt13
-rw-r--r--src/nvim/api/buffer.c5
-rw-r--r--src/nvim/api/extmark.c28
-rw-r--r--src/nvim/api/keysets.lua4
-rw-r--r--src/nvim/api/private/helpers.c2
-rw-r--r--src/nvim/api/vim.c120
-rw-r--r--src/nvim/api/vimscript.c4
-rw-r--r--src/nvim/assert.h2
-rw-r--r--src/nvim/aucmd.c5
-rw-r--r--src/nvim/auevents.lua8
-rw-r--r--src/nvim/autocmd.c27
-rw-r--r--src/nvim/buffer.c85
-rw-r--r--src/nvim/buffer_defs.h16
-rw-r--r--src/nvim/change.c297
-rw-r--r--src/nvim/change.h7
-rw-r--r--src/nvim/channel.c5
-rw-r--r--src/nvim/charset.c11
-rw-r--r--src/nvim/charset.h4
-rw-r--r--src/nvim/cursor.c2
-rw-r--r--src/nvim/cursor_shape.c2
-rw-r--r--src/nvim/debugger.c2
-rw-r--r--src/nvim/diff.c4
-rw-r--r--src/nvim/digraph.c1
-rw-r--r--src/nvim/edit.c155
-rw-r--r--src/nvim/eval.c302
-rw-r--r--src/nvim/eval.h14
-rw-r--r--src/nvim/eval.lua189
-rw-r--r--src/nvim/eval/decode.c10
-rw-r--r--src/nvim/eval/encode.c46
-rw-r--r--src/nvim/eval/funcs.c56
-rw-r--r--src/nvim/eval/typval.c3
-rw-r--r--src/nvim/eval/typval.h2
-rw-r--r--src/nvim/eval/userfunc.c7
-rw-r--r--src/nvim/event/rstream.c2
-rw-r--r--src/nvim/ex_cmds.c65
-rw-r--r--src/nvim/ex_cmds2.c6
-rw-r--r--src/nvim/ex_cmds_defs.h6
-rw-r--r--src/nvim/ex_docmd.c59
-rw-r--r--src/nvim/ex_eval.c49
-rw-r--r--src/nvim/ex_eval.h4
-rw-r--r--src/nvim/ex_getln.c55
-rw-r--r--src/nvim/ex_session.c9
-rw-r--r--src/nvim/file_search.c16
-rw-r--r--src/nvim/fileio.c32
-rw-r--r--src/nvim/fold.c18
-rw-r--r--src/nvim/fold.h8
-rw-r--r--src/nvim/generators/gen_char_blob.lua52
-rw-r--r--src/nvim/getchar.c872
-rw-r--r--src/nvim/globals.h55
-rw-r--r--src/nvim/hardcopy.c172
-rw-r--r--src/nvim/highlight_defs.h4
-rw-r--r--src/nvim/if_cscope.c57
-rw-r--r--src/nvim/indent.c1
-rw-r--r--src/nvim/indent_c.c1
-rw-r--r--src/nvim/input.c255
-rw-r--r--src/nvim/input.h9
-rw-r--r--src/nvim/lib/kbtree.h2
-rw-r--r--src/nvim/lib/khash.h4
-rw-r--r--src/nvim/lua/converter.c16
-rw-r--r--src/nvim/lua/executor.c26
-rw-r--r--src/nvim/lua/stdlib.c13
-rw-r--r--src/nvim/lua/vim.lua13
-rw-r--r--src/nvim/lua/xdiff.c2
-rw-r--r--src/nvim/macros.h2
-rw-r--r--src/nvim/main.c45
-rw-r--r--src/nvim/mark.c2
-rw-r--r--src/nvim/mbyte.c20
-rw-r--r--src/nvim/memfile.c2
-rw-r--r--src/nvim/memline.c33
-rw-r--r--src/nvim/memory.c7
-rw-r--r--src/nvim/menu.c7
-rw-r--r--src/nvim/message.c83
-rw-r--r--src/nvim/misc1.c1061
-rw-r--r--src/nvim/misc1.h17
-rw-r--r--src/nvim/mouse.c33
-rw-r--r--src/nvim/move.c12
-rw-r--r--src/nvim/msgpack_rpc/channel.c1
-rw-r--r--src/nvim/msgpack_rpc/helpers.c16
-rw-r--r--src/nvim/normal.c893
-rw-r--r--src/nvim/ops.c891
-rw-r--r--src/nvim/option.c282
-rw-r--r--src/nvim/os/env.c2
-rw-r--r--src/nvim/os/fs.c3
-rw-r--r--src/nvim/os/input.c35
-rw-r--r--src/nvim/os/os_defs.h4
-rw-r--r--src/nvim/os/pty_process_unix.c122
-rw-r--r--src/nvim/os/shell.c113
-rw-r--r--src/nvim/os/signal.c1
-rw-r--r--src/nvim/os/stdpaths.c2
-rw-r--r--src/nvim/os/users.c60
-rw-r--r--src/nvim/os_unix.c1
-rw-r--r--src/nvim/path.c50
-rw-r--r--src/nvim/po/check.vim5
-rw-r--r--src/nvim/quickfix.c18
-rw-r--r--src/nvim/regexp.c34
-rw-r--r--src/nvim/regexp_nfa.c33
-rw-r--r--src/nvim/runtime.c9
-rw-r--r--src/nvim/screen.c85
-rw-r--r--src/nvim/search.c73
-rw-r--r--src/nvim/shada.c2
-rw-r--r--src/nvim/sign.c67
-rw-r--r--src/nvim/sign_defs.h1
-rw-r--r--src/nvim/spell.c54
-rw-r--r--src/nvim/spellfile.c85
-rw-r--r--src/nvim/state.c34
-rw-r--r--src/nvim/strings.c17
-rw-r--r--src/nvim/syntax.c108
-rw-r--r--src/nvim/tag.c18
-rw-r--r--src/nvim/terminal.c34
-rw-r--r--src/nvim/testdir/runtest.vim5
-rw-r--r--src/nvim/testdir/test_arglist.vim16
-rw-r--r--src/nvim/testdir/test_autochdir.vim38
-rw-r--r--src/nvim/testdir/test_autocmd.vim606
-rw-r--r--src/nvim/testdir/test_blockedit.vim52
-rw-r--r--src/nvim/testdir/test_breakindent.vim2
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim207
-rw-r--r--src/nvim/testdir/test_cd.vim41
-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.vim5
-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_edit.vim94
-rw-r--r--src/nvim/testdir/test_environ.vim2
-rw-r--r--src/nvim/testdir/test_ex_mode.vim2
-rw-r--r--src/nvim/testdir/test_execute_func.vim14
-rw-r--r--src/nvim/testdir/test_expr.vim6
-rw-r--r--src/nvim/testdir/test_filetype.vim131
-rw-r--r--src/nvim/testdir/test_fold.vim3
-rw-r--r--src/nvim/testdir/test_functions.vim41
-rw-r--r--src/nvim/testdir/test_highlight.vim17
-rw-r--r--src/nvim/testdir/test_listchars.vim147
-rw-r--r--src/nvim/testdir/test_listlbr.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.vim15
-rw-r--r--src/nvim/testdir/test_quickfix.vim7
-rw-r--r--src/nvim/testdir/test_registers.vim5
-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.vim57
-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.vim7
-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_textobjects.vim32
-rw-r--r--src/nvim/testdir/test_timers.vim12
-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/tui/input.c6
-rw-r--r--src/nvim/tui/tui.c43
-rw-r--r--src/nvim/ui.c39
-rw-r--r--src/nvim/undo.c41
-rw-r--r--src/nvim/version.c8
-rw-r--r--src/nvim/vim.h7
-rw-r--r--src/nvim/viml/parser/expressions.c224
-rw-r--r--src/nvim/window.c186
-rw-r--r--src/uncrustify.cfg152
174 files changed, 6199 insertions, 4149 deletions
diff --git a/src/mpack/object.h b/src/mpack/object.h
index 5327e56e18..e69821f9de 100644
--- a/src/mpack/object.h
+++ b/src/mpack/object.h
@@ -22,7 +22,7 @@ enum {
};
/* Storing integer in pointers in undefined behavior according to the C
- * standard. Define a union type to accomodate arbitrary user data associated
+ * standard. Define a union type to accommodate arbitrary user data associated
* with nodes(and with requests in rpc.h). */
typedef union {
void *p;
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 185d55daed..9c4b778169 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -326,7 +326,9 @@ add_custom_command(
add_custom_command(
OUTPUT ${VIM_MODULE_FILE}
- COMMAND ${LUA_PRG} ${CHAR_BLOB_GENERATOR} ${VIM_MODULE_FILE}
+ COMMAND ${CMAKE_COMMAND} -E env
+ "LUAC_PRG=${LUAC_PRG}"
+ ${LUA_PRG} ${CHAR_BLOB_GENERATOR} -c ${VIM_MODULE_FILE}
${LUA_VIM_MODULE_SOURCE} vim_module
${LUA_SHARED_MODULE_SOURCE} shared_module
${LUA_INSPECT_MODULE_SOURCE} inspect_module
@@ -339,6 +341,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE}
${LUA_F_MODULE_SOURCE}
${LUA_META_MODULE_SOURCE}
+ VERBATIM
)
list(APPEND NVIM_GENERATED_SOURCES
@@ -468,9 +471,11 @@ list(APPEND NVIM_LINK_LIBRARIES
if(UNIX)
list(APPEND NVIM_LINK_LIBRARIES
- m
- util
- )
+ m)
+ if (NOT CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ list(APPEND NVIM_LINK_LIBRARIES
+ util)
+ endif()
endif()
set(NVIM_EXEC_LINK_LIBRARIES ${NVIM_LINK_LIBRARIES} ${LUA_PREFERRED_LIBRARIES})
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 4076a0d220..7988bff25a 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -29,7 +29,6 @@
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/undo.h"
@@ -535,7 +534,7 @@ end:
/// @param channel_id
/// @param buffer Buffer handle, or 0 for current buffer
/// @param start_row First line index
-/// @param start_column Last column
+/// @param start_column First column
/// @param end_row Last line index
/// @param end_column Last column
/// @param replacement Array of lines to use as replacement
@@ -1246,7 +1245,7 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
/// If the current window already shows "buffer", the window is not switched
/// If a window inside the current tabpage (including a float) already shows the
/// buffer One of these windows will be set as current window temporarily.
-/// Otherwise a temporary scratch window (calleed the "autocmd window" for
+/// Otherwise a temporary scratch window (called the "autocmd window" for
/// historical reasons) will be used.
///
/// This is useful e.g. to call vimL functions that only work with the current
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 6f1fb15dac..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;
}
@@ -839,7 +849,7 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start,
/// - on_win: called when starting to redraw a specific window.
/// ["win", winid, bufnr, topline, botline_guess]
/// - on_line: called for each buffer line being redrawn. (The
-/// interation with fold lines is subject to change)
+/// interaction with fold lines is subject to change)
/// ["win", winid, bufnr, row]
/// - on_end: called at the end of a redraw cycle
/// ["end", tick]
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 144c252687..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";
@@ -58,5 +59,8 @@ return {
"highlights";
"use_tabline";
};
+ option = {
+ "scope";
+ };
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index d470def277..9b407eab8b 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -513,7 +513,7 @@ String cbuf_to_string(const char *buf, size_t size)
String cstrn_to_string(const char *str, size_t maxsize)
FUNC_ATTR_NONNULL_ALL
{
- return cbuf_to_string(str, strnlen(str, maxsize));
+ return cbuf_to_string(str, STRNLEN(str, maxsize));
}
/// Creates a String using the given C string. Unlike
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index c1374ff00e..4f7c320129 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -71,7 +71,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
FUNC_API_SINCE(3)
{
Dictionary result = ARRAY_DICT_INIT;
- int id = syn_name2id((const char_u *)name.data);
+ int id = syn_name2id(name.data);
if (id == 0) {
api_set_error(err, kErrorTypeException, "Invalid highlight name: %s",
@@ -642,7 +642,7 @@ void nvim_set_vvar(String name, Object value, Error *err)
dict_set_var(&vimvardict, name, value, false, false, err);
}
-/// Gets an option value string.
+/// Gets the global value of an option.
///
/// @param name Option name
/// @param[out] err Error details, if any
@@ -653,6 +653,115 @@ Object nvim_get_option(String name, Error *err)
return get_option_from(NULL, SREQ_GLOBAL, name, err);
}
+/// Gets the value of an option. The behavior of this function matches that of
+/// |:set|: the local value of an option is returned if it exists; otherwise,
+/// the global value is returned. Local values always correspond to the current
+/// buffer or window. To get a buffer-local or window-local option for a
+/// specific buffer or window, use |nvim_buf_get_option()| or
+/// |nvim_win_get_option()|.
+///
+/// @param name Option name
+/// @param opts Optional parameters
+/// - scope: One of 'global' or 'local'. Analagous to
+/// |:setglobal| and |:setlocal|, respectively.
+/// @param[out] err Error details, if any
+/// @return Option value
+Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
+ FUNC_API_SINCE(9)
+{
+ Object rv = OBJECT_INIT;
+
+ int scope = 0;
+ if (opts->scope.type == kObjectTypeString) {
+ if (!strcmp(opts->scope.data.string.data, "local")) {
+ scope = OPT_LOCAL;
+ } else if (!strcmp(opts->scope.data.string.data, "global")) {
+ scope = OPT_GLOBAL;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'");
+ goto end;
+ }
+ } else if (HAS_KEY(opts->scope)) {
+ api_set_error(err, kErrorTypeValidation, "invalid value for key: scope");
+ goto end;
+ }
+
+ long numval = 0;
+ char *stringval = NULL;
+ switch (get_option_value(name.data, &numval, (char_u **)&stringval, scope)) {
+ case 0:
+ rv = STRING_OBJ(cstr_as_string(stringval));
+ break;
+ case 1:
+ rv = INTEGER_OBJ(numval);
+ break;
+ case 2:
+ rv = BOOLEAN_OBJ(!!numval);
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data);
+ goto end;
+ }
+
+end:
+ return rv;
+}
+
+/// Sets the value of an option. The behavior of this function matches that of
+/// |:set|: for global-local options, both the global and local value are set
+/// unless otherwise specified with {scope}.
+///
+/// @param name Option name
+/// @param value New option value
+/// @param opts Optional parameters
+/// - scope: One of 'global' or 'local'. Analagous to
+/// |:setglobal| and |:setlocal|, respectively.
+/// @param[out] err Error details, if any
+void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err)
+ FUNC_API_SINCE(9)
+{
+ int scope = 0;
+ if (opts->scope.type == kObjectTypeString) {
+ if (!strcmp(opts->scope.data.string.data, "local")) {
+ scope = OPT_LOCAL;
+ } else if (!strcmp(opts->scope.data.string.data, "global")) {
+ scope = OPT_GLOBAL;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'");
+ return;
+ }
+ } else if (HAS_KEY(opts->scope)) {
+ api_set_error(err, kErrorTypeValidation, "invalid value for key: scope");
+ return;
+ }
+
+ long numval = 0;
+ char *stringval = NULL;
+
+ switch (value.type) {
+ case kObjectTypeInteger:
+ numval = value.data.integer;
+ break;
+ case kObjectTypeBoolean:
+ numval = value.data.boolean ? 1 : 0;
+ break;
+ case kObjectTypeString:
+ stringval = value.data.string.data;
+ break;
+ case kObjectTypeNil:
+ // Do nothing
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "invalid value for option");
+ return;
+ }
+
+ char *e = set_option_value(name.data, numval, stringval, scope);
+ if (e) {
+ api_set_error(err, kErrorTypeException, "%s", e);
+ }
+}
+
/// Gets the option information for all options.
///
/// The dictionary has the full option names as keys and option metadata
@@ -694,7 +803,7 @@ Dictionary nvim_get_option_info(String name, Error *err)
return get_vimoption(name, err);
}
-/// Sets an option value.
+/// Sets the global value of an option.
///
/// @param channel_id
/// @param name Option name
@@ -733,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");
@@ -1733,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/api/vimscript.c b/src/nvim/api/vimscript.c
index c516cedaf4..640144b234 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -390,7 +390,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
FUNC_API_SINCE(4) FUNC_API_FAST
{
int pflags = 0;
- for (size_t i = 0 ; i < flags.size ; i++) {
+ for (size_t i = 0; i < flags.size; i++) {
switch (flags.data[i]) {
case 'm':
pflags |= kExprFlagsMulti; break;
@@ -478,7 +478,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
.capacity = kv_size(colors),
.size = kv_size(colors),
};
- for (size_t i = 0 ; i < kv_size(colors) ; i++) {
+ for (size_t i = 0; i < kv_size(colors); i++) {
const ParserHighlightChunk chunk = kv_A(colors, i);
Array chunk_arr = (Array) {
.items = xmalloc(4 * sizeof(chunk_arr.items[0])),
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index ad92d9a2af..65519a8004 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -1,3 +1,5 @@
+// uncrustify:off
+
#ifndef NVIM_ASSERT_H
#define NVIM_ASSERT_H
diff --git a/src/nvim/aucmd.c b/src/nvim/aucmd.c
index af519dcba9..d7f73fa4a1 100644
--- a/src/nvim/aucmd.c
+++ b/src/nvim/aucmd.c
@@ -25,13 +25,14 @@ void do_autocmd_uienter(uint64_t chanid, bool attached)
}
recursive = true;
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
assert(chanid < VARNUMBER_MAX);
tv_dict_add_nr(dict, S_LEN("chan"), (varnumber_T)chanid);
tv_dict_set_keys_readonly(dict);
apply_autocmds(attached ? EVENT_UIENTER : EVENT_UILEAVE,
NULL, NULL, false, curbuf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
recursive = false;
}
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 6be51c504c..8fe623fc96 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -37,6 +37,7 @@ return {
'CursorHoldI', -- idem, in Insert mode
'CursorMoved', -- cursor was moved
'CursorMovedI', -- cursor was moved in Insert mode
+ 'DiagnosticChanged', -- diagnostics in a buffer were modified
'DiffUpdated', -- diffs have been updated
'DirChanged', -- directory changed
'EncodingChanged', -- after changing the 'encoding' option
@@ -69,11 +70,15 @@ return {
'InsertLeave', -- just after leaving Insert mode
'InsertLeavePre', -- just before leaving Insert mode
'MenuPopup', -- just before popup menu is displayed
+ 'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
'QuickFixCmdPost', -- after :make, :grep etc.
'QuickFixCmdPre', -- before :make, :grep etc.
'QuitPre', -- before :quit
+ 'RecordingEnter', -- when starting to record a macro
+ 'RecordingLeave', -- just before a macro stops recording
'RemoteReply', -- upon string reception from a remote vim
+ 'SearchWrapped', -- after the search wrapped around
'SessionLoadPost', -- after loading a session file
'ShellCmdPost', -- after ":!cmd"
'ShellFilterPost', -- after ":1,2!cmd", ":w !cmd", ":r !cmd".
@@ -126,7 +131,10 @@ return {
-- syntax file
nvim_specific = {
BufModifiedSet=true,
+ DiagnosticChanged=true,
DirChanged=true,
+ RecordingEnter=true,
+ RecordingLeave=true,
Signal=true,
TabClosed=true,
TabNew=true,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 2d0c0f3fd5..3780cad1d6 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -15,8 +15,8 @@
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
#include "nvim/state.h"
@@ -925,6 +925,13 @@ static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, c
return FAIL;
}
}
+
+ // need to initialize last_mode for the first ModeChanged autocmd
+ if (event == EVENT_MODECHANGED && !has_event(EVENT_MODECHANGED)) {
+ xfree(last_mode);
+ last_mode = get_mode();
+ }
+
ap->cmds = NULL;
*prev_ap = ap;
last_autopat[(int)event] = ap;
@@ -1206,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;
@@ -1440,7 +1450,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
// invalid.
if (fname_io == NULL) {
if (event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
- || event == EVENT_OPTIONSET) {
+ || event == EVENT_OPTIONSET || event == EVENT_MODECHANGED) {
autocmd_fname = NULL;
} else if (fname != NULL && !ends_excmd(*fname)) {
autocmd_fname = fname;
@@ -1494,11 +1504,12 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
|| event == EVENT_CMDWINLEAVE || event == EVENT_CMDUNDEFINED
|| event == EVENT_COLORSCHEME || event == EVENT_COLORSCHEMEPRE
|| event == EVENT_DIRCHANGED || event == EVENT_FILETYPE
- || event == EVENT_FUNCUNDEFINED || event == EVENT_OPTIONSET
- || event == EVENT_QUICKFIXCMDPOST || event == EVENT_QUICKFIXCMDPRE
- || event == EVENT_REMOTEREPLY || event == EVENT_SPELLFILEMISSING
- || event == EVENT_SYNTAX || event == EVENT_SIGNAL
- || event == EVENT_TABCLOSED || event == EVENT_WINCLOSED) {
+ || event == EVENT_FUNCUNDEFINED || event == EVENT_MODECHANGED
+ || event == EVENT_OPTIONSET || event == EVENT_QUICKFIXCMDPOST
+ || event == EVENT_QUICKFIXCMDPRE || event == EVENT_REMOTEREPLY
+ || event == EVENT_SPELLFILEMISSING || event == EVENT_SYNTAX
+ || event == EVENT_SIGNAL || event == EVENT_TABCLOSED
+ || event == EVENT_WINCLOSED) {
fname = vim_strsave(fname);
} else {
fname = (char_u *)FullName_save((char *)fname, false);
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index e9d89c2f91..89baea83f8 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -57,7 +57,6 @@
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
@@ -1305,7 +1304,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit)
if (buf == NULL) { // No previous buffer, Try 2'nd approach
forward = true;
buf = curbuf->b_next;
- for (;; ) {
+ for (;;) {
if (buf == NULL) {
if (!forward) { // tried both directions
break;
@@ -1587,7 +1586,7 @@ void do_autochdir(void)
if (starting == 0
&& curbuf->b_ffname != NULL
&& vim_chdirfile(curbuf->b_ffname, kCdCauseAuto) == OK) {
- post_chdir(kCdScopeGlobal, false);
+ last_chdir_reason = "autochdir";
shorten_fnames(true);
}
}
@@ -2163,7 +2162,7 @@ int buflist_findpat(const char_u *pattern, const char_u *pattern_end, bool unlis
// First try finding a listed buffer. If not found and "unlisted"
// is true, try finding an unlisted buffer.
find_listed = true;
- for (;; ) {
+ for (;;) {
for (attempt = 0; attempt <= 3; attempt++) {
// may add '^' and '$'
if (toggledollar) {
@@ -2719,7 +2718,7 @@ void buflist_list(exarg_T *eap)
IObuff[len++] = ' ';
} while (--i > 0 && len < IOSIZE - 18);
if (vim_strchr(eap->arg, 't') && buf->b_last_used) {
- add_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used);
+ undo_fmt_time(IObuff + len, (size_t)(IOSIZE - len), buf->b_last_used);
} else {
vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
_("line %" PRId64),
@@ -3130,7 +3129,7 @@ void fileinfo(int fullname, int shorthelp, int dont_truncate)
// before redrawing).
// - When the screen was scrolled but there is no wait-return
// prompt.
- set_keep_msg((char_u *)p, 0);
+ set_keep_msg(p, 0);
}
}
@@ -3429,7 +3428,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
static int *stl_separator_locations = NULL;
#define TMPLEN 70
- char_u buf_tmp[TMPLEN];
+ char buf_tmp[TMPLEN];
char_u win_tmp[TMPLEN];
char_u *usefmt = fmt;
const int save_must_redraw = must_redraw;
@@ -3511,7 +3510,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Proceed character by character through the statusline format string
// fmt_p is the current position in the input buffer
- for (char_u *fmt_p = usefmt; *fmt_p; ) {
+ for (char_u *fmt_p = usefmt; *fmt_p;) {
if (curitem == (int)stl_items_len) {
size_t new_len = stl_items_len * 3 / 2;
@@ -3856,7 +3855,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
bool itemisflag = false;
bool fillable = true;
long num = -1;
- char_u *str = NULL;
+ char *str = NULL;
switch (opt) {
case STL_FILEPATH:
case STL_FULLPATH:
@@ -3873,9 +3872,9 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
}
trans_characters(NameBuff, MAXPATHL);
if (opt != STL_FILENAME) {
- str = NameBuff;
+ str = (char *)NameBuff;
} else {
- str = path_tail(NameBuff);
+ str = (char *)path_tail(NameBuff);
}
break;
case STL_VIM_EXPR: // '{'
@@ -3912,8 +3911,8 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// { Evaluate the expression
// Store the current buffer number as a string variable
- vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum);
- set_internal_string_var("g:actual_curbuf", buf_tmp);
+ vim_snprintf(buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum);
+ set_internal_string_var("g:actual_curbuf", (char_u *)buf_tmp);
vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->handle);
set_internal_string_var("g:actual_curwin", win_tmp);
@@ -3928,7 +3927,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
}
// Note: The result stored in `t` is unused.
- str = eval_to_string_safe(out_p, &t, use_sandbox);
+ str = (char *)eval_to_string_safe(out_p, &t, use_sandbox);
curwin = save_curwin;
curbuf = save_curbuf;
@@ -3943,8 +3942,8 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Check if the evaluated result is a number.
// If so, convert the number to an int and free the string.
if (str != NULL && *str != 0) {
- if (*skipdigits(str) == NUL) {
- num = atoi((char *)str);
+ if (*skipdigits((char_u *)str) == NUL) {
+ num = atoi(str);
XFREE_CLEAR(str);
itemisflag = false;
}
@@ -3957,8 +3956,8 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
&& strchr((const char *)str, '%') != NULL
&& evaldepth < MAX_STL_EVAL_DEPTH) {
size_t parsed_usefmt = (size_t)(block_start - usefmt);
- size_t str_length = strlen((const char *)str);
- size_t fmt_length = strlen((const char *)fmt_p);
+ size_t str_length = STRLEN(str);
+ size_t fmt_length = STRLEN(fmt_p);
size_t new_fmt_len = parsed_usefmt
+ str_length + fmt_length + 3;
char_u *new_fmt = (char_u *)xmalloc(new_fmt_len * sizeof(char_u));
@@ -4029,7 +4028,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Store the position percentage in our temporary buffer.
// Note: We cannot store the value in `num` because
// `get_rel_pos` can return a named position. Ex: "Top"
- get_rel_pos(wp, buf_tmp, TMPLEN);
+ get_rel_pos(wp, (char_u *)buf_tmp, TMPLEN);
str = buf_tmp;
break;
@@ -4044,14 +4043,14 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// Note: The call will only return true if it actually
// appended data to the `buf_tmp` buffer.
- if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), false)) {
+ if (append_arg_number(wp, (char_u *)buf_tmp, (int)sizeof(buf_tmp), false)) {
str = buf_tmp;
}
break;
case STL_KEYMAP:
fillable = false;
- if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN)) {
+ if (get_keymap_str(wp, (char_u *)"<%s>", (char_u *)buf_tmp, TMPLEN)) {
str = buf_tmp;
}
break;
@@ -4090,7 +4089,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
case STL_ROFLAG_ALT:
itemisflag = true;
if (wp->w_buffer->b_p_ro) {
- str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"));
+ str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]");
}
break;
@@ -4098,8 +4097,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
case STL_HELPFLAG_ALT:
itemisflag = true;
if (wp->w_buffer->b_help) {
- str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
- : _("[Help]"));
+ str = (opt == STL_HELPFLAG_ALT) ? ",HLP" : _("[Help]");
}
break;
@@ -4109,7 +4107,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// (including the brackets and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) {
- vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]",
+ vim_snprintf(buf_tmp, sizeof(buf_tmp), "[%s]",
wp->w_buffer->b_p_ft);
str = buf_tmp;
}
@@ -4122,10 +4120,10 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// (including the comma and null terminating character)
if (*wp->w_buffer->b_p_ft != NUL
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) {
- vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s",
+ vim_snprintf(buf_tmp, sizeof(buf_tmp), ",%s",
wp->w_buffer->b_p_ft);
// Uppercase the file extension
- for (char_u *t = buf_tmp; *t != 0; t++) {
+ for (char_u *t = (char_u *)buf_tmp; *t != 0; t++) {
*t = (char_u)TOUPPER_LOC(*t);
}
str = buf_tmp;
@@ -4135,16 +4133,13 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
case STL_PREVIEWFLAG_ALT:
itemisflag = true;
if (wp->w_p_pvw) {
- str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
- : _("[Preview]"));
+ str = (opt == STL_PREVIEWFLAG_ALT) ? ",PRV" : _("[Preview]");
}
break;
case STL_QUICKFIX:
if (bt_quickfix(wp->w_buffer)) {
- str = (char_u *)(wp->w_llist_ref
- ? _(msg_loclist)
- : _(msg_qflist));
+ str = wp->w_llist_ref ? _(msg_loclist) : _(msg_qflist);
}
break;
@@ -4155,17 +4150,17 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
+ bufIsChanged(wp->w_buffer) * 2
+ (!MODIFIABLE(wp->w_buffer)) * 4) {
case 2:
- str = (char_u *)"[+]"; break;
+ str = "[+]"; break;
case 3:
- str = (char_u *)",+"; break;
+ str = ",+"; break;
case 4:
- str = (char_u *)"[-]"; break;
+ str = "[-]"; break;
case 5:
- str = (char_u *)",-"; break;
+ str = ",-"; break;
case 6:
- str = (char_u *)"[+-]"; break;
+ str = "[+-]"; break;
case 7:
- str = (char_u *)",+-"; break;
+ str = ",+-"; break;
}
break;
@@ -4199,7 +4194,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
if (str != NULL && *str) {
// { Skip the leading `,` or ` ` if the item is a flag
// and the proper conditions are met
- char_u *t = str;
+ char_u *t = (char_u *)str;
if (itemisflag) {
if ((t[0] && t[1])
&& ((!prevchar_isitem && *t == ',')
@@ -4411,7 +4406,7 @@ int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use
// string to find the last character that will fit.
trunc_p = out;
width = 0;
- for (;; ) {
+ for (;;) {
width += ptr2cells(trunc_p);
if (width >= maxwidth) {
break;
@@ -4762,7 +4757,7 @@ void do_arg_all(int count, int forceit, int keep_tabs)
if (had_tab > 0) {
goto_tabpage_tp(first_tabpage, true, true);
}
- for (;; ) {
+ for (;;) {
win_T *wpnext = NULL;
tpnext = curtab->tp_next;
for (win_T *wp = firstwin; wp != NULL; wp = wpnext) {
@@ -5013,7 +5008,7 @@ void ex_buffer_all(exarg_T *eap)
if (had_tab > 0) {
goto_tabpage_tp(first_tabpage, true, true);
}
- for (;; ) {
+ for (;;) {
tpnext = curtab->tp_next;
for (wp = firstwin; wp != NULL; wp = wpnext) {
wpnext = wp->w_next;
@@ -5024,8 +5019,8 @@ void ex_buffer_all(exarg_T *eap)
: wp->w_width != Columns)
|| (had_tab > 0 && wp != firstwin))
&& !ONE_WINDOW
- && !(wp->w_closing ||
- wp->w_buffer->b_locked > 0)) {
+ && !(wp->w_closing
+ || wp->w_buffer->b_locked > 0)) {
win_close(wp, false);
wpnext = firstwin; // just in case an autocommand does
// something strange with windows
@@ -5142,7 +5137,7 @@ void ex_buffer_all(exarg_T *eap)
/*
* Close superfluous windows.
*/
- for (wp = lastwin; open_wins > count; ) {
+ for (wp = lastwin; open_wins > count;) {
r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
|| autowrite(wp->w_buffer, false) == OK);
if (!win_valid(wp)) {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index bd9c5efa44..49e527e98b 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1121,14 +1121,14 @@ typedef struct {
/// @{
enum {
MENU_INDEX_INVALID = -1,
- MENU_INDEX_NORMAL = 0,
- MENU_INDEX_VISUAL = 1,
- MENU_INDEX_SELECT = 2,
- MENU_INDEX_OP_PENDING = 3,
- MENU_INDEX_INSERT = 4,
- MENU_INDEX_CMDLINE = 5,
- MENU_INDEX_TIP = 6,
- MENU_MODES = 7,
+ MENU_INDEX_NORMAL = 0,
+ MENU_INDEX_VISUAL = 1,
+ MENU_INDEX_SELECT = 2,
+ MENU_INDEX_OP_PENDING = 3,
+ MENU_INDEX_INSERT = 4,
+ MENU_INDEX_CMDLINE = 5,
+ MENU_INDEX_TIP = 6,
+ MENU_MODES = 7,
};
typedef struct VimMenu vimmenu_T;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 6ec4979dac..1dbbfff024 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -19,7 +19,6 @@
#include "nvim/indent_c.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/plines.h"
@@ -131,7 +130,7 @@ void changed_internal(void)
curbuf->b_changed = true;
curbuf->b_changed_invalid = true;
ml_setflags(curbuf);
- check_status(curbuf);
+ redraw_buf_status_later(curbuf);
redraw_tabline = true;
need_maketitle = true; // set window title later
}
@@ -517,7 +516,7 @@ void unchanged(buf_T *buf, int ff, bool always_inc_changedtick)
if (ff) {
save_file_ff(buf);
}
- check_status(buf);
+ redraw_buf_status_later(buf);
redraw_tabline = true;
need_maketitle = true; // set window title later
buf_inc_changedtick(buf);
@@ -625,7 +624,7 @@ void ins_char_bytes(char_u *buf, size_t charlen)
}
}
- char_u *newp = xmalloc((size_t)(linelen + newlen - oldlen));
+ char_u *newp = xmalloc(linelen + newlen - oldlen);
// Copy bytes before the cursor.
if (col > 0) {
@@ -1355,7 +1354,7 @@ int open_line(int dir, int flags, int second_line_indent)
int c = 0;
int off = 0;
- for (p = lead_flags; *p != NUL && *p != ':'; ) {
+ for (p = lead_flags; *p != NUL && *p != ':';) {
if (*p == COM_RIGHT || *p == COM_LEFT) {
c = *p++;
} else if (ascii_isdigit(*p) || *p == '-') {
@@ -1841,7 +1840,7 @@ void del_lines(long nlines, bool undo)
return;
}
- for (n = 0; n < nlines; ) {
+ for (n = 0; n < nlines;) {
if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete
break;
}
@@ -1863,3 +1862,289 @@ void del_lines(long nlines, bool undo)
// adjust marks, mark the buffer as changed and prepare for displaying
deleted_lines_mark(first, n);
}
+
+/// Returns the length in bytes of the prefix of the given string which introduces a comment.
+///
+/// If this string is not a comment then 0 is returned.
+/// When "flags" is not NULL, it is set to point to the flags of the recognized comment leader.
+/// "backward" must be true for the "O" command.
+/// If "include_space" is set, include trailing whitespace while calculating the length.
+int get_leader_len(char_u *line, char_u **flags, bool backward, bool include_space)
+{
+ int i, j;
+ int result;
+ int got_com = false;
+ int found_one;
+ char_u part_buf[COM_MAX_LEN]; // buffer for one option part
+ char_u *string; // pointer to comment string
+ char_u *list;
+ int middle_match_len = 0;
+ char_u *prev_list;
+ char_u *saved_flags = NULL;
+
+ result = i = 0;
+ while (ascii_iswhite(line[i])) { // leading white space is ignored
+ i++;
+ }
+
+ // Repeat to match several nested comment strings.
+ while (line[i] != NUL) {
+ // scan through the 'comments' option for a match
+ found_one = false;
+ for (list = curbuf->b_p_com; *list;) {
+ // Get one option part into part_buf[]. Advance "list" to next
+ // one. Put "string" at start of string.
+ if (!got_com && flags != NULL) {
+ *flags = list; // remember where flags started
+ }
+ prev_list = list;
+ (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ string = vim_strchr(part_buf, ':');
+ if (string == NULL) { // missing ':', ignore this part
+ continue;
+ }
+ *string++ = NUL; // isolate flags from string
+
+ // If we found a middle match previously, use that match when this
+ // is not a middle or end.
+ if (middle_match_len != 0
+ && vim_strchr(part_buf, COM_MIDDLE) == NULL
+ && vim_strchr(part_buf, COM_END) == NULL) {
+ break;
+ }
+
+ // When we already found a nested comment, only accept further
+ // nested comments.
+ if (got_com && vim_strchr(part_buf, COM_NEST) == NULL) {
+ continue;
+ }
+
+ // When 'O' flag present and using "O" command skip this one.
+ if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL) {
+ continue;
+ }
+
+ // Line contents and string must match.
+ // When string starts with white space, must have some white space
+ // (but the amount does not need to match, there might be a mix of
+ // TABs and spaces).
+ if (ascii_iswhite(string[0])) {
+ if (i == 0 || !ascii_iswhite(line[i - 1])) {
+ continue; // missing white space
+ }
+ while (ascii_iswhite(string[0])) {
+ string++;
+ }
+ }
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; j++) {
+ }
+ if (string[j] != NUL) {
+ continue; // string doesn't match
+ }
+ // When 'b' flag used, there must be white space or an
+ // end-of-line after the string in the line.
+ if (vim_strchr(part_buf, COM_BLANK) != NULL
+ && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
+ continue;
+ }
+
+ // We have found a match, stop searching unless this is a middle
+ // comment. The middle comment can be a substring of the end
+ // comment in which case it's better to return the length of the
+ // end comment and its flags. Thus we keep searching with middle
+ // and end matches and use an end match if it matches better.
+ if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
+ if (middle_match_len == 0) {
+ middle_match_len = j;
+ saved_flags = prev_list;
+ }
+ continue;
+ }
+ if (middle_match_len != 0 && j > middle_match_len) {
+ // Use this match instead of the middle match, since it's a
+ // longer thus better match.
+ middle_match_len = 0;
+ }
+
+ if (middle_match_len == 0) {
+ i += j;
+ }
+ found_one = true;
+ break;
+ }
+
+ if (middle_match_len != 0) {
+ // Use the previously found middle match after failing to find a
+ // match with an end.
+ if (!got_com && flags != NULL) {
+ *flags = saved_flags;
+ }
+ i += middle_match_len;
+ found_one = true;
+ }
+
+ // No match found, stop scanning.
+ if (!found_one) {
+ break;
+ }
+
+ result = i;
+
+ // Include any trailing white space.
+ while (ascii_iswhite(line[i])) {
+ i++;
+ }
+
+ if (include_space) {
+ result = i;
+ }
+
+ // If this comment doesn't nest, stop here.
+ got_com = true;
+ if (vim_strchr(part_buf, COM_NEST) == NULL) {
+ break;
+ }
+ }
+ return result;
+}
+
+/// Return the offset at which the last comment in line starts. If there is no
+/// comment in the whole line, -1 is returned.
+///
+/// When "flags" is not null, it is set to point to the flags describing the
+/// recognized comment leader.
+int get_last_leader_offset(char_u *line, char_u **flags)
+{
+ int result = -1;
+ int i, j;
+ int lower_check_bound = 0;
+ char_u *string;
+ char_u *com_leader;
+ char_u *com_flags;
+ char_u *list;
+ int found_one;
+ char_u part_buf[COM_MAX_LEN]; // buffer for one option part
+
+ // Repeat to match several nested comment strings.
+ i = (int)STRLEN(line);
+ while (--i >= lower_check_bound) {
+ // scan through the 'comments' option for a match
+ found_one = false;
+ for (list = curbuf->b_p_com; *list;) {
+ char_u *flags_save = list;
+
+ // Get one option part into part_buf[]. Advance list to next one.
+ // put string at start of string.
+ (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
+ string = vim_strchr(part_buf, ':');
+ if (string == NULL) { // If everything is fine, this cannot actually
+ // happen.
+ continue;
+ }
+ *string++ = NUL; // Isolate flags from string.
+ com_leader = string;
+
+ // Line contents and string must match.
+ // When string starts with white space, must have some white space
+ // (but the amount does not need to match, there might be a mix of
+ // TABs and spaces).
+ if (ascii_iswhite(string[0])) {
+ if (i == 0 || !ascii_iswhite(line[i - 1])) {
+ continue;
+ }
+ while (ascii_iswhite(*string)) {
+ string++;
+ }
+ }
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; j++) {
+ // do nothing
+ }
+ if (string[j] != NUL) {
+ continue;
+ }
+
+ // When 'b' flag used, there must be white space or an
+ // end-of-line after the string in the line.
+ if (vim_strchr(part_buf, COM_BLANK) != NULL
+ && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
+ continue;
+ }
+
+ if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
+ // For a middlepart comment, only consider it to match if
+ // everything before the current position in the line is
+ // whitespace. Otherwise we would think we are inside a
+ // comment if the middle part appears somewhere in the middle
+ // of the line. E.g. for C the "*" appears often.
+ for (j = 0; j <= i && ascii_iswhite(line[j]); j++) {
+ }
+ if (j < i) {
+ continue;
+ }
+ }
+
+ // We have found a match, stop searching.
+ found_one = true;
+
+ if (flags) {
+ *flags = flags_save;
+ }
+ com_flags = flags_save;
+
+ break;
+ }
+
+ if (found_one) {
+ char_u part_buf2[COM_MAX_LEN]; // buffer for one option part
+ int len1, len2, off;
+
+ result = i;
+ // If this comment nests, continue searching.
+ if (vim_strchr(part_buf, COM_NEST) != NULL) {
+ continue;
+ }
+
+ lower_check_bound = i;
+
+ // Let's verify whether the comment leader found is a substring
+ // of other comment leaders. If it is, let's adjust the
+ // lower_check_bound so that we make sure that we have determined
+ // the comment leader correctly.
+
+ while (ascii_iswhite(*com_leader)) {
+ com_leader++;
+ }
+ len1 = (int)STRLEN(com_leader);
+
+ for (list = curbuf->b_p_com; *list;) {
+ char_u *flags_save = list;
+
+ (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
+ if (flags_save == com_flags) {
+ continue;
+ }
+ string = vim_strchr(part_buf2, ':');
+ string++;
+ while (ascii_iswhite(*string)) {
+ string++;
+ }
+ len2 = (int)STRLEN(string);
+ if (len2 == 0) {
+ continue;
+ }
+
+ // Now we have to verify whether string ends with a substring
+ // beginning the com_leader.
+ for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2;) {
+ off--;
+ if (!STRNCMP(string + off, com_leader, len2 - off)) {
+ if (i - off < lower_check_bound) {
+ lower_check_bound = i - off;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
diff --git a/src/nvim/change.h b/src/nvim/change.h
index e1a1bfba17..e7c8a2b031 100644
--- a/src/nvim/change.h
+++ b/src/nvim/change.h
@@ -4,6 +4,13 @@
#include "nvim/buffer_defs.h" // for buf_T
#include "nvim/pos.h" // for linenr_T
+// flags for open_line()
+#define OPENLINE_DELSPACES 1 // delete spaces after cursor
+#define OPENLINE_DO_COM 2 // format comments
+#define OPENLINE_KEEPTRAIL 4 // keep trailing spaces
+#define OPENLINE_MARKFIX 8 // fix mark positions
+#define OPENLINE_COM_LIST 16 // format comments with list/2nd line indent
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "change.h.generated.h"
#endif
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 9662f6205f..cd5134fe5f 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -821,7 +821,8 @@ static void set_info_event(void **argv)
Channel *chan = argv[0];
event_T event = (event_T)(ptrdiff_t)argv[1];
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
Dictionary info = channel_info(chan->id);
typval_T retval;
(void)object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
@@ -829,7 +830,7 @@ static void set_info_event(void **argv)
apply_autocmds(event, NULL, NULL, false, curbuf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
api_free_dictionary(info);
channel_decref(chan);
}
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 5e18f9d86e..599d662993 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -21,7 +21,6 @@
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os_unix.h"
@@ -1642,6 +1641,16 @@ int hex2nr(int c)
return c - '0';
}
+/// Convert two hex characters to a byte.
+/// Return -1 if one of the characters is not hex.
+int hexhex2nr(char_u *p)
+{
+ if (!ascii_isxdigit(p[0]) || !ascii_isxdigit(p[1])) {
+ return -1;
+ }
+ return (hex2nr(p[0]) << 4) + hex2nr(p[1]);
+}
+
/// Check that "str" starts with a backslash that should be removed.
/// For Windows this is only done when the character after the
/// backslash is not a normal file name character.
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..6e2c6232d7 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -14,7 +14,6 @@
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/plines.h"
#include "nvim/screen.h"
@@ -108,6 +107,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/cursor_shape.c b/src/nvim/cursor_shape.c
index 644bb2c324..6b0a5dfe12 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -168,7 +168,7 @@ char *parse_shape_opt(int what)
}
// Parse the part after the colon
- for (p = colonp + 1; *p && *p != ','; ) {
+ for (p = colonp + 1; *p && *p != ',';) {
{
/*
* First handle the ones with a number argument.
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c
index 3ac128a20f..b6e35f3047 100644
--- a/src/nvim/debugger.c
+++ b/src/nvim/debugger.c
@@ -109,7 +109,7 @@ void do_debug(char_u *cmd)
smsg(_("cmd: %s"), cmd);
}
// Repeat getting a command and executing it.
- for (;; ) {
+ for (;;) {
msg_scroll = true;
need_wait_return = false;
// Save the current typeahead buffer and replace it with an empty one.
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 4e03f4761c..0233b3a5ab 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -29,7 +29,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
@@ -39,6 +38,7 @@
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
+#include "nvim/ui.h"
#include "nvim/vim.h"
#include "nvim/window.h"
#include "xdiff/xdiff.h"
@@ -739,7 +739,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
len = 0;
for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
- for (s = ml_get_buf(buf, lnum, false); *s != NUL; ) {
+ for (s = ml_get_buf(buf, lnum, false); *s != NUL;) {
if (diff_flags & DIFF_ICASE) {
char_u cbuf[MB_MAXBYTES + 1];
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index d1dd9b8309..8eda173cac 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -20,7 +20,6 @@
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/normal.h"
#include "nvim/os/input.h"
#include "nvim/screen.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index ca903fdcf7..2135d0bcd2 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -35,7 +35,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -227,6 +226,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 +290,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
@@ -385,6 +386,7 @@ static void insert_enter(InsertState *s)
State = INSERT;
}
+ trigger_modechanged();
stop_insert_mode = false;
// Need to recompute the cursor position, it might move when the cursor is
@@ -584,7 +586,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
@@ -654,10 +657,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.
@@ -821,6 +831,16 @@ static int insert_execute(VimState *state, int key)
return insert_handle_key(s);
}
+
+/// Return true when need to go to Insert mode because of 'insertmode'.
+///
+/// Don't do this when still processing a command or a mapping.
+/// Don't do this when inside a ":normal" command.
+bool goto_im(void)
+{
+ return p_im && stuff_empty() && typebuf_typed();
+}
+
static int insert_handle_key(InsertState *s)
{
// The big switch to handle a character in insert mode.
@@ -983,6 +1003,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;
@@ -1652,10 +1681,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.
@@ -2048,6 +2088,8 @@ static void ins_ctrl_x(void)
// CTRL-V look like CTRL-N
ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
}
+
+ trigger_modechanged();
}
// Whether other than default completion has been selected.
@@ -2660,6 +2702,7 @@ void set_completion(colnr_T startcol, list_T *list)
show_pum(save_w_wrow, save_w_leftcol);
}
+ trigger_modechanged();
ui_flush();
}
@@ -2715,12 +2758,13 @@ static bool pum_enough_matches(void)
static void trigger_complete_changed_event(int cur)
{
static bool recursive = false;
+ save_v_event_T save_v_event;
if (recursive) {
return;
}
- dict_T *v_event = get_vim_var_dict(VV_EVENT);
+ dict_T *v_event = get_v_event(&save_v_event);
if (cur < 0) {
tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
} else {
@@ -2736,7 +2780,7 @@ static void trigger_complete_changed_event(int cur)
textlock--;
recursive = false;
- tv_dict_clear(v_event);
+ restore_v_event(v_event, &save_v_event);
}
/// Show the popup menu for the list of matches.
@@ -3292,16 +3336,11 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
dict_T *di = tv_dict_alloc();
tv_list_append_dict(li, di);
- tv_dict_add_str(di, S_LEN("word"),
- (char *)EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(di, S_LEN("abbr"),
- (char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(di, S_LEN("menu"),
- (char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(di, S_LEN("kind"),
- (char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(di, S_LEN("info"),
- (char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
+ tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
tv_dict_add_str(di, S_LEN("user_data"), "");
} else {
@@ -3843,6 +3882,8 @@ static bool ins_compl_prep(int c)
ins_apply_autocmds(EVENT_COMPLETEDONE);
}
+ trigger_modechanged();
+
/* reset continue_* if we left expansion-mode, if we stay they'll be
* (re)set properly in ins_complete() */
if (!vim_is_ctrl_x_key(c)) {
@@ -3924,7 +3965,8 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
/// Get the user-defined completion function name for completion 'type'
-static char_u *get_complete_funcname(int type) {
+static char_u *get_complete_funcname(int type)
+{
switch (type) {
case CTRL_X_FUNCTION:
return curbuf->b_p_cfu;
@@ -4171,7 +4213,7 @@ static int ins_compl_get_exp(pos_T *ini)
pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
// For ^N/^P loop over all the flags/windows/buffers in 'complete'
- for (;; ) {
+ for (;;) {
found_new_match = FAIL;
set_match_pos = false;
@@ -4389,7 +4431,7 @@ static int ins_compl_get_exp(pos_T *ini)
p_ws = true;
}
bool looped_around = false;
- for (;; ) {
+ for (;;) {
bool cont_s_ipos = false;
msg_silent++; // Don't want messages for wrapscan.
@@ -4591,6 +4633,8 @@ static int ins_compl_get_exp(pos_T *ini)
compl_curr_match = compl_old_match;
}
}
+ trigger_modechanged();
+
return i;
}
@@ -4635,16 +4679,11 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
{
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
- tv_dict_add_str(dict, S_LEN("word"),
- (const char *)EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(dict, S_LEN("abbr"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(dict, S_LEN("menu"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(dict, S_LEN("kind"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(dict, S_LEN("info"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
+ tv_dict_add_str(dict, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(dict, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(dict, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(dict, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(dict, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
tv_dict_add_str(dict, S_LEN("user_data"), "");
} else {
@@ -5241,7 +5280,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;
@@ -5580,7 +5619,7 @@ int get_literal(void)
no_mapping++; // don't map the next key hits
cc = 0;
i = 0;
- for (;; ) {
+ for (;;) {
nc = plain_vgetc();
if (!(State & CMDLINE)
&& MB_BYTE2LEN_CHECK(nc) == 1) {
@@ -6574,7 +6613,7 @@ static void spell_back_to_badword(void)
int stop_arrow(void)
{
if (arrow_used) {
- Insstart = curwin->w_cursor; //new insertion starts here
+ Insstart = curwin->w_cursor; // new insertion starts here
if (Insstart.col > Insstart_orig.col && !ins_need_undo) {
// Don't update the original insert position when moved to the
// right, except when nothing was inserted yet.
@@ -6687,7 +6726,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
curwin->w_cursor = *end_insert_pos;
check_cursor_col(); // make sure it is not past the line
- for (;; ) {
+ for (;;) {
if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) {
--curwin->w_cursor.col;
}
@@ -6878,7 +6917,7 @@ int oneleft(void)
// We might get stuck on 'showbreak', skip over it.
width = 1;
- for (;; ) {
+ for (;;) {
coladvance(v - width);
// getviscol() is slow, skip it when 'showbreak' is empty,
// 'breakindent' is not set and there are no multi-byte
@@ -7212,7 +7251,7 @@ static void replace_join(int off)
{
int i;
- for (i = replace_stack_nr; --i >= 0; ) {
+ for (i = replace_stack_nr; --i >= 0;) {
if (replace_stack[i] == NUL && off-- <= 0) {
--replace_stack_nr;
memmove(replace_stack + i, replace_stack + i + 1,
@@ -7261,7 +7300,7 @@ static void mb_replace_pop_ins(int cc)
}
// Handle composing chars.
- for (;; ) {
+ for (;;) {
c = replace_pop();
if (c == -1) { // stack empty
break;
@@ -7640,16 +7679,34 @@ int hkmap(int c)
KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV,
};
- static char_u map[26] =
- { (char_u)hALEF /*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
- (char_u)DALET /*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit /*f*/,
- (char_u)GIMEL /*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
- (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
- (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
- (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
- (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
- (char_u)VAV /*v*/, (char_u)hSHIN /*w*/, (char_u)-1 /*x*/,
- (char_u)AIN /*y*/, (char_u)ZADI /*z*/ };
+ static char_u map[26] = {
+ (char_u)hALEF, // a
+ (char_u)BET, // b
+ (char_u)hKAF, // c
+ (char_u)DALET, // d
+ (char_u)-1, // e
+ (char_u)PEIsofit, // f
+ (char_u)GIMEL, // g
+ (char_u)HEI, // h
+ (char_u)IUD, // i
+ (char_u)HET, // j
+ (char_u)KOF, // k
+ (char_u)LAMED, // l
+ (char_u)MEM, // m
+ (char_u)NUN, // n
+ (char_u)SAMEH, // o
+ (char_u)PEI, // p
+ (char_u)-1, // q
+ (char_u)RESH, // r
+ (char_u)ZAIN, // s
+ (char_u)TAV, // t
+ (char_u)TET, // u
+ (char_u)VAV, // v
+ (char_u)hSHIN, // w
+ (char_u)-1, // x
+ (char_u)AIN, // y
+ (char_u)ZADI, // z
+ };
if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') {
return (int)(map[CharOrd(c)] - 1 + p_aleph);
@@ -7975,6 +8032,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
State = NORMAL;
+ trigger_modechanged();
// need to position cursor again (e.g. when on a TAB )
changed_cline_bef_curs();
@@ -8076,6 +8134,7 @@ static void ins_insert(int replaceState)
} else {
State = replaceState | (State & LANGMAP);
}
+ trigger_modechanged();
AppendCharToRedobuff(K_INS);
showmode();
ui_cursor_shape(); // may show different cursor shape
@@ -8221,7 +8280,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
@@ -9022,7 +9081,7 @@ static bool ins_tab(void)
// correct replace stack.
if ((State & REPLACE_FLAG)
&& !(State & VREPLACE_FLAG)) {
- for (temp = i; --temp >= 0; ) {
+ for (temp = i; --temp >= 0;) {
replace_join(repl_off);
}
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0123c7265b..86384bc5b2 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -35,7 +35,6 @@
#include "nvim/lua/executor.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
@@ -134,13 +133,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 +151,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
@@ -298,6 +302,31 @@ const list_T *eval_msgpack_type_lists[] = {
[kMPExt] = NULL,
};
+dict_T *get_v_event(save_v_event_T *sve)
+{
+ dict_T *v_event = get_vim_var_dict(VV_EVENT);
+
+ if (v_event->dv_hashtab.ht_used > 0) {
+ // recursive use of v:event, save, make empty and restore later
+ sve->sve_did_save = true;
+ sve->sve_hashtab = v_event->dv_hashtab;
+ hash_init(&v_event->dv_hashtab);
+ } else {
+ sve->sve_did_save = false;
+ }
+ return v_event;
+}
+
+void restore_v_event(dict_T *v_event, save_v_event_T *sve)
+{
+ tv_dict_free_contents(v_event);
+ if (sve->sve_did_save) {
+ v_event->dv_hashtab = sve->sve_hashtab;
+ } else {
+ hash_init(&v_event->dv_hashtab);
+ }
+}
+
// Return "n1" divided by "n2", taking care of dividing by zero.
varnumber_T num_divide(varnumber_T n1, varnumber_T n2)
FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
@@ -344,7 +373,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;
@@ -1551,7 +1580,7 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count, int *semic
if (*arg == '[') {
// "[var, var]": find the matching ']'.
p = arg;
- for (;; ) {
+ for (;;) {
p = skipwhite(p + 1); // skip whites after '[', ';' or ','
s = skip_var_one(p);
if (s == p) {
@@ -2448,7 +2477,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, co
// Check whether any of the list items is locked
for (ri = tv_list_first(rettv->vval.v_list);
- ri != NULL && ll_li != NULL; ) {
+ ri != NULL && ll_li != NULL;) {
if (var_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name,
TV_CSTRING)) {
return;
@@ -2464,7 +2493,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, co
/*
* Assign the List values to the list items.
*/
- for (ri = tv_list_first(rettv->vval.v_list); ri != NULL; ) {
+ for (ri = tv_list_first(rettv->vval.v_list); ri != NULL;) {
if (op != NULL && *op != '=') {
eexe_mod_op(TV_LIST_ITEM_TV(lp->ll_li), TV_LIST_ITEM_TV(ri), op);
} else {
@@ -2691,7 +2720,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
xp->xp_context = EXPAND_USER_VARS;
if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL) {
// ":let var1 var2 ...": find last space.
- for (p = arg + STRLEN(arg); p >= arg; ) {
+ for (p = arg + STRLEN(arg); p >= arg;) {
xp->xp_pattern = p;
MB_PTR_BACK(arg, p);
if (ascii_iswhite(*p)) {
@@ -3732,7 +3761,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
/*
* Repeat computing, until no '+', '-' or '.' is following.
*/
- for (;; ) {
+ for (;;) {
op = **arg;
if (op != '+' && op != '-' && op != '.') {
break;
@@ -3907,7 +3936,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
/*
* Repeat computing, until no '*', '/' or '%' is following.
*/
- for (;; ) {
+ for (;;) {
op = **arg;
if (op != '*' && op != '/' && op != '%') {
break;
@@ -4523,7 +4552,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;
@@ -4828,7 +4857,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval
} else if (opt_type == -1) { // hidden number option
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
- } else if (opt_type == 1) { // number option
+ } else if (opt_type == 1 || opt_type == 2) { // number or boolean option
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = numval;
} else { // string option
@@ -4890,7 +4919,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = name;
- for (p = *arg + 1; *p != NUL && *p != '"'; ) {
+ for (p = *arg + 1; *p != NUL && *p != '"';) {
if (*p == '\\') {
switch (*++p) {
case 'b':
@@ -5026,7 +5055,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = str;
- for (p = *arg + 1; *p != NUL; ) {
+ for (p = *arg + 1; *p != NUL;) {
if (*p == '\'') {
if (p[1] != '\'') {
break;
@@ -6086,7 +6115,7 @@ int assert_equalfile(typval_T *argvars)
snprintf((char *)IObuff, IOSIZE, (char *)e_notread, fname2);
} else {
int64_t linecount = 1;
- for (int64_t count = 0; ; count++) {
+ for (int64_t count = 0;; count++) {
const int c1 = fgetc(fd1);
const int c2 = fgetc(fd2);
if (c1 == EOF) {
@@ -6603,8 +6632,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;
@@ -6851,7 +6881,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
tv_dict_add_nr(dict, S_LEN("width"), wp->w_width);
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1);
-
+ tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp));
tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
tv_dict_add_nr(dict, S_LEN("loclist"),
@@ -7146,30 +7176,30 @@ void dict_list(typval_T *const tv, typval_T *const rettv, const DictListType wha
typval_T tv_item = { .v_lock = VAR_UNLOCKED };
switch (what) {
- case kDictListKeys:
- tv_item.v_type = VAR_STRING;
- tv_item.vval.v_string = vim_strsave(di->di_key);
- break;
- case kDictListValues:
- tv_copy(&di->di_tv, &tv_item);
- break;
- case kDictListItems: {
- // items()
- list_T *const sub_l = tv_list_alloc(2);
- tv_item.v_type = VAR_LIST;
- tv_item.vval.v_list = sub_l;
- tv_list_ref(sub_l);
-
- tv_list_append_owned_tv(sub_l, (typval_T) {
+ case kDictListKeys:
+ tv_item.v_type = VAR_STRING;
+ tv_item.vval.v_string = vim_strsave(di->di_key);
+ break;
+ case kDictListValues:
+ tv_copy(&di->di_tv, &tv_item);
+ break;
+ case kDictListItems: {
+ // items()
+ list_T *const sub_l = tv_list_alloc(2);
+ tv_item.v_type = VAR_LIST;
+ tv_item.vval.v_list = sub_l;
+ tv_list_ref(sub_l);
+
+ tv_list_append_owned_tv(sub_l, (typval_T) {
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
.vval.v_string = (char_u *)xstrdup((const char *)di->di_key),
});
- tv_list_append_tv(sub_l, &di->di_tv);
+ tv_list_append_tv(sub_l, &di->di_tv);
- break;
- }
+ break;
+ }
}
tv_list_append_owned_tv(rettv->vval.v_list, tv_item);
@@ -7382,7 +7412,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
}
// Default result is zero == OK.
- for (;; ) {
+ for (;;) {
if (lines->v_type == VAR_LIST) {
// List argument, get next string.
if (li == NULL) {
@@ -9649,8 +9679,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 +10476,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..a9ec5d47a6 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,
@@ -190,6 +193,13 @@ extern const list_T *eval_msgpack_type_lists[LAST_MSGPACK_TYPE + 1];
#undef LAST_MSGPACK_TYPE
+// Struct passed to get_v_event() and restore_v_event().
+typedef struct {
+ bool sve_did_save;
+ hashtab_T sve_hashtab;
+} save_v_event_T;
+
+
/// trans_function_name() flags
typedef enum {
TFN_INT = 1, ///< May use internal function name
@@ -209,8 +219,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..9507a12a02 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},
@@ -277,6 +277,7 @@ return {
readfile={args={1, 3}, base=1},
reg_executing={},
reg_recording={},
+ reg_recorded={},
reltime={args={0, 2}, base=1},
reltimefloat={args=1, base=1},
reltimestr={args=1, base=1},
@@ -291,82 +292,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 +375,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/encode.c b/src/nvim/eval/encode.c
index b457353838..6f4357421b 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -29,8 +29,6 @@
#include "nvim/message.h"
#include "nvim/vim.h" // For _()
-#define utf_ptr2char(b) utf_ptr2char((char_u *)b)
-#define utf_ptr2len(b) ((size_t)utf_ptr2len((char_u *)b))
#define utf_char2len(b) ((size_t)utf_char2len(b))
const char *const encode_bool_var_names[] = {
@@ -354,20 +352,20 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
const float_T flt_ = (flt); \
switch (xfpclassify(flt_)) { \
case FP_NAN: { \
- ga_concat(gap, "str2float('nan')"); \
- break; \
+ ga_concat(gap, "str2float('nan')"); \
+ break; \
} \
case FP_INFINITE: { \
- if (flt_ < 0) { \
- ga_append(gap, '-'); \
- } \
- ga_concat(gap, "str2float('inf')"); \
- break; \
+ if (flt_ < 0) { \
+ ga_append(gap, '-'); \
+ } \
+ ga_concat(gap, "str2float('inf')"); \
+ break; \
} \
default: { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
- ga_concat(gap, numbuf); \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
+ ga_concat(gap, numbuf); \
} \
} \
} while (0)
@@ -558,18 +556,18 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s
const float_T flt_ = (flt); \
switch (xfpclassify(flt_)) { \
case FP_NAN: { \
- emsg(_("E474: Unable to represent NaN value in JSON")); \
- return FAIL; \
+ emsg(_("E474: Unable to represent NaN value in JSON")); \
+ return FAIL; \
} \
case FP_INFINITE: { \
- emsg(_("E474: Unable to represent infinity in JSON")); \
- return FAIL; \
+ emsg(_("E474: Unable to represent infinity in JSON")); \
+ return FAIL; \
} \
default: { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
- ga_concat(gap, numbuf); \
- break; \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
+ ga_concat(gap, numbuf); \
+ break; \
} \
} \
} while (0)
@@ -614,8 +612,8 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const
#define ENCODE_RAW(ch) \
(ch >= 0x20 && utf_printable(ch))
for (size_t i = 0; i < utf_len;) {
- const int ch = utf_ptr2char(utf_buf + i);
- const size_t shift = (ch == 0? 1: utf_ptr2len(utf_buf + i));
+ const int ch = utf_ptr2char((char_u *)utf_buf + i);
+ const size_t shift = (ch == 0 ? 1 : ((size_t)utf_ptr2len((char_u *)utf_buf + i)));
assert(shift > 0);
i += shift;
switch (ch) {
@@ -654,11 +652,11 @@ static inline int convert_to_json_string(garray_T *const gap, const char *const
ga_append(gap, '"');
ga_grow(gap, (int)str_len);
for (size_t i = 0; i < utf_len;) {
- const int ch = utf_ptr2char(utf_buf + i);
+ const int ch = utf_ptr2char((char_u *)utf_buf + i);
const size_t shift = (ch == 0? 1: utf_char2len(ch));
assert(shift > 0);
// Is false on invalid unicode, but this should already be handled.
- assert(ch == 0 || shift == utf_ptr2len(utf_buf + i));
+ assert(ch == 0 || shift == ((size_t)utf_ptr2len((char_u *)utf_buf + i)));
switch (ch) {
case BS:
case TAB:
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1d9ebdb596..d43eeb4a15 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -33,12 +33,12 @@
#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/input.h"
#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/mark.h"
#include "nvim/math.h"
#include "nvim/memline.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/msgpack_rpc/channel.h"
@@ -2663,12 +2663,12 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char buf[NUMBUFLEN];
const char *fname = tv_get_string_chk(&argvars[0]);
const char *const mods = tv_get_string_buf_chk(&argvars[1], buf);
- if (fname == NULL) {
+ if (mods == NULL || fname == NULL) {
fname = NULL;
- } else if (mods != NULL && *mods != NUL) {
+ } else {
len = strlen(fname);
- size_t usedlen = 0;
if (*mods != NUL) {
+ size_t usedlen = 0;
(void)modify_fname((char_u *)mods, false, &usedlen,
(char_u **)&fname, &fbuf, &len);
}
@@ -3174,7 +3174,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv)
bool error = false;
no_mapping++;
- for (;; ) {
+ for (;;) {
// Position the cursor. Needed after a message that ends in a space,
// or if event processing caused a redraw.
ui_cursor_goto(msg_row, msg_col);
@@ -3386,15 +3386,17 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsg(_(e_invarg));
return;
}
+ const char *pattern = tv_get_string(&argvars[0]);
if (strcmp(type, "cmdline") == 0) {
- set_one_cmd_context(&xpc, tv_get_string(&argvars[0]));
+ set_one_cmd_context(&xpc, pattern);
xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
+ xpc.xp_col = STRLEN(pattern);
goto theend;
}
ExpandInit(&xpc);
- xpc.xp_pattern = (char_u *)tv_get_string(&argvars[0]);
+ xpc.xp_pattern = (char_u *)pattern;
xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
xpc.xp_context = cmdcomplete_str_to_type(type);
if (xpc.xp_context == EXPAND_NOTHING) {
@@ -3447,7 +3449,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
int scope_number[] = {
- [kCdScopeWindow ] = 0, // Number of window to look at.
+ [kCdScopeWindow] = 0, // Number of window to look at.
[kCdScopeTabpage] = 0, // Number of tab to look at.
};
@@ -3485,11 +3487,6 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- // If the user didn't specify anything, default to window scope
- if (scope == kCdScopeInvalid) {
- scope = MIN_CD_SCOPE;
- }
-
// Find the tabpage by number
if (scope_number[kCdScopeTabpage] > 0) {
tp = find_tabpage(scope_number[kCdScopeTabpage]);
@@ -3535,16 +3532,17 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
case kCdScopeGlobal:
if (globaldir) { // `globaldir` is not always set.
from = globaldir;
- } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD.
+ break;
+ }
+ FALLTHROUGH; // In global directory, just need to get OS CWD.
+ case kCdScopeInvalid: // If called without any arguments, get OS CWD.
+ if (os_dirname(cwd, MAXPATHL) == FAIL) {
from = (char_u *)""; // Return empty string on failure.
}
- break;
- case kCdScopeInvalid: // We should never get here
- abort();
}
if (from) {
- xstrlcpy((char *)cwd, (char *)from, MAXPATHL);
+ STRLCPY(cwd, from, MAXPATHL);
}
rettv->vval.v_string = vim_strsave(cwd);
@@ -4667,7 +4665,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Numbers of the scope objects (window, tab) we want the working directory
// of. A `-1` means to skip this scope, a `0` means the current object.
int scope_number[] = {
- [kCdScopeWindow ] = 0, // Number of window to look at.
+ [kCdScopeWindow] = 0, // Number of window to look at.
[kCdScopeTabpage] = 0, // Number of tab to look at.
};
@@ -4867,7 +4865,7 @@ static void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = syn_name2id((const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
}
/*
@@ -4875,7 +4873,7 @@ static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = highlight_exists((const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
}
/*
@@ -6182,7 +6180,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
if (regmatch.regprog != NULL) {
regmatch.rm_ic = p_ic;
- for (;; ) {
+ for (;;) {
if (l != NULL) {
if (li == NULL) {
match = false;
@@ -7400,6 +7398,11 @@ static void f_reg_recording(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return_register(reg_recording, rettv);
}
+static void f_reg_recorded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ return_register(reg_recorded, rettv);
+}
+
/// list2proftime - convert a List to proftime_T
///
/// @param arg The input list, must be of type VAR_LIST and have
@@ -7727,8 +7730,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char *const buf = xmallocz(MAXPATHL);
char *cpy;
- for (;; ) {
- for (;; ) {
+ for (;;) {
+ for (;;) {
len = readlink(p, buf, MAXPATHL);
if (len <= 0) {
break;
@@ -8603,7 +8606,7 @@ long do_searchpair(const char *spat, const char *mpat, const char *epat, int dir
clearpos(&firstpos);
clearpos(&foundpos);
pat = pat3;
- for (;; ) {
+ for (;;) {
searchit_arg_T sia;
memset(&sia, 0, sizeof(sia));
sia.sa_stop_lnum = lnum_stop;
@@ -11553,6 +11556,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/eval/typval.c b/src/nvim/eval/typval.c
index 3e37e8cbb6..11bbaaed9c 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -28,11 +28,10 @@
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/os/input.h"
#include "nvim/pos.h"
#include "nvim/types.h"
#include "nvim/vim.h"
-// TODO(ZyX-I): Move line_breakcheck out of misc1
-#include "nvim/misc1.h" // For line_breakcheck
#include "nvim/os/fileio.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 69732f1a7d..d1275d6512 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -141,7 +141,7 @@ typedef struct {
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
partial_T *v_partial; ///< Closure: function with args.
blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL.
- } vval; ///< Actual value.
+ } vval; ///< Actual value.
} typval_T;
/// Values for (struct dictvar_S).dv_scope
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 6fe75e5e1f..eb241eb8ae 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -17,7 +17,6 @@
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/lua/executor.h"
-#include "nvim/misc1.h"
#include "nvim/os/input.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
@@ -1818,7 +1817,7 @@ char_u *trans_function_name(char_u **pp, bool skip, int flags, funcdict_T *fdp,
if (name != NULL) {
name = vim_strsave(name);
*pp = (char_u *)end;
- if (strncmp((char *)name, "<SNR>", 5) == 0) {
+ if (STRNCMP(name, "<SNR>", 5) == 0) {
// Change "<SNR>" to the byte sequence.
name[0] = K_SPECIAL;
name[1] = KS_EXTRA;
@@ -2141,7 +2140,7 @@ void ex_function(exarg_T *eap)
}
// find extra arguments "range", "dict", "abort" and "closure"
- for (;; ) {
+ for (;;) {
p = skipwhite(p);
if (STRNCMP(p, "range", 5) == 0) {
flags |= FC_RANGE;
@@ -2204,7 +2203,7 @@ void ex_function(exarg_T *eap)
indent = 2;
nesting = 0;
- for (;; ) {
+ for (;;) {
if (KeyTyped) {
msg_scroll = true;
saved_wait_return = false;
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index f070c8179f..3c43d1f98d 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -12,7 +12,7 @@
#include "nvim/event/rstream.h"
#include "nvim/log.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
+#include "nvim/main.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 145fe33284..c0cb17fa61 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -39,6 +39,7 @@
#include "nvim/getchar.h"
#include "nvim/highlight.h"
#include "nvim/indent.h"
+#include "nvim/input.h"
#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/mark.h"
@@ -46,7 +47,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -303,11 +303,10 @@ void ex_align(exarg_T *eap)
* Now try to move the line as much as possible to
* the right. Stop when it moves too far.
*/
- do{
+ do {
(void)set_indent(++new_indent, 0);
- }
- while (linelen(NULL) <= width);
- --new_indent;
+ } while (linelen(NULL) <= width);
+ new_indent--;
break;
}
--new_indent;
@@ -774,7 +773,7 @@ void ex_retab(exarg_T *eap)
col = 0;
vcol = 0;
did_undo = false;
- for (;; ) {
+ for (;;) {
if (ascii_iswhite(ptr[col])) {
if (!got_tab && num_spaces == 0) {
// First consecutive white-space
@@ -1440,7 +1439,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd,
_("%" PRId64 " lines filtered"), (int64_t)linecount);
if (msg(msg_buf) && !msg_scroll) {
// save message to display it after redraw
- set_keep_msg((char_u *)msg_buf, 0);
+ set_keep_msg(msg_buf, 0);
}
} else {
msgmore((long)linecount);
@@ -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;
}
/*
@@ -2150,7 +2147,7 @@ static int check_readonly(int *forceit, buf_T *buf)
if (buf->b_p_ro) {
dialog_msg(buff,
- _( "'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
+ _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
buf->b_fname);
} else {
dialog_msg(buff,
@@ -2944,8 +2941,8 @@ void ex_append(exarg_T *eap)
State |= LANGMAP;
}
- for (;; ) {
- msg_scroll = TRUE;
+ for (;;) {
+ 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
@@ -3280,7 +3275,7 @@ static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub, char_u *cm
// TODO(vim): find a generic solution to make line-joining operations more
// efficient, avoid allocating a string that grows in size.
if (pat != NULL
- && strcmp((const char *)pat, "\\n") == 0
+ && STRCMP(pat, "\\n") == 0
&& *sub == NUL
&& (*cmd == NUL || (cmd[1] == NUL
&& (*cmd == 'g'
@@ -3719,7 +3714,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle
* 4. if subflags.do_all is set, find next match
* 5. break if there isn't another match in this line
*/
- for (;; ) {
+ for (;;) {
SubResult current_match = {
.start = { 0, 0 },
.end = { 0, 0 },
@@ -4468,7 +4463,7 @@ bool do_sub_msg(bool count_only)
(int64_t)sub_nsubs, (int64_t)sub_nlines);
if (msg(msg_buf)) {
// save message to display it after redraw
- set_keep_msg((char_u *)msg_buf, 0);
+ set_keep_msg(msg_buf, 0);
}
return true;
}
@@ -5030,9 +5025,9 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool
// When the string starting with "expr-" and containing '?' and matches
// the table, it is taken literally (but ~ is escaped). Otherwise '?'
// is recognized as a wildcard.
- for (i = (int)ARRAY_SIZE(expr_table); --i >= 0; ) {
+ for (i = (int)ARRAY_SIZE(expr_table); --i >= 0;) {
if (STRCMP(arg + 5, expr_table[i]) == 0) {
- for (int si = 0, di = 0; ; si++) {
+ for (int si = 0, di = 0;; si++) {
if (arg[si] == '~') {
d[di++] = '\\';
}
@@ -5047,7 +5042,7 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool
} else {
// Recognize a few exceptions to the rule. Some strings that contain
// '*' with "star". Otherwise '*' is recognized as a wildcard.
- for (i = (int)ARRAY_SIZE(mtable); --i >= 0; ) {
+ for (i = (int)ARRAY_SIZE(mtable); --i >= 0;) {
if (STRCMP(arg, mtable[i]) == 0) {
STRCPY(d, rtable[i]);
break;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 787b3f07b2..33f9477608 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -35,12 +35,12 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/os/fs_defs.h"
+#include "nvim/os/input.h"
#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
@@ -410,7 +410,7 @@ static void script_dump_profile(FILE *fd)
} else {
// Keep going till the end of file, so that trailing
// continuation lines are listed.
- for (int i = 0; ; i++) {
+ for (int i = 0;; i++) {
if (vim_fgets(IObuff, IOSIZE, sfd)) {
break;
}
@@ -2505,7 +2505,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp)
// Loop until there is a finished line (or end-of-file).
sp->sourcing_lnum++;
- for (;; ) {
+ for (;;) {
// make room to read at least 120 (more) characters
ga_grow(&ga, 120);
buf = (char_u *)ga.ga_data;
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 6e5dd144ad..ea899b660b 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -135,10 +135,10 @@ typedef struct {
// Flags for the cs_lflags item in cstack_T.
enum {
- CSL_HAD_LOOP = 1, // just found ":while" or ":for"
+ CSL_HAD_LOOP = 1, // just found ":while" or ":for"
CSL_HAD_ENDLOOP = 2, // just found ":endwhile" or ":endfor"
- CSL_HAD_CONT = 4, // just found ":continue"
- CSL_HAD_FINA = 8, // just found ":finally"
+ CSL_HAD_CONT = 4, // just found ":continue"
+ CSL_HAD_FINA = 8, // just found ":finally"
};
/// Arguments used for Ex commands.
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 499c6ed4f9..9f0f8d93a3 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -39,6 +39,7 @@
#include "nvim/globals.h"
#include "nvim/hardcopy.h"
#include "nvim/if_cscope.h"
+#include "nvim/input.h"
#include "nvim/keymap.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
@@ -48,7 +49,6 @@
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -68,6 +68,7 @@
#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/strings.h"
+#include "nvim/state.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
#include "nvim/terminal.h"
@@ -196,6 +197,7 @@ void do_exmode(void)
exmode_active = true;
State = NORMAL;
+ trigger_modechanged();
// When using ":global /pat/ visual" and then "Q" we return to continue
// the :global command.
@@ -432,9 +434,9 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
if (next_cmdline == NULL
&& !force_abort
&& cstack.cs_idx < 0
- && !(getline_is_func &&
- func_has_abort(real_cookie))) {
- did_emsg = FALSE;
+ && !(getline_is_func
+ && func_has_abort(real_cookie))) {
+ did_emsg = false;
}
/*
@@ -818,7 +820,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
// of interrupts or errors to exceptions, and ensure that no more
// commands are executed.
if (current_exception) {
- void *p = NULL;
+ char *p = NULL;
char_u *saved_sourcing_name;
int saved_sourcing_lnum;
struct msglist *messages = NULL;
@@ -835,7 +837,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
vim_snprintf((char *)IObuff, IOSIZE,
_("E605: Exception not caught: %s"),
current_exception->value);
- p = vim_strsave(IObuff);
+ p = (char *)vim_strsave(IObuff);
break;
case ET_ERROR:
messages = current_exception->messages;
@@ -2065,7 +2067,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, bool skip_only)
eap->save_msg_silent = -1;
// Repeat until no more command modifiers are found.
- for (;; ) {
+ for (;;) {
while (*eap->cmd == ' '
|| *eap->cmd == '\t'
|| *eap->cmd == ':') {
@@ -2647,7 +2649,7 @@ static char_u *find_command(exarg_T *eap, int *full)
const int c2 = len == 1 ? NUL : eap->cmd[1];
if (command_count != CMD_SIZE) {
- iemsg((char *)_("E943: Command table needs to be updated, run 'make'"));
+ iemsg(_("E943: Command table needs to be updated, run 'make'"));
getout(1);
}
@@ -2715,8 +2717,8 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *
* Look for buffer-local user commands first, then global ones.
*/
gap = &curbuf->b_ucmds;
- for (;; ) {
- for (j = 0; j < gap->ga_len; ++j) {
+ for (;;) {
+ for (j = 0; j < gap->ga_len; j++) {
uc = USER_CMD_GA(gap, j);
cp = eap->cmd;
np = uc->uc_name;
@@ -4071,7 +4073,7 @@ static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, in
}
}
- for (;; ) {
+ for (;;) {
cmd = skipwhite(cmd);
if (*cmd != '-' && *cmd != '+' && !ascii_isdigit(*cmd)) {
break;
@@ -5326,8 +5328,8 @@ static void uc_list(char_u *name, size_t name_len)
garray_T *gap = (cmdwin_type != 0 && get_cmdline_type() == NUL)
? &prevwin->w_buffer->b_ucmds
: &curbuf->b_ucmds;
- for (;; ) {
- for (i = 0; i < gap->ga_len; ++i) {
+ for (;;) {
+ for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
a = cmd->uc_argt;
@@ -5713,8 +5715,8 @@ static void ex_delcommand(exarg_T *eap)
garray_T *gap;
gap = &curbuf->b_ucmds;
- for (;; ) {
- for (i = 0; i < gap->ga_len; ++i) {
+ for (;;) {
+ for (i = 0; i < gap->ga_len; i++) {
cmd = USER_CMD_GA(gap, i);
cmp = STRCMP(eap->arg, cmd->uc_name);
if (cmp <= 0) {
@@ -6153,12 +6155,12 @@ static void do_ucmd(exarg_T *eap)
* Second round: copy result into "buf".
*/
buf = NULL;
- for (;; ) {
+ for (;;) {
p = cmd->uc_rep; // source
q = buf; // destination
totlen = 0;
- for (;; ) {
+ for (;;) {
start = vim_strchr(p, '<');
if (start != NULL) {
end = vim_strchr(start + 1, '>');
@@ -6184,7 +6186,7 @@ static void do_ucmd(exarg_T *eap)
}
}
- // break if there no <item> is found
+ // break if no <item> is found
if (start == NULL || end == NULL) {
break;
}
@@ -7753,6 +7755,7 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
abort();
}
+ last_chdir_reason = NULL;
shorten_fnames(true);
if (trigger_dirchanged) {
@@ -7870,7 +7873,9 @@ static void ex_pwd(exarg_T *eap)
#endif
if (p_verbose > 0) {
char *context = "global";
- if (curwin->w_localdir != NULL) {
+ if (last_chdir_reason != NULL) {
+ context = last_chdir_reason;
+ } else if (curwin->w_localdir != NULL) {
context = "window";
} else if (curtab->tp_localdir != NULL) {
context = "tabpage";
@@ -8334,9 +8339,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);
}
}
@@ -8983,8 +8986,8 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
/// @return an allocated string if a valid match was found.
/// Returns NULL if no match was found. "usedlen" then still contains the
/// number of characters to skip.
-char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump,
- char **errormsg, int *escaped)
+char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump, char **errormsg,
+ int *escaped)
{
int i;
char_u *s;
@@ -9130,7 +9133,7 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum
// postponed to avoid a delay when <afile> is not used.
result = (char_u *)FullName_save((char *)autocmd_fname, false);
// Copy into `autocmd_fname`, don't reassign it. #8165
- xstrlcpy((char *)autocmd_fname, (char *)result, MAXPATHL);
+ STRLCPY(autocmd_fname, result, MAXPATHL);
xfree(result);
}
result = autocmd_fname;
@@ -9252,7 +9255,7 @@ static char_u *arg_all(void)
* first time: compute the total length
* second time: concatenate the names
*/
- for (;; ) {
+ for (;;) {
len = 0;
for (idx = 0; idx < ARGCOUNT; ++idx) {
p = alist_name(&ARGLIST[idx]);
@@ -9315,7 +9318,7 @@ char_u *expand_sfile(char_u *arg)
result = vim_strsave(arg);
- for (p = result; *p; ) {
+ for (p = result; *p;) {
if (STRNCMP(p, "<sfile>", 7) != 0) {
++p;
} else {
@@ -9461,7 +9464,7 @@ static void ex_filetype(exarg_T *eap)
}
// Accept "plugin" and "indent" in any order.
- for (;; ) {
+ for (;;) {
if (STRNCMP(arg, "plugin", 6) == 0) {
plugin = true;
arg = skipwhite(arg + 6);
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index cfc8eb7316..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;
}
@@ -566,7 +566,7 @@ static void discard_exception(except_T *excp, bool was_finished)
} else {
verbose_leave();
}
- xstrlcpy((char *)IObuff, (const char *)saved_IObuff, IOSIZE);
+ STRLCPY(IObuff, saved_IObuff, IOSIZE);
xfree(saved_IObuff);
}
if (excp->type != ET_INTERRUPT) {
@@ -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));
+ do {
+ 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].
@@ -2091,7 +2088,7 @@ int has_loop_cmd(char_u *p)
int len;
// skip modifiers, white space and ':'
- for (;; ) {
+ for (;;) {
while (*p == ' ' || *p == '\t' || *p == ':') {
++p;
}
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 9ccbdbaf58..ba2238ace2 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -48,7 +48,6 @@
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/ops.h"
@@ -880,7 +879,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
TryState tstate;
Error err = ERROR_INIT;
bool tl_ret = true;
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
char firstcbuf[2];
firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
firstcbuf[1] = 0;
@@ -894,7 +894,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
apply_autocmds(EVENT_CMDLINEENTER, (char_u *)firstcbuf, (char_u *)firstcbuf,
false, curbuf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
tl_ret = try_leave(&tstate, &err);
@@ -906,6 +906,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
tl_ret = true;
}
+ trigger_modechanged();
state_enter(&s->state);
@@ -924,7 +925,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
if (tv_dict_get_number(dict, "abort") != 0) {
s->gotesc = 1;
}
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
}
cmdmsg_rl = false;
@@ -1665,7 +1666,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_
static void command_line_next_histidx(CommandLineState *s, bool next_match)
{
int j = (int)STRLEN(s->lookfor);
- for (;; ) {
+ for (;;) {
// one step backwards
if (!next_match) {
if (s->hiscnt == hislen) {
@@ -2289,7 +2290,8 @@ static int command_line_changed(CommandLineState *s)
if (has_event(EVENT_CMDLINECHANGED)) {
TryState tstate;
Error err = ERROR_INIT;
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
char firstcbuf[2];
firstcbuf[0] = (char)(s->firstc > 0 ? s->firstc : '-');
@@ -2303,7 +2305,7 @@ static int command_line_changed(CommandLineState *s)
apply_autocmds(EVENT_CMDLINECHANGED, (char_u *)firstcbuf,
(char_u *)firstcbuf, false, curbuf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
bool tl_ret = try_leave(&tstate, &err);
if (!tl_ret && ERROR_SET(&err)) {
@@ -2488,27 +2490,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)
@@ -2686,7 +2686,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
viml_parser_destroy(&pstate);
kv_resize(ret_ccline_colors->colors, kv_size(colors));
size_t prev_end = 0;
- for (size_t i = 0 ; i < kv_size(colors) ; i++) {
+ for (size_t i = 0; i < kv_size(colors); i++) {
const ParserHighlightChunk chunk = kv_A(colors, i);
assert(chunk.start.col < INT_MAX);
assert(chunk.end_col < INT_MAX);
@@ -2697,7 +2697,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
.attr = 0,
}));
}
- const int id = syn_name2id((const char_u *)chunk.group);
+ const int id = syn_name2id(chunk.group);
const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)chunk.start.col,
@@ -2899,7 +2899,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
if (group == NULL) {
goto color_cmdline_error;
}
- const int id = syn_name2id((char_u *)group);
+ const int id = syn_name2id(group);
const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = (int)start,
@@ -3466,7 +3466,7 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
int len;
// Locate start of last word in the cmd buffer.
- for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; ) {
+ for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff;) {
len = utf_head_off(ccline.cmdbuff, w - 1) + 1;
if (!vim_iswordc(utf_ptr2char(w - len))) {
break;
@@ -4386,7 +4386,7 @@ static int showmatches(expand_T *xp, int wildmenu)
msg_outtrans_long_attr(p + 2, HL_ATTR(HLF_D));
break;
}
- for (j = maxlen - lastlen; --j >= 0; ) {
+ for (j = maxlen - lastlen; --j >= 0;) {
msg_putchar(' ');
}
if (xp->xp_context == EXPAND_FILES
@@ -4457,7 +4457,7 @@ char_u *sm_gettail(char_u *s, bool eager)
char_u *t = s;
int had_sep = FALSE;
- for (p = s; *p != NUL; ) {
+ for (p = s; *p != NUL;) {
if (vim_ispathsep(*p)
#ifdef BACKSLASH_IN_FILENAME
&& !rem_backslash(p)
@@ -4989,13 +4989,13 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
- char_u *tofree = NULL;
+ char *tofree = NULL;
if (xp->xp_context == EXPAND_USER_FUNC && STRNCMP(pat, "^s:", 3) == 0) {
const size_t len = STRLEN(pat) + 20;
tofree = xmalloc(len);
- snprintf((char *)tofree, len, "^<SNR>\\d\\+_%s", pat + 3);
- pat = tofree;
+ snprintf(tofree, len, "^<SNR>\\d\\+_%s", pat + 3);
+ pat = (char_u *)tofree;
}
if (xp->xp_context == EXPAND_LUA) {
@@ -5219,7 +5219,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int
ga_init(&ga, (int)sizeof(char *), 10);
hashtab_T found_ht;
hash_init(&found_ht);
- for (s = path; ; s = e) {
+ for (s = path;; s = e) {
e = vim_strchr(s, ENV_SEPCHAR);
if (e == NULL) {
e = s + STRLEN(s);
@@ -6547,6 +6547,7 @@ static int open_cmdwin(void)
cmdmsg_rl = save_cmdmsg_rl;
State = save_State;
+ trigger_modechanged();
setmouse();
return cmdwin_result;
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 9aa8cc0107..a37cad9f2d 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -28,7 +28,6 @@
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/keymap.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
@@ -345,8 +344,8 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr
// Load the file.
//
if (wp->w_buffer->b_ffname != NULL
- && (!bt_nofile(wp->w_buffer) ||
- wp->w_buffer->terminal)) {
+ && (!bt_nofile(wp->w_buffer)
+ || wp->w_buffer->terminal)) {
// Editing a file in this buffer: use ":edit file".
// This may have side effects! (e.g., compressed or network file).
//
@@ -431,8 +430,8 @@ static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int curr
//
if ((*flagp & SSOP_FOLDS)
&& wp->w_buffer->b_ffname != NULL
- && (bt_normal(wp->w_buffer) ||
- bt_help(wp->w_buffer))) {
+ && (bt_normal(wp->w_buffer)
+ || bt_help(wp->w_buffer))) {
if (put_folds(fd, wp) == FAIL) {
return FAIL;
}
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 36257fefb3..d31021b3ef 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -57,7 +57,6 @@
#include "nvim/globals.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/fs_defs.h"
#include "nvim/os/input.h"
@@ -605,9 +604,9 @@ char_u *vim_findfile(void *search_ctx_arg)
}
// upward search loop
- for (;; ) {
+ for (;;) {
// downward search loop
- for (;; ) {
+ for (;;) {
// check if user user wants to stop the search
os_breakcheck();
if (got_int) {
@@ -829,7 +828,7 @@ char_u *vim_findfile(void *search_ctx_arg)
} else {
suf = curbuf->b_p_sua;
}
- for (;; ) {
+ for (;;) {
// if file exists and we didn't already find it
if ((path_with_url((char *)file_path)
|| (os_path_exists(file_path)
@@ -1500,7 +1499,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first
/* When the file doesn't exist, try adding parts of
* 'suffixesadd'. */
buf = suffixes;
- for (;; ) {
+ for (;;) {
if (
(os_path_exists(NameBuff)
&& (find_what == FINDFILE_BOTH
@@ -1530,7 +1529,7 @@ char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first
did_findfile_init = FALSE;
}
- for (;; ) {
+ for (;;) {
if (did_findfile_init) {
file_name = vim_findfile(fdip_search_ctx);
if (file_name != NULL) {
@@ -1603,7 +1602,8 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
recursive = true;
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
char buf[8];
switch (scope) {
@@ -1648,7 +1648,7 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, CdCause cause)
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
curbuf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
recursive = false;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index cf4037308b..f8cf341836 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -30,12 +30,12 @@
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/iconv.h"
+#include "nvim/input.h"
#include "nvim/mbyte.h"
#include "nvim/memfile.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
@@ -100,8 +100,8 @@ struct bw_info {
char_u bw_rest[CONV_RESTLEN]; // not converted bytes
int bw_restlen; // nr of bytes in bw_rest[]
int bw_first; // first write call
- char_u *bw_conv_buf; // buffer for writing converted chars
- int bw_conv_buflen; // size of bw_conv_buf
+ char_u *bw_conv_buf; // buffer for writing converted chars
+ size_t bw_conv_buflen; // size of bw_conv_buf
int bw_conv_error; // set for conversion error
linenr_T bw_conv_error_lnum; // first line with error or zero
linenr_T bw_start_lnum; // line number at start of buffer
@@ -125,7 +125,7 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
}
add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)name);
// Avoid an over-long translation to cause trouble.
- xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
+ STRLCAT(IObuff, s, IOSIZE);
// For the first message may have to start a new line.
// For further ones overwrite the previous one, reset msg_scroll before
// calling filemess().
@@ -995,7 +995,7 @@ retry:
long tlen;
tlen = 0;
- for (;; ) {
+ for (;;) {
p = ml_get(read_buf_lnum) + read_buf_col;
n = (int)STRLEN(p);
if ((int)tlen + n + 1 > size) {
@@ -1360,6 +1360,10 @@ retry:
u8c += (unsigned)(*--p) << 16;
u8c += (unsigned)(*--p) << 24;
}
+ // Replace characters over INT_MAX with Unicode replacement character
+ if (u8c > INT_MAX) {
+ u8c = 0xfffd;
+ }
} else { // UTF-8
if (*--p < 0x80) {
u8c = *p;
@@ -1847,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
@@ -1857,7 +1861,7 @@ failed:
// - When restart_edit is set (otherwise there will be a delay before
// redrawing).
// - When the screen was scrolled but there is no wait-return prompt.
- set_keep_msg(p, 0);
+ set_keep_msg((char *)p, 0);
}
msg_scrolled_ign = false;
}
@@ -3125,7 +3129,7 @@ nobackup:
// If conversion is taking place, we may first pretend to write and check
// for conversion errors. Then loop again to write for real.
// When not doing conversion this writes for real right away.
- for (checking_conversion = true; ; checking_conversion = false) {
+ for (checking_conversion = true;; checking_conversion = false) {
// There is no need to check conversion when:
// - there is no conversion
// - we make a backup file, that can be restored in case of conversion
@@ -3536,7 +3540,7 @@ restore_backup:
}
}
- set_keep_msg((char_u *)msg_trunc_attr((char *)IObuff, FALSE, 0), 0);
+ set_keep_msg(msg_trunc_attr((char *)IObuff, false, 0), 0);
}
/* When written everything correctly: reset 'modified'. Unless not
@@ -4265,8 +4269,8 @@ static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags)
len = 4;
} else if (flags == (FIO_UCS2 | FIO_ENDIAN_L)) {
name = "ucs-2le"; // FF FE
- } else if (flags == FIO_ALL ||
- flags == (FIO_UTF16 | FIO_ENDIAN_L)) {
+ } else if (flags == FIO_ALL
+ || flags == (FIO_UTF16 | FIO_ENDIAN_L)) {
// utf-16le is preferred, it also works for ucs-2le text
name = "utf-16le"; // FF FE
}
@@ -4811,8 +4815,8 @@ int check_timestamps(int focus)
}
if (!stuff_empty() || global_busy || !typebuf_typed()
- || autocmd_busy || curbuf->b_ro_locked > 0 ||
- allbuf_lock > 0) {
+ || autocmd_busy || curbuf->b_ro_locked > 0
+ || allbuf_lock > 0) {
need_check_timestamps = true; // check later
} else {
no_wait_return++;
@@ -5727,7 +5731,7 @@ long read_eintr(int fd, void *buf, size_t bufsize)
{
long ret;
- for (;; ) {
+ for (;;) {
ret = read(fd, buf, bufsize);
if (ret >= 0 || errno != EINTR) {
break;
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index daf0df9326..b1d4321d4c 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -28,10 +28,10 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/plines.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
@@ -202,7 +202,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp
* Recursively search for a fold that contains "lnum".
*/
garray_T *gap = &win->w_folds;
- for (;; ) {
+ for (;;) {
if (!foldFind(gap, lnum_rel, &fp)) {
break;
}
@@ -455,7 +455,7 @@ void foldOpenCursor(void)
checkupdate(curwin);
if (hasAnyFolding(curwin)) {
- for (;; ) {
+ for (;;) {
done = DONE_NOTHING;
(void)setManualFold(curwin->w_cursor, true, false, &done);
if (!(done & DONE_ACTION)) {
@@ -716,7 +716,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const
garray_T *found_ga = NULL;
linenr_T lnum_off = 0;
bool use_level = false;
- for (;; ) {
+ for (;;) {
if (!foldFind(gap, lnum - lnum_off, &fp)) {
break;
}
@@ -897,7 +897,7 @@ int foldMoveTo(const bool updown, const int dir, const long count)
linenr_T lnum_found = curwin->w_cursor.lnum;
int level = 0;
bool last = false;
- for (;; ) {
+ for (;;) {
if (!foldFind(gap, curwin->w_cursor.lnum - lnum_off, &fp)) {
if (!updown || gap->ga_len == 0) {
break;
@@ -1155,7 +1155,7 @@ static int foldLevelWin(win_T *wp, linenr_T lnum)
// Recursively search for a fold that contains "lnum".
gap = &wp->w_folds;
- for (;; ) {
+ for (;;) {
if (!foldFind(gap, lnum_rel, &fp)) {
break;
}
@@ -1265,7 +1265,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recu
* Find the fold, open or close it.
*/
gap = &wp->w_folds;
- for (;; ) {
+ for (;;) {
if (!foldFind(gap, lnum, &fp)) {
// If there is a following fold, continue there next time.
if (fp != NULL && fp < (fold_T *)gap->ga_data + gap->ga_len) {
@@ -1928,7 +1928,7 @@ void foldtext_cleanup(char_u *str)
}
parseMarker(curwin);
- for (s = str; *s != NUL; ) {
+ for (s = str; *s != NUL;) {
size_t len = 0;
if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0) {
len = foldstartmarkerlen;
@@ -2603,7 +2603,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level,
}
// delete following folds that end before the current line
- for (;; ) {
+ for (;;) {
fp2 = fp + 1;
if (fp2 >= (fold_T *)gap->ga_data + gap->ga_len
|| fp2->fd_top > flp->lnum) {
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/generators/gen_char_blob.lua b/src/nvim/generators/gen_char_blob.lua
index a7dad50d48..3ec1ff2caf 100644
--- a/src/nvim/generators/gen_char_blob.lua
+++ b/src/nvim/generators/gen_char_blob.lua
@@ -1,12 +1,26 @@
if arg[1] == '--help' then
print('Usage:')
- print(' '..arg[0]..' target source varname [source varname]...')
+ print(' '..arg[0]..' [-c] target source varname [source varname]...')
print('')
print('Generates C file with big uint8_t blob.')
print('Blob will be stored in a static const array named varname.')
os.exit()
end
+-- Recognized options:
+-- -c compile Lua bytecode
+local options = {}
+
+while true do
+ local opt = string.match(arg[1], "^-(%w)")
+ if not opt then
+ break
+ end
+
+ options[opt] = true
+ table.remove(arg, 1)
+end
+
assert(#arg >= 3 and (#arg - 1) % 2 == 0)
local target_file = arg[1] or error('Need a target file')
@@ -14,6 +28,7 @@ local target = io.open(target_file, 'w')
target:write('#include <stdint.h>\n\n')
+local warn_on_missing_compiler = true
local varnames = {}
for argi = 2, #arg, 2 do
local source_file = arg[argi]
@@ -23,11 +38,26 @@ for argi = 2, #arg, 2 do
end
varnames[varname] = source_file
- local source = io.open(source_file, 'r')
- or error(string.format("source_file %q doesn't exist", source_file))
-
target:write(('static const uint8_t %s[] = {\n'):format(varname))
+ local output
+ if options.c then
+ local luac = os.getenv("LUAC_PRG")
+ if luac and luac ~= "" then
+ output = io.popen(luac:format(source_file), "r"):read("*a")
+ elseif warn_on_missing_compiler then
+ print("LUAC_PRG is missing, embedding raw source")
+ warn_on_missing_compiler = false
+ end
+ end
+
+ if not output then
+ local source = io.open(source_file, "r")
+ or error(string.format("source_file %q doesn't exist", source_file))
+ output = source:read("*a")
+ source:close()
+ end
+
local num_bytes = 0
local MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line
target:write(' ')
@@ -41,19 +71,13 @@ for argi = 2, #arg, 2 do
end
end
- for line in source:lines() do
- for i = 1, string.len(line) do
- local byte = line:byte(i)
- assert(byte ~= 0)
- target:write(string.format(' %3u,', byte))
- increase_num_bytes()
- end
- target:write(string.format(' %3u,', string.byte('\n', 1)))
+ for i = 1, string.len(output) do
+ local byte = output:byte(i)
+ target:write(string.format(' %3u,', byte))
increase_num_bytes()
end
- target:write(' 0};\n')
- source:close()
+ target:write(' 0};\n')
end
target:close()
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 5267b313c7..6b1150cefa 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -29,6 +29,7 @@
#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/input.h"
#include "nvim/keymap.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
@@ -36,7 +37,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
@@ -458,6 +458,15 @@ void flush_buffers(flush_buffers_T flush_typeahead)
}
}
+/// flush map and typeahead buffers and give a warning for an error
+void beep_flush(void)
+{
+ if (emsg_silent == 0) {
+ flush_buffers(FLUSH_MINIMAL);
+ vim_beep(BO_ERROR);
+ }
+}
+
/*
* The previous contents of the redo buffer is kept in old_redobuffer.
* This is used for the CTRL-O <.> command in insert mode.
@@ -1453,7 +1462,7 @@ int vgetc(void)
} else {
mod_mask = 0x0;
last_recorded_len = 0;
- for (;; ) { // this is done twice if there are modifiers
+ for (;;) { // this is done twice if there are modifiers
bool did_inc = false;
if (mod_mask) { // no mapping after modifier has been read
no_mapping++;
@@ -1680,6 +1689,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; // get character from typeahead
+ } 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 +2043,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 +2076,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 +2093,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.
- */
- for (;; ) {
- /*
- * os_breakcheck() is slow, don't use it too often when
- * inside a mapping. But call it each time for typed
- * characters.
- */
+ // 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.
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 +2137,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;
- }
- }
-
- /* 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;
- }
- }
- }
- }
+ // Check for a mapping in "typebuf".
+ map_result_T result = (map_result_T)handle_mapping(&keylen, &timedout, &mapdepth);
- /* 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;
+ KeyNoremap = typebuf.tb_noremap[typebuf.tb_off];
+ del_typebuf(1, 0);
}
-
- /*
- * 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;
- }
-
- /*
- * 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; // got character, break the for loop
}
+
+ // 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 +2190,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 +2207,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 +2223,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 +2251,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 +2297,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 +2309,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 +2333,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 +2352,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 +2362,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 +2377,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 +2387,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();
}
@@ -2550,7 +2528,7 @@ int inchar(char_u *buf, int maxlen, long wait_time)
#define DUM_LEN MAXMAPLEN * 3 + 3
char_u dum[DUM_LEN + 1];
- for (;; ) {
+ for (;;) {
len = os_inchar(dum, DUM_LEN, 0L, 0, NULL);
if (len == 0 || (len == 1 && dum[0] == 3)) {
break;
@@ -3599,7 +3577,7 @@ char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, bool forc
expand_isabbrev = isabbrev;
xp->xp_context = EXPAND_MAPPINGS;
expand_buffer = false;
- for (;; ) {
+ for (;;) {
if (STRNCMP(arg, "<buffer>", 8) == 0) {
expand_buffer = true;
arg = skipwhite(arg + 8);
@@ -3987,7 +3965,7 @@ char_u *vim_strsave_escape_csi(char_u *p)
// 0xc0 -> 0xc3 - 0x80 -> 0xc3 K_SPECIAL KS_SPECIAL KE_FILLER
char_u *res = xmalloc(STRLEN(p) * 4 + 1);
char_u *d = res;
- for (char_u *s = p; *s != NUL; ) {
+ for (char_u *s = p; *s != NUL;) {
if (s[0] == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
// Copy special key unmodified.
*d++ = *s++;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index e2d3378402..697d4b11a7 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"
@@ -201,7 +202,6 @@ EXTERN bool msg_did_scroll INIT(= false);
EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw
EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg
-EXTERN bool keep_msg_more INIT(= false); // keep_msg was set by msgmore()
EXTERN bool need_fileinfo INIT(= false); // do fileinfo() after redraw
EXTERN int msg_scroll INIT(= false); // msg_start() will scroll
EXTERN bool msg_didout INIT(= false); // msg_outstr() was used in line
@@ -533,6 +533,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;
@@ -627,6 +632,7 @@ EXTERN bool ex_no_reprint INIT(=false); // No need to print after z or p.
EXTERN int reg_recording INIT(= 0); // register for recording or zero
EXTERN int reg_executing INIT(= 0); // register being executed or zero
+EXTERN int reg_recorded INIT(= 0); // last recorded register or zero
EXTERN int no_mapping INIT(= false); // currently no mapping allowed
EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed
@@ -727,6 +733,7 @@ EXTERN bool listcmd_busy INIT(= false); // set when :argdo, :windo or
// :bufdo is executing
EXTERN bool need_start_insertmode INIT(= false);
// start insert mode soon
+EXTERN char *last_mode INIT(= NULL);
EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":)
EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "."
EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline
@@ -789,6 +796,8 @@ extern char_u *compiled_sys;
// directory is not a local directory, globaldir is NULL.
EXTERN char_u *globaldir INIT(= NULL);
+EXTERN char *last_chdir_reason INIT(= NULL);
+
// Whether 'keymodel' contains "stopsel" and "startsel".
EXTERN bool km_stopsel INIT(= false);
EXTERN bool km_startsel INIT(= false);
@@ -842,6 +851,7 @@ EXTERN disptick_T display_tick INIT(= 0);
// cursor position in Insert mode.
EXTERN linenr_T spell_redraw_lnum INIT(= 0);
+// uncrustify:off
// The error messages that can be shared are included here.
// Excluded are errors that are only used once and debugging messages.
@@ -850,12 +860,8 @@ EXTERN char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup"
EXTERN char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job"));
EXTERN char e_argreq[] INIT(= N_("E471: Argument required"));
EXTERN char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &"));
-EXTERN char e_cmdwin[] INIT(=
- N_(
- "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
-EXTERN char e_curdir[] INIT(=
- N_(
- "E12: Command not allowed from exrc/vimrc in current dir or tag search"));
+EXTERN char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; <CR> executes, CTRL-C quits"));
+EXTERN char e_curdir[] INIT(= N_( "E12: Command not allowed from exrc/vimrc in current dir or tag search"));
EXTERN char e_endif[] INIT(= N_("E171: Missing :endif"));
EXTERN char e_endtry[] INIT(= N_("E600: Missing :endtry"));
EXTERN char e_endwhile[] INIT(= N_("E170: Missing :endwhile"));
@@ -885,10 +891,7 @@ EXTERN char e_channotpty[] INIT(= N_("E904: channel is not a pty"));
EXTERN char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s"));
EXTERN char e_invstream[] INIT(= N_("E906: invalid stream for channel"));
EXTERN char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'"));
-EXTERN char e_streamkey[] INIT(=
- N_(
- "E5210: dict key '%s' already set for buffered stream in channel %"
- PRIu64));
+EXTERN char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64));
EXTERN char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\""));
EXTERN char e_fsync[] INIT(= N_("E667: Fsync failed: %s"));
EXTERN char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s"));
@@ -939,9 +942,7 @@ EXTERN char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")
EXTERN char e_listreq[] INIT(= N_("E714: List required"));
EXTERN char e_listblobreq[] INIT(= N_("E897: List or Blob required"));
EXTERN char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary"));
-EXTERN char e_listdictblobarg[] INIT(=
- N_(
- "E896: Argument of %s must be a List, Dictionary or Blob"));
+EXTERN char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob"));
EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
EXTERN char e_secure[] INIT(= N_("E523: Not allowed here"));
@@ -980,25 +981,23 @@ EXTERN char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
EXTERN char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String"));
-EXTERN char e_autocmd_err[] INIT(=N_("E5500: autocmd has thrown an exception: %s"));
-EXTERN char e_cmdmap_err[] INIT(=N_("E5520: <Cmd> mapping must end with <CR>"));
-EXTERN char
-e_cmdmap_repeated[] INIT(=N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
-EXTERN char e_cmdmap_key[] INIT(=N_("E5522: <Cmd> mapping must not include %s key"));
+EXTERN char e_autocmd_err[] INIT(= N_("E5500: autocmd has thrown an exception: %s"));
+EXTERN char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>"));
+EXTERN char e_cmdmap_repeated[] INIT(= N_("E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
+EXTERN char e_cmdmap_key[] INIT(= N_("E5522: <Cmd> mapping must not include %s key"));
-EXTERN char e_api_error[] INIT(=N_("E5555: API call: %s"));
+EXTERN char e_api_error[] INIT(= N_("E5555: API call: %s"));
-EXTERN char e_luv_api_disabled[] INIT(=N_("E5560: %s must not be called in a lua loop callback"));
+EXTERN char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback"));
-EXTERN char e_floatonly[] INIT(=N_(
- "E5601: Cannot close window, only floating window would remain"));
-EXTERN char e_floatexchange[] INIT(=N_("E5602: Cannot exchange or rotate float"));
+EXTERN char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain"));
+EXTERN char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float"));
EXTERN char e_non_empty_string_required[] INIT(= N_("E1142: Non-empty string required"));
-EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(=
- N_(
- "E1155: Cannot define autocommands for ALL events"));
+EXTERN char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events"));
+
+EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
@@ -1020,6 +1019,8 @@ EXTERN bool embedded_mode INIT(= false);
// Do not start a UI nor read/write to stdio (unless embedding).
EXTERN bool headless_mode INIT(= false);
+// uncrustify:on
+
/// Used to track the status of external functions.
/// Currently only used for iconv().
typedef enum {
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 296c5cbdbf..6fc70144ac 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -461,10 +461,10 @@ static void prt_line_number(prt_settings_T *const psettings, const int page_line
// Leave two spaces between the number and the text; depends on
// PRINT_NUMBER_WIDTH.
- char_u tbuf[20];
- snprintf((char *)tbuf, sizeof(tbuf), "%6ld", (long)lnum);
+ char tbuf[20];
+ snprintf(tbuf, sizeof(tbuf), "%6ld", (long)lnum);
for (int i = 0; i < 6; i++) {
- (void)mch_print_text_out(&tbuf[i], 1);
+ (void)mch_print_text_out((char_u *)(&tbuf[i]), 1);
}
if (psettings->do_syntax) {
@@ -571,7 +571,7 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, const
// Use a negative line number to indicate printing in the top margin.
int page_line = 0 - prt_header_height();
mch_print_start_line(true, page_line);
- for (char_u *p = tbuf; *p != NUL; ) {
+ for (char_u *p = tbuf; *p != NUL;) {
const int l = utfc_ptr2len(p);
assert(l >= 0);
if (mch_print_text_out(p, (size_t)l)) {
@@ -669,7 +669,7 @@ void ex_hardcopy(exarg_T *eap)
// Syntax highlighting of line numbers.
if (prt_use_number() && settings.do_syntax) {
- int id = syn_name2id((char_u *)"LineNr");
+ int id = syn_name2id("LineNr");
if (id > 0) {
id = syn_get_final_id(id);
}
@@ -986,8 +986,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
#define PRT_PS_DEFAULT_DPI (72) // Default user space resolution
#define PRT_PS_DEFAULT_FONTSIZE (10)
-#define PRT_MEDIASIZE_LEN (sizeof(prt_mediasize) / \
- sizeof(struct prt_mediasize_S))
+#define PRT_MEDIASIZE_LEN ARRAY_SIZE(prt_mediasize)
static struct prt_mediasize_S prt_mediasize[] =
{
@@ -1254,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;
/*
@@ -1310,7 +1309,7 @@ static int prt_collate;
/*
* Buffers used when generating PostScript output
*/
-static char_u prt_line_buffer[257];
+static char prt_line_buffer[257];
static garray_T prt_ps_buffer = GA_EMPTY_INIT_VALUE;
static int prt_do_conv;
@@ -1330,13 +1329,13 @@ 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;
}
}
-static void prt_write_file(char_u *buffer)
+static void prt_write_file(char *buffer)
{
- prt_write_file_len(buffer, STRLEN(buffer));
+ prt_write_file_len((char_u *)buffer, STRLEN(buffer));
}
static void prt_write_file_len(char_u *buffer, size_t bytes)
@@ -1349,7 +1348,7 @@ static void prt_write_file_len(char_u *buffer, size_t bytes)
*/
static void prt_write_string(char *s)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%s", s);
prt_write_file(prt_line_buffer);
}
@@ -1358,7 +1357,7 @@ static void prt_write_string(char *s)
*/
static void prt_write_int(int i)
{
- sprintf((char *)prt_line_buffer, "%d ", i);
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%d ", i);
prt_write_file(prt_line_buffer);
}
@@ -1367,7 +1366,7 @@ static void prt_write_int(int i)
*/
static void prt_write_boolean(int b)
{
- sprintf((char *)prt_line_buffer, "%s ", (b ? "T" : "F"));
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%s ", (b ? "T" : "F"));
prt_write_file(prt_line_buffer);
}
@@ -1376,14 +1375,14 @@ static void prt_write_boolean(int b)
*/
static void prt_def_font(char *new_name, char *encoding, int height, char *font)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
prt_write_file(prt_line_buffer);
if (prt_out_mbyte) {
- sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
- new_name, height, 500./prt_ps_courier_font.wx, new_name);
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "/%s %d %f /_%s sffs\n",
+ new_name, height, 500./prt_ps_courier_font.wx, new_name);
} else {
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/%s %d /_%s ffs\n", new_name, height, new_name);
}
prt_write_file(prt_line_buffer);
@@ -1394,10 +1393,10 @@ static void prt_def_font(char *new_name, char *encoding, int height, char *font)
*/
static void prt_def_cidfont(char *new_name, int height, char *cidfont)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
prt_write_file(prt_line_buffer);
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/%s %d /_%s ffs\n", new_name, height, new_name);
prt_write_file(prt_line_buffer);
}
@@ -1407,7 +1406,7 @@ static void prt_def_cidfont(char *new_name, int height, char *cidfont)
*/
static void prt_dup_cidfont(char *original_name, char *new_name)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/%s %s d\n", new_name, original_name);
prt_write_file(prt_line_buffer);
}
@@ -1444,7 +1443,7 @@ static void prt_write_real(double val, int prec)
prt_real_bits(val, prec, &integer, &fraction);
// Emit integer part
- snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%d", integer);
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%d", integer);
prt_write_file(prt_line_buffer);
// Only emit fraction if necessary
if (fraction != 0) {
@@ -1454,11 +1453,11 @@ static void prt_write_real(double val, int prec)
fraction /= 10;
}
// Emit fraction left padded with zeros
- snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), ".%0*d",
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), ".%0*d",
prec, fraction);
prt_write_file(prt_line_buffer);
}
- sprintf((char *)prt_line_buffer, " ");
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), " ");
prt_write_file(prt_line_buffer);
}
@@ -1467,11 +1466,11 @@ static void prt_write_real(double val, int prec)
*/
static void prt_def_var(char *name, double value, int prec)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"/%s ", name);
prt_write_file(prt_line_buffer);
prt_write_real(value, prec);
- sprintf((char *)prt_line_buffer, "d\n");
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "d\n");
prt_write_file(prt_line_buffer);
}
@@ -1569,8 +1568,8 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource)
// Look for named resource file in runtimepath
STRCPY(buffer, "print");
add_pathsep((char *)buffer);
- xstrlcat((char *)buffer, name, MAXPATHL);
- xstrlcat((char *)buffer, ".ps", MAXPATHL);
+ STRLCAT(buffer, name, MAXPATHL);
+ STRLCAT(buffer, ".ps", MAXPATHL);
resource->filename[0] = NUL;
retval = (do_in_runtimepath(buffer, 0, prt_resource_name, resource->filename)
&& resource->filename[0] != NUL);
@@ -1833,14 +1832,14 @@ static void prt_dsc_start(void)
static void prt_dsc_noarg(char *comment)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%%s\n", comment);
prt_write_file(prt_line_buffer);
}
static void prt_dsc_textline(char *comment, char *text)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%%s: %s\n", comment, text);
prt_write_file(prt_line_buffer);
}
@@ -1848,7 +1847,7 @@ static void prt_dsc_textline(char *comment, char *text)
static void prt_dsc_text(char *comment, char *text)
{
// TODO(vim): - should scan 'text' for any chars needing escaping!
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%%s: (%s)\n", comment, text);
prt_write_file(prt_line_buffer);
}
@@ -1859,12 +1858,12 @@ static void prt_dsc_ints(char *comment, int count, int *ints)
{
int i;
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%%s:", comment);
prt_write_file(prt_line_buffer);
for (i = 0; i < count; i++) {
- sprintf((char *)prt_line_buffer, " %d", ints[i]);
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), " %d", ints[i]);
prt_write_file(prt_line_buffer);
}
@@ -1876,15 +1875,15 @@ static void prt_dsc_resources(const char *comment, const char *type, const char
FUNC_ATTR_NONNULL_ARG(2, 3)
{
if (comment != NULL) {
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%%s: %s", comment, type);
} else {
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%+ %s", type);
}
prt_write_file(prt_line_buffer);
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
" %s\n", string);
prt_write_file(prt_line_buffer);
}
@@ -1910,7 +1909,7 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color,
return;
}
- sprintf((char *)prt_line_buffer, "%%%%Requirements:");
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%%%%Requirements:");
prt_write_file(prt_line_buffer);
if (duplex) {
@@ -1928,7 +1927,7 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color,
if (num_copies > 1) {
prt_write_string(" numcopies(");
// Note: no space wanted so don't use prt_write_int()
- snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%d",
+ snprintf(prt_line_buffer, sizeof(prt_line_buffer), "%d",
num_copies);
prt_write_file(prt_line_buffer);
prt_write_string(")");
@@ -1939,7 +1938,7 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color,
static void prt_dsc_docmedia(char *paper_name, double width, double height, double weight,
char *colour, char *type)
{
- vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
+ vim_snprintf(prt_line_buffer, sizeof(prt_line_buffer),
"%%%%DocumentMedia: %s ", paper_name);
prt_write_file(prt_line_buffer);
prt_write_real(width, 2);
@@ -1982,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);
@@ -2204,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
@@ -2216,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, "-");
@@ -2232,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
@@ -2426,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];
@@ -2440,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:
@@ -2450,19 +2449,19 @@ 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);
- for (;; ) {
+ for (;;) {
bytes_read = fread((char *)resource_buffer, sizeof(char_u),
sizeof(resource_buffer), fd_resource);
if (ferror(fd_resource)) {
semsg(_("E457: Can't read PostScript resource file \"%s\""),
resource->filename);
fclose(fd_resource);
- return FALSE;
+ return false;
}
if (bytes_read == 0) {
break;
@@ -2470,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);
@@ -2479,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;
@@ -2492,11 +2491,10 @@ int mch_print_begin(prt_settings_T *psettings)
struct prt_ps_resource_S res_prolog;
struct prt_ps_resource_S res_encoding;
char buffer[256];
- char_u *p_encoding;
+ char *p_encoding;
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!
@@ -2568,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;
}
}
@@ -2595,45 +2593,45 @@ int mch_print_begin(prt_settings_T *psettings)
// that cannot be found then default to "latin1".
// Note: VIM specific encoding header is always skipped.
if (!prt_out_mbyte) {
- p_encoding = enc_skip(p_penc);
+ p_encoding = (char *)enc_skip(p_penc);
if (*p_encoding == NUL
- || !prt_find_resource((char *)p_encoding, &res_encoding)) {
+ || !prt_find_resource(p_encoding, &res_encoding)) {
// 'printencoding' not set or not supported - find alternate
int props;
- p_encoding = enc_skip(p_enc);
- props = enc_canon_props(p_encoding);
+ p_encoding = (char *)enc_skip(p_enc);
+ props = enc_canon_props((char_u *)p_encoding);
if (!(props & ENC_8BIT)
- || !prt_find_resource((char *)p_encoding, &res_encoding)) {
+ || !prt_find_resource(p_encoding, &res_encoding)) {
// 8-bit 'encoding' is not supported
// Use latin1 as default printing encoding
- p_encoding = (char_u *)"latin1";
- if (!prt_find_resource((char *)p_encoding, &res_encoding)) {
+ p_encoding = "latin1";
+ 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
} else {
- p_encoding = enc_skip(p_penc);
+ p_encoding = (char *)enc_skip(p_penc);
if (*p_encoding == NUL) {
- p_encoding = enc_skip(p_enc);
+ p_encoding = (char *)enc_skip(p_enc);
}
if (prt_use_courier) {
// Include ASCII range encoding vector
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
@@ -2641,9 +2639,9 @@ int mch_print_begin(prt_settings_T *psettings)
}
prt_conv.vc_type = CONV_NONE;
- if (!(enc_canon_props(p_enc) & enc_canon_props(p_encoding) & ENC_8BIT)) {
+ if (!(enc_canon_props(p_enc) & enc_canon_props((char_u *)p_encoding) & ENC_8BIT)) {
// Set up encoding conversion if required
- if (convert_setup(&prt_conv, p_enc, p_encoding) == FAIL) {
+ if (convert_setup(&prt_conv, p_enc, (char_u *)p_encoding) == FAIL) {
semsg(_("E620: Unable to convert to print encoding \"%s\""),
p_encoding);
return false;
@@ -2656,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;
}
}
@@ -2737,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;
}
}
@@ -2766,23 +2764,23 @@ int mch_print_begin(prt_settings_T *psettings)
// When using Courier for ASCII range when printing multi-byte, need to
// pick up ASCII encoding to use with it.
if (prt_use_courier) {
- p_encoding = (char_u *)prt_ascii_encoding;
+ p_encoding = prt_ascii_encoding;
}
prt_dsc_resources("IncludeResource", "font",
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
- prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
+ prt_def_font("F0", p_encoding, (int)prt_line_height,
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
prt_dsc_resources("IncludeResource", "font",
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
- prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
+ prt_def_font("F1", p_encoding, (int)prt_line_height,
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
prt_dsc_resources("IncludeResource", "font",
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
- prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
+ prt_def_font("F2", p_encoding, (int)prt_line_height,
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
prt_dsc_resources("IncludeResource", "font",
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
- prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
+ prt_def_font("F3", p_encoding, (int)prt_line_height,
prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
}
if (prt_out_mbyte) {
@@ -2847,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)
@@ -2865,7 +2861,7 @@ void mch_print_end(prt_settings_T *psettings)
// Write CTRL-D to close serial communication link if used.
// NOTHING MUST BE WRITTEN AFTER THIS!
- prt_write_file((char_u *)"\004");
+ prt_write_file("\004");
if (!prt_file_error && psettings->outfile == NULL
&& !got_int && !psettings->user_abort) {
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index d4d53c4126..50a03e0c02 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -65,6 +65,8 @@ typedef enum {
HLF_LNA, // LineNrAbove
HLF_LNB, // LineNrBelow
HLF_CLN, // current line number when 'cursorline' is set
+ HLF_CLS, // current line sign column
+ HLF_CLF, // current line fold
HLF_R, // return to continue message and yes/no questions
HLF_S, // status lines
HLF_SNC, // status lines of not-current windows
@@ -122,6 +124,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_LNA] = "LineNrAbove",
[HLF_LNB] = "LineNrBelow",
[HLF_CLN] = "CursorLineNr",
+ [HLF_CLS] = "CursorLineSign",
+ [HLF_CLF] = "CursorLineFold",
[HLF_R] = "Question",
[HLF_S] = "StatusLine",
[HLF_SNC] = "StatusLineNC",
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 5b5f056164..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;
}
@@ -557,7 +557,7 @@ static int cs_cnt_matches(size_t idx)
int nlines = 0;
char *buf = xmalloc(CSREAD_BUFSIZE);
- for (;; ) {
+ for (;;) {
errno = 0;
if (!fgets(buf, CSREAD_BUFSIZE, csinfo[idx].fr_fp)) {
if (errno == EINTR) {
@@ -601,7 +601,7 @@ static int cs_cnt_matches(size_t idx)
if ((stok = strtok(NULL, (const char *)" ")) == NULL) {
continue;
}
- if (strncmp((const char *)stok, "lines", 5)) {
+ if (strncmp(stok, "lines", 5)) {
continue;
}
@@ -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;
@@ -966,8 +966,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int us
qfpos++;
// 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;
+ (void)semsg(_("E469: invalid cscopequickfix flag %c for %c"), *qfpos, *(qfpos - 1));
+ 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);
@@ -1214,8 +1214,8 @@ static cscmd_T *cs_lookup_cmd(exarg_T *eap)
}
len = strlen(stok);
- for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp) {
- if (strncmp((const char *)(stok), cmdp->name, len) == 0) {
+ for (cmdp = cs_cmds; cmdp->name != NULL; cmdp++) {
+ if (strncmp(stok, cmdp->name, len) == 0) {
return cmdp;
}
}
@@ -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/indent.c b/src/nvim/indent.c
index f49aff6643..8cc5bc2436 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -17,7 +17,6 @@
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/plines.h"
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 3e3e07e9d6..faa9b38cf7 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -8,7 +8,6 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/misc1.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
diff --git a/src/nvim/input.c b/src/nvim/input.c
new file mode 100644
index 0000000000..2f7c5c2c16
--- /dev/null
+++ b/src/nvim/input.c
@@ -0,0 +1,255 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// input.c: high level functions for prompting the user or input
+// like yes/no or number prompts.
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "nvim/func_attr.h"
+#include "nvim/getchar.h"
+#include "nvim/mbyte.h"
+#include "nvim/memory.h"
+#include "nvim/input.h"
+#include "nvim/mouse.h"
+#include "nvim/os/input.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "input.c.generated.h"
+#endif
+
+/// Ask for a reply from the user, 'y' or 'n'
+///
+/// No other characters are accepted, the message is repeated until a valid
+/// reply is entered or <C-c> is hit.
+///
+/// @param[in] str Prompt: question to ask user. Is always followed by
+/// " (y/n)?".
+/// @param[in] direct Determines what function to use to get user input. If
+/// true then ui_inchar() will be used, otherwise vgetc().
+/// I.e. when direct is true then characters are obtained
+/// directly from the user without buffers involved.
+///
+/// @return 'y' or 'n'. Last is also what will be returned in case of interrupt.
+int ask_yesno(const char *const str, const bool direct)
+{
+ const int save_State = State;
+
+ no_wait_return++;
+ State = CONFIRM; // Mouse behaves like with :confirm.
+ setmouse(); // Disable mouse in xterm.
+ no_mapping++;
+
+ int r = ' ';
+ while (r != 'y' && r != 'n') {
+ // Same highlighting as for wait_return.
+ smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
+ if (direct) {
+ r = get_keystroke(NULL);
+ } else {
+ r = plain_vgetc();
+ }
+ if (r == Ctrl_C || r == ESC) {
+ r = 'n';
+ }
+ msg_putchar(r); // Show what you typed.
+ ui_flush();
+ }
+ no_wait_return--;
+ State = save_State;
+ setmouse();
+ no_mapping--;
+
+ return r;
+}
+
+/// Get a key stroke directly from the user.
+///
+/// Ignores mouse clicks and scrollbar events, except a click for the left
+/// button (used at the more prompt).
+/// Doesn't use vgetc(), because it syncs undo and eats mapped characters.
+/// Disadvantage: typeahead is ignored.
+/// Translates the interrupt character for unix to ESC.
+int get_keystroke(MultiQueue *events)
+{
+ char_u *buf = NULL;
+ int buflen = 150;
+ int maxlen;
+ int len = 0;
+ int n;
+ int save_mapped_ctrl_c = mapped_ctrl_c;
+ int waited = 0;
+
+ mapped_ctrl_c = 0; // mappings are not used here
+ for (;;) {
+ // flush output before waiting
+ ui_flush();
+ // Leave some room for check_termcode() to insert a key code into (max
+ // 5 chars plus NUL). And fix_input_buffer() can triple the number of
+ // bytes.
+ maxlen = (buflen - 6 - len) / 3;
+ if (buf == NULL) {
+ buf = xmalloc((size_t)buflen);
+ } else if (maxlen < 10) {
+ // Need some more space. This might happen when receiving a long
+ // escape sequence.
+ buflen += 100;
+ buf = xrealloc(buf, (size_t)buflen);
+ maxlen = (buflen - 6 - len) / 3;
+ }
+
+ // First time: blocking wait. Second time: wait up to 100ms for a
+ // terminal code to complete.
+ n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events);
+ if (n > 0) {
+ // Replace zero and CSI by a special key code.
+ n = fix_input_buffer(buf + len, n);
+ len += n;
+ waited = 0;
+ } else if (len > 0) {
+ waited++; // keep track of the waiting time
+ }
+ if (n > 0) { // found a termcode: adjust length
+ len = n;
+ }
+ if (len == 0) { // nothing typed yet
+ continue;
+ }
+
+ // Handle modifier and/or special key code.
+ n = buf[0];
+ if (n == K_SPECIAL) {
+ n = TO_SPECIAL(buf[1], buf[2]);
+ if (buf[1] == KS_MODIFIER
+ || n == K_IGNORE
+ || (is_mouse_key(n) && n != K_LEFTMOUSE)) {
+ if (buf[1] == KS_MODIFIER) {
+ mod_mask = buf[2];
+ }
+ len -= 3;
+ if (len > 0) {
+ memmove(buf, buf + 3, (size_t)len);
+ }
+ continue;
+ }
+ break;
+ }
+ if (MB_BYTE2LEN(n) > len) {
+ // more bytes to get.
+ continue;
+ }
+ buf[len >= buflen ? buflen - 1 : len] = NUL;
+ n = utf_ptr2char(buf);
+ break;
+ }
+ xfree(buf);
+
+ mapped_ctrl_c = save_mapped_ctrl_c;
+ return n;
+}
+
+/// Get a number from the user.
+/// When "mouse_used" is not NULL allow using the mouse.
+///
+/// @param colon allow colon to abort
+int get_number(int colon, int *mouse_used)
+{
+ int n = 0;
+ int c;
+ int typed = 0;
+
+ if (mouse_used != NULL) {
+ *mouse_used = false;
+ }
+
+ // When not printing messages, the user won't know what to type, return a
+ // zero (as if CR was hit).
+ if (msg_silent != 0) {
+ return 0;
+ }
+
+ no_mapping++;
+ for (;;) {
+ ui_cursor_goto(msg_row, msg_col);
+ c = safe_vgetc();
+ if (ascii_isdigit(c)) {
+ n = n * 10 + c - '0';
+ msg_putchar(c);
+ typed++;
+ } else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) {
+ if (typed > 0) {
+ msg_puts("\b \b");
+ typed--;
+ }
+ n /= 10;
+ } else if (mouse_used != NULL && c == K_LEFTMOUSE) {
+ *mouse_used = true;
+ n = mouse_row + 1;
+ break;
+ } else if (n == 0 && c == ':' && colon) {
+ stuffcharReadbuff(':');
+ if (!exmode_active) {
+ cmdline_row = msg_row;
+ }
+ skip_redraw = true; // skip redraw once
+ do_redraw = false;
+ break;
+ } else if (c == Ctrl_C || c == ESC || c == 'q') {
+ n = 0;
+ break;
+ } else if (c == CAR || c == NL) {
+ break;
+ }
+ }
+ no_mapping--;
+ return n;
+}
+
+/// Ask the user to enter a number.
+///
+/// When "mouse_used" is not NULL allow using the mouse and in that case return
+/// the line number.
+int prompt_for_number(int *mouse_used)
+{
+ int i;
+ int save_cmdline_row;
+ int save_State;
+
+ // When using ":silent" assume that <CR> was entered.
+ if (mouse_used != NULL) {
+ msg_puts(_("Type number and <Enter> or click with the mouse "
+ "(q or empty cancels): "));
+ } else {
+ msg_puts(_("Type number and <Enter> (q or empty cancels): "));
+ }
+
+ // Set the state such that text can be selected/copied/pasted and we still
+ // get mouse events.
+ save_cmdline_row = cmdline_row;
+ cmdline_row = 0;
+ save_State = State;
+ State = ASKMORE; // prevents a screen update when using a timer
+ // May show different mouse shape.
+ setmouse();
+
+ i = get_number(true, mouse_used);
+ if (KeyTyped) {
+ // don't call wait_return() now
+ if (msg_row > 0) {
+ cmdline_row = msg_row - 1;
+ }
+ need_wait_return = false;
+ msg_didany = false;
+ msg_didout = false;
+ } else {
+ cmdline_row = save_cmdline_row;
+ }
+ State = save_State;
+ // May need to restore mouse shape.
+ setmouse();
+
+ return i;
+}
diff --git a/src/nvim/input.h b/src/nvim/input.h
new file mode 100644
index 0000000000..7975f21215
--- /dev/null
+++ b/src/nvim/input.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_INPUT_H
+#define NVIM_INPUT_H
+
+#include "nvim/vim.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "input.h.generated.h"
+#endif
+#endif // NVIM_INPUT_H
diff --git a/src/nvim/lib/kbtree.h b/src/nvim/lib/kbtree.h
index 5d9c1095bc..617773a79a 100644
--- a/src/nvim/lib/kbtree.h
+++ b/src/nvim/lib/kbtree.h
@@ -53,7 +53,7 @@
bool is_internal; \
key_t key[2*T-1]; \
kbnode_##name##_t *ptr[]; \
- } ; \
+ }; \
typedef struct { \
kbnode_##name##_t *root; \
int n_keys, n_nodes; \
diff --git a/src/nvim/lib/khash.h b/src/nvim/lib/khash.h
index e0faf94db9..e81db43038 100644
--- a/src/nvim/lib/khash.h
+++ b/src/nvim/lib/khash.h
@@ -459,7 +459,7 @@ static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) {
- for (++s ; *s; ++s) { h = (h << 5) - h + (uint8_t)*s; }
+ for (++s; *s; ++s) { h = (h << 5) - h + (uint8_t)*s; }
}
return h;
}
@@ -666,7 +666,7 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
} \
}
-// More conenient interfaces
+// More convenient interfaces
/*! @function
@abstract Instantiate a hash set containing integer keys
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 9f2372f831..b6792a5a97 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -782,10 +782,10 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
break;
}
#define ADD_TYPE(type, data_key) \
-case kObjectType##type: { \
- nlua_push_##type(lstate, obj.data.data_key, special); \
- break; \
-}
+ case kObjectType##type: { \
+ nlua_push_##type(lstate, obj.data.data_key, special); \
+ break; \
+ }
ADD_TYPE(Boolean, boolean)
ADD_TYPE(Integer, integer)
ADD_TYPE(Float, floating)
@@ -794,10 +794,10 @@ case kObjectType##type: { \
ADD_TYPE(Dictionary, dictionary)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
-case kObjectType##type: { \
- nlua_push_##type(lstate, (type)obj.data.integer, special); \
- break; \
-}
+ case kObjectType##type: { \
+ nlua_push_##type(lstate, (type)obj.data.integer, special); \
+ break; \
+ }
ADD_REMOTE_TYPE(Buffer)
ADD_REMOTE_TYPE(Window)
ADD_REMOTE_TYPE(Tabpage)
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index b27b1ae7a8..107ff22913 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -31,7 +31,6 @@
#include "nvim/map.h"
#include "nvim/memline.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/os.h"
#include "nvim/screen.h"
@@ -405,9 +404,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
const char *code = (char *)&shared_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/shared.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(shared_module) - 1, "@vim/shared.lua")
|| nlua_pcall(lstate, 0, 0)) {
- nlua_error(lstate, _("E5106: Error while creating shared module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n"));
return 1;
}
}
@@ -417,18 +416,18 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_getfield(lstate, -1, "loaded"); // [package, loaded]
const char *code = (char *)&inspect_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/inspect.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(inspect_module) - 1, "@vim/inspect.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s\n"));
return 1;
}
// [package, loaded, inspect]
lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded]
code = (char *)&lua_F_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/F.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(lua_F_module) - 1, "@vim/F.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s\n"));
return 1;
}
// [package, loaded, module]
@@ -439,9 +438,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
const char *code = (char *)&vim_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(vim_module) - 1, "@vim.lua")
|| nlua_pcall(lstate, 0, 0)) {
- nlua_error(lstate, _("E5106: Error while creating vim module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim module: %.*s\n"));
return 1;
}
}
@@ -451,9 +450,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_getfield(lstate, -1, "loaded"); // [package, loaded]
const char *code = (char *)&lua_meta_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/_meta.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(lua_meta_module) - 1, "@vim/_meta.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s\n"));
return 1;
}
// [package, loaded, module]
@@ -521,6 +520,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]) {
@@ -957,7 +959,7 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
while ((line = fgetline(0, cookie, 0, false)) != NULL) {
GA_APPEND(char_u *, &ga, line);
}
- char *code = (char *)ga_concat_strings_sep(&ga, "\n");
+ char *code = ga_concat_strings_sep(&ga, "\n");
size_t len = strlen(code);
nlua_typval_exec(code, len, name, NULL, 0, false, NULL);
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index db79e9e7e9..0d6789317c 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -34,7 +34,6 @@
#include "nvim/map.h"
#include "nvim/memline.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/os.h"
#include "nvim/regexp.h"
@@ -175,13 +174,13 @@ int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
size_t s1_len;
const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
intptr_t idx;
- if (lua_gettop(lstate) >= 2) {
+ if (lua_isnoneornil(lstate, 2)) {
+ idx = (intptr_t)s1_len;
+ } else {
idx = luaL_checkinteger(lstate, 2);
if (idx < 0 || idx > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- } else {
- idx = (intptr_t)s1_len;
}
size_t codepoints = 0, codeunits = 0;
@@ -231,8 +230,8 @@ static int nlua_str_utf_start(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int tail_offset = mb_head_off((char_u *)s1, (char_u *)s1 + (char_u)offset - 1);
- lua_pushinteger(lstate, tail_offset);
+ int head_offset = mb_head_off((char_u *)s1, (char_u *)s1 + offset - 1);
+ lua_pushinteger(lstate, head_offset);
return 1;
}
@@ -251,7 +250,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int tail_offset = mb_tail_off((char_u *)s1, (char_u *)s1 + (char_u)offset - 1);
+ int tail_offset = mb_tail_off((char_u *)s1, (char_u *)s1 + offset - 1);
lua_pushinteger(lstate, tail_offset);
return 1;
}
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 30c7034209..c1a1e7f162 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -323,6 +323,7 @@ end
do
local validate = vim.validate
+ --@private
local function make_dict_accessor(scope, handle)
validate {
scope = {scope, 's'};
@@ -422,11 +423,10 @@ end
---
--- Without a runtime, writes to :Messages
---@see :help nvim_notify
----@param msg Content of the notification to show to the user
----@param log_level Optional log level
----@param opts Dictionary with optional options (timeout, etc)
-function vim.notify(msg, log_level, _opts)
-
+---@param msg string Content of the notification to show to the user
+---@param log_level number|nil enum from vim.log.levels
+---@param opts table|nil additional options (timeout, etc)
+function vim.notify(msg, log_level, opts) -- luacheck: no unused
if log_level == vim.log.levels.ERROR then
vim.api.nvim_err_writeln(msg)
elseif log_level == vim.log.levels.WARN then
@@ -454,7 +454,7 @@ local on_key_cbs = {}
--- On each key press, Nvim passes the key char to fn(). |i_CTRL-V|
--- If {fn} is nil, it removes the callback for the associated {ns_id}
---@param ns_id number? Namespace ID. If nil or 0, generates and returns a new
---- |nvim_create_namesapce()| id.
+--- |nvim_create_namespace()| id.
---
---@return number Namespace id associated with {fn}. Or count of all callbacks
---if on_key() is called without arguments.
@@ -580,6 +580,7 @@ function vim._expand_pat(pat, env)
end
local keys = {}
+ ---@private
local function insert_keys(obj)
for k,_ in pairs(obj) do
if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index 7eda9b6270..b2e971f9f3 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -17,7 +17,7 @@
#include "xdiff/xdiff.h"
typedef enum {
- kNluaXdiffModeUnified = 0,
+ kNluaXdiffModeUnified = 0,
kNluaXdiffModeOnHunkCB,
kNluaXdiffModeLocations,
} NluaXdiffMode;
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index faef0f69b2..c2b2c89abf 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -54,7 +54,7 @@
#define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || ascii_isdigit(c))
// Returns empty string if it is NULL.
-#define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"")
+#define EMPTY_IF_NULL(x) (char *)((x) ? (x) : (char_u *)"")
// Adjust chars in a language according to 'langmap' option.
// NOTE that there is no noticeable overhead if 'langmap' is not set.
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 921bc883cf..cbd1f53727 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -39,7 +39,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -696,6 +695,50 @@ void getout(int exitval)
os_exit(exitval);
}
+/// Preserve files and exit.
+/// @note IObuff must contain a message.
+/// @note This may be called from deadly_signal() in a signal handler, avoid
+/// unsafe functions, such as allocating memory.
+void preserve_exit(void)
+ FUNC_ATTR_NORETURN
+{
+ // 'true' when we are sure to exit, e.g., after a deadly signal
+ static bool really_exiting = false;
+
+ // Prevent repeated calls into this method.
+ if (really_exiting) {
+ if (input_global_fd() >= 0) {
+ // normalize stream (#2598)
+ stream_set_blocking(input_global_fd(), true);
+ }
+ exit(2);
+ }
+
+ really_exiting = true;
+ // Ignore SIGHUP while we are already exiting. #9274
+ signal_reject_deadly();
+ mch_errmsg(IObuff);
+ mch_errmsg("\n");
+ ui_flush();
+
+ ml_close_notmod(); // close all not-modified buffers
+
+ FOR_ALL_BUFFERS(buf) {
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
+ mch_errmsg("Vim: preserving files...\r\n");
+ ui_flush();
+ ml_sync_all(false, false, true); // preserve all swap files
+ break;
+ }
+ }
+
+ ml_close_all(false); // close all memfiles, without deleting
+
+ mch_errmsg("Vim: Finished.\r\n");
+
+ getout(1);
+}
+
/// Gets the integer value of a numeric command line argument if given,
/// such as '-o10'.
///
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 51f4ba635f..39f18b333d 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -235,7 +235,7 @@ pos_T *movemark(int count)
return (pos_T *)NULL;
}
- for (;; ) {
+ for (;;) {
if (curwin->w_jumplistidx + count < 0
|| curwin->w_jumplistidx + count >= curwin->w_jumplistlen) {
return (pos_T *)NULL;
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 12460646ed..5eb209a6f6 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -42,13 +42,13 @@
#include "nvim/eval.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/getchar.h"
#include "nvim/iconv.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
@@ -764,7 +764,7 @@ int utfc_ptr2char(const char_u *p, int *pcc)
&& p[len] >= 0x80
&& utf_composinglike(p, p + len)) {
cc = utf_ptr2char(p + len);
- for (;; ) {
+ for (;;) {
pcc[i++] = cc;
if (i == MAX_MCO) {
break;
@@ -1322,7 +1322,7 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2
int c1, c2, cdiff;
char_u buffer[6];
- for (;; ) {
+ for (;;) {
c1 = utf_safe_read_char_adv(&s1, &n1);
c2 = utf_safe_read_char_adv(&s2, &n2);
@@ -1609,7 +1609,8 @@ void show_utf8(void)
msg((char *)IObuff);
}
-/// Return offset from "p" to the first byte of the character it points into.
+/// Return offset from "p" to the start of a character, including composing characters.
+/// "base" must be the start of the string, which must be NUL terminated.
/// If "p" points to the NUL at the end of the string return 0.
/// Returns 0 when already at the first byte of a character.
int utf_head_off(const char_u *base, const char_u *p)
@@ -1850,10 +1851,9 @@ int mb_off_next(char_u *base, char_u *p)
return i;
}
-/*
- * Return the offset from "p" to the last byte of the character it points
- * into. Can start anywhere in a stream of bytes.
- */
+/// Return the offset from "p" to the last byte of the character it points
+/// into. Can start anywhere in a stream of bytes.
+/// Composing characters are not included.
int mb_tail_off(char_u *base, char_u *p)
{
int i;
@@ -1933,7 +1933,7 @@ void utf_find_illegal(void)
}
curwin->w_cursor.coladd = 0;
- for (;; ) {
+ for (;;) {
p = get_cursor_pos_ptr();
if (vimconv.vc_type != CONV_NONE) {
xfree(tofree);
@@ -2363,7 +2363,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen
from = (char *)str;
fromlen = slen;
- for (;; ) {
+ for (;;) {
if (len == 0 || ICONV_ERRNO == ICONV_E2BIG) {
// Allocate enough room for most conversions. When re-allocating
// increase the buffer size.
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 2a0ea9a269..3397296b3a 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -505,7 +505,7 @@ bool mf_release_all(void)
// Flush as many blocks as possible, only if there is a swapfile.
if (mfp->mf_fd >= 0) {
- for (bhdr_T *hp = mfp->mf_used_last; hp != NULL; ) {
+ for (bhdr_T *hp = mfp->mf_used_last; hp != NULL;) {
if (!(hp->bh_flags & BH_LOCKED)
&& (!(hp->bh_flags & BH_DIRTY)
|| mf_write(mfp, hp) != FAIL)) {
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 456b1013c1..08521c0dc3 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -51,6 +51,7 @@
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
#include "nvim/getchar.h"
+#include "nvim/input.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -58,7 +59,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
@@ -407,7 +407,7 @@ void ml_setname(buf_T *buf)
*/
dirp = p_dir;
bool found_existing_dir = false;
- for (;; ) {
+ for (;;) {
if (*dirp == NUL) { // tried all directories, fail
break;
}
@@ -504,7 +504,7 @@ void ml_open_file(buf_T *buf)
*/
dirp = p_dir;
bool found_existing_dir = false;
- for (;; ) {
+ for (;;) {
if (*dirp == NUL) {
break;
}
@@ -1236,7 +1236,7 @@ void ml_recover(bool checkext)
} else if (error) {
++no_wait_return;
msg(">>>>>>>>>>>>>");
- emsg(_( "E312: Errors detected while recovering; look for lines starting with ???"));
+ emsg(_("E312: Errors detected while recovering; look for lines starting with ???"));
--no_wait_return;
msg(_("See \":help E312\" for more information."));
msg(">>>>>>>>>>>>>");
@@ -1841,6 +1841,17 @@ char_u *ml_get_pos(const pos_T *pos)
return ml_get_buf(curbuf, pos->lnum, false) + pos->col;
}
+/// get codepoint at pos. pos must be either valid or have col set to MAXCOL!
+int gchar_pos(pos_T *pos)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ // When searching columns is sometimes put at the end of a line.
+ if (pos->col == MAXCOL) {
+ return NUL;
+ }
+ return utf_ptr2char(ml_get_pos(pos));
+}
+
/// Return a pointer to a line in a specific buffer
///
/// @param will_change true mark the buffer dirty (chars in the line will be changed)
@@ -2349,7 +2360,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b
* move some of the pointer into the new block
* prepare for updating the parent block
*/
- for (;; ) { // do this twice when splitting block 1
+ for (;;) { // do this twice when splitting block 1
hp_new = ml_new_ptr(mfp);
if (hp_new == NULL) { // TODO: try to fix tree
return FAIL;
@@ -2564,7 +2575,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
*/
if (buf->b_ml.ml_line_count == 1) { // file becomes empty
if (message) {
- set_keep_msg((char_u *)_(no_lines_msg), 0);
+ set_keep_msg(_(no_lines_msg), 0);
}
i = ml_replace((linenr_T)1, (char_u *)"", true);
@@ -2733,7 +2744,7 @@ linenr_T ml_firstmarked(void)
* The search starts with lowest_marked line. This is the last line where
* a mark was found, adjusted by inserting/deleting lines.
*/
- for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; ) {
+ for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) {
/*
* Find the data block containing the line.
* This also fills the stack with the blocks from the root to the data
@@ -2775,7 +2786,7 @@ void ml_clearmarked(void)
/*
* The search starts with line lowest_marked.
*/
- for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count; ) {
+ for (lnum = lowest_marked; lnum <= curbuf->b_ml.ml_line_count;) {
/*
* Find the data block containing the line.
* This also fills the stack with the blocks from the root to the data
@@ -3034,7 +3045,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
/*
* search downwards in the tree until a data block is found
*/
- for (;; ) {
+ for (;;) {
if ((hp = mf_get(mfp, bnum, page_count)) == NULL) {
goto error_noblock;
}
@@ -3211,7 +3222,7 @@ int resolve_symlink(const char_u *fname, char_u *buf)
// Put the result so far in tmp[], starting with the original name.
STRLCPY(tmp, fname, MAXPATHL);
- for (;; ) {
+ for (;;) {
// Limit symlink depth to 100, catch recursive loops.
if (++depth == 100) {
semsg(_("E773: Symlink loop for \"%s\""), fname);
@@ -3481,7 +3492,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
fname = (char *)makeswapname((char_u *)buf_fname, buf->b_ffname, buf,
(char_u *)dir_name);
- for (;; ) {
+ for (;;) {
if (fname == NULL) { // must be out of memory
break;
}
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 547a9015b7..677ff8f522 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -17,7 +17,6 @@
#include "nvim/memfile.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/sign.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -573,7 +572,6 @@ void free_all_mem(void)
return;
}
entered_free_all_mem = true;
-
// Don't want to trigger autocommands from here on.
block_autocmds();
@@ -632,6 +630,7 @@ void free_all_mem(void)
clear_sb_text(true); // free any scrollback text
// Free some global vars.
+ xfree(last_mode);
xfree(last_cmdline);
xfree(new_last_cmdline);
set_keep_msg(NULL, 0);
@@ -672,7 +671,7 @@ void free_all_mem(void)
first_tabpage = NULL;
// message history
- for (;; ) {
+ for (;;) {
if (delete_first_msg() == FAIL) {
break;
}
@@ -687,7 +686,7 @@ void free_all_mem(void)
// Must be after eval_clear to avoid it trying to access b:changedtick after
// freeing it.
p_acd = false;
- for (buf = firstbuf; buf != NULL; ) {
+ for (buf = firstbuf; buf != NULL;) {
bufref_T bufref;
set_bufref(&bufref, buf);
nextbuf = buf->b_next;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index c2b6a5e402..ac4d52c392 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -22,7 +22,6 @@
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -80,7 +79,7 @@ void ex_menu(exarg_T *eap)
modes = get_menu_cmd_modes((char *)eap->cmd, eap->forceit, &noremap, &unmenu);
arg = eap->arg;
- for (;; ) {
+ for (;;) {
if (STRNCMP(arg, "<script>", 8) == 0) {
noremap = REMAP_SCRIPT;
arg = skipwhite(arg + 8);
@@ -449,7 +448,7 @@ static int add_menu_path(const char_u *const menu_path, vimmenu_T *menuarg,
}
if (c != 0) {
- menu->strings[i] = xmalloc(STRLEN(call_data) + 5 );
+ menu->strings[i] = xmalloc(STRLEN(call_data) + 5);
menu->strings[i][0] = c;
if (d == 0) {
STRCPY(menu->strings[i] + 1, call_data);
@@ -1315,7 +1314,7 @@ static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext)
}
// Find mnemonic characters "&a" and reduce "&&" to "&".
- for (p = text; p != NULL; ) {
+ for (p = text; p != NULL;) {
p = vim_strchr(p, '&');
if (p != NULL) {
if (p[1] == NUL) { // trailing "&"
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 7b6337bea2..befca8c76b 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -23,12 +23,12 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/input.h"
#include "nvim/keymap.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
@@ -76,6 +76,8 @@ static int msg_hist_len = 0;
static FILE *verbose_fd = NULL;
static int verbose_did_open = FALSE;
+bool keep_msg_more = false; // keep_msg was set by msgmore()
+
/*
* When writing messages to the screen, there are many different situations.
* A number of variables is used to remember the current state:
@@ -329,7 +331,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
if (keep && retval && vim_strsize((char_u *)s) < (int)(Rows - cmdline_row - 1)
* Columns + sc_col) {
- set_keep_msg((char_u *)s, 0);
+ set_keep_msg((char *)s, 0);
}
xfree(buf);
@@ -401,7 +403,7 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen)
}
len += n;
buf[e] = s[e];
- for (n = utfc_ptr2len(s + e); --n > 0; ) {
+ for (n = utfc_ptr2len(s + e); --n > 0;) {
if (++e == buflen) {
break;
}
@@ -732,7 +734,7 @@ static bool emsg_multiline(const char *s, bool multiline)
/// @return true if wait_return not called
bool emsg(const char *s)
{
- return emsg_multiline((const char *)s, false);
+ return emsg_multiline(s, false);
}
void emsg_invreg(int name)
@@ -839,13 +841,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 +869,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;
@@ -883,7 +883,7 @@ char_u *msg_may_trunc(int force, char_u *s)
return s;
}
int n;
- for (n = 0; size >= room; ) {
+ for (n = 0; size >= room;) {
size -= utf_ptr2cells(s + n);
n += utfc_ptr2len(s + n);
}
@@ -1288,11 +1288,11 @@ static void hit_return_msg(void)
/*
* Set "keep_msg" to "s". Free the old value and check for NULL pointer.
*/
-void set_keep_msg(char_u *s, int attr)
+void set_keep_msg(char *s, int attr)
{
xfree(keep_msg);
if (s != NULL && msg_silent == 0) {
- keep_msg = vim_strsave(s);
+ keep_msg = vim_strsave((char_u *)s);
} else {
keep_msg = NULL;
}
@@ -1300,6 +1300,49 @@ void set_keep_msg(char_u *s, int attr)
keep_msg_attr = attr;
}
+void msgmore(long n)
+{
+ long pn;
+
+ if (global_busy // no messages now, wait until global is finished
+ || !messaging()) { // 'lazyredraw' set, don't do messages now
+ return;
+ }
+
+ // We don't want to overwrite another important message, but do overwrite
+ // a previous "more lines" or "fewer lines" message, so that "5dd" and
+ // then "put" reports the last action.
+ if (keep_msg != NULL && !keep_msg_more) {
+ return;
+ }
+
+ if (n > 0) {
+ pn = n;
+ } else {
+ pn = -n;
+ }
+
+ if (pn > p_report) {
+ if (n > 0) {
+ vim_snprintf(msg_buf, MSG_BUF_LEN,
+ NGETTEXT("%ld more line", "%ld more lines", pn),
+ pn);
+ } else {
+ vim_snprintf(msg_buf, MSG_BUF_LEN,
+ NGETTEXT("%ld line less", "%ld fewer lines", pn),
+ pn);
+ }
+ if (got_int) {
+ xstrlcat(msg_buf, _(" (Interrupted)"), MSG_BUF_LEN);
+ }
+ if (msg(msg_buf)) {
+ set_keep_msg(msg_buf, 0);
+ keep_msg_more = true;
+ }
+ }
+}
+
+
void msg_ext_set_kind(const char *msg_kind)
{
// Don't change the label of an existing batch:
@@ -2056,7 +2099,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs
msg_ext_last_attr = attr;
}
// Concat pieces with the same highlight
- size_t len = strnlen((char *)str, maxlen); // -V781
+ size_t len = STRNLEN(str, maxlen); // -V781
ga_concat_len(&msg_ext_last_chunk, (char *)str, len);
msg_ext_cur_len += len;
return;
@@ -2549,7 +2592,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
msgchunk_T *mp = smp;
char_u *p;
- for (;; ) {
+ for (;;) {
msg_row = row;
msg_col = mp->sb_msg_col;
p = mp->sb_text;
@@ -2688,7 +2731,7 @@ static int do_more_prompt(int typed_char)
if (typed_char == NUL) {
msg_moremsg(FALSE);
}
- for (;; ) {
+ for (;;) {
/*
* Get a typed character directly from the user.
*/
@@ -3342,7 +3385,7 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
}
if (msg_attr((const char *)message, keep_msg_attr) && msg_scrolled == 0) {
- set_keep_msg(message, keep_msg_attr);
+ set_keep_msg((char *)message, keep_msg_attr);
}
msg_didout = false; // Overwrite this message.
msg_nowait = true; // Don't wait for this message.
@@ -3436,7 +3479,7 @@ int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfl
++no_wait_return;
hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
- for (;; ) {
+ for (;;) {
// Get a typed character directly from the user.
c = get_keystroke(NULL);
switch (c) {
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
deleted file mode 100644
index faf0b0f633..0000000000
--- a/src/nvim/misc1.c
+++ /dev/null
@@ -1,1061 +0,0 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
-/*
- * misc1.c: functions that didn't seem to fit elsewhere
- */
-
-#include <assert.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <string.h>
-
-#include "nvim/ascii.h"
-#include "nvim/buffer.h"
-#include "nvim/buffer_updates.h"
-#include "nvim/charset.h"
-#include "nvim/cursor.h"
-#include "nvim/diff.h"
-#include "nvim/edit.h"
-#include "nvim/eval.h"
-#include "nvim/event/stream.h"
-#include "nvim/ex_cmds.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
-#include "nvim/fold.h"
-#include "nvim/func_attr.h"
-#include "nvim/garray.h"
-#include "nvim/getchar.h"
-#include "nvim/indent.h"
-#include "nvim/indent_c.h"
-#include "nvim/main.h"
-#include "nvim/mbyte.h"
-#include "nvim/memline.h"
-#include "nvim/memory.h"
-#include "nvim/message.h"
-#include "nvim/misc1.h"
-#include "nvim/mouse.h"
-#include "nvim/move.h"
-#include "nvim/option.h"
-#include "nvim/os/input.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/os/signal.h"
-#include "nvim/os/time.h"
-#include "nvim/os_unix.h"
-#include "nvim/quickfix.h"
-#include "nvim/regexp.h"
-#include "nvim/screen.h"
-#include "nvim/search.h"
-#include "nvim/state.h"
-#include "nvim/strings.h"
-#include "nvim/tag.h"
-#include "nvim/ui.h"
-#include "nvim/undo.h"
-#include "nvim/vim.h"
-#include "nvim/window.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "misc1.c.generated.h"
-#endif
-// All user names (for ~user completion as done by shell).
-static garray_T ga_users = GA_EMPTY_INIT_VALUE;
-
-/*
- * get_leader_len() returns the length in bytes of the prefix of the given
- * string which introduces a comment. If this string is not a comment then
- * 0 is returned.
- * When "flags" is not NULL, it is set to point to the flags of the recognized
- * comment leader.
- * "backward" must be true for the "O" command.
- * If "include_space" is set, include trailing whitespace while calculating the
- * length.
- */
-int get_leader_len(char_u *line, char_u **flags, bool backward, bool include_space)
-{
- int i, j;
- int result;
- int got_com = FALSE;
- int found_one;
- char_u part_buf[COM_MAX_LEN]; // buffer for one option part
- char_u *string; // pointer to comment string
- char_u *list;
- int middle_match_len = 0;
- char_u *prev_list;
- char_u *saved_flags = NULL;
-
- result = i = 0;
- while (ascii_iswhite(line[i])) { // leading white space is ignored
- ++i;
- }
-
- /*
- * Repeat to match several nested comment strings.
- */
- while (line[i] != NUL) {
- /*
- * scan through the 'comments' option for a match
- */
- found_one = FALSE;
- for (list = curbuf->b_p_com; *list; ) {
- // Get one option part into part_buf[]. Advance "list" to next
- // one. Put "string" at start of string.
- if (!got_com && flags != NULL) {
- *flags = list; // remember where flags started
- }
- prev_list = list;
- (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
- string = vim_strchr(part_buf, ':');
- if (string == NULL) { // missing ':', ignore this part
- continue;
- }
- *string++ = NUL; // isolate flags from string
-
- // If we found a middle match previously, use that match when this
- // is not a middle or end.
- if (middle_match_len != 0
- && vim_strchr(part_buf, COM_MIDDLE) == NULL
- && vim_strchr(part_buf, COM_END) == NULL) {
- break;
- }
-
- // When we already found a nested comment, only accept further
- // nested comments.
- if (got_com && vim_strchr(part_buf, COM_NEST) == NULL) {
- continue;
- }
-
- // When 'O' flag present and using "O" command skip this one.
- if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL) {
- continue;
- }
-
- // Line contents and string must match.
- // When string starts with white space, must have some white space
- // (but the amount does not need to match, there might be a mix of
- // TABs and spaces).
- if (ascii_iswhite(string[0])) {
- if (i == 0 || !ascii_iswhite(line[i - 1])) {
- continue; // missing white space
- }
- while (ascii_iswhite(string[0])) {
- ++string;
- }
- }
- for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) {
- }
- if (string[j] != NUL) {
- continue; // string doesn't match
- }
- // When 'b' flag used, there must be white space or an
- // end-of-line after the string in the line.
- if (vim_strchr(part_buf, COM_BLANK) != NULL
- && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
- continue;
- }
-
- // We have found a match, stop searching unless this is a middle
- // comment. The middle comment can be a substring of the end
- // comment in which case it's better to return the length of the
- // end comment and its flags. Thus we keep searching with middle
- // and end matches and use an end match if it matches better.
- if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
- if (middle_match_len == 0) {
- middle_match_len = j;
- saved_flags = prev_list;
- }
- continue;
- }
- if (middle_match_len != 0 && j > middle_match_len) {
- // Use this match instead of the middle match, since it's a
- // longer thus better match.
- middle_match_len = 0;
- }
-
- if (middle_match_len == 0) {
- i += j;
- }
- found_one = TRUE;
- break;
- }
-
- if (middle_match_len != 0) {
- // Use the previously found middle match after failing to find a
- // match with an end.
- if (!got_com && flags != NULL) {
- *flags = saved_flags;
- }
- i += middle_match_len;
- found_one = TRUE;
- }
-
- // No match found, stop scanning.
- if (!found_one) {
- break;
- }
-
- result = i;
-
- // Include any trailing white space.
- while (ascii_iswhite(line[i])) {
- ++i;
- }
-
- if (include_space) {
- result = i;
- }
-
- // If this comment doesn't nest, stop here.
- got_com = TRUE;
- if (vim_strchr(part_buf, COM_NEST) == NULL) {
- break;
- }
- }
- return result;
-}
-
-/*
- * Return the offset at which the last comment in line starts. If there is no
- * comment in the whole line, -1 is returned.
- *
- * When "flags" is not null, it is set to point to the flags describing the
- * recognized comment leader.
- */
-int get_last_leader_offset(char_u *line, char_u **flags)
-{
- int result = -1;
- int i, j;
- int lower_check_bound = 0;
- char_u *string;
- char_u *com_leader;
- char_u *com_flags;
- char_u *list;
- int found_one;
- char_u part_buf[COM_MAX_LEN]; // buffer for one option part
-
- /*
- * Repeat to match several nested comment strings.
- */
- i = (int)STRLEN(line);
- while (--i >= lower_check_bound) {
- /*
- * scan through the 'comments' option for a match
- */
- found_one = FALSE;
- for (list = curbuf->b_p_com; *list; ) {
- char_u *flags_save = list;
-
- /*
- * Get one option part into part_buf[]. Advance list to next one.
- * put string at start of string.
- */
- (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
- string = vim_strchr(part_buf, ':');
- if (string == NULL) { // If everything is fine, this cannot actually
- // happen.
- continue;
- }
- *string++ = NUL; // Isolate flags from string.
- com_leader = string;
-
- /*
- * Line contents and string must match.
- * When string starts with white space, must have some white space
- * (but the amount does not need to match, there might be a mix of
- * TABs and spaces).
- */
- if (ascii_iswhite(string[0])) {
- if (i == 0 || !ascii_iswhite(line[i - 1])) {
- continue;
- }
- while (ascii_iswhite(*string)) {
- string++;
- }
- }
- for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) {
- // do nothing
- }
- if (string[j] != NUL) {
- continue;
- }
-
- /*
- * When 'b' flag used, there must be white space or an
- * end-of-line after the string in the line.
- */
- if (vim_strchr(part_buf, COM_BLANK) != NULL
- && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
- continue;
- }
-
- if (vim_strchr(part_buf, COM_MIDDLE) != NULL) {
- // For a middlepart comment, only consider it to match if
- // everything before the current position in the line is
- // whitespace. Otherwise we would think we are inside a
- // comment if the middle part appears somewhere in the middle
- // of the line. E.g. for C the "*" appears often.
- for (j = 0; j <= i && ascii_iswhite(line[j]); j++) {
- }
- if (j < i) {
- continue;
- }
- }
-
- /*
- * We have found a match, stop searching.
- */
- found_one = TRUE;
-
- if (flags) {
- *flags = flags_save;
- }
- com_flags = flags_save;
-
- break;
- }
-
- if (found_one) {
- char_u part_buf2[COM_MAX_LEN]; // buffer for one option part
- int len1, len2, off;
-
- result = i;
- /*
- * If this comment nests, continue searching.
- */
- if (vim_strchr(part_buf, COM_NEST) != NULL) {
- continue;
- }
-
- lower_check_bound = i;
-
- // Let's verify whether the comment leader found is a substring
- // of other comment leaders. If it is, let's adjust the
- // lower_check_bound so that we make sure that we have determined
- // the comment leader correctly.
-
- while (ascii_iswhite(*com_leader)) {
- ++com_leader;
- }
- len1 = (int)STRLEN(com_leader);
-
- for (list = curbuf->b_p_com; *list; ) {
- char_u *flags_save = list;
-
- (void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
- if (flags_save == com_flags) {
- continue;
- }
- string = vim_strchr(part_buf2, ':');
- ++string;
- while (ascii_iswhite(*string)) {
- ++string;
- }
- len2 = (int)STRLEN(string);
- if (len2 == 0) {
- continue;
- }
-
- // Now we have to verify whether string ends with a substring
- // beginning the com_leader.
- for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2; ) {
- --off;
- if (!STRNCMP(string + off, com_leader, len2 - off)) {
- if (i - off < lower_check_bound) {
- lower_check_bound = i - off;
- }
- }
- }
- }
- }
- }
- return result;
-}
-
-int gchar_pos(pos_T *pos)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- // When searching columns is sometimes put at the end of a line.
- if (pos->col == MAXCOL) {
- return NUL;
- }
- return utf_ptr2char(ml_get_pos(pos));
-}
-
-/*
- * check_status: called when the status bars for the buffer 'buf'
- * need to be updated
- */
-void check_status(buf_T *buf)
-{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == buf && wp->w_status_height) {
- wp->w_redr_status = TRUE;
- if (must_redraw < VALID) {
- must_redraw = VALID;
- }
- }
- }
-}
-
-/// Ask for a reply from the user, 'y' or 'n'
-///
-/// No other characters are accepted, the message is repeated until a valid
-/// reply is entered or <C-c> is hit.
-///
-/// @param[in] str Prompt: question to ask user. Is always followed by
-/// " (y/n)?".
-/// @param[in] direct Determines what function to use to get user input. If
-/// true then ui_inchar() will be used, otherwise vgetc().
-/// I.e. when direct is true then characters are obtained
-/// directly from the user without buffers involved.
-///
-/// @return 'y' or 'n'. Last is also what will be returned in case of interrupt.
-int ask_yesno(const char *const str, const bool direct)
-{
- const int save_State = State;
-
- no_wait_return++;
- State = CONFIRM; // Mouse behaves like with :confirm.
- setmouse(); // Disable mouse in xterm.
- no_mapping++;
-
- int r = ' ';
- while (r != 'y' && r != 'n') {
- // Same highlighting as for wait_return.
- smsg_attr(HL_ATTR(HLF_R), "%s (y/n)?", str);
- if (direct) {
- r = get_keystroke(NULL);
- } else {
- r = plain_vgetc();
- }
- if (r == Ctrl_C || r == ESC) {
- r = 'n';
- }
- msg_putchar(r); // Show what you typed.
- ui_flush();
- }
- no_wait_return--;
- State = save_State;
- setmouse();
- no_mapping--;
-
- return r;
-}
-
-/*
- * Return TRUE if "c" is a mouse key.
- */
-int is_mouse_key(int c)
-{
- return c == K_LEFTMOUSE
- || c == K_LEFTMOUSE_NM
- || c == K_LEFTDRAG
- || c == K_LEFTRELEASE
- || c == K_LEFTRELEASE_NM
- || c == K_MOUSEMOVE
- || c == K_MIDDLEMOUSE
- || c == K_MIDDLEDRAG
- || c == K_MIDDLERELEASE
- || c == K_RIGHTMOUSE
- || c == K_RIGHTDRAG
- || c == K_RIGHTRELEASE
- || c == K_MOUSEDOWN
- || c == K_MOUSEUP
- || c == K_MOUSELEFT
- || c == K_MOUSERIGHT
- || c == K_X1MOUSE
- || c == K_X1DRAG
- || c == K_X1RELEASE
- || c == K_X2MOUSE
- || c == K_X2DRAG
- || c == K_X2RELEASE;
-}
-
-/*
- * Get a key stroke directly from the user.
- * Ignores mouse clicks and scrollbar events, except a click for the left
- * button (used at the more prompt).
- * Doesn't use vgetc(), because it syncs undo and eats mapped characters.
- * Disadvantage: typeahead is ignored.
- * Translates the interrupt character for unix to ESC.
- */
-int get_keystroke(MultiQueue *events)
-{
- char_u *buf = NULL;
- int buflen = 150;
- int maxlen;
- int len = 0;
- int n;
- int save_mapped_ctrl_c = mapped_ctrl_c;
- int waited = 0;
-
- mapped_ctrl_c = 0; // mappings are not used here
- for (;; ) {
- // flush output before waiting
- ui_flush();
- // Leave some room for check_termcode() to insert a key code into (max
- // 5 chars plus NUL). And fix_input_buffer() can triple the number of
- // bytes.
- maxlen = (buflen - 6 - len) / 3;
- if (buf == NULL) {
- buf = xmalloc((size_t)buflen);
- } else if (maxlen < 10) {
- // Need some more space. This might happen when receiving a long
- // escape sequence.
- buflen += 100;
- buf = xrealloc(buf, (size_t)buflen);
- maxlen = (buflen - 6 - len) / 3;
- }
-
- // First time: blocking wait. Second time: wait up to 100ms for a
- // terminal code to complete.
- n = os_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0, events);
- if (n > 0) {
- // Replace zero and CSI by a special key code.
- n = fix_input_buffer(buf + len, n);
- len += n;
- waited = 0;
- } else if (len > 0) {
- ++waited; // keep track of the waiting time
- }
- if (n > 0) { // found a termcode: adjust length
- len = n;
- }
- if (len == 0) { // nothing typed yet
- continue;
- }
-
- // Handle modifier and/or special key code.
- n = buf[0];
- if (n == K_SPECIAL) {
- n = TO_SPECIAL(buf[1], buf[2]);
- if (buf[1] == KS_MODIFIER
- || n == K_IGNORE
- || (is_mouse_key(n) && n != K_LEFTMOUSE)) {
- if (buf[1] == KS_MODIFIER) {
- mod_mask = buf[2];
- }
- len -= 3;
- if (len > 0) {
- memmove(buf, buf + 3, (size_t)len);
- }
- continue;
- }
- break;
- }
- if (MB_BYTE2LEN(n) > len) {
- // more bytes to get.
- continue;
- }
- buf[len >= buflen ? buflen - 1 : len] = NUL;
- n = utf_ptr2char(buf);
- break;
- }
- xfree(buf);
-
- mapped_ctrl_c = save_mapped_ctrl_c;
- return n;
-}
-
-/// Get a number from the user.
-/// When "mouse_used" is not NULL allow using the mouse.
-///
-/// @param colon allow colon to abort
-int get_number(int colon, int *mouse_used)
-{
- int n = 0;
- int c;
- int typed = 0;
-
- if (mouse_used != NULL) {
- *mouse_used = FALSE;
- }
-
- // When not printing messages, the user won't know what to type, return a
- // zero (as if CR was hit).
- if (msg_silent != 0) {
- return 0;
- }
-
- no_mapping++;
- for (;; ) {
- ui_cursor_goto(msg_row, msg_col);
- c = safe_vgetc();
- if (ascii_isdigit(c)) {
- n = n * 10 + c - '0';
- msg_putchar(c);
- ++typed;
- } else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) {
- if (typed > 0) {
- msg_puts("\b \b");
- --typed;
- }
- n /= 10;
- } else if (mouse_used != NULL && c == K_LEFTMOUSE) {
- *mouse_used = TRUE;
- n = mouse_row + 1;
- break;
- } else if (n == 0 && c == ':' && colon) {
- stuffcharReadbuff(':');
- if (!exmode_active) {
- cmdline_row = msg_row;
- }
- skip_redraw = true; // skip redraw once
- do_redraw = false;
- break;
- } else if (c == Ctrl_C || c == ESC || c == 'q') {
- n = 0;
- break;
- } else if (c == CAR || c == NL) {
- break;
- }
- }
- no_mapping--;
- return n;
-}
-
-/*
- * Ask the user to enter a number.
- * When "mouse_used" is not NULL allow using the mouse and in that case return
- * the line number.
- */
-int prompt_for_number(int *mouse_used)
-{
- int i;
- int save_cmdline_row;
- int save_State;
-
- // When using ":silent" assume that <CR> was entered.
- if (mouse_used != NULL) {
- msg_puts(_("Type number and <Enter> or click with the mouse "
- "(q or empty cancels): "));
- } else {
- msg_puts(_("Type number and <Enter> (q or empty cancels): "));
- }
-
- /* Set the state such that text can be selected/copied/pasted and we still
- * get mouse events. */
- save_cmdline_row = cmdline_row;
- cmdline_row = 0;
- save_State = State;
- State = ASKMORE; // prevents a screen update when using a timer
- // May show different mouse shape.
- setmouse();
-
- i = get_number(TRUE, mouse_used);
- if (KeyTyped) {
- // don't call wait_return() now
- if (msg_row > 0) {
- cmdline_row = msg_row - 1;
- }
- need_wait_return = false;
- msg_didany = false;
- msg_didout = false;
- } else {
- cmdline_row = save_cmdline_row;
- }
- State = save_State;
- // May need to restore mouse shape.
- setmouse();
-
- return i;
-}
-
-void msgmore(long n)
-{
- long pn;
-
- if (global_busy // no messages now, wait until global is finished
- || !messaging()) { // 'lazyredraw' set, don't do messages now
- return;
- }
-
- // We don't want to overwrite another important message, but do overwrite
- // a previous "more lines" or "fewer lines" message, so that "5dd" and
- // then "put" reports the last action.
- if (keep_msg != NULL && !keep_msg_more) {
- return;
- }
-
- if (n > 0) {
- pn = n;
- } else {
- pn = -n;
- }
-
- if (pn > p_report) {
- if (n > 0) {
- vim_snprintf(msg_buf, MSG_BUF_LEN,
- NGETTEXT("%ld more line", "%ld more lines", pn),
- pn);
- } else {
- vim_snprintf(msg_buf, MSG_BUF_LEN,
- NGETTEXT("%ld line less", "%ld fewer lines", pn),
- pn);
- }
- if (got_int) {
- xstrlcat(msg_buf, _(" (Interrupted)"), MSG_BUF_LEN);
- }
- if (msg(msg_buf)) {
- set_keep_msg((char_u *)msg_buf, 0);
- keep_msg_more = true;
- }
- }
-}
-
-/*
- * flush map and typeahead buffers and give a warning for an error
- */
-void beep_flush(void)
-{
- if (emsg_silent == 0) {
- flush_buffers(FLUSH_MINIMAL);
- vim_beep(BO_ERROR);
- }
-}
-
-// Give a warning for an error
-// val is one of the BO_ values, e.g., BO_OPER
-void vim_beep(unsigned val)
-{
- called_vim_beep = true;
-
- if (emsg_silent == 0) {
- if (!((bo_flags & val) || (bo_flags & BO_ALL))) {
- static int beeps = 0;
- static uint64_t start_time = 0;
-
- // Only beep up to three times per half a second,
- // otherwise a sequence of beeps would freeze Vim.
- if (start_time == 0 || os_hrtime() - start_time > 500000000u) {
- beeps = 0;
- start_time = os_hrtime();
- }
- beeps++;
- if (beeps <= 3) {
- if (p_vb) {
- ui_call_visual_bell();
- } else {
- ui_call_bell();
- }
- }
- }
-
- // When 'debug' contains "beep" produce a message. If we are sourcing
- // a script or executing a function give the user a hint where the beep
- // comes from.
- if (vim_strchr(p_debug, 'e') != NULL) {
- msg_source(HL_ATTR(HLF_W));
- msg_attr(_("Beep!"), HL_ATTR(HLF_W));
- }
- }
-}
-
-#if defined(EXITFREE)
-
-void free_users(void)
-{
- ga_clear_strings(&ga_users);
-}
-
-#endif
-
-/*
- * Find all user names for user completion.
- * Done only once and then cached.
- */
-static void init_users(void)
-{
- static int lazy_init_done = FALSE;
-
- if (lazy_init_done) {
- return;
- }
-
- lazy_init_done = TRUE;
-
- os_get_usernames(&ga_users);
-}
-
-/*
- * Function given to ExpandGeneric() to obtain an user names.
- */
-char_u *get_users(expand_T *xp, int idx)
-{
- init_users();
- if (idx < ga_users.ga_len) {
- return ((char_u **)ga_users.ga_data)[idx];
- }
- return NULL;
-}
-
-/*
- * Check whether name matches a user name. Return:
- * 0 if name does not match any user name.
- * 1 if name partially matches the beginning of a user name.
- * 2 is name fully matches a user name.
- */
-int match_user(char_u *name)
-{
- int n = (int)STRLEN(name);
- int result = 0;
-
- init_users();
- for (int i = 0; i < ga_users.ga_len; i++) {
- if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) {
- return 2; // full match
- }
- if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) {
- result = 1; // partial match
- }
- }
- return result;
-}
-
-/// Preserve files and exit.
-/// @note IObuff must contain a message.
-/// @note This may be called from deadly_signal() in a signal handler, avoid
-/// unsafe functions, such as allocating memory.
-void preserve_exit(void)
- FUNC_ATTR_NORETURN
-{
- // 'true' when we are sure to exit, e.g., after a deadly signal
- static bool really_exiting = false;
-
- // Prevent repeated calls into this method.
- if (really_exiting) {
- if (input_global_fd() >= 0) {
- // normalize stream (#2598)
- stream_set_blocking(input_global_fd(), true);
- }
- exit(2);
- }
-
- really_exiting = true;
- // Ignore SIGHUP while we are already exiting. #9274
- signal_reject_deadly();
- mch_errmsg(IObuff);
- mch_errmsg("\n");
- ui_flush();
-
- ml_close_notmod(); // close all not-modified buffers
-
- FOR_ALL_BUFFERS(buf) {
- if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
- mch_errmsg("Vim: preserving files...\r\n");
- ui_flush();
- ml_sync_all(false, false, true); // preserve all swap files
- break;
- }
- }
-
- ml_close_all(false); // close all memfiles, without deleting
-
- mch_errmsg("Vim: Finished.\r\n");
-
- getout(1);
-}
-
-/*
- * Check for CTRL-C pressed, but only once in a while.
- * Should be used instead of os_breakcheck() for functions that check for
- * each line in the file. Calling os_breakcheck() each time takes too much
- * time, because it can be a system call.
- */
-
-#ifndef BREAKCHECK_SKIP
-# define BREAKCHECK_SKIP 1000
-#endif
-
-static int breakcheck_count = 0;
-
-void line_breakcheck(void)
-{
- if (++breakcheck_count >= BREAKCHECK_SKIP) {
- breakcheck_count = 0;
- os_breakcheck();
- }
-}
-
-/*
- * Like line_breakcheck() but check 10 times less often.
- */
-void fast_breakcheck(void)
-{
- if (++breakcheck_count >= BREAKCHECK_SKIP * 10) {
- breakcheck_count = 0;
- os_breakcheck();
- }
-}
-
-// Like line_breakcheck() but check 100 times less often.
-void veryfast_breakcheck(void)
-{
- if (++breakcheck_count >= BREAKCHECK_SKIP * 100) {
- breakcheck_count = 0;
- os_breakcheck();
- }
-}
-
-/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
-/// Invalidates cached tags.
-///
-/// @return shell command exit code
-int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
-{
- int retval;
- proftime_T wait_time;
-
- if (p_verbose > 3) {
- verbose_enter();
- smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd);
- msg_putchar('\n');
- verbose_leave();
- }
-
- if (do_profiling == PROF_YES) {
- prof_child_enter(&wait_time);
- }
-
- if (*p_sh == NUL) {
- emsg(_(e_shellempty));
- retval = -1;
- } else {
- // The external command may update a tags file, clear cached tags.
- tag_freematch();
-
- retval = os_call_shell(cmd, opts, extra_shell_arg);
- }
-
- set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T)retval);
- if (do_profiling == PROF_YES) {
- prof_child_exit(&wait_time);
- }
-
- return retval;
-}
-
-/// Get the stdout of an external command.
-/// If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
-/// NULL store the length there.
-///
-/// @param cmd command to execute
-/// @param infile optional input file name
-/// @param flags can be kShellOptSilent or 0
-/// @param ret_len length of the stdout
-///
-/// @return an allocated string, or NULL for error.
-char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret_len)
-{
- char_u *buffer = NULL;
-
- if (check_secure()) {
- return NULL;
- }
-
- // get a name for the temp file
- char_u *tempname = vim_tempname();
- if (tempname == NULL) {
- emsg(_(e_notmp));
- return NULL;
- }
-
- // Add the redirection stuff
- char_u *command = make_filter_cmd(cmd, infile, tempname);
-
- /*
- * Call the shell to execute the command (errors are ignored).
- * Don't check timestamps here.
- */
- ++no_check_timestamps;
- call_shell(command, kShellOptDoOut | kShellOptExpand | flags, NULL);
- --no_check_timestamps;
-
- xfree(command);
-
- // read the names from the file into memory
- FILE *fd = os_fopen((char *)tempname, READBIN);
-
- if (fd == NULL) {
- semsg(_(e_notopen), tempname);
- goto done;
- }
-
- fseek(fd, 0L, SEEK_END);
- size_t len = (size_t)ftell(fd); // get size of temp file
- fseek(fd, 0L, SEEK_SET);
-
- buffer = xmalloc(len + 1);
- size_t i = fread((char *)buffer, 1, len, fd);
- fclose(fd);
- os_remove((char *)tempname);
- if (i != len) {
- semsg(_(e_notread), tempname);
- XFREE_CLEAR(buffer);
- } else if (ret_len == NULL) {
- // Change NUL into SOH, otherwise the string is truncated.
- for (i = 0; i < len; ++i) {
- if (buffer[i] == NUL) {
- buffer[i] = 1;
- }
- }
-
- buffer[len] = NUL; // make sure the buffer is terminated
- } else {
- *ret_len = len;
- }
-
-done:
- xfree(tempname);
- return buffer;
-}
-
-/*
- * Free the list of files returned by expand_wildcards() or other expansion
- * functions.
- */
-void FreeWild(int count, char_u **files)
-{
- if (count <= 0 || files == NULL) {
- return;
- }
- while (count--) {
- xfree(files[count]);
- }
- xfree(files);
-}
-
-/*
- * Return TRUE when need to go to Insert mode because of 'insertmode'.
- * Don't do this when still processing a command or a mapping.
- * Don't do this when inside a ":normal" command.
- */
-int goto_im(void)
-{
- return p_im && stuff_empty() && typebuf_typed();
-}
-
-/// Put the timestamp of an undo header in "buf[buflen]" in a nice format.
-void add_time(char_u *buf, size_t buflen, time_t tt)
-{
- struct tm curtime;
-
- if (time(NULL) - tt >= 100) {
- os_localtime_r(&tt, &curtime);
- if (time(NULL) - tt < (60L * 60L * 12L)) {
- // within 12 hours
- (void)strftime((char *)buf, buflen, "%H:%M:%S", &curtime);
- } else {
- // longer ago
- (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", &curtime);
- }
- } else {
- int64_t seconds = time(NULL) - tt;
- vim_snprintf((char *)buf, buflen,
- NGETTEXT("%" PRId64 " second ago",
- "%" PRId64 " seconds ago", (uint32_t)seconds),
- seconds);
- }
-}
diff --git a/src/nvim/misc1.h b/src/nvim/misc1.h
deleted file mode 100644
index 4ce142c4c5..0000000000
--- a/src/nvim/misc1.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef NVIM_MISC1_H
-#define NVIM_MISC1_H
-
-#include "nvim/os/shell.h"
-#include "nvim/vim.h"
-
-// flags for open_line()
-#define OPENLINE_DELSPACES 1 // delete spaces after cursor
-#define OPENLINE_DO_COM 2 // format comments
-#define OPENLINE_KEEPTRAIL 4 // keep trailing spaces
-#define OPENLINE_MARKFIX 8 // fix mark positions
-#define OPENLINE_COM_LIST 16 // format comments with list/2nd line indent
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "misc1.h.generated.h"
-#endif
-#endif // NVIM_MISC1_H
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index f02c000e82..5d007fb173 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -10,7 +10,6 @@
#include "nvim/diff.h"
#include "nvim/fold.h"
#include "nvim/memline.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/os_unix.h"
@@ -31,6 +30,32 @@
static linenr_T orig_topline = 0;
static int orig_topfill = 0;
+/// Return true if "c" is a mouse key.
+bool is_mouse_key(int c)
+{
+ return c == K_LEFTMOUSE
+ || c == K_LEFTMOUSE_NM
+ || c == K_LEFTDRAG
+ || c == K_LEFTRELEASE
+ || c == K_LEFTRELEASE_NM
+ || c == K_MOUSEMOVE
+ || c == K_MIDDLEMOUSE
+ || c == K_MIDDLEDRAG
+ || c == K_MIDDLERELEASE
+ || c == K_RIGHTMOUSE
+ || c == K_RIGHTDRAG
+ || c == K_RIGHTRELEASE
+ || c == K_MOUSEDOWN
+ || c == K_MOUSEUP
+ || c == K_MOUSELEFT
+ || c == K_MOUSERIGHT
+ || c == K_X1MOUSE
+ || c == K_X1DRAG
+ || c == K_X1RELEASE
+ || c == K_X2MOUSE
+ || c == K_X2DRAG
+ || c == K_X2RELEASE;
+}
/// Move the cursor to the specified row and column on the screen.
/// Change current window if necessary. Returns an integer with the
/// CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
@@ -245,7 +270,7 @@ retnomove:
// Scroll by however many rows outside the window we are.
if (row < 0) {
count = 0;
- for (first = true; curwin->w_topline > 1; ) {
+ for (first = true; curwin->w_topline > 1;) {
if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
count++;
} else {
@@ -270,7 +295,7 @@ retnomove:
row = 0;
} else if (row >= curwin->w_height_inner) {
count = 0;
- for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count; ) {
+ for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count;) {
if (curwin->w_topfill > 0) {
++count;
} else {
@@ -448,7 +473,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
fp = topframe;
*rowp -= firstwin->w_winrow;
- for (;; ) {
+ for (;;) {
if (fp->fr_layout == FR_LEAF) {
break;
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 5114cd6d8a..15ba6645f5 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -23,9 +23,9 @@
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/fold.h"
+#include "nvim/getchar.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/plines.h"
@@ -382,8 +382,8 @@ static bool check_top_offset(void)
topline_back(curwin, &loff);
// Stop when included a line above the window.
if (loff.lnum < curwin->w_topline
- || (loff.lnum == curwin->w_topline &&
- loff.fill > 0)) {
+ || (loff.lnum == curwin->w_topline
+ && loff.fill > 0)) {
break;
}
n += loff.height;
@@ -1011,7 +1011,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
col -= wp->w_leftcol;
if (col >= 0 && col < wp->w_width) {
- coloff = col - scol + (local ? 0 : wp->w_wincol) + 1;
+ coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_border_adj[3]) + 1;
} else {
scol = ccol = ecol = 0;
// character is left or right of the window
@@ -1022,7 +1022,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
}
}
}
- *rowp = (local ? 0 : wp->w_winrow) + row + rowoff;
+ *rowp = (local ? 0 : wp->w_winrow + wp->w_border_adj[0]) + row + rowoff;
*scolp = scol + coloff;
*ccolp = ccol + coloff;
*ecolp = ecol + coloff;
@@ -1661,7 +1661,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
boff.fill = curwin->w_topfill;
boff.lnum = curwin->w_topline - 1;
int i;
- for (i = 0; i < scrolled && boff.lnum < curwin->w_botline; ) {
+ for (i = 0; i < scrolled && boff.lnum < curwin->w_botline;) {
botline_forw(curwin, &boff);
i += boff.height;
++line_count;
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index a1a1f0f8c0..299651ee97 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -24,7 +24,6 @@
#include "nvim/map.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/os/input.h"
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index f805858904..32014fcf2b 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -92,15 +92,15 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
break;
}
#define STR_CASE(type, attr, obj, dest, conv) \
-case type: { \
- dest = conv(((String) { \
+ case type: { \
+ dest = conv(((String) { \
.size = obj->via.attr.size, \
.data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \
? xmemdupz("", 0) \
: xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), \
})); \
- break; \
-}
+ break; \
+ }
STR_CASE(MSGPACK_OBJECT_STR, str, cur.mobj, *cur.aobj, STRING_OBJ)
STR_CASE(MSGPACK_OBJECT_BIN, bin, cur.mobj, *cur.aobj, STRING_OBJ)
case MSGPACK_OBJECT_ARRAY: {
@@ -143,10 +143,10 @@ case type: { \
const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key;
switch (key->type) {
#define ID(x) x
- STR_CASE(MSGPACK_OBJECT_STR, str, key,
- cur.aobj->data.dictionary.items[idx].key, ID)
- STR_CASE(MSGPACK_OBJECT_BIN, bin, key,
- cur.aobj->data.dictionary.items[idx].key, ID)
+ STR_CASE(MSGPACK_OBJECT_STR, str, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
+ STR_CASE(MSGPACK_OBJECT_BIN, bin, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
#undef ID
case MSGPACK_OBJECT_NIL:
case MSGPACK_OBJECT_BOOLEAN:
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 1effeefd32..3246596f16 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"
@@ -40,7 +40,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -84,12 +83,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
@@ -236,7 +229,7 @@ static const struct nv_cmd {
{ 'N', nv_next, 0, SEARCH_REV },
{ 'O', nv_open, 0, 0 },
{ 'P', nv_put, 0, 0 },
- { 'Q', nv_exmode, NV_NCW, 0 },
+ { 'Q', nv_regreplay, 0, 0 },
{ 'R', nv_Replace, 0, false },
{ 'S', nv_subst, NV_KEEPREG, 0 },
{ 'T', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD },
@@ -487,6 +480,7 @@ static void normal_prepare(NormalState *s)
if (finish_op != c) {
ui_cursor_shape(); // may show different cursor shape
}
+ trigger_modechanged();
// When not finishing an operator and no register name typed, reset the count.
if (!finish_op && !s->oa.regname) {
@@ -570,8 +564,8 @@ static bool normal_need_additional_char(NormalState *s)
//
// TODO(tarruda): Visual state needs to be refactored into a
// separate state that "inherits" from normal state.
- || ((cmdchar == 'a' || cmdchar == 'i') &&
- (pending_op || VIsual_active)));
+ || ((cmdchar == 'a' || cmdchar == 'i')
+ && (pending_op || VIsual_active)));
}
static bool normal_need_redraw_mode_message(NormalState *s)
@@ -928,6 +922,7 @@ normal_end:
// Reset finish_op, in case it was set
s->c = finish_op;
finish_op = false;
+ trigger_modechanged();
// Redraw the cursor with another shape, if we were in Operator-pending
// mode or did a replace command.
if (s->c || s->ca.cmdchar == 'r') {
@@ -965,6 +960,7 @@ normal_end:
&& s->oa.regname == 0) {
if (restart_VIsual_select == 1) {
VIsual_select = true;
+ trigger_modechanged();
showmode();
restart_VIsual_select = 0;
}
@@ -1452,758 +1448,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)
@@ -2283,7 +1527,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
save_cursor = curwin->w_cursor;
- for (;; ) {
+ for (;;) {
which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
if (is_drag) {
/* If the next character is the same mouse event then use that
@@ -3066,6 +2310,7 @@ void end_visual_mode(void)
may_clear_cmdline();
adjust_cursor_eol();
+ trigger_modechanged();
}
/*
@@ -3092,6 +2337,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.
@@ -3270,7 +2523,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
@@ -3327,7 +2580,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;
@@ -3336,7 +2589,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();
@@ -3366,7 +2619,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
@@ -3928,7 +3181,7 @@ bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_
// Search forward for the identifier, ignore comment lines.
clearpos(&found_pos);
- for (;; ) {
+ for (;;) {
t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
pat, 1L, searchflags, RE_LAST, NULL);
if (curwin->w_cursor.lnum >= old_pos.lnum) {
@@ -4307,7 +3560,7 @@ static void nv_zet(cmdarg_T *cap)
return;
}
n = nchar - '0';
- for (;; ) {
+ for (;;) {
no_mapping++;
nchar = plain_vgetc();
LANGMAP_ADJUST(nchar, true);
@@ -4775,15 +4028,18 @@ dozet:
/*
* "Q" command.
*/
-static void nv_exmode(cmdarg_T *cap)
+static void nv_regreplay(cmdarg_T *cap)
{
- /*
- * Ignore 'Q' in Visual mode, just give a beep.
- */
- if (VIsual_active) {
- vim_beep(BO_EX);
- } else if (!checkclearop(cap->oap)) {
- do_exmode();
+ if (checkclearop(cap->oap)) {
+ return;
+ }
+
+ while (cap->count1-- && !got_int) {
+ if (do_execreg(reg_recorded, false, false, false) == false) {
+ clearopbeep(cap->oap);
+ break;
+ }
+ line_breakcheck();
}
}
@@ -4851,6 +4107,7 @@ static void nv_ctrlg(cmdarg_T *cap)
{
if (VIsual_active) { // toggle Selection/Visual mode
VIsual_select = !VIsual_select;
+ trigger_modechanged();
showmode();
} else if (!checkclearop(cap->oap)) {
// print full name if count given or :cd used
@@ -4894,6 +4151,7 @@ static void nv_ctrlo(cmdarg_T *cap)
{
if (VIsual_active && VIsual_select) {
VIsual_select = false;
+ trigger_modechanged();
showmode();
restart_VIsual_select = 2; // restart Select mode later
} else {
@@ -5341,8 +4599,8 @@ static void nv_right(cmdarg_T *cap)
for (n = cap->count1; n > 0; --n) {
if ((!PAST_LINE && oneright() == false)
- || (PAST_LINE &&
- *get_cursor_pos_ptr() == NUL)) {
+ || (PAST_LINE
+ && *get_cursor_pos_ptr() == NUL)) {
// <Space> wraps to next line if 'whichwrap' has 's'.
// 'l' wraps to next line if 'whichwrap' has 'l'.
// CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
@@ -5838,7 +5096,7 @@ static void nv_brackets(cmdarg_T *cap)
pos = NULL;
}
while (n > 0) {
- for (;; ) {
+ for (;;) {
if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0) {
// if not found anything, that's an error
if (pos == NULL) {
@@ -6680,6 +5938,7 @@ static void nv_visual(cmdarg_T *cap)
// or char/line mode
VIsual_mode = cap->cmdchar;
showmode();
+ trigger_modechanged();
}
redraw_curbuf_later(INVERTED); // update the inversion
} else { // start Visual mode
@@ -6793,6 +6052,7 @@ static void n_start_visual_mode(int c)
foldAdjustVisual();
+ trigger_modechanged();
setmouse();
// Check for redraw after changing the state.
conceal_check_cursor_line();
@@ -7688,8 +6948,8 @@ static void adjust_cursor(oparg_T *oap)
// - 'virtualedit' is not "all" and not "onemore".
if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL
&& (!VIsual_active || *p_sel == 'o')
- && !virtual_active() &&
- (ve_flags & VE_ONEMORE) == 0) {
+ && !virtual_active()
+ && (ve_flags & VE_ONEMORE) == 0) {
curwin->w_cursor.col--;
// prevent cursor from moving on the trail byte
mb_adjust_cursor();
@@ -7730,7 +6990,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;
@@ -8320,71 +7580,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 7d7db2a8a6..c6f9c5f04f 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"
@@ -36,7 +38,7 @@
#include "nvim/memline.h"
#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"
@@ -378,7 +380,7 @@ static void shift_block(oparg_T *oap, int amount)
bd.startspaces = 0;
}
}
- for (; ascii_iswhite(*bd.textstart); ) {
+ for (; ascii_iswhite(*bd.textstart);) {
// TODO: is passing bd.textstart for start of the line OK?
incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, (bd.start_vcol));
total += incr;
@@ -910,13 +912,14 @@ int do_record(int c)
showmode();
regname = c;
retval = OK;
- }
- } else { // stop recording
- /*
- * Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
- * needs to be removed again to put it in a register. exec_reg then
- * adds the escaping back later.
- */
+ apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf);
+ }
+ } else { // stop recording
+ // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
+ // needs to be removed again to put it in a register. exec_reg then
+ // adds the escaping back later.
+ apply_autocmds(EVENT_RECORDINGLEAVE, NULL, NULL, false, curbuf);
+ reg_recorded = reg_recording;
reg_recording = 0;
if (ui_has(kUIMessages)) {
showmode();
@@ -930,10 +933,8 @@ int do_record(int c)
// Remove escaping for CSI and K_SPECIAL in multi-byte chars.
vim_unescape_csi(p);
- /*
- * We don't want to change the default register here, so save and
- * restore the current register name.
- */
+ // We don't want to change the default register here, so save and
+ // restore the current register name.
old_y_previous = y_previous;
retval = stuff_yank(regname, p);
@@ -1768,7 +1769,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;
@@ -2037,7 +2038,7 @@ void op_tilde(oparg_T *oap)
did_change = swapchars(oap->op_type, &pos,
oap->end.col - pos.col + 1);
} else {
- for (;; ) {
+ for (;;) {
did_change |= swapchars(oap->op_type, &pos,
pos.lnum == oap->end.lnum ? oap->end.col + 1 :
(int)STRLEN(ml_get_pos(&pos)));
@@ -2162,7 +2163,8 @@ void op_insert(oparg_T *oap, long count1)
{
long ins_len, pre_textlen = 0;
char_u *firstline, *ins_text;
- colnr_T ind_pre = 0;
+ colnr_T ind_pre_col = 0, ind_post_col;
+ int ind_pre_vcol = 0, ind_post_vcol = 0;
struct block_def bd;
int i;
pos_T t1;
@@ -2196,7 +2198,8 @@ void op_insert(oparg_T *oap, long count1)
// Get the info about the block before entering the text
block_prep(oap, &bd, oap->start.lnum, true);
// Get indent information
- ind_pre = (colnr_T)getwhitecols_curline();
+ ind_pre_col = (colnr_T)getwhitecols_curline();
+ ind_pre_vcol = get_indent();
firstline = ml_get(oap->start.lnum) + bd.textcol;
if (oap->op_type == OP_APPEND) {
@@ -2261,10 +2264,11 @@ void op_insert(oparg_T *oap, long count1)
// if indent kicked in, the firstline might have changed
// but only do that, if the indent actually increased
- const colnr_T ind_post = (colnr_T)getwhitecols_curline();
- if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) {
- bd.textcol += ind_post - ind_pre;
- bd.start_vcol += ind_post - ind_pre;
+ ind_post_col = (colnr_T)getwhitecols_curline();
+ if (curbuf->b_op_start.col > ind_pre_col && ind_post_col > ind_pre_col) {
+ bd.textcol += ind_post_col - ind_pre_col;
+ ind_post_vcol = get_indent();
+ bd.start_vcol += ind_post_vcol - ind_pre_vcol;
did_indent = true;
}
@@ -2297,12 +2301,26 @@ void op_insert(oparg_T *oap, long count1)
}
}
- /*
- * Spaces and tabs in the indent may have changed to other spaces and
- * tabs. Get the starting column again and correct the length.
- * Don't do this when "$" used, end-of-line will have changed.
- */
+ // Spaces and tabs in the indent may have changed to other spaces and
+ // tabs. Get the starting column again and correct the length.
+ // Don't do this when "$" used, end-of-line will have changed.
+ //
+ // if indent was added and the inserted text was after the indent,
+ // correct the selection for the new indent.
+ if (did_indent && bd.textcol - ind_post_col > 0) {
+ oap->start.col += ind_post_col - ind_pre_col;
+ oap->start_vcol += ind_post_vcol - ind_pre_vcol;
+ oap->end.col += ind_post_col - ind_pre_col;
+ oap->end_vcol += ind_post_vcol - ind_pre_vcol;
+ }
block_prep(oap, &bd2, oap->start.lnum, true);
+ if (did_indent && bd.textcol - ind_post_col > 0) {
+ // undo for where "oap" is used below
+ oap->start.col -= ind_post_col - ind_pre_col;
+ oap->start_vcol -= ind_post_vcol - ind_pre_vcol;
+ oap->end.col -= ind_post_col - ind_pre_col;
+ oap->end_vcol -= ind_post_vcol - ind_pre_vcol;
+ }
if (!bd.is_MAX || bd2.textlen < bd.textlen) {
if (oap->op_type == OP_APPEND) {
pre_textlen += bd2.textlen - bd.textlen;
@@ -2792,8 +2810,9 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
recursive = true;
+ save_v_event_T save_v_event;
// Set the v:event dictionary with information about the yank.
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ dict_T *dict = get_v_event(&save_v_event);
// The yanked text contents.
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
@@ -2830,7 +2849,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
textlock++;
apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
textlock--;
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
recursive = false;
}
@@ -2987,7 +3006,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/* For the = register we need to split the string at NL
* characters.
* Loop twice: count the number of lines and save them. */
- for (;; ) {
+ for (;;) {
y_size = 0;
ptr = insert_string;
while (ptr != NULL) {
@@ -3204,7 +3223,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// get the old line and advance to the position to insert at
oldp = get_cursor_line_ptr();
oldlen = STRLEN(oldp);
- for (ptr = oldp; vcol < col && *ptr; ) {
+ for (ptr = oldp; vcol < col && *ptr;) {
// Count a tab for what it's worth (if list mode not on)
incr = lbr_chartabsize_adv(oldp, &ptr, vcol);
vcol += incr;
@@ -3340,6 +3359,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (y_type == kMTCharWise && y_size == 1) {
linenr_T end_lnum = 0; // init for gcc
linenr_T start_lnum = lnum;
+ int first_byte_off = 0;
if (VIsual_active) {
end_lnum = curbuf->b_visual.vi_end.lnum;
@@ -3386,6 +3406,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
STRMOVE(ptr, oldp + col);
ml_replace(lnum, newp, false);
+
+ // compute the byte offset for the last character
+ first_byte_off = utf_head_off(newp, ptr - 1);
+
// Place cursor on last putted char.
if (lnum == curwin->w_cursor.lnum) {
// make sure curwin->w_virtcol is updated
@@ -3405,10 +3429,15 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
lnum--;
}
+ // put '] at the first byte of the last character
curbuf->b_op_end = curwin->w_cursor;
+ curbuf->b_op_end.col -= first_byte_off;
+
// For "CTRL-O p" in Insert mode, put cursor after last char
if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND))) {
curwin->w_cursor.col++;
+ } else {
+ curwin->w_cursor.col -= first_byte_off;
}
} else {
// Insert at least one line. When y_type is kMTCharWise, break the first
@@ -3520,12 +3549,13 @@ error:
curbuf->b_op_start.lnum, nr_lines, true);
}
- // put '] mark at last inserted character
+ // Put the '] mark on the first byte of the last inserted character.
+ // Correct the length for change in indent.
curbuf->b_op_end.lnum = lnum;
- // correct length for change in indent
col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
if (col > 1) {
- curbuf->b_op_end.col = col - 1;
+ curbuf->b_op_end.col = col - 1 - utf_head_off(y_array[y_size - 1],
+ y_array[y_size - 1] + col - 1);
} else {
curbuf->b_op_end.col = 0;
}
@@ -3936,8 +3966,8 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions
|| (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
&& (!has_format_option(FO_MBYTE_JOIN2)
|| (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1))
- || (endcurr1 < 0x100 &&
- !utf_eat_space(utf_ptr2char(curr))))) {
+ || (endcurr1 < 0x100
+ && !utf_eat_space(utf_ptr2char(curr))))) {
// don't add a space if the line is ending in a space
if (endcurr1 == ' ') {
endcurr1 = endcurr2;
@@ -4148,7 +4178,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;
@@ -4216,7 +4246,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
@@ -5631,7 +5661,7 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *c
varnumber_T chars = 0;
int is_word = 0;
- for (i = 0; i < limit && line[i] != NUL; ) {
+ for (i = 0; i < limit && line[i] != NUL;) {
if (is_word) {
if (ascii_isspace(line[i])) {
words++;
@@ -5907,6 +5937,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 b7df856949..2ceb1bd992 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -55,7 +55,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -262,6 +261,7 @@ typedef struct vimoption {
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
"i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr," \
+ "G:CursorLineSign,O:CursorLineFold" \
"r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \
"W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \
"-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \
@@ -1233,7 +1233,7 @@ int do_set(char_u *arg, int opt_flags)
}
errmsg = set_bool_option(opt_idx, varp, (int)value,
- opt_flags);
+ opt_flags);
} else { // Numeric or string.
if (vim_strchr((const char_u *)"=:&<", nextchar) == NULL
|| prefix != 1) {
@@ -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;
@@ -2315,8 +2353,8 @@ static bool valid_spellfile(const char_u *val)
/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
/// @param value_checked value was checked to be safe, no need to set P_INSECURE
static char *did_set_string_option(int opt_idx, char_u **varp, bool new_value_alloced,
- char_u *oldval, char *errbuf, size_t errbuflen,
- int opt_flags, int *value_checked)
+ char_u *oldval, char *errbuf, size_t errbuflen, int opt_flags,
+ int *value_checked)
{
char *errmsg = NULL;
char_u *s, *p;
@@ -2419,7 +2457,7 @@ static char *did_set_string_option(int opt_idx, char_u **varp, bool new_value_al
}
} else if (varp == &p_hl) {
// 'highlight'
- if (strcmp((char *)(*varp), HIGHLIGHT_INIT) != 0) {
+ if (STRCMP(*varp, HIGHLIGHT_INIT) != 0) {
errmsg = e_unsupportedoption;
}
} else if (varp == &p_jop) { // 'jumpoptions'
@@ -2625,7 +2663,7 @@ ambw_end:
}
}
} else if (gvarp == &p_com) { // 'comments'
- for (s = *varp; *s; ) {
+ for (s = *varp; *s;) {
while (*s && *s != ':') {
if (vim_strchr((char_u *)COM_ALL, *s) == NULL
&& !ascii_isdigit(*s) && *s != '-') {
@@ -2650,24 +2688,38 @@ ambw_end:
}
s = skip_to_option_part(s);
}
- } else if (varp == &p_lcs) { // 'listchars'
+ } else if (varp == &p_lcs) { // global 'listchars'
errmsg = set_chars_option(curwin, varp, false);
- if (!errmsg) {
+ if (errmsg == NULL) {
+ // The current window is set to use the global 'listchars' value.
+ // So clear the window-local value.
+ if (!(opt_flags & OPT_GLOBAL)) {
+ clear_string_option(&curwin->w_p_lcs);
+ }
FOR_ALL_TAB_WINDOWS(tp, wp) {
- set_chars_option(wp, &wp->w_p_lcs, true);
+ // If no error was returned above, we don't expect an error
+ // here, so ignore the return value.
+ (void)set_chars_option(wp, &wp->w_p_lcs, true);
}
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
} else if (varp == &curwin->w_p_lcs) { // local 'listchars'
errmsg = set_chars_option(curwin, varp, true);
- } else if (varp == &p_fcs) { // 'fillchars'
+ } else if (varp == &p_fcs) { // global 'fillchars'
errmsg = set_chars_option(curwin, varp, false);
- if (!errmsg) {
+ if (errmsg == NULL) {
+ // The current window is set to use the global 'fillchars' value.
+ // So clear the window-local value.
+ if (!(opt_flags & OPT_GLOBAL)) {
+ clear_string_option(&curwin->w_p_fcs);
+ }
FOR_ALL_TAB_WINDOWS(tp, wp) {
- set_chars_option(wp, &wp->w_p_fcs, true);
+ // If no error was returned above, we don't expect an error
+ // here, so ignore the return value.
+ (void)set_chars_option(wp, &wp->w_p_fcs, true);
}
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
} else if (varp == &curwin->w_p_fcs) { // local 'fillchars'
errmsg = set_chars_option(curwin, varp, true);
} else if (varp == &p_cedit) { // 'cedit'
@@ -2690,7 +2742,7 @@ ambw_end:
// there would be a disconnect between the check for P_ALLOCED at the start
// of the function and the set of P_ALLOCED at the end of the function.
free_oldval = (options[opt_idx].flags & P_ALLOCED);
- for (s = p_shada; *s; ) {
+ for (s = p_shada; *s;) {
// Check it's a valid character
if (vim_strchr((char_u *)"!\"%'/:<@cfhnrs", *s) == NULL) {
errmsg = illegal_char(errbuf, errbuflen, *s);
@@ -2735,7 +2787,7 @@ ambw_end:
errmsg = N_("E528: Must specify a ' value");
}
} else if (gvarp == &p_sbr) { // 'showbreak'
- for (s = *varp; *s; ) {
+ for (s = *varp; *s;) {
if (ptr2cells(s) != 1) {
errmsg = N_("E595: 'showbreak' contains unprintable or wide character");
}
@@ -2879,7 +2931,7 @@ ambw_end:
}
} else if (gvarp == &p_cpt) {
// check if it is a valid value for 'complete' -- Acevedo
- for (s = *varp; *s; ) {
+ for (s = *varp; *s;) {
while (*s == ',' || *s == ' ') {
s++;
}
@@ -3355,7 +3407,7 @@ char *check_colorcolumn(win_T *wp)
return NULL; // buffer was closed
}
- for (s = wp->w_p_cc; *s != NUL && count < 255; ) {
+ for (s = wp->w_p_cc; *s != NUL && count < 255;) {
if (*s == '-' || *s == '+') {
// -N and +N: add to 'textwidth'
col = (*s == '-') ? -1 : 1;
@@ -3422,6 +3474,37 @@ void check_blending(win_T *wp)
wp->w_p_winbl > 0 || (wp->w_floating && wp->w_float_config.shadow);
}
+/// Calls mb_cptr2char_adv(p) and returns the character.
+/// If "p" starts with "\x", "\u" or "\U" the hex or unicode value is used.
+/// Returns 0 for invalid hex or invalid UTF-8 byte.
+static int get_encoded_char_adv(char_u **p)
+{
+ char_u *s = *p;
+
+ if (s[0] == '\\' && (s[1] == 'x' || s[1] == 'u' || s[1] == 'U')) {
+ int64_t num = 0;
+ int bytes;
+ int n;
+ for (bytes = s[1] == 'x' ? 1 : s[1] == 'u' ? 2 : 4; bytes > 0; bytes--) {
+ *p += 2;
+ n = hexhex2nr(*p);
+ if (n < 0) {
+ return 0;
+ }
+ num = num * 256 + n;
+ }
+ *p += 2;
+ return (int)num;
+ }
+
+ // TODO(bfredl): use schar_T representation and utfc_ptr2len
+ int clen = utf_ptr2len(s);
+ int c = mb_cptr2char_adv((const char_u **)p);
+ if (clen == 1 && c > 127) { // Invalid UTF-8 byte
+ return 0;
+ }
+ return c;
+}
/// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters
@@ -3526,26 +3609,21 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
&& p[len + 1] != NUL) {
c2 = c3 = 0;
s = p + len + 1;
-
- // TODO(bfredl): use schar_T representation and utfc_ptr2len
- int c1len = utf_ptr2len(s);
- c1 = mb_cptr2char_adv((const char_u **)&s);
- if (utf_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
+ c1 = get_encoded_char_adv(&s);
+ if (c1 == 0 || utf_char2cells(c1) > 1) {
return e_invarg;
}
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
if (*s == NUL) {
return e_invarg;
}
- int c2len = utf_ptr2len(s);
- c2 = mb_cptr2char_adv((const char_u **)&s);
- if (utf_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
+ c2 = get_encoded_char_adv(&s);
+ if (c2 == 0 || utf_char2cells(c2) > 1) {
return e_invarg;
}
if (!(*s == ',' || *s == NUL)) {
- int c3len = utf_ptr2len(s);
- c3 = mb_cptr2char_adv((const char_u **)&s);
- if (utf_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
+ c3 = get_encoded_char_adv(&s);
+ if (c3 == 0 || utf_char2cells(c3) > 1) {
return e_invarg;
}
}
@@ -3578,9 +3656,8 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
last_multispace = p;
multispace_len = 0;
while (*s != NUL && *s != ',') {
- int c1len = utf_ptr2len(s);
- c1 = mb_cptr2char_adv((const char_u **)&s);
- if (utf_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
+ c1 = get_encoded_char_adv(&s);
+ if (c1 == 0 || utf_char2cells(c1) > 1) {
return e_invarg;
}
multispace_len++;
@@ -3593,7 +3670,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
} else {
int multispace_pos = 0;
while (*s != NUL && *s != ',') {
- c1 = mb_cptr2char_adv((const char_u **)&s);
+ c1 = get_encoded_char_adv(&s);
if (p == last_multispace) {
wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
}
@@ -3812,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)
@@ -3819,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);
@@ -4095,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();
}
@@ -4142,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.
@@ -4151,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;
@@ -4495,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();
}
@@ -4526,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
@@ -4539,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();
}
}
@@ -4732,7 +4881,8 @@ static int findoption(const char *const arg)
/// @param stringval NULL when only checking existence
///
/// @returns:
-/// Number or Toggle option: 1, *numval gets value.
+/// Toggle option: 2, *numval gets value.
+/// Number option: 1, *numval gets value.
/// String option: 0, *stringval gets allocated string.
/// Hidden Number or Toggle option: -1.
/// hidden String option: -2.
@@ -4765,16 +4915,18 @@ int get_option_value(const char *name, long *numval, char_u **stringval, int opt
}
if (options[opt_idx].flags & P_NUM) {
*numval = *(long *)varp;
+ return 1;
+ }
+
+ // Special case: 'modified' is b_changed, but we also want to consider
+ // it set when 'ff' or 'fenc' changed.
+ if ((int *)varp == &curbuf->b_changed) {
+ *numval = curbufIsChanged();
} else {
- // Special case: 'modified' is b_changed, but we also want to consider
- // it set when 'ff' or 'fenc' changed.
- if ((int *)varp == &curbuf->b_changed) {
- *numval = curbufIsChanged();
- } else {
- *numval = (long)*(int *)varp; // NOLINT(whitespace/cast)
- }
+ *numval = (long)*(int *)varp; // NOLINT(whitespace/cast)
}
- return 1;
+
+ return 2;
}
// Returns the option attributes and its value. Unlike the above function it
@@ -4870,7 +5022,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
// only getting a pointer, no need to use aucmd_prepbuf()
curbuf = (buf_T *)from;
curwin->w_buffer = curbuf;
- varp = get_varp(p);
+ varp = get_varp_scope(p, OPT_LOCAL);
curbuf = save_curbuf;
curwin->w_buffer = curbuf;
}
@@ -4878,7 +5030,7 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
win_T *save_curwin = curwin;
curwin = (win_T *)from;
curbuf = curwin->w_buffer;
- varp = get_varp(p);
+ varp = get_varp_scope(p, OPT_LOCAL);
curwin = save_curwin;
curbuf = curwin->w_buffer;
}
@@ -6779,7 +6931,7 @@ static void langmap_set(void)
ga_clear(&langmap_mapga); // clear the previous map first
langmap_init(); // back to one-to-one map
- for (p = p_langmap; p[0] != NUL; ) {
+ for (p = p_langmap; p[0] != NUL;) {
for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
MB_PTR_ADV(p2)) {
if (p2[0] == '\\' && p2[1] != NUL) {
@@ -7746,7 +7898,7 @@ void set_fileformat(int eol_style, int opt_flags)
}
// This may cause the buffer to become (un)modified.
- check_status(curbuf);
+ redraw_buf_status_later(curbuf);
redraw_tabline = true;
need_maketitle = true; // Set window title later.
}
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 727b10f7a7..e9f44d2775 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -1048,7 +1048,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst
}
if (buf != NULL && buf->b_help) {
- const size_t dlen = xstrlcpy((char *)dst, (char *)path_tail(src), dstlen);
+ const size_t dlen = STRLCPY(dst, path_tail(src), dstlen);
return MIN(dlen, dstlen - 1);
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 3ff13c2b3f..24c7678633 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -21,7 +21,6 @@
#include "nvim/assert.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
@@ -369,7 +368,7 @@ static bool is_executable_in_path(const char *name, char **abspath)
// is an executable file.
char *p = path;
bool rv = false;
- for (;; ) {
+ for (;;) {
char *e = xstrchrnul(p, ENV_SEPCHAR);
// Combine the $PATH segment with `name`.
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 5b231f205b..3790eba212 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -17,7 +17,6 @@
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/os/input.h"
#include "nvim/state.h"
@@ -183,6 +182,40 @@ void os_breakcheck(void)
updating_screen = save_us;
}
+#define BREAKCHECK_SKIP 1000
+static int breakcheck_count = 0;
+
+/// Check for CTRL-C pressed, but only once in a while.
+///
+/// Should be used instead of os_breakcheck() for functions that check for
+/// each line in the file. Calling os_breakcheck() each time takes too much
+/// time, because it will use system calls to check for input.
+void line_breakcheck(void)
+{
+ if (++breakcheck_count >= BREAKCHECK_SKIP) {
+ breakcheck_count = 0;
+ os_breakcheck();
+ }
+}
+
+/// Like line_breakcheck() but check 10 times less often.
+void fast_breakcheck(void)
+{
+ if (++breakcheck_count >= BREAKCHECK_SKIP * 10) {
+ breakcheck_count = 0;
+ os_breakcheck();
+ }
+}
+
+/// Like line_breakcheck() but check 100 times less often.
+void veryfast_breakcheck(void)
+{
+ if (++breakcheck_count >= BREAKCHECK_SKIP * 100) {
+ breakcheck_count = 0;
+ os_breakcheck();
+ }
+}
+
/// Test whether a file descriptor refers to a terminal.
///
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index 8049b3b80e..dce4b0c187 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -13,6 +13,10 @@
# include "nvim/os/unix_defs.h"
#endif
+#if !defined(NAME_MAX) && defined(_XOPEN_NAME_MAX)
+#define NAME_MAX _XOPEN_NAME_MAX
+#endif
+
#define BASENAMELEN (NAME_MAX - 5)
// Use the system path length if it makes sense.
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 24ecf5c24f..3459646bad 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -15,6 +15,12 @@
# include <libutil.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
+#elif defined(__sun)
+# include <sys/stream.h>
+# include <sys/syscall.h>
+# include <fcntl.h>
+# include <unistd.h>
+# include <signal.h>
#else
# include <pty.h>
#endif
@@ -38,6 +44,118 @@
# include "os/pty_process_unix.c.generated.h"
#endif
+#if defined(__sun) && !defined(HAVE_FORKPTY)
+
+// this header defines STR, just as nvim.h, but it is defined as ('S'<<8),
+// to avoid #undef STR, #undef STR, #define STR ('S'<<8) just delay the
+// inclusion of the header even though it gets include out of order.
+#include <sys/stropts.h>
+
+static int openpty(int *amaster, int *aslave, char *name,
+ struct termios *termp, struct winsize *winp)
+{
+ int slave = -1;
+ int master = open("/dev/ptmx", O_RDWR);
+ if (master == -1) {
+ goto error;
+ }
+
+ // grantpt will invoke a setuid program to change permissions
+ // and might fail if SIGCHLD handler is set, temporarily reset
+ // while running
+ void(*sig_saved)(int) = signal(SIGCHLD, SIG_DFL);
+ int res = grantpt(master);
+ signal(SIGCHLD, sig_saved);
+
+ if (res == -1 || unlockpt(master) == -1) {
+ goto error;
+ }
+
+ char *slave_name = ptsname(master);
+ if (slave_name == NULL) {
+ goto error;
+ }
+
+ slave = open(slave_name, O_RDWR|O_NOCTTY);
+ if (slave == -1) {
+ goto error;
+ }
+
+ // ptem emulates a terminal when used on a pseudo terminal driver,
+ // must be pushed before ldterm
+ ioctl(slave, I_PUSH, "ptem");
+ // ldterm provides most of the termio terminal interface
+ ioctl(slave, I_PUSH, "ldterm");
+ // ttcompat compatability with older terminal ioctls
+ ioctl(slave, I_PUSH, "ttcompat");
+
+ if (termp) {
+ tcsetattr(slave, TCSAFLUSH, termp);
+ }
+ if (winp) {
+ ioctl(slave, TIOCSWINSZ, winp);
+ }
+
+ *amaster = master;
+ *aslave = slave;
+ // ignoring name, not passed and size is unknown in the API
+
+ return 0;
+
+error:
+ if (slave != -1) {
+ close(slave);
+ }
+ if (master != -1) {
+ close(master);
+ }
+ return -1;
+}
+
+static int login_tty(int fd)
+{
+ setsid();
+ if (ioctl(fd, TIOCSCTTY, NULL) == -1) {
+ return -1;
+ }
+
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO) {
+ close(fd);
+ }
+
+ return 0;
+}
+
+static pid_t forkpty(int *amaster, char *name,
+ struct termios *termp, struct winsize *winp)
+{
+ int master, slave;
+ if (openpty(&master, &slave, name, termp, winp) == -1) {
+ return -1;
+ }
+
+ pid_t pid = fork();
+ switch (pid) {
+ case -1:
+ close(master);
+ close(slave);
+ return -1;
+ case 0:
+ close(master);
+ login_tty(slave);
+ return 0;
+ default:
+ close(slave);
+ *amaster = master;
+ return pid;
+ }
+}
+
+#endif
+
/// termios saved at startup (for TUI) or initialized by pty_process_spawn().
static struct termios termios_default;
@@ -198,7 +316,9 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
termios->c_cflag = CS8|CREAD;
termios->c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK;
- cfsetspeed(termios, 38400);
+ // not using cfsetspeed, not available on all platforms
+ cfsetispeed(termios, 38400);
+ cfsetospeed(termios, 38400);
#ifdef IUTF8
termios->c_iflag |= IUTF8;
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 6ef0aa1091..e618b2788b 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -12,6 +12,7 @@
#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
+#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/fileio.h"
#include "nvim/lib/kvec.h"
@@ -20,7 +21,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option_defs.h"
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
@@ -28,6 +28,7 @@
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/types.h"
+#include "nvim/tag.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -681,6 +682,116 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
return exitcode;
}
+/// os_call_shell() wrapper. Handles 'verbose', :profile, and v:shell_error.
+/// Invalidates cached tags.
+///
+/// @return shell command exit code
+int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
+{
+ int retval;
+ proftime_T wait_time;
+
+ if (p_verbose > 3) {
+ verbose_enter();
+ smsg(_("Executing command: \"%s\""), cmd == NULL ? p_sh : cmd);
+ msg_putchar('\n');
+ verbose_leave();
+ }
+
+ if (do_profiling == PROF_YES) {
+ prof_child_enter(&wait_time);
+ }
+
+ if (*p_sh == NUL) {
+ emsg(_(e_shellempty));
+ retval = -1;
+ } else {
+ // The external command may update a tags file, clear cached tags.
+ tag_freematch();
+
+ retval = os_call_shell(cmd, opts, extra_shell_arg);
+ }
+
+ set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T)retval);
+ if (do_profiling == PROF_YES) {
+ prof_child_exit(&wait_time);
+ }
+
+ return retval;
+}
+
+/// Get the stdout of an external command.
+/// If "ret_len" is NULL replace NUL characters with NL. When "ret_len" is not
+/// NULL store the length there.
+///
+/// @param cmd command to execute
+/// @param infile optional input file name
+/// @param flags can be kShellOptSilent or 0
+/// @param ret_len length of the stdout
+///
+/// @return an allocated string, or NULL for error.
+char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret_len)
+{
+ char_u *buffer = NULL;
+
+ if (check_secure()) {
+ return NULL;
+ }
+
+ // get a name for the temp file
+ char_u *tempname = vim_tempname();
+ if (tempname == NULL) {
+ emsg(_(e_notmp));
+ return NULL;
+ }
+
+ // Add the redirection stuff
+ char_u *command = make_filter_cmd(cmd, infile, tempname);
+
+ // Call the shell to execute the command (errors are ignored).
+ // Don't check timestamps here.
+ no_check_timestamps++;
+ call_shell(command, kShellOptDoOut | kShellOptExpand | flags, NULL);
+ no_check_timestamps--;
+
+ xfree(command);
+
+ // read the names from the file into memory
+ FILE *fd = os_fopen((char *)tempname, READBIN);
+
+ if (fd == NULL) {
+ semsg(_(e_notopen), tempname);
+ goto done;
+ }
+
+ fseek(fd, 0L, SEEK_END);
+ size_t len = (size_t)ftell(fd); // get size of temp file
+ fseek(fd, 0L, SEEK_SET);
+
+ buffer = xmalloc(len + 1);
+ size_t i = fread((char *)buffer, 1, len, fd);
+ fclose(fd);
+ os_remove((char *)tempname);
+ if (i != len) {
+ semsg(_(e_notread), tempname);
+ XFREE_CLEAR(buffer);
+ } else if (ret_len == NULL) {
+ // Change NUL into SOH, otherwise the string is truncated.
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == NUL) {
+ buffer[i] = 1;
+ }
+ }
+
+ buffer[len] = NUL; // make sure the buffer is terminated
+ } else {
+ *ret_len = len;
+ }
+
+done:
+ xfree(tempname);
+ return buffer;
+}
/// os_system - synchronously execute a command in the shell
///
/// example:
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index 0d125ec964..a8bf68a1a2 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -18,7 +18,6 @@
#include "nvim/main.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/os/signal.h"
#include "nvim/vim.h"
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 10b0d391bf..5b824d23f4 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -146,7 +146,7 @@ char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathse
const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0);
if (numcommas || trailing_pathseps) {
ret = xrealloc(ret, len + trailing_pathseps + numcommas + 1);
- for (size_t i = 0 ; i < len + numcommas ; i++) {
+ for (size_t i = 0; i < len + numcommas; i++) {
if (ret[i] == ',') {
memmove(ret + i + 1, ret + i, len - i + numcommas);
ret[i] = '\\';
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index 9952e2b387..e0ce3fec31 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -18,6 +18,9 @@
# include <lm.h>
#endif
+// All user names (for ~user completion as done by shell).
+static garray_T ga_users = GA_EMPTY_INIT_VALUE;
+
// Add a user name to the list of users in garray_T *users.
// Do nothing if user name is NULL or empty.
static void add_user(garray_T *users, char *user, bool need_copy)
@@ -157,3 +160,60 @@ char *os_get_user_directory(const char *name)
return NULL;
}
+
+#if defined(EXITFREE)
+
+void free_users(void)
+{
+ ga_clear_strings(&ga_users);
+}
+
+#endif
+
+/// Find all user names for user completion.
+///
+/// Done only once and then cached.
+static void init_users(void)
+{
+ static int lazy_init_done = false;
+
+ if (lazy_init_done) {
+ return;
+ }
+
+ lazy_init_done = true;
+
+ os_get_usernames(&ga_users);
+}
+
+/// Given to ExpandGeneric() to obtain an user names.
+char_u *get_users(expand_T *xp, int idx)
+{
+ init_users();
+ if (idx < ga_users.ga_len) {
+ return ((char_u **)ga_users.ga_data)[idx];
+ }
+ return NULL;
+}
+
+/// Check whether name matches a user name.
+///
+/// @return 0 if name does not match any user name.
+/// 1 if name partially matches the beginning of a user name.
+/// 2 is name fully matches a user name.
+int match_user(char_u *name)
+{
+ int n = (int)STRLEN(name);
+ int result = 0;
+
+ init_users();
+ for (int i = 0; i < ga_users.ga_len; i++) {
+ if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) {
+ return 2; // full match
+ }
+ if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) {
+ result = 1; // partial match
+ }
+ }
+ return result;
+}
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 9396a5896a..1398dba0e4 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -20,7 +20,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/os/input.h"
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 1085f7a10c..674d67e21a 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -18,7 +18,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
@@ -65,7 +64,7 @@ FileComparison path_full_compare(char_u *const s1, char_u *const s2, const bool
if (expandenv) {
expand_env(s1, exp1, MAXPATHL);
} else {
- xstrlcpy((char *)exp1, (const char *)s1, MAXPATHL);
+ STRLCPY(exp1, s1, MAXPATHL);
}
bool id_ok_1 = os_fileid((char *)exp1, &file_id_1);
bool id_ok_2 = os_fileid((char *)s2, &file_id_2);
@@ -1079,7 +1078,7 @@ const char *gettail_dir(const char *const fname)
const char *next_dir_end = fname;
bool look_for_sep = true;
- for (const char *p = fname; *p != NUL; ) {
+ for (const char *p = fname; *p != NUL;) {
if (vim_ispathsep(*p)) {
if (look_for_sep) {
next_dir_end = p;
@@ -1289,8 +1288,8 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
&& !path_is_absolute(p)
&& !(p[0] == '.'
&& (vim_ispathsep(p[1])
- || (p[1] == '.' &&
- vim_ispathsep(p[2]))))) {
+ || (p[1] == '.'
+ && vim_ispathsep(p[2]))))) {
/* :find completion where 'path' is used.
* Recursiveness is OK here. */
recursive = false;
@@ -1337,6 +1336,17 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? OK : FAIL;
}
+/// Free the list of files returned by expand_wildcards() or other expansion functions.
+void FreeWild(int count, char_u **files)
+{
+ if (count <= 0 || files == NULL) {
+ return;
+ }
+ while (count--) {
+ xfree(files[count]);
+ }
+ xfree(files);
+}
/*
* Return TRUE if we can expand this backtick thing here.
@@ -1505,7 +1515,7 @@ void simplify_filename(char_u *filename)
if (vim_ispathsep(*p)) {
relative = false;
- do{
+ do {
++p;
}
while (vim_ispathsep(*p));
@@ -1517,8 +1527,8 @@ void simplify_filename(char_u *filename)
* or "p" is at the "start" of the (absolute or relative) path name. */
if (vim_ispathsep(*p)) {
STRMOVE(p, p + 1); // remove duplicate "/"
- } else if (p[0] == '.' &&
- (vim_ispathsep(p[1]) || p[1] == NUL)) {
+ } else if (p[0] == '.'
+ && (vim_ispathsep(p[1]) || p[1] == NUL)) {
if (p == start && relative) {
p += 1 + (p[1] != NUL); // keep single "." or leading "./"
} else {
@@ -2198,7 +2208,7 @@ int match_suffix(char_u *fname)
size_t fnamelen = STRLEN(fname);
size_t setsuflen = 0;
- for (char_u *setsuf = p_su; *setsuf; ) {
+ for (char_u *setsuf = p_su; *setsuf;) {
setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,");
if (setsuflen == 0) {
char_u *tail = path_tail(fname);
@@ -2245,11 +2255,17 @@ int path_full_dir_name(char *directory, char *buffer, size_t len)
}
if (os_chdir(directory) != SUCCESS) {
- // Do not return immediately since we may be in the wrong directory.
- retval = FAIL;
- }
-
- if (retval == FAIL || os_dirname((char_u *)buffer, len) == FAIL) {
+ // Path does not exist (yet). For a full path fail,
+ // will use the path as-is. For a relative path use
+ // the current directory and append the file name.
+ if (path_is_absolute((const char_u *)directory)) {
+ // Do not return immediately since we may be in the wrong directory.
+ retval = FAIL;
+ } else {
+ xstrlcpy(buffer, old_dir, len);
+ append_path(buffer, directory, len);
+ }
+ } else if (os_dirname((char_u *)buffer, len) == FAIL) {
// Do not return immediately since we are in the wrong directory.
retval = FAIL;
}
@@ -2395,9 +2411,9 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize)
if (dir_len + 1 > sizeof(NameBuff)) {
continue;
}
- xstrlcpy((char *)NameBuff, dir, dir_len + 1);
- xstrlcat((char *)NameBuff, PATHSEPSTR, sizeof(NameBuff));
- xstrlcat((char *)NameBuff, argv0, sizeof(NameBuff));
+ STRLCPY(NameBuff, dir, dir_len + 1);
+ STRLCAT(NameBuff, PATHSEPSTR, sizeof(NameBuff));
+ STRLCAT(NameBuff, argv0, sizeof(NameBuff));
if (os_can_exe((char *)NameBuff, NULL, false)) {
xstrlcpy(buf, (char *)NameBuff, bufsize);
return;
diff --git a/src/nvim/po/check.vim b/src/nvim/po/check.vim
index d55d4cfa4d..aca878f9d5 100644
--- a/src/nvim/po/check.vim
+++ b/src/nvim/po/check.vim
@@ -162,7 +162,10 @@ endwhile
" Check that the file is well formed according to msgfmts understanding
if executable("msgfmt")
let filename = expand("%")
- let a = system("msgfmt --statistics OLD_PO_FILE_INPUT=yes " . filename)
+ " Newer msgfmt does not take OLD_PO_FILE_INPUT argument, must be in
+ " environment.
+ let $OLD_PO_FILE_INPUT = 'yes'
+ let a = system("msgfmt --statistics " . filename)
if v:shell_error != 0
let error = matchstr(a, filename.':\zs\d\+\ze:')+0
for line in split(a, '\n') | echomsg line | endfor
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 950d187ad5..32d0ebe8eb 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -27,7 +27,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
@@ -539,7 +538,7 @@ static size_t efm_regpat_bufsz(char_u *efm)
size_t sz;
sz = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2);
- for (int i = FMT_PATTERNS - 1; i >= 0; ) {
+ for (int i = FMT_PATTERNS - 1; i >= 0;) {
sz += STRLEN(fmt_pat[i--].pattern);
}
#ifdef BACKSLASH_IN_FILENAME
@@ -658,7 +657,8 @@ static int qf_get_next_str_line(qfstate_T *state)
state->linebuf = IObuff;
state->linelen = len;
}
- STRLCPY(state->linebuf, p_str, state->linelen + 1);
+ memcpy(state->linebuf, p_str, state->linelen);
+ state->linebuf[state->linelen] = '\0';
// Increment using len in order to discard the rest of the line if it
// exceeds LINE_MAXLEN.
@@ -1183,7 +1183,7 @@ static void qf_store_title(qf_list_T *qfl, const char_u *title)
char_u *p = xmallocz(len);
qfl->qf_title = p;
- xstrlcpy((char *)p, (const char *)title, len + 1);
+ STRLCPY(p, title, len + 1);
}
}
@@ -1402,7 +1402,7 @@ static int qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
len = CMDBUFFSIZE - 5;
}
STRCPY(fields->pattern, "^\\V");
- xstrlcat((char *)fields->pattern, (char *)rmp->startp[midx], len + 4);
+ STRLCAT(fields->pattern, rmp->startp[midx], len + 4);
fields->pattern[len + 3] = '\\';
fields->pattern[len + 4] = '$';
fields->pattern[len + 5] = NUL;
@@ -1424,7 +1424,7 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
if (dsize > CMDBUFFSIZE) {
dsize = CMDBUFFSIZE;
}
- xstrlcat((char *)fields->module, (char *)rmp->startp[midx], dsize);
+ STRLCAT(fields->module, rmp->startp[midx], dsize);
return QF_OK;
}
@@ -2028,7 +2028,7 @@ void copy_loclist_stack(win_T *from, win_T *to)
/// Get buffer number for file "directory/fname".
/// Also sets the b_has_qf_entry flag.
-static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname )
+static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname)
{
char_u *ptr = NULL;
char_u *bufname;
@@ -3231,7 +3231,7 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
memset(buf + len, ' ', 34 - len);
buf[34] = NUL;
}
- xstrlcat((char *)buf, title, IOSIZE);
+ STRLCAT(buf, title, IOSIZE);
}
trunc_string(buf, buf, Columns - 1, IOSIZE);
msg((char *)buf);
@@ -4380,7 +4380,7 @@ static char_u *get_mef_name(void)
}
// Keep trying until the name doesn't exist yet.
- for (;; ) {
+ for (;;) {
if (start == -1) {
start = (int)os_get_pid();
} else {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index bec3bc9648..45e580dbee 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -64,7 +64,7 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
+#include "nvim/os/input.h"
#include "nvim/plines.h"
#include "nvim/garray.h"
#include "nvim/strings.h"
@@ -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/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 5df5cc5975..eac1b4596e 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -16,23 +16,22 @@
#include "nvim/ascii.h"
#include "nvim/garray.h"
-
-/*
- * Logging of NFA engine.
- *
- * The NFA engine can write four log files:
- * - Error log: Contains NFA engine's fatal errors.
- * - Dump log: Contains compiled NFA state machine's information.
- * - Run log: Contains information of matching procedure.
- * - Debug log: Contains detailed information of matching procedure. Can be
- * disabled by undefining NFA_REGEXP_DEBUG_LOG.
- * The first one can also be used without debug mode.
- * The last three are enabled when compiled as debug mode and individually
- * disabled by commenting them out.
- * The log files can get quite big!
- * Do disable all of this when compiling Vim for debugging, undefine REGEXP_DEBUG in
- * regexp.c
- */
+#include "nvim/os/input.h"
+
+// Logging of NFA engine.
+//
+// The NFA engine can write four log files:
+// - Error log: Contains NFA engine's fatal errors.
+// - Dump log: Contains compiled NFA state machine's information.
+// - Run log: Contains information of matching procedure.
+// - Debug log: Contains detailed information of matching procedure. Can be
+// disabled by undefining NFA_REGEXP_DEBUG_LOG.
+// The first one can also be used without debug mode.
+// The last three are enabled when compiled as debug mode and individually
+// disabled by commenting them out.
+// The log files can get quite big!
+// To disable all of this when compiling Vim for debugging, undefine REGEXP_DEBUG in
+// regexp.c
#ifdef REGEXP_DEBUG
# define NFA_REGEXP_ERROR_LOG "nfa_regexp_error.log"
# define NFA_REGEXP_DUMP_LOG "nfa_regexp_dump.log"
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 674d807e96..1c04cb16b3 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -12,7 +12,6 @@
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/lua/executor.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
#include "nvim/runtime.h"
@@ -479,7 +478,7 @@ RuntimeSearchPath runtime_search_path_build(void)
CharVec after_path = KV_INITIAL_VALUE;
static char_u buf[MAXPATHL];
- for (char *entry = (char *)p_pp; *entry != NUL; ) {
+ for (char *entry = (char *)p_pp; *entry != NUL;) {
char *cur_entry = entry;
copy_option_part((char_u **)&entry, buf, MAXPATHL, ",");
@@ -491,7 +490,7 @@ RuntimeSearchPath runtime_search_path_build(void)
char *rtp_entry;
- for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL; ) {
+ for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL;) {
char *cur_entry = rtp_entry;
copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ",");
size_t buflen = STRLEN(buf);
@@ -663,7 +662,7 @@ static int add_pack_dir_to_rtp(char_u *fname, bool is_pack)
}
const char *insp = NULL;
const char *after_insp = NULL;
- for (const char *entry = (const char *)p_rtp; *entry != NUL; ) {
+ for (const char *entry = (const char *)p_rtp; *entry != NUL;) {
const char *cur_entry = entry;
copy_option_part((char_u **)&entry, buf, MAXPATHL, ",");
@@ -872,7 +871,7 @@ static void add_pack_start_dir(char_u *fname, void *cookie)
continue;
}
STRLCPY(buf, fname, MAXPATHL);
- xstrlcat((char *)buf, start_pat[i], sizeof buf);
+ STRLCAT(buf, start_pat[i], sizeof buf);
if (pack_has_entries(buf)) {
add_pack_dir_to_rtp(buf, true);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 63e904079e..a938a3b062 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -98,7 +98,6 @@
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
@@ -314,6 +313,19 @@ void update_curbuf(int type)
update_screen(type);
}
+/// called when the status bars for the buffer 'buf' need to be updated
+void redraw_buf_status_later(buf_T *buf)
+{
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer == buf && wp->w_status_height) {
+ wp->w_redr_status = true;
+ if (must_redraw < VALID) {
+ must_redraw = VALID;
+ }
+ }
+ }
+}
+
/// Redraw the parts of the screen that is marked for redraw.
///
/// Most code shouldn't call this directly, rather use redraw_later() and
@@ -451,9 +463,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 +568,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) {
@@ -1084,7 +1098,7 @@ static void win_update(win_T *wp, Providers *providers)
*/
bot_start = 0;
idx = 0;
- for (;; ) {
+ for (;;) {
wp->w_lines[idx] = wp->w_lines[j];
/* stop at line that didn't fit, unless it is still
* valid (no lines deleted) */
@@ -1359,7 +1373,7 @@ static void win_update(win_T *wp, Providers *providers)
win_check_ns_hl(wp);
- for (;; ) {
+ for (;;) {
/* stop updating when reached the end of the window (check for _past_
* the end of the window is at the end of the loop) */
if (row == wp->w_grid.Rows) {
@@ -1508,7 +1522,7 @@ static void win_update(win_T *wp, Providers *providers)
int x = row + new_rows;
// move entries in w_lines[] upwards
- for (;; ) {
+ for (;;) {
// stop at last valid entry in w_lines[]
if (i >= wp->w_lines_valid) {
wp->w_lines_valid = j;
@@ -1692,7 +1706,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;
@@ -2707,7 +2721,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int sign_idx = 0;
// Repeat for the whole displayed line.
- for (;; ) {
+ for (;;) {
int has_match_conc = 0; ///< match wants to conceal
bool did_decrement_ptr = false;
@@ -2744,7 +2758,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
p_extra = p_extra_free;
c_extra = NUL;
c_final = NUL;
- char_attr = win_hl_attr(wp, HLF_FC);
+ if (use_cursor_line_sign(wp, lnum)) {
+ char_attr = win_hl_attr(wp, HLF_CLF);
+ } else {
+ char_attr = win_hl_attr(wp, HLF_FC);
+ }
}
}
@@ -2755,7 +2773,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
* buffer or when using Netbeans. */
int count = win_signcol_count(wp);
if (count > 0) {
- get_sign_display_info(false, wp, sattrs, row,
+ get_sign_display_info(false, wp, lnum, sattrs, row,
startrow, filler_lines, filler_todo, count,
&c_extra, &c_final, extra, sizeof(extra),
&p_extra, &n_extra,
@@ -2776,7 +2794,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'
&& num_signs > 0) {
int count = win_signcol_count(wp);
- get_sign_display_info(true, wp, sattrs, row,
+ get_sign_display_info(true, wp, lnum, sattrs, row,
startrow, filler_lines, filler_todo, count,
&c_extra, &c_final, extra, sizeof(extra),
&p_extra, &n_extra,
@@ -3117,7 +3135,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// the match.
if (cur != NULL
&& shl != &search_hl
- && syn_name2id((char_u *)"Conceal") == cur->hlg_id) {
+ && syn_name2id("Conceal") == cur->hlg_id) {
has_match_conc = v == (long)shl->startcol ? 2 : 1;
match_conc = cur->conceal_char;
} else {
@@ -4413,8 +4431,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|| filler_todo > 0
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
&& p_extra != at_end_str)
- || (n_extra != 0 &&
- (c_extra != NUL || *p_extra != NUL)))) {
+ || (n_extra != 0
+ && (c_extra != NUL || *p_extra != NUL)))) {
bool wrap = wp->w_p_wrap // Wrapping enabled.
&& filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
@@ -4615,6 +4633,14 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
}
}
+// Return true if CursorLineSign highlight is to be used.
+static bool use_cursor_line_sign(win_T *wp, linenr_T lnum)
+{
+ return wp->w_p_cul
+ && lnum == wp->w_cursor.lnum
+ && (wp->w_p_culopt_flags & CULOPT_NBR);
+}
+
// Get information needed to display the sign in line 'lnum' in window 'wp'.
// If 'nrcol' is TRUE, the sign is going to be displayed in the number column.
// Otherwise the sign is going to be displayed in the sign column.
@@ -4622,11 +4648,11 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
// @param count max number of signs
// @param[out] n_extrap number of characters from pp_extra to display
// @param[in, out] sign_idxp Index of the displayed sign
-static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[], int row,
- int startrow, int filler_lines, int filler_todo, int count,
- int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size,
- char_u **pp_extra, int *n_extrap, int *char_attrp,
- int *draw_statep, int *sign_idxp)
+static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, sign_attrs_T sattrs[],
+ int row, int startrow, int filler_lines, int filler_todo,
+ int count, int *c_extrap, int *c_finalp, char_u *extra,
+ size_t extra_size, char_u **pp_extra, int *n_extrap,
+ int *char_attrp, int *draw_statep, int *sign_idxp)
{
// Draw cells with the sign value or blank.
*c_extrap = ' ';
@@ -4634,7 +4660,11 @@ static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[],
if (nrcol) {
*n_extrap = number_width(wp) + 1;
} else {
- *char_attrp = win_hl_attr(wp, HLF_SC);
+ if (use_cursor_line_sign(wp, lnum)) {
+ *char_attrp = win_hl_attr(wp, HLF_CLS);
+ } else {
+ *char_attrp = win_hl_attr(wp, HLF_SC);
+ }
*n_extrap = win_signcol_width(wp);
}
@@ -4674,7 +4704,12 @@ static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[],
(*pp_extra)[*n_extrap] = NUL;
}
}
- *char_attrp = sattr->sat_texthl;
+
+ if (use_cursor_line_sign(wp, lnum) && sattr->sat_culhl > 0) {
+ *char_attrp = sattr->sat_culhl;
+ } else {
+ *char_attrp = sattr->sat_texthl;
+ }
}
}
@@ -5011,8 +5046,8 @@ static int skip_status_match_char(expand_T *xp, char_u *s)
if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
|| ((xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES)
- && (s[0] == '\t' ||
- (s[0] == '\\' && s[1] != NUL)))) {
+ && (s[0] == '\t'
+ || (s[0] == '\\' && s[1] != NUL)))) {
#ifndef BACKSLASH_IN_FILENAME
if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') {
return 2;
@@ -6144,7 +6179,7 @@ static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T minc
* or none is found in this line.
*/
called_emsg = FALSE;
- for (;; ) {
+ for (;;) {
// Stop searching after passing the time limit.
if (profile_passed_limit(shl->tm)) {
shl->lnum = 0; // no match found in time
@@ -6930,7 +6965,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 +7045,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/search.c b/src/nvim/search.c
index 0756fbf37d..906c9a6f47 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -14,6 +14,7 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
+#include "nvim/change.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
@@ -31,11 +32,11 @@
#include "nvim/memline.h"
#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/option.h"
+#include "nvim/os/input.h"
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/regexp.h"
@@ -370,8 +371,8 @@ int ignorecase_opt(char_u *pat, int ic_in, int scs)
{
int ic = ic_in;
if (ic && !no_smartcase && scs
- && !(ctrl_x_mode_not_default() &&
- curbuf->b_p_inf)) {
+ && !(ctrl_x_mode_not_default()
+ && curbuf->b_p_inf)) {
ic = !pat_has_uppercase(pat);
}
no_smartcase = false;
@@ -757,7 +758,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir,
* relative to the end of the match.
*/
match_ok = false;
- for (;; ) {
+ for (;;) {
// Remember a position that is before the start
// position, we use it if it's the last match in
// the line. Always accept a position after
@@ -1105,7 +1106,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
/*
* Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
*/
- for (;; ) {
+ for (;;) {
bool show_top_bot_msg = false;
searchstr = pat;
@@ -1353,6 +1354,10 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
}
retval = 1; // pattern found
+ if (sia && sia->sa_wrapped) {
+ apply_autocmds(EVENT_SEARCHWRAPPED, NULL, NULL, false, NULL);
+ }
+
/*
* Add character and/or line offset
*/
@@ -1465,7 +1470,7 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat)
if (buf->b_ml.ml_line_count == 0) {
return FAIL;
}
- for (;; ) {
+ for (;;) {
pos->lnum += dir;
if (pos->lnum < 1) {
if (p_ws) {
@@ -1585,7 +1590,7 @@ int searchc(cmdarg_T *cap, int t_cmd)
len = (int)STRLEN(p);
while (count--) {
- for (;; ) {
+ for (;;) {
if (dir > 0) {
col += utfc_ptr2len(p + col);
if (col >= len) {
@@ -1808,6 +1813,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
initc = NUL;
} else if (initc != '#' && initc != NUL) {
find_mps_values(&initc, &findc, &backwards, true);
+ if (dir) {
+ backwards = (dir == FORWARD) ? false : true;
+ }
if (findc == NUL) {
return NULL;
}
@@ -1870,7 +1878,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
if (linep[pos.col] == NUL && pos.col) {
--pos.col;
}
- for (;; ) {
+ for (;;) {
initc = utf_ptr2char(linep + pos.col);
if (initc == NUL) {
break;
@@ -1894,7 +1902,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
// Set "match_escaped" if there are an odd number of
// backslashes.
- for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) {
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col);) {
bslcnt++;
}
match_escaped = (bslcnt & 1);
@@ -2278,7 +2286,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
int col, bslcnt = 0;
if (!cpo_bsl) {
- for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) {
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col);) {
bslcnt++;
}
}
@@ -2520,7 +2528,7 @@ int findsent(Direction dir, long count)
const int startlnum = pos.lnum;
const bool cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
- for (;; ) { // find end of sentence
+ for (;;) { // find end of sentence
c = gchar_pos(&pos);
if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) {
if (dir == BACKWARD && pos.lnum != startlnum) {
@@ -2530,7 +2538,7 @@ int findsent(Direction dir, long count)
}
if (c == '.' || c == '!' || c == '?') {
tpos = pos;
- do{
+ do {
if ((c = inc(&tpos)) == -1) {
break;
}
@@ -3004,7 +3012,7 @@ static void back_in_line(void)
int sclass; // starting class
sclass = cls();
- for (;; ) {
+ for (;;) {
if (curwin->w_cursor.col == 0) { // stop at start of line
break;
}
@@ -3427,12 +3435,22 @@ int current_block(oparg_T *oap, long count, int include, int what, int other)
// user wants.
save_cpo = p_cpo;
p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%");
- while (count-- > 0) {
- if ((pos = findmatch(NULL, what)) == NULL) {
- break;
+ if ((pos = findmatch(NULL, what)) != NULL) {
+ while (count-- > 0) {
+ if ((pos = findmatch(NULL, what)) == NULL) {
+ break;
+ }
+ curwin->w_cursor = *pos;
+ start_pos = *pos; // the findmatch for end_pos will overwrite *pos
+ }
+ } else {
+ while (count-- > 0) {
+ if ((pos = findmatchlimit(NULL, what, FM_FORWARD, 0)) == NULL) {
+ break;
+ }
+ curwin->w_cursor = *pos;
+ start_pos = *pos; // the findmatch for end_pos will overwrite *pos
}
- curwin->w_cursor = *pos;
- start_pos = *pos; // the findmatch for end_pos will overwrite *pos
}
p_cpo = save_cpo;
@@ -3527,7 +3545,7 @@ static bool in_html_tag(bool end_tag)
int lc = NUL;
pos_T pos;
- for (p = line + curwin->w_cursor.col; p > line; ) {
+ for (p = line + curwin->w_cursor.col; p > line;) {
if (*p == '<') { // find '<' under/before cursor
break;
}
@@ -3555,7 +3573,7 @@ static bool in_html_tag(bool end_tag)
}
// check that the matching '>' is not preceded by '/'
- for (;; ) {
+ for (;;) {
if (inc(&pos) < 0) {
return false;
}
@@ -3791,7 +3809,7 @@ extend:
} else {
dir = FORWARD;
}
- for (i = count; --i >= 0; ) {
+ for (i = count; --i >= 0;) {
if (start_lnum ==
(dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) {
retval = FAIL;
@@ -3806,7 +3824,7 @@ extend:
start_lnum -= dir;
break;
}
- for (;; ) {
+ for (;;) {
if (start_lnum == (dir == BACKWARD
? 1 : curbuf->b_ml.ml_line_count)) {
break;
@@ -3946,7 +3964,7 @@ static int find_next_quote(char_u *line, int col, int quotechar, char_u *escape)
{
int c;
- for (;; ) {
+ for (;;) {
c = line[col];
if (c == NUL) {
return -1;
@@ -4118,7 +4136,7 @@ bool current_quote(oparg_T *oap, long count, bool include, int quotechar)
// Also do this when there is a Visual area, a' may leave the cursor
// in between two strings.
col_start = 0;
- for (;; ) {
+ for (;;) {
// Find open quote character.
col_start = find_next_quote(line, col_start, quotechar, NULL);
if (col_start < 0 || col_start > first_col) {
@@ -4842,7 +4860,7 @@ void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bo
}
line = ml_get(lnum);
- for (;; ) {
+ for (;;) {
if (incl_regmatch.regprog != NULL
&& vim_regexec(&incl_regmatch, line, (colnr_T)0)) {
char_u *p_fname = (curr_fname == curbuf->b_fname)
@@ -5235,6 +5253,9 @@ search_line:
if (depth == -1) {
// match in current file
if (l_g_do_tagpreview != 0) {
+ if (!win_valid(curwin_save)) {
+ break;
+ }
if (!GETFILE_SUCCESS(getfile(curwin_save->w_buffer->b_fnum, NULL,
NULL, true, lnum, false))) {
break; // failed to jump to file
@@ -5379,7 +5400,7 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action,
if (got_int) { // 'q' typed at "--more--" message
return;
}
- for (;; ) {
+ for (;;) {
p = line + STRLEN(line) - 1;
if (fp != NULL) {
// We used fgets(), so get rid of newline at end
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 89f9d3a719..e75a244031 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -3977,7 +3977,7 @@ static bool shada_removable(const char *name)
bool retval = false;
char *new_name = (char *)home_replace_save(NULL, (char_u *)name);
- for (p = (char *)p_shada; *p; ) {
+ for (p = (char *)p_shada; *p;) {
(void)copy_option_part((char_u **)&p, (char_u *)part, ARRAY_SIZE(part), ", ");
if (part[0] == 'r') {
home_replace(NULL, (char_u *)(part + 1), (char_u *)NameBuff, MAXPATHL, true);
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index dfa863d0ff..32be714184 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -31,6 +31,7 @@ struct sign {
char_u *sn_text; // text used instead of pixmap
int sn_line_hl; // highlight ID for line
int sn_text_hl; // highlight ID for text
+ int sn_cul_hl; // highlight ID for text on current line when 'cursorline' is set
int sn_num_hl; // highlight ID for line number
};
@@ -80,7 +81,7 @@ static signgroup_T *sign_group_ref(const char_u *groupname)
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
if (HASHITEM_EMPTY(hi)) {
// new group
- group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+ group = xmalloc(sizeof(signgroup_T) + STRLEN(groupname));
STRCPY(group->sg_name, groupname);
group->sg_refcount = 1;
@@ -499,6 +500,9 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
if (sp->sn_line_hl != 0) {
sattr.sat_linehl = syn_id2attr(sp->sn_line_hl);
}
+ if (sp->sn_cul_hl != 0) {
+ sattr.sat_culhl = syn_id2attr(sp->sn_cul_hl);
+ }
if (sp->sn_num_hl != 0) {
sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
}
@@ -774,7 +778,7 @@ static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd)
char_u save = *end_cmd;
*end_cmd = (char_u)NUL;
- for (idx = 0; ; idx++) {
+ for (idx = 0;; idx++) {
if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
break;
}
@@ -816,7 +820,7 @@ static sign_T *alloc_new_sign(char_u *name)
// Check that next_sign_typenr is not already being used.
// This only happens after wrapping around. Hopefully
// another one got deleted and we can use its number.
- for (lp = first_sign; lp != NULL; ) {
+ for (lp = first_sign; lp != NULL;) {
if (lp->sn_typenr == next_sign_typenr) {
next_sign_typenr++;
if (next_sign_typenr == MAX_TYPENR) {
@@ -901,7 +905,7 @@ static int sign_define_init_text(sign_T *sp, char_u *text)
/// Define a new sign or update an existing sign
int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl,
- char *numhl)
+ char_u *culhl, char *numhl)
{
sign_T *sp_prev;
sign_T *sp;
@@ -939,15 +943,35 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text
}
if (linehl != NULL) {
- sp->sn_line_hl = syn_check_group((char *)linehl, (int)STRLEN(linehl));
+ if (*linehl == NUL) {
+ sp->sn_line_hl = 0;
+ } else {
+ sp->sn_line_hl = syn_check_group((char *)linehl, (int)STRLEN(linehl));
+ }
}
if (texthl != NULL) {
- sp->sn_text_hl = syn_check_group((char *)texthl, (int)STRLEN(texthl));
+ if (*texthl == NUL) {
+ sp->sn_text_hl = 0;
+ } else {
+ sp->sn_text_hl = syn_check_group((char *)texthl, (int)STRLEN(texthl));
+ }
+ }
+
+ if (culhl != NULL) {
+ if (*culhl == NUL) {
+ sp->sn_cul_hl = 0;
+ } else {
+ sp->sn_cul_hl = syn_check_group((char *)culhl, (int)STRLEN(culhl));
+ }
}
if (numhl != NULL) {
- sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl));
+ if (*numhl == NUL) {
+ sp->sn_num_hl = 0;
+ } else {
+ sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl));
+ }
}
return OK;
@@ -1133,6 +1157,7 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
char_u *text = NULL;
char_u *linehl = NULL;
char_u *texthl = NULL;
+ char_u *culhl = NULL;
char_u *numhl = NULL;
int failed = false;
@@ -1155,6 +1180,9 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
} else if (STRNCMP(arg, "texthl=", 7) == 0) {
arg += 7;
texthl = vim_strnsave(arg, (size_t)(p - arg));
+ } else if (STRNCMP(arg, "culhl=", 6) == 0) {
+ arg += 6;
+ culhl = vim_strnsave(arg, (size_t)(p - arg));
} else if (STRNCMP(arg, "numhl=", 6) == 0) {
arg += 6;
numhl = vim_strnsave(arg, (size_t)(p - arg));
@@ -1166,13 +1194,14 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
}
if (!failed) {
- sign_define_by_name(sign_name, icon, linehl, text, texthl, (char *)numhl);
+ sign_define_by_name(sign_name, icon, linehl, text, texthl, culhl, (char *)numhl);
}
xfree(icon);
xfree(text);
xfree(linehl);
xfree(texthl);
+ xfree(culhl);
xfree(numhl);
}
@@ -1481,6 +1510,13 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict)
}
tv_dict_add_str(retdict, S_LEN("texthl"), (char *)p);
}
+ if (sp->sn_cul_hl > 0) {
+ p = get_highlight_name_ext(NULL, sp->sn_cul_hl - 1, false);
+ if (p == NULL) {
+ p = "NONE";
+ }
+ tv_dict_add_str(retdict, S_LEN("culhl"), (char *)p);
+ }
if (sp->sn_num_hl > 0) {
p = get_highlight_name_ext(NULL, sp->sn_num_hl - 1, false);
if (p == NULL) {
@@ -1609,6 +1645,16 @@ static void sign_list_defined(sign_T *sp)
msg_puts(p);
}
}
+ if (sp->sn_cul_hl > 0) {
+ msg_puts(" culhl=");
+ const char *const p = get_highlight_name_ext(NULL,
+ sp->sn_cul_hl - 1, false);
+ if (p == NULL) {
+ msg_puts("NONE");
+ } else {
+ msg_puts(p);
+ }
+ }
if (sp->sn_num_hl > 0) {
msg_puts(" numhl=");
const char *const p = get_highlight_name_ext(NULL,
@@ -1847,6 +1893,7 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict)
char *linehl = NULL;
char *text = NULL;
char *texthl = NULL;
+ char *culhl = NULL;
char *numhl = NULL;
int retval = -1;
@@ -1866,11 +1913,12 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict)
linehl = tv_dict_get_string(dict, "linehl", true);
text = tv_dict_get_string(dict, "text", true);
texthl = tv_dict_get_string(dict, "texthl", true);
+ culhl = tv_dict_get_string(dict, "culhl", true);
numhl = tv_dict_get_string(dict, "numhl", true);
}
if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl,
- (char_u *)text, (char_u *)texthl, numhl)
+ (char_u *)text, (char_u *)texthl, (char_u *)culhl, numhl)
== OK) {
retval = 0;
}
@@ -1881,6 +1929,7 @@ cleanup:
xfree(linehl);
xfree(text);
xfree(texthl);
+ xfree(culhl);
xfree(numhl);
return retval;
diff --git a/src/nvim/sign_defs.h b/src/nvim/sign_defs.h
index 46436b2c8e..c734502878 100644
--- a/src/nvim/sign_defs.h
+++ b/src/nvim/sign_defs.h
@@ -38,6 +38,7 @@ typedef struct sign_attrs_S {
char_u *sat_text;
int sat_texthl;
int sat_linehl;
+ int sat_culhl;
int sat_numhl;
} sign_attrs_T;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 20081bce4f..bd31e98faa 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -94,12 +94,12 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
+#include "nvim/input.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/normal.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
@@ -622,7 +622,7 @@ static void find_word(matchinf_T *mip, int mode)
// - there is a byte that doesn't match,
// - we reach the end of the tree,
// - or we reach the end of the line.
- for (;; ) {
+ for (;;) {
if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
}
@@ -689,7 +689,7 @@ static void find_word(matchinf_T *mip, int mode)
// One space in the good word may stand for several spaces in the
// checked word.
if (c == ' ') {
- for (;; ) {
+ for (;;) {
if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
}
@@ -1269,7 +1269,7 @@ static void find_prefix(matchinf_T *mip, int mode)
// - there is a byte that doesn't match,
// - we reach the end of the tree,
// - or we reach the end of the line.
- for (;; ) {
+ for (;;) {
if (flen == 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
}
@@ -2083,7 +2083,7 @@ char *did_set_spelllang(win_T *wp)
wp->w_s->b_cjk = 0;
// Loop over comma separated language names.
- for (splp = spl_copy; *splp != NUL; ) {
+ for (splp = spl_copy; *splp != NUL;) {
// Get one language name.
copy_option_part(&splp, lang, MAXWLEN, ",");
region = NULL;
@@ -2354,7 +2354,7 @@ static void use_midword(slang_T *lp, win_T *wp)
return;
}
- for (char_u *p = lp->sl_midword; *p != NUL; ) {
+ for (char_u *p = lp->sl_midword; *p != NUL;) {
const int c = utf_ptr2char(p);
const int l = utfc_ptr2len(p);
if (c < 256 && l <= 2) {
@@ -2759,7 +2759,7 @@ int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int bufle
int outi = 0;
// Fold one character at a time.
- for (char_u *p = str; p < str + len; ) {
+ for (char_u *p = str; p < str + len;) {
if (outi + MB_MAXBYTES > buflen) {
buf[outi] = NUL;
return FAIL;
@@ -2806,7 +2806,7 @@ int spell_check_sps(void)
sps_flags = 0;
sps_limit = 9999;
- for (p = p_sps; *p != NUL; ) {
+ for (p = p_sps; *p != NUL;) {
copy_option_part(&p, buf, MAXPATHL, ",");
f = 0;
@@ -3118,7 +3118,7 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
regmatch.regprog = curwin->w_s->b_cap_prog;
regmatch.rm_ic = FALSE;
p = line + endcol;
- for (;; ) {
+ for (;;) {
MB_PTR_BACK(line, p);
if (p == line || spell_iswordp_nmw(p, curwin)) {
break;
@@ -3330,7 +3330,7 @@ static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int ma
sps_copy = vim_strsave(p_sps);
// Loop over the items in 'spellsuggest'.
- for (p = sps_copy; *p != NUL; ) {
+ for (p = sps_copy; *p != NUL;) {
copy_option_part(&p, buf, MAXPATHL, ",");
if (STRNCMP(buf, "expr:", 5) == 0) {
@@ -3557,7 +3557,7 @@ void onecap_copy(char_u *word, char_u *wcopy, bool upper)
static void allcap_copy(char_u *word, char_u *wcopy)
{
char_u *d = wcopy;
- for (char_u *s = word; *s != NUL; ) {
+ for (char_u *s = word; *s != NUL;) {
int c = mb_cptr2char_adv((const char_u **)&s);
if (c == 0xdf) {
@@ -4352,8 +4352,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// just deleted this byte, accepting it is always cheaper than
// delete + substitute.
if (c == fword[sp->ts_fidx]
- || (sp->ts_tcharlen > 0 &&
- sp->ts_isdiff != DIFF_NONE)) {
+ || (sp->ts_tcharlen > 0
+ && sp->ts_isdiff != DIFF_NONE)) {
newscore = 0;
} else {
newscore = SCORE_SUBST;
@@ -4513,7 +4513,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// skip over NUL bytes
n = sp->ts_arridx;
- for (;; ) {
+ for (;;) {
if (sp->ts_curi > byts[n]) {
// Only NUL bytes at this node, go to next state.
PROF_STORE(sp->ts_state)
@@ -5257,7 +5257,7 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *
// space.
if (ascii_iswhite(su->su_badptr[su->su_badlen])
&& *skiptowhite(stp->st_word) == NUL) {
- for (p = fword; *(p = skiptowhite(p)) != NUL; ) {
+ for (p = fword; *(p = skiptowhite(p)) != NUL;) {
STRMOVE(p, p + 1);
}
}
@@ -5568,7 +5568,7 @@ static int soundfold_find(slang_T *slang, char_u *word)
byts = slang->sl_sbyts;
idxs = slang->sl_sidxs;
- for (;; ) {
+ for (;;) {
// First byte is the number of possible bytes.
len = byts[arridx++];
@@ -5701,7 +5701,7 @@ static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword,
// "thee the" is added next to changing the first "the" the "thee".
const char_u *pgood = goodword + STRLEN(goodword);
char_u *pbad = su->su_badptr + badlenarg;
- for (;; ) {
+ for (;;) {
goodlen = (int)(pgood - goodword);
badlen = (int)(pbad - su->su_badptr);
if (goodlen <= 0 || badlen <= 0) {
@@ -6004,7 +6004,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
// The sl_sal_first[] table contains the translation for chars up to
// 255, sl_sal the rest.
- for (char_u *s = inword; *s != NUL; ) {
+ for (char_u *s = inword; *s != NUL;) {
int c = mb_cptr2char_adv((const char_u **)&s);
if (utf_class(c) == 0) {
c = ' ';
@@ -6015,7 +6015,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
if (ip == NULL) { // empty list, can't match
c = NUL;
} else {
- for (;; ) { // find "c" in the list
+ for (;;) { // find "c" in the list
if (*ip == 0) { // not found
c = NUL;
break;
@@ -6069,7 +6069,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// Remove accents, if wanted. We actually remove all non-word characters.
// But keep white space.
wordlen = 0;
- for (const char_u *s = inword; *s != NUL; ) {
+ for (const char_u *s = inword; *s != NUL;) {
const char_u *t = s;
c = mb_cptr2char_adv(&s);
if (slang->sl_rem_accents) {
@@ -6591,12 +6591,12 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
// Get the characters from the multi-byte strings and put them in an
// int array for easy access.
badlen = 0;
- for (const char_u *p = badword; *p != NUL; ) {
+ for (const char_u *p = badword; *p != NUL;) {
wbadword[badlen++] = mb_cptr2char_adv(&p);
}
wbadword[badlen++] = 0;
goodlen = 0;
- for (const char_u *p = goodword; *p != NUL; ) {
+ for (const char_u *p = goodword; *p != NUL;) {
wgoodword[goodlen++] = mb_cptr2char_adv(&p);
}
wgoodword[goodlen++] = 0;
@@ -6690,12 +6690,12 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
// Get the characters from the multi-byte strings and put them in an
// int array for easy access.
bi = 0;
- for (const char_u *p = badword; *p != NUL; ) {
+ for (const char_u *p = badword; *p != NUL;) {
wbadword[bi++] = mb_cptr2char_adv(&p);
}
wbadword[bi++] = 0;
gi = 0;
- for (const char_u *p = goodword; *p != NUL; ) {
+ for (const char_u *p = goodword; *p != NUL;) {
wgoodword[gi++] = mb_cptr2char_adv(&p);
}
wgoodword[gi++] = 0;
@@ -6713,9 +6713,9 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
score = 0;
minscore = limit + 1;
- for (;; ) {
+ for (;;) {
// Skip over an equal part, score remains the same.
- for (;; ) {
+ for (;;) {
bc = wbadword[bi];
gc = wgoodword[gi];
@@ -7289,7 +7289,7 @@ int spell_word_start(int startcol)
// Find a word character before "startcol".
line = get_cursor_line_ptr();
- for (p = line + startcol; p > line; ) {
+ for (p = line + startcol; p > line;) {
MB_PTR_BACK(line, p);
if (spell_iswordp_nmw(p, curwin)) {
break;
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 0fc9012f27..42bb3c61a5 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -237,8 +237,8 @@
#include "nvim/fileio.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/regexp.h"
@@ -549,7 +549,7 @@ static inline int spell_check_magic_string(FILE *const fd)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
char buf[VIMSPELLMAGICL];
- SPELL_READ_BYTES(buf, VIMSPELLMAGICL, fd, ; );
+ SPELL_READ_BYTES(buf, VIMSPELLMAGICL, fd,; );
if (memcmp(buf, VIMSPELLMAGIC, VIMSPELLMAGICL) != 0) {
return SP_FORMERROR;
}
@@ -640,7 +640,7 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile
// <SECTIONS>: <section> ... <sectionend>
// <section>: <sectionID> <sectionflags> <sectionlen> (section contents)
- for (;; ) {
+ for (;;) {
n = getc(fd); // <sectionID> or <sectionend>
if (n == SN_END) {
break;
@@ -960,7 +960,7 @@ someerror:
ga_init(&ga, 1, 100);
for (wordnr = 0; wordnr < wcount; ++wordnr) {
ga.ga_len = 0;
- for (;; ) {
+ for (;;) {
c = getc(fd); // <sugline>
if (c < 0) {
goto someerror;
@@ -1030,7 +1030,7 @@ static int read_region_section(FILE *fd, slang_T *lp, int len)
if (len > MAXREGIONS * 2) {
return SP_FORMERROR;
}
- SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd, ; );
+ SPELL_READ_NONNUL_BYTES((char *)lp->sl_regions, (size_t)len, fd,; );
lp->sl_regions[len] = NUL;
return 0;
}
@@ -1097,7 +1097,7 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
if (n > 0) {
char buf[MAXWLEN + 1];
buf[0] = '^'; // always match at one position only
- SPELL_READ_NONNUL_BYTES(buf + 1, (size_t)n, fd, ; );
+ SPELL_READ_NONNUL_BYTES(buf + 1, (size_t)n, fd,; );
buf[n + 1] = NUL;
lp->sl_prefprog[i] = vim_regcomp((char_u *)buf, RE_MAGIC | RE_STRING);
}
@@ -1548,7 +1548,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// First count the number of items for each list. Temporarily use
// sl_sal_first[] for this.
- for (p = from, s = to; *p != NUL && *s != NUL; ) {
+ for (p = from, s = to; *p != NUL && *s != NUL;) {
const int c = mb_cptr2char_adv((const char_u **)&p);
MB_CPTR_ADV(s);
if (c >= 256) {
@@ -1571,7 +1571,7 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// Put the characters up to 255 in sl_sal_first[] the rest in a sl_sal
// list.
memset(lp->sl_sal_first, 0, sizeof(salfirst_T) * 256);
- for (p = from, s = to; *p != NUL && *s != NUL; ) {
+ for (p = from, s = to; *p != NUL && *s != NUL;) {
const int c = mb_cptr2char_adv((const char_u **)&p);
const int i = mb_cptr2char_adv((const char_u **)&s);
if (c >= 256) {
@@ -1647,7 +1647,7 @@ static int *mb_str2wide(char_u *s)
int i = 0;
int *res = xmalloc((mb_charlen(s) + 1) * sizeof(int));
- for (char_u *p = s; *p != NUL; ) {
+ for (char_u *p = s; *p != NUL;) {
res[i++] = mb_ptr2char_adv((const char_u **)&p);
}
res[i] = NUL;
@@ -2095,7 +2095,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// Split the line up in white separated items. Put a NUL after each
// item.
itemcnt = 0;
- for (p = line;; ) {
+ for (p = line;;) {
while (*p != NUL && *p <= ' ') { // skip white space and CR/NL
++p;
}
@@ -2646,7 +2646,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
int c;
// Check that every character appears only once.
- for (p = items[1]; *p != NUL; ) {
+ for (p = items[1]; *p != NUL;) {
c = mb_ptr2char_adv((const char_u **)&p);
if ((!GA_EMPTY(&spin->si_map)
&& vim_strchr(spin->si_map.ga_data, c)
@@ -2804,7 +2804,7 @@ static void aff_process_flags(afffile_T *affile, affentry_T *entry)
if (entry->ae_flags != NULL
&& (affile->af_compforbid != 0 || affile->af_comppermit != 0)) {
- for (p = entry->ae_flags; *p != NUL; ) {
+ for (p = entry->ae_flags; *p != NUL;) {
prevp = p;
flag = get_affitem(affile->af_flagtype, &p);
if (flag == affile->af_comppermit || flag == affile->af_compforbid) {
@@ -2922,7 +2922,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
spin->si_compflags = p;
tp = p + STRLEN(p);
- for (p = compflags; *p != NUL; ) {
+ for (p = compflags; *p != NUL;) {
if (vim_strchr((char_u *)"/?*+[]", *p) != NULL) {
// Copy non-flag characters directly.
*tp++ = *p++;
@@ -2985,7 +2985,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
case AFT_CAPLONG:
case AFT_LONG:
- for (p = afflist; *p != NUL; ) {
+ for (p = afflist; *p != NUL;) {
n = mb_ptr2char_adv((const char_u **)&p);
if ((flagtype == AFT_LONG || (n >= 'A' && n <= 'Z'))
&& *p != NUL) {
@@ -2998,7 +2998,7 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
break;
case AFT_NUM:
- for (p = afflist; *p != NUL; ) {
+ for (p = afflist; *p != NUL;) {
int digits = getdigits_int(&p, true, 0);
assert(digits >= 0);
n = (unsigned int)digits;
@@ -3248,9 +3248,9 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
// Extract flags from the affix list.
flags |= get_affix_flags(affile, afflist);
- if (affile->af_needaffix != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist,
- affile->af_needaffix)) {
+ if (affile->af_needaffix != 0
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needaffix)) {
need_affix = true;
}
@@ -3311,32 +3311,32 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist)
{
int flags = 0;
- if (affile->af_keepcase != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist,
- affile->af_keepcase)) {
+ if (affile->af_keepcase != 0
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_keepcase)) {
flags |= WF_KEEPCAP | WF_FIXCAP;
}
- if (affile->af_rare != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) {
+ if (affile->af_rare != 0
+ && flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) {
flags |= WF_RARE;
}
- if (affile->af_bad != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) {
+ if (affile->af_bad != 0
+ && flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) {
flags |= WF_BANNED;
}
- if (affile->af_needcomp != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist,
- affile->af_needcomp)) {
+ if (affile->af_needcomp != 0
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needcomp)) {
flags |= WF_NEEDCOMP;
}
- if (affile->af_comproot != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist,
- affile->af_comproot)) {
+ if (affile->af_comproot != 0
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_comproot)) {
flags |= WF_COMPROOT;
}
- if (affile->af_nosuggest != 0 &&
- flag_in_afflist(affile->af_flagtype, afflist,
- affile->af_nosuggest)) {
+ if (affile->af_nosuggest != 0
+ && flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_nosuggest)) {
flags |= WF_NOSUGGEST;
}
return flags;
@@ -3355,7 +3355,7 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
char_u key[AH_KEY_LEN];
hashitem_T *hi;
- for (p = afflist; *p != NUL; ) {
+ for (p = afflist; *p != NUL;) {
prevp = p;
if (get_affitem(affile->af_flagtype, &p) != 0) {
// A flag is a postponed prefix flag if it appears in "af_pref"
@@ -3389,7 +3389,7 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl
char_u key[AH_KEY_LEN];
hashitem_T *hi;
- for (p = afflist; *p != NUL; ) {
+ for (p = afflist; *p != NUL;) {
prevp = p;
if (get_affitem(affile->af_flagtype, &p) != 0) {
// A flag is a compound flag if it appears in "af_comp".
@@ -4446,10 +4446,10 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
putc(SN_PREFCOND, fd); // <sectionID>
putc(SNF_REQUIRED, fd); // <sectionflags>
- size_t l = (size_t)write_spell_prefcond(NULL, &spin->si_prefcond);
+ size_t l = (size_t)write_spell_prefcond(NULL, &spin->si_prefcond, &fwv);
put_bytes(fd, l, 4); // <sectionlen>
- write_spell_prefcond(fd, &spin->si_prefcond);
+ write_spell_prefcond(fd, &spin->si_prefcond, &fwv);
}
// SN_REP: <repcount> <rep> ...
@@ -5793,7 +5793,7 @@ static int set_spell_finish(spelltab_T *new_st)
// Write the table with prefix conditions to the .spl file.
// When "fd" is NULL only count the length of what is written.
-static int write_spell_prefcond(FILE *fd, garray_T *gap)
+static int write_spell_prefcond(FILE *fd, garray_T *gap, size_t *fwv)
{
assert(gap->ga_len >= 0);
@@ -5801,8 +5801,7 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
put_bytes(fd, (uintmax_t)gap->ga_len, 2); // <prefcondcnt>
}
size_t totlen = 2 + (size_t)gap->ga_len; // <prefcondcnt> and <condlen> bytes
- size_t x = 1; // collect return value of fwrite()
- for (int i = 0; i < gap->ga_len; ++i) {
+ for (int i = 0; i < gap->ga_len; i++) {
// <prefcond> : <condlen> <condstr>
char_u *p = ((char_u **)gap->ga_data)[i];
if (p != NULL) {
@@ -5810,7 +5809,7 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
if (fd != NULL) {
assert(len <= INT_MAX);
fputc((int)len, fd);
- x &= fwrite(p, len, 1, fd);
+ *fwv &= fwrite(p, len, 1, fd);
}
totlen += len;
} else if (fd != NULL) {
@@ -5845,7 +5844,7 @@ static void set_map_str(slang_T *lp, char_u *map)
// The similar characters are stored separated with slashes:
// "aaa/bbb/ccc/". Fill sl_map_array[c] with the character before c and
// before the same slash. For characters above 255 sl_map_hash is used.
- for (p = map; *p != NUL; ) {
+ for (p = map; *p != NUL;) {
c = mb_cptr2char_adv((const char_u **)&p);
if (c == '/') {
headc = 0;
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 4eb0073873..68bc76660d 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -4,7 +4,9 @@
#include <assert.h>
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
#include "nvim/edit.h"
+#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/getchar.h"
#include "nvim/lib/kvec.h"
@@ -136,7 +138,7 @@ int get_real_state(void)
/// @returns[allocated] mode string
char *get_mode(void)
{
- char *buf = xcalloc(4, sizeof(char));
+ char *buf = xcalloc(MODE_MAX_LENGTH, sizeof(char));
if (VIsual_active) {
if (VIsual_select) {
@@ -202,3 +204,33 @@ char *get_mode(void)
return buf;
}
+
+/// Fires a ModeChanged autocmd.
+void trigger_modechanged(void)
+{
+ if (!has_event(EVENT_MODECHANGED)) {
+ return;
+ }
+
+ char *mode = get_mode();
+ if (STRCMP(mode, last_mode) == 0) {
+ xfree(mode);
+ return;
+ }
+
+ save_v_event_T save_v_event;
+ dict_T *v_event = get_v_event(&save_v_event);
+ tv_dict_add_str(v_event, S_LEN("new_mode"), mode);
+ tv_dict_add_str(v_event, S_LEN("old_mode"), last_mode);
+
+ char_u *pat_pre = concat_str((char_u *)last_mode, (char_u *)":");
+ char_u *pat = concat_str(pat_pre, (char_u *)mode);
+ xfree(pat_pre);
+
+ apply_autocmds(EVENT_MODECHANGED, pat, NULL, false, curbuf);
+ xfree(last_mode);
+ last_mode = mode;
+
+ xfree(pat);
+ restore_v_event(v_event, &save_v_event);
+}
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 47cbf01996..e2a8108c45 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -31,7 +31,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
@@ -242,7 +241,7 @@ char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_n
#endif
*d++ = '\'';
- for (const char_u *p = string; *p != NUL; ) {
+ for (const char_u *p = string; *p != NUL;) {
#ifdef WIN32
if (!p_ssl) {
if (*p == '"') {
@@ -394,6 +393,18 @@ void del_trailing_spaces(char_u *ptr)
}
}
+#if !defined(HAVE_STRNLEN)
+size_t xstrnlen(const char *s, size_t n)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
+{
+ const char *end = memchr(s, '\0', n);
+ if (end == NULL) {
+ return n;
+ }
+ return end - s;
+}
+#endif
+
#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP))
/*
* Compare two strings, ignoring case, using current locale.
@@ -405,7 +416,7 @@ int vim_stricmp(const char *s1, const char *s2)
{
int i;
- for (;; ) {
+ for (;;) {
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
if (i != 0) {
return i; // this character different
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 504d1cd16e..a9447165c2 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -32,8 +32,8 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os_unix.h"
@@ -115,6 +115,8 @@ static int include_none = 0; // when 1 include "nvim/None"
static int include_default = 0; // when 1 include "nvim/default"
static int include_link = 0; // when 2 include "nvim/link" and "clear"
+#define MAX_SYN_NAME 200
+
/// The "term", "cterm" and "gui" arguments can be any combination of the
/// following names, separated by commas (but no spaces!).
static char *(hl_name_table[]) =
@@ -691,7 +693,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
* Restrict the search for the end of a comment to b_syn_sync_maxlines.
*/
if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL) {
- for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) {
+ for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) {
if (SYN_ITEMS(syn_block)[idx].sp_syn.id
== syn_block->b_syn_sync_id
&& SYN_ITEMS(syn_block)[idx].sp_type == SPTYPE_START) {
@@ -752,7 +754,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum) {
syn_start_line();
- for (;; ) {
+ for (;;) {
had_sync_point = syn_finish_line(true);
// When a sync point has been found, remember where, and
// continue to look for another one, further on in the line.
@@ -1146,7 +1148,7 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
linenr_T n;
prev = NULL;
- for (p = block->b_sst_first; p != NULL; ) {
+ for (p = block->b_sst_first; p != NULL;) {
if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top) {
n = p->sst_lnum + buf->b_mod_xlines;
if (n <= buf->b_mod_bot) {
@@ -1449,7 +1451,7 @@ static bool syn_stack_equal(synstate_T *sp)
}
int i;
- for (i = current_state.ga_len; --i >= 0; ) {
+ for (i = current_state.ga_len; --i >= 0;) {
// If the item has another index the state is different.
if (bp[i].bs_idx != CUR_STATE(i).si_idx) {
break;
@@ -1788,9 +1790,9 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
line = syn_getcurline();
const char_u *cur_pos = line + current_col;
if (vim_iswordp_buf(cur_pos, syn_buf)
- && (current_col == 0 ||
- !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1),
- syn_buf))) {
+ && (current_col == 0
+ || !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1),
+ syn_buf))) {
syn_id = check_keyword_id(line, (int)current_col, &endcol, &flags,
&next_list, cur_si, &cchar);
if (syn_id != 0) {
@@ -1852,7 +1854,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
*/
next_match_idx = 0; // no match in this line yet
next_match_col = MAXCOL;
- for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) {
+ for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0;) {
synpat_T *const spp = &(SYN_ITEMS(syn_block)[idx]);
if (spp->sp_syncing == syncing
&& (displaying || !(spp->sp_flags & HL_DISPLAY))
@@ -2207,7 +2209,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
/// @return true if we already matched pattern "idx" at the current column.
static bool did_match_already(int idx, garray_T *gap)
{
- for (int i = current_state.ga_len; --i >= 0; ) {
+ for (int i = current_state.ga_len; --i >= 0;) {
if (CUR_STATE(i).si_m_startcol == (int)current_col
&& CUR_STATE(i).si_m_lnum == (int)current_lnum
&& CUR_STATE(i).si_idx == idx) {
@@ -2217,7 +2219,7 @@ static bool did_match_already(int idx, garray_T *gap)
// Zero-width matches with a nextgroup argument are not put on the syntax
// stack, and can only be matched once anyway.
- for (int i = gap->ga_len; --i >= 0; ) {
+ for (int i = gap->ga_len; --i >= 0;) {
if (((int *)(gap->ga_data))[i] == idx) {
return true;
}
@@ -2318,7 +2320,7 @@ static void check_state_ends(void)
int had_extend;
cur_si = &CUR_STATE(current_state.ga_len - 1);
- for (;; ) {
+ for (;;) {
if (cur_si->si_ends
&& (cur_si->si_m_endpos.lnum < current_lnum
|| (cur_si->si_m_endpos.lnum == current_lnum
@@ -2658,7 +2660,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_
/*
* Find the SKIP or first END pattern after the last START pattern.
*/
- for (;; ) {
+ for (;;) {
spp = &(SYN_ITEMS(syn_block)[idx]);
if (spp->sp_type != SPTYPE_START) {
break;
@@ -2687,7 +2689,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_
// use syntax iskeyword option
save_chartab(buf_chartab);
- for (;; ) {
+ for (;;) {
/*
* Find end pattern that matches first after "matchcol".
*/
@@ -3286,13 +3288,13 @@ void syntax_clear(synblock_T *block)
clear_keywtab(&block->b_keywtab_ic);
// free the syntax patterns
- for (int i = block->b_syn_patterns.ga_len; --i >= 0; ) {
+ for (int i = block->b_syn_patterns.ga_len; --i >= 0;) {
syn_clear_pattern(block, i);
}
ga_clear(&block->b_syn_patterns);
// free the syntax clusters
- for (int i = block->b_syn_clusters.ga_len; --i >= 0; ) {
+ for (int i = block->b_syn_clusters.ga_len; --i >= 0;) {
syn_clear_cluster(block, i);
}
ga_clear(&block->b_syn_clusters);
@@ -3336,7 +3338,7 @@ void reset_synblock(win_T *wp)
static void syntax_sync_clear(void)
{
// free the syntax patterns
- for (int i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) {
+ for (int i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0;) {
if (SYN_ITEMS(curwin->w_s)[i].sp_syncing) {
syn_remove_pattern(curwin->w_s, i);
}
@@ -3484,7 +3486,7 @@ static void syn_clear_one(const int id, const bool syncing)
}
// clear the patterns for "id"
- for (int idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0; ) {
+ for (int idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0;) {
spp = &(SYN_ITEMS(curwin->w_s)[idx]);
if (spp->sp_syn.id != id || spp->sp_syncing != syncing) {
continue;
@@ -3874,7 +3876,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const
msg_putchar(c);
// output the pattern, in between a char that is not in the pattern
- for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; ) {
+ for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL;) {
if (sepchars[++i] == NUL) {
i = 0; // no good char found, just use the first one
break;
@@ -4015,7 +4017,7 @@ static void syn_clear_keyword(int id, hashtab_T *ht)
}
--todo;
kp_prev = NULL;
- for (kp = HI2KE(hi); kp != NULL; ) {
+ for (kp = HI2KE(hi); kp != NULL;) {
if (kp->k_syn.id == id) {
kp_next = kp->ke_next;
if (kp_prev == NULL) {
@@ -4191,7 +4193,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha
opt->flags |= HL_CONCEAL;
}
- for (;; ) {
+ for (;;) {
/*
* This is used very often when a large number of keywords is defined.
* Need to skip quickly when no option name is found.
@@ -4201,7 +4203,7 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha
break;
}
- for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0; ) {
+ for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0;) {
p = flagtab[fidx].name;
int i;
for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) {
@@ -4271,9 +4273,9 @@ static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_cha
if (STRCMP(gname, "NONE") == 0) {
*opt->sync_idx = NONE_IDX;
} else {
- syn_id = syn_name2id(gname);
+ syn_id = syn_name2id((char *)gname);
int i;
- for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) {
+ for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0;) {
if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id
&& SYN_ITEMS(curwin->w_s)[i].sp_type == SPTYPE_START) {
*opt->sync_idx = i;
@@ -4460,7 +4462,7 @@ static void syn_cmd_keyword(exarg_T *eap, int syncing)
// 2: Add an entry for each keyword.
for (kw = keyword_copy; --cnt >= 0; kw += STRLEN(kw) + 1) {
- for (p = vim_strchr(kw, '[');; ) {
+ for (p = vim_strchr(kw, '[');;) {
if (p != NULL) {
*p = NUL;
}
@@ -4972,7 +4974,7 @@ static int syn_scl_name2id(char_u *name)
// Avoid using stricmp() too much, it's slow on some systems
char_u *name_u = vim_strsave_up(name);
int i;
- for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0; ) {
+ for (i = curwin->w_s->b_syn_clusters.ga_len; --i >= 0;) {
if (SYN_CLSTR(curwin->w_s)[i].scl_name_u != NULL
&& STRCMP(name_u, SYN_CLSTR(curwin->w_s)[i].scl_name_u) == 0) {
break;
@@ -5078,7 +5080,7 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing)
}
scl_id -= SYNID_CLUSTER;
- for (;; ) {
+ for (;;) {
if (STRNICMP(rest, "add", 3) == 0
&& (ascii_iswhite(rest[3]) || rest[3] == '=')) {
opt_len = 3;
@@ -5174,7 +5176,7 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
*/
++end;
do {
- for (idx = SPO_COUNT; --idx >= 0; ) {
+ for (idx = SPO_COUNT; --idx >= 0;) {
if (STRNCMP(end, spo_name_tab[idx], 3) == 0) {
break;
}
@@ -5264,7 +5266,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
}
next_arg = skipwhite(arg_end);
} else if (!eap->skip) {
- curwin->w_s->b_syn_sync_id = syn_name2id((char_u *)"Comment");
+ curwin->w_s->b_syn_sync_id = syn_name2id("Comment");
}
} else if (STRNCMP(key, "LINES", 5) == 0
|| STRNCMP(key, "MINLINES", 8) == 0
@@ -5401,7 +5403,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
do {
for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) {
}
- char_u *const name = xmalloc((int)(end - p + 3)); // leave room for "^$"
+ char_u *const name = xmalloc(end - p + 3); // leave room for "^$"
STRLCPY(name + 1, p, end - p + 1);
if (STRCMP(name + 1, "ALLBUT") == 0
|| STRCMP(name + 1, "ALL") == 0
@@ -5456,7 +5458,7 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
regmatch.rm_ic = TRUE;
id = 0;
- for (int i = highlight_ga.ga_len; --i >= 0; ) {
+ for (int i = highlight_ga.ga_len; --i >= 0;) {
if (vim_regexec(&regmatch, HL_TABLE()[i].sg_name, (colnr_T)0)) {
if (round == 2) {
// Got more items than expected; can happen
@@ -6175,6 +6177,8 @@ static const char *highlight_init_both[] = {
"default link LineNrAbove LineNr",
"default link LineNrBelow LineNr",
"default link QuickFixLine Search",
+ "default link CursorLineSign SignColumn",
+ "default link CursorLineFold FoldColumn",
"default link Substitute Search",
"default link Whitespace NonText",
"default link MsgSeparator StatusLine",
@@ -6520,7 +6524,7 @@ const char *const highlight_init_cmdline[] = {
/// Create default links for Nvim* highlight groups used for cmdline coloring
void syn_init_cmdline_highlight(bool reset, bool init)
{
- for (size_t i = 0 ; highlight_init_cmdline[i] != NULL ; i++) {
+ for (size_t i = 0; highlight_init_cmdline[i] != NULL; i++) {
do_highlight(highlight_init_cmdline[i], reset, init);
}
}
@@ -6968,7 +6972,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
attr = 0;
off = 0;
while (arg[off] != NUL) {
- for (i = ARRAY_SIZE(hl_attr_table); --i >= 0; ) {
+ for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) {
len = (int)STRLEN(hl_name_table[i]);
if (STRNICMP(arg + off, hl_name_table[i], len) == 0) {
attr |= hl_attr_table[i];
@@ -7040,7 +7044,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} else {
// Reduce calls to STRICMP a bit, it can be slow.
off = TOUPPER_ASC(*arg);
- for (i = ARRAY_SIZE(color_names); --i >= 0; ) {
+ for (i = ARRAY_SIZE(color_names); --i >= 0;) {
if (off == color_names[i][0]
&& STRICMP(arg + 1, color_names[i] + 1) == 0) {
break;
@@ -7403,9 +7407,9 @@ static bool highlight_list_arg(const int id, bool didh, const int type, int iarg
for (int i = 0; hl_attr_table[i] != 0; i++) {
if (iarg & hl_attr_table[i]) {
if (buf[0] != NUL) {
- xstrlcat((char *)buf, ",", 100);
+ xstrlcat(buf, ",", 100);
}
- xstrlcat((char *)buf, hl_name_table[i], 100);
+ xstrlcat(buf, hl_name_table[i], 100);
iarg &= ~hl_attr_table[i]; // don't want "inverse"
}
}
@@ -7536,6 +7540,7 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i
{
int endcol = 19;
bool newline = true;
+ int name_col = 0;
bool adjust = true;
if (!did_header) {
@@ -7544,6 +7549,7 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i
return true;
}
msg_outtrans(HL_TABLE()[id - 1].sg_name);
+ name_col = msg_col;
endcol = 15;
} else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
msg_putchar(' ');
@@ -7570,6 +7576,9 @@ static bool syn_list_header(const bool did_header, const int outlen, const int i
// Show "xxx" with the attributes.
if (!did_header) {
+ if (endcol == Columns - 1 && endcol <= name_col) {
+ msg_putchar(' ');
+ }
msg_puts_attr("xxx", syn_id2attr(id));
msg_putchar(' ');
}
@@ -7605,10 +7614,10 @@ static void set_hl_attr(int idx)
}
}
-int syn_name2id(const char_u *name)
+int syn_name2id(const char *name)
FUNC_ATTR_NONNULL_ALL
{
- return syn_name2id_len(name, STRLEN(name));
+ return syn_name2id_len((char_u *)name, STRLEN(name));
}
/// Lookup a highlight group name and return its ID.
@@ -7618,10 +7627,9 @@ int syn_name2id(const char_u *name)
int syn_name2id_len(const char_u *name, size_t len)
FUNC_ATTR_NONNULL_ALL
{
- char name_u[201];
+ char name_u[MAX_SYN_NAME + 1];
- if (len == 0 || len > 200) {
- // ID names over 200 chars don't deserve to be found!
+ if (len == 0 || len > MAX_SYN_NAME) {
return 0;
}
@@ -7641,7 +7649,7 @@ int syn_name2id_len(const char_u *name, size_t len)
int syn_name2attr(const char_u *name)
FUNC_ATTR_NONNULL_ALL
{
- int id = syn_name2id(name);
+ int id = syn_name2id((char *)name);
if (id != 0) {
return syn_id2attr(id);
@@ -7652,7 +7660,7 @@ int syn_name2attr(const char_u *name)
/*
* Return TRUE if highlight group "name" exists.
*/
-int highlight_exists(const char_u *name)
+int highlight_exists(const char *name)
{
return syn_name2id(name) > 0;
}
@@ -7679,6 +7687,10 @@ char_u *syn_id2name(int id)
/// @return 0 for failure else the id of the group
int syn_check_group(const char *name, int len)
{
+ if (len > MAX_SYN_NAME) {
+ emsg(_(e_highlight_group_name_too_long));
+ return 0;
+ }
int id = syn_name2id_len((char_u *)name, len);
if (id == 0) { // doesn't exist yet
return syn_add_group(vim_strnsave((char_u *)name, len));
@@ -7784,7 +7796,7 @@ int syn_get_final_id(int hl_id)
* Follow links until there is no more.
* Look out for loops! Break after 100 links.
*/
- for (count = 100; --count >= 0; ) {
+ for (count = 100; --count >= 0;) {
struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
// ACHTUNG: when using "tmp" attribute (no link) the function might be
@@ -7870,7 +7882,7 @@ static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int
void highlight_changed(void)
{
int id;
- char_u userhl[30]; // use 30 to avoid compiler warning
+ char userhl[30]; // use 30 to avoid compiler warning
int id_S = -1;
int id_SNC = 0;
int hlcnt;
@@ -7919,7 +7931,7 @@ void highlight_changed(void)
id_S = hlcnt + 10;
}
for (int i = 0; i < 9; i++) {
- sprintf((char *)userhl, "User%d", i + 1);
+ snprintf(userhl, sizeof(userhl), "User%d", i + 1);
id = syn_name2id(userhl);
if (id == 0) {
highlight_user[i] = 0;
@@ -7983,10 +7995,10 @@ static void highlight_list(void)
{
int i;
- for (i = 10; --i >= 0; ) {
+ for (i = 10; --i >= 0;) {
highlight_list_two(i, HL_ATTR(HLF_D));
}
- for (i = 40; --i >= 0; ) {
+ for (i = 40; --i >= 0;) {
highlight_list_two(99, 0);
}
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 673ebc2668..a10a2a0c32 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -25,11 +25,11 @@
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/if_cscope.h"
+#include "nvim/input.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os/input.h"
@@ -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;
@@ -431,7 +431,7 @@ int do_tag(char_u *tag, int type, int count, int forceit, int verbose)
/*
* Repeat searching for tags, when a file has not been found.
*/
- for (;; ) {
+ for (;;) {
int other_name;
char_u *name;
@@ -1638,7 +1638,7 @@ int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int
/*
* Read and parse the lines in the file one by one
*/
- for (;; ) {
+ for (;;) {
// check for CTRL-C typed, more often when jumping around
if (state == TS_BINARY || state == TS_SKIP_BACK) {
line_breakcheck();
@@ -2403,7 +2403,7 @@ int get_tagfname(tagname_T *tnp, int first, char_u *buf)
* tnp->tn_did_filefind_init == FALSE: setup for next part in 'tags'.
* tnp->tn_did_filefind_init == TRUE: find next file in this part.
*/
- for (;; ) {
+ for (;;) {
if (tnp->tn_did_filefind_init) {
fname = vim_findfile(tnp->tn_search_ctx);
if (fname != NULL) {
@@ -2687,7 +2687,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
// copy the command to pbuf[], remove trailing CR/NL
str = tagp.command;
- for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) {
+ for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r';) {
*pbuf_end++ = *str++;
if (pbuf_end - pbuf + 1 >= LSIZE) {
break;
@@ -3056,7 +3056,7 @@ static int find_extra(char_u **pp)
char_u first_char = **pp;
// Repeat for addresses separated with ';'
- for (;; ) {
+ for (;;) {
if (ascii_isdigit(*str)) {
str = skipdigits(str + 1);
} else if (*str == '/' || *str == '?') {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 9002ac4967..d97c24dcf7 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"
@@ -63,7 +64,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/option.h"
@@ -324,10 +324,11 @@ void terminal_close(Terminal *term, int status)
}
if (buf && !is_autocmd_blocked()) {
- dict_T *dict = get_vim_var_dict(VV_EVENT);
+ save_v_event_T save_v_event;
+ dict_T *dict = get_v_event(&save_v_event);
tv_dict_add_nr(dict, S_LEN("status"), status);
apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
- tv_dict_clear(dict);
+ restore_v_event(dict, &save_v_event);
}
}
@@ -393,7 +394,7 @@ void terminal_enter(void)
long save_w_p_so = curwin->w_p_so;
long save_w_p_siso = curwin->w_p_siso;
if (curwin->w_p_cul && curwin->w_p_culopt_flags & CULOPT_NBR) {
- if (strcmp((char *)curwin->w_p_culopt, "number")) {
+ if (STRCMP(curwin->w_p_culopt, "number")) {
save_w_p_culopt = curwin->w_p_culopt;
curwin->w_p_culopt = (char_u *)xstrdup("number");
}
@@ -412,6 +413,7 @@ void terminal_enter(void)
curwin->w_redr_status = true; // For mode() in statusline. #8323
ui_busy_start();
apply_autocmds(EVENT_TERMENTER, NULL, NULL, false, curbuf);
+ trigger_modechanged();
s->state.execute = terminal_execute;
s->state.check = terminal_check;
@@ -462,9 +464,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.
@@ -1466,6 +1466,17 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
int width, height;
vterm_get_size(term->vt, &height, &width);
+ // May still have pending scrollback after increase in terminal height if the
+ // scrollback wasn't refreshed in time; append these to the top of the buffer.
+ int row_offset = term->sb_pending;
+ while (term->sb_pending > 0 && buf->b_ml.ml_line_count < height) {
+ fetch_row(term, term->sb_pending - row_offset - 1, width);
+ ml_append(0, (uint8_t *)term->textbuf, 0, false);
+ appended_lines(0, 1);
+ term->sb_pending--;
+ }
+
+ row_offset -= term->sb_pending;
while (term->sb_pending > 0) {
// This means that either the window height has decreased or the screen
// became full and libvterm had to push all rows up. Convert the first
@@ -1476,7 +1487,7 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
ml_delete(1, false);
deleted_lines(1, 1);
}
- fetch_row(term, -term->sb_pending, width);
+ fetch_row(term, -term->sb_pending - row_offset, width);
int buf_index = (int)buf->b_ml.ml_line_count - height;
ml_append(buf_index, (uint8_t *)term->textbuf, 0, false);
appended_lines(buf_index, 1);
@@ -1506,6 +1517,13 @@ static void refresh_screen(Terminal *term, buf_T *buf)
// Terminal height may have decreased before `invalid_end` reflects it.
term->invalid_end = MIN(term->invalid_end, height);
+ // There are no invalid rows.
+ if (term->invalid_start >= term->invalid_end) {
+ term->invalid_start = INT_MAX;
+ term->invalid_end = -1;
+ return;
+ }
+
for (int r = term->invalid_start, linenr = row_to_linenr(term, r);
r < term->invalid_end; r++, linenr++) {
fetch_row(term, r, width);
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_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 8fd60d6a5a..164149476f 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -1,5 +1,9 @@
" Test argument list commands
+func Reset_arglist()
+ args a | %argd
+endfunc
+
func Test_argidx()
args a b c
last
@@ -26,6 +30,8 @@ func Test_argidx()
endfunc
func Test_argadd()
+ call Reset_arglist()
+
%argdelete
argadd a b c
call assert_equal(0, argidx())
@@ -115,8 +121,7 @@ endfunc
" Test for [count]argument and [count]argdelete commands
" Ported from the test_argument_count.in test script
func Test_argument()
- " Clean the argument list
- arga a | %argd
+ call Reset_arglist()
let save_hidden = &hidden
set hidden
@@ -244,8 +249,7 @@ endfunc
" Test for 0argadd and 0argedit
" Ported from the test_argument_0count.in test script
func Test_zero_argadd()
- " Clean the argument list
- arga a | %argd
+ call Reset_arglist()
arga a b c d
2argu
@@ -272,10 +276,6 @@ func Test_zero_argadd()
call assert_equal('file with spaces', expand('%'))
endfunc
-func Reset_arglist()
- args a | %argd
-endfunc
-
" Test for argc()
func Test_argc()
call Reset_arglist()
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 0b76828dd7..9ad727241e 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -26,4 +26,42 @@ func Test_set_filename()
call delete('samples/Xtest')
endfunc
+func Test_verbose_pwd()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ call test_autochdir()
+
+ edit global.txt
+ call assert_match('\[global\].*testdir$', execute('verbose pwd'))
+
+ call mkdir('Xautodir')
+ split Xautodir/local.txt
+ lcd Xautodir
+ call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+
+ set acd
+ wincmd w
+ call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
+ execute 'lcd' cwd
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
+ execute 'tcd' cwd
+ call assert_match('\[tabpage\].*testdir$', execute('verbose pwd'))
+ execute 'cd' cwd
+ call assert_match('\[global\].*testdir$', execute('verbose pwd'))
+ edit
+ call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+ set noacd
+ call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[global\].*testdir', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+
+ bwipe!
+ call chdir(cwd)
+ call delete('Xautodir', 'rf')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index c350a17236..4e1a24af61 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -33,7 +33,7 @@ if has('timers')
let g:triggered = 0
au CursorHoldI * let g:triggered += 1
set updatetime=20
- call timer_start(LoadAdjust(100), 'ExitInsertMode')
+ call timer_start(LoadAdjust(200), 'ExitInsertMode')
call feedkeys('a', 'x!')
call assert_equal(1, g:triggered)
unlet g:triggered
@@ -222,6 +222,7 @@ func Test_win_tab_autocmd()
augroup testing
au WinNew * call add(g:record, 'WinNew')
+ au WinClosed * call add(g:record, 'WinClosed')
au WinEnter * call add(g:record, 'WinEnter')
au WinLeave * call add(g:record, 'WinLeave')
au TabNew * call add(g:record, 'TabNew')
@@ -238,8 +239,8 @@ func Test_win_tab_autocmd()
call assert_equal([
\ 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
- \ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
- \ 'WinLeave', 'WinEnter'
+ \ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
+ \ 'WinLeave', 'WinClosed', 'WinEnter'
\ ], g:record)
let g:record = []
@@ -250,7 +251,7 @@ func Test_win_tab_autocmd()
call assert_equal([
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
- \ 'TabClosed'
+ \ 'WinClosed', 'TabClosed'
\ ], g:record)
augroup testing
@@ -259,6 +260,45 @@ func Test_win_tab_autocmd()
unlet g:record
endfunc
+func Test_WinClosed()
+ " Test that the pattern is matched against the closed window's ID, and both
+ " <amatch> and <afile> are set to it.
+ new
+ let winid = win_getid()
+ let g:matched = v:false
+ augroup test-WinClosed
+ autocmd!
+ execute 'autocmd WinClosed' winid 'let g:matched = v:true'
+ autocmd WinClosed * let g:amatch = str2nr(expand('<amatch>'))
+ autocmd WinClosed * let g:afile = str2nr(expand('<afile>'))
+ augroup END
+ close
+ call assert_true(g:matched)
+ call assert_equal(winid, g:amatch)
+ call assert_equal(winid, g:afile)
+
+ " Test that WinClosed is non-recursive.
+ new
+ new
+ call assert_equal(3, winnr('$'))
+ let g:triggered = 0
+ augroup test-WinClosed
+ autocmd!
+ autocmd WinClosed * let g:triggered += 1
+ autocmd WinClosed * 2 wincmd c
+ augroup END
+ close
+ call assert_equal(1, winnr('$'))
+ call assert_equal(1, g:triggered)
+
+ autocmd! test-WinClosed
+ augroup! test-WinClosed
+ unlet g:matched
+ unlet g:amatch
+ unlet g:afile
+ unlet g:triggered
+endfunc
+
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
@@ -486,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')
@@ -540,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
@@ -556,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])
+
+
+ " 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])
- " 18: Setting string option"
+ " 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)
@@ -1857,6 +2360,26 @@ func Test_autocmd_CmdWinEnter()
call delete(filename)
endfunc
+func Test_autocmd_was_using_freed_memory()
+ pedit xx
+ n x
+ augroup winenter
+ au WinEnter * if winnr('$') > 2 | quit | endif
+ augroup END
+ " Nvim needs large 'winwidth' and 'nowinfixwidth' to crash
+ set winwidth=99999 nowinfixwidth
+ split
+
+ augroup winenter
+ au! WinEnter
+ augroup END
+
+ set winwidth& winfixwidth&
+ bwipe xx
+ bwipe x
+ pclose
+endfunc
+
func Test_FileChangedShell_reload()
if !has('unix')
return
@@ -2085,6 +2608,19 @@ func Test_autocmd_closes_window()
au! BufWinLeave
endfunc
+func Test_autocmd_quit_psearch()
+ sn aa bb
+ augroup aucmd_win_test
+ au!
+ au BufEnter,BufLeave,BufNew,WinEnter,WinLeave,WinNew * if winnr('$') > 1 | q | endif
+ augroup END
+ ps /
+
+ augroup aucmd_win_test
+ au!
+ augroup END
+endfunc
+
func Test_autocmd_closing_cmdwin()
au BufWinLeave * nested q
call assert_fails("norm 7q?\n", 'E855:')
diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim
index 180524cd73..38978ef689 100644
--- a/src/nvim/testdir/test_blockedit.vim
+++ b/src/nvim/testdir/test_blockedit.vim
@@ -15,6 +15,58 @@ func Test_blockinsert_indent()
bwipe!
endfunc
+func Test_blockinsert_autoindent()
+ new
+ let lines =<< trim END
+ var d = {
+ a: () => 0,
+ b: () => 0,
+ c: () => 0,
+ }
+ END
+ call setline(1, lines)
+ filetype plugin indent on
+ setlocal sw=2 et ft=vim
+ setlocal indentkeys+=:
+ exe "norm! 2Gf)\<c-v>2jA: asdf\<esc>"
+ let expected =<< trim END
+ var d = {
+ a: (): asdf => 0,
+ b: (): asdf => 0,
+ c: (): asdf => 0,
+ }
+ END
+ call assert_equal(expected, getline(1, 5))
+
+ " insert on the next column should do exactly the same
+ :%dele
+ call setline(1, lines)
+ exe "norm! 2Gf)l\<c-v>2jI: asdf\<esc>"
+ call assert_equal(expected, getline(1, 5))
+
+ :%dele
+ call setline(1, lines)
+ setlocal sw=8 noet
+ exe "norm! 2Gf)\<c-v>2jA: asdf\<esc>"
+ let expected =<< trim END
+ var d = {
+ a: (): asdf => 0,
+ b: (): asdf => 0,
+ c: (): asdf => 0,
+ }
+ END
+ call assert_equal(expected, getline(1, 5))
+
+ " insert on the next column should do exactly the same
+ :%dele
+ call setline(1, lines)
+ exe "norm! 2Gf)l\<c-v>2jI: asdf\<esc>"
+ call assert_equal(expected, getline(1, 5))
+
+ filetype off
+ bwipe!
+endfunc
+
func Test_blockinsert_delete()
new
let _bs = &bs
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 bb672cf0ec..a6eb93b4be 100644
--- a/src/nvim/testdir/test_bufwintabinfo.vim
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -1,108 +1,113 @@
" Tests for the getbufinfo(), getwininfo() and gettabinfo() functions
function Test_getbufwintabinfo()
- edit Xtestfile1
- edit Xtestfile2
- let buflist = getbufinfo()
- call assert_equal(2, len(buflist))
- call assert_match('Xtestfile1', buflist[0].name)
- call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name)
- call assert_equal([], getbufinfo(2016))
- edit Xtestfile1
- hide edit Xtestfile2
- hide enew
- call assert_equal(3, len(getbufinfo({'bufloaded':1})))
-
- set tabstop&vim
- let b:editor = 'vim'
+ edit Xtestfile1
+ edit Xtestfile2
+ let buflist = getbufinfo()
+ call assert_equal(2, len(buflist))
+ call assert_match('Xtestfile1', buflist[0].name)
+ call assert_match('Xtestfile2', getbufinfo('Xtestfile2')[0].name)
+ call assert_equal([], getbufinfo(2016))
+ edit Xtestfile1
+ hide edit Xtestfile2
+ hide enew
+ call assert_equal(3, len(getbufinfo({'bufloaded':1})))
+
+ set tabstop&vim
+ let b:editor = 'vim'
+ let l = getbufinfo('%')
+ call assert_equal(bufnr('%'), l[0].bufnr)
+ 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"])
+ let l = getbufinfo({'bufmodified' : 1})
+ call assert_equal(1, len(l))
+ call assert_equal(bufnr('Xtestfile1'), l[0].bufnr)
+
+ if has('signs')
+ call append(0, ['Linux', 'Windows', 'Mac'])
+ sign define Mark text=>> texthl=Search
+ exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%')
let l = getbufinfo('%')
- call assert_equal(bufnr('%'), l[0].bufnr)
- call assert_equal('vim', l[0].variables.editor)
- call assert_notequal(-1, index(l[0].windows, '%'->bufwinid()))
-
- " Test for getbufinfo() with 'bufmodified'
- call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
- call setbufline('Xtestfile1', 1, ["Line1"])
- let l = getbufinfo({'bufmodified' : 1})
- call assert_equal(1, len(l))
- call assert_equal(bufnr('Xtestfile1'), l[0].bufnr)
-
- if has('signs')
- call append(0, ['Linux', 'Windows', 'Mac'])
- sign define Mark text=>> texthl=Search
- exe "sign place 2 line=3 name=Mark buffer=" . bufnr('%')
- let l = getbufinfo('%')
- call assert_equal(2, l[0].signs[0].id)
- call assert_equal(3, l[0].signs[0].lnum)
- call assert_equal('Mark', l[0].signs[0].name)
- sign unplace *
- sign undefine Mark
- enew!
- endif
-
- only
- let w1_id = win_getid()
- new
- let w2_id = win_getid()
- tabnew | let w3_id = win_getid()
- new | let w4_id = win_getid()
- vert new | let w5_id = win_getid()
- call setwinvar(0, 'signal', 'green')
- tabfirst
- let winlist = getwininfo()
- call assert_equal(5, len(winlist))
- call assert_equal(winwidth(1), winlist[0].width)
- call assert_equal(1, winlist[0].wincol)
- " tabline adds one row in terminal, not in GUI
- let tablineheight = winlist[0].winrow == 2 ? 1 : 0
- call assert_equal(tablineheight + 1, winlist[0].winrow)
-
- call assert_equal(winbufnr(2), winlist[1].bufnr)
- call assert_equal(winheight(2), winlist[1].height)
- call assert_equal(1, winlist[1].wincol)
- call assert_equal(tablineheight + winheight(1) + 2, winlist[1].winrow)
-
- call assert_equal(1, winlist[2].winnr)
- call assert_equal(tablineheight + 1, winlist[2].winrow)
- call assert_equal(1, winlist[2].wincol)
-
- call assert_equal(winlist[2].width + 2, winlist[3].wincol)
- call assert_equal(1, winlist[4].wincol)
-
- call assert_equal(1, winlist[0].tabnr)
- call assert_equal(1, winlist[1].tabnr)
- call assert_equal(2, winlist[2].tabnr)
- call assert_equal(2, winlist[3].tabnr)
- call assert_equal(2, winlist[4].tabnr)
-
- call assert_equal('green', winlist[2].variables.signal)
- call assert_equal(w4_id, winlist[3].winid)
- let winfo = w5_id->getwininfo()[0]
- call assert_equal(2, winfo.tabnr)
- call assert_equal([], getwininfo(3))
-
- call settabvar(1, 'space', 'build')
- let tablist = gettabinfo()
- call assert_equal(2, len(tablist))
- call assert_equal(3, len(tablist[1].windows))
- call assert_equal(2, tablist[1].tabnr)
- call assert_equal('build', tablist[0].variables.space)
- call assert_equal(w2_id, tablist[0].windows[0])
- call assert_equal([], 3->gettabinfo())
-
- tabonly | only
-
- lexpr ''
- lopen
- copen
- let winlist = getwininfo()
- call assert_false(winlist[0].quickfix)
- call assert_false(winlist[0].loclist)
- call assert_true(winlist[1].quickfix)
- call assert_true(winlist[1].loclist)
- call assert_true(winlist[2].quickfix)
- call assert_false(winlist[2].loclist)
- wincmd t | only
+ call assert_equal(2, l[0].signs[0].id)
+ call assert_equal(3, l[0].signs[0].lnum)
+ call assert_equal('Mark', l[0].signs[0].name)
+ sign unplace *
+ sign undefine Mark
+ enew!
+ endif
+
+ only
+ let w1_id = win_getid()
+ setl foldcolumn=3
+ new
+ let w2_id = win_getid()
+ tabnew | let w3_id = win_getid()
+ new | let w4_id = win_getid()
+ vert new | let w5_id = win_getid()
+ eval 'green'->setwinvar(0, 'signal')
+ tabfirst
+ let winlist = getwininfo()
+ call assert_equal(5, len(winlist))
+ call assert_equal(winwidth(1), winlist[0].width)
+ call assert_equal(1, winlist[0].wincol)
+ " tabline adds one row in terminal, not in GUI
+ let tablineheight = winlist[0].winrow == 2 ? 1 : 0
+ call assert_equal(tablineheight + 1, winlist[0].winrow)
+
+ call assert_equal(winbufnr(2), winlist[1].bufnr)
+ call assert_equal(winheight(2), winlist[1].height)
+ call assert_equal(1, winlist[1].wincol)
+ call assert_equal(3, winlist[1].textoff) " foldcolumn
+ call assert_equal(tablineheight + winheight(1) + 2, winlist[1].winrow)
+
+ call assert_equal(1, winlist[2].winnr)
+ call assert_equal(tablineheight + 1, winlist[2].winrow)
+ call assert_equal(1, winlist[2].wincol)
+
+ call assert_equal(winlist[2].width + 2, winlist[3].wincol)
+ call assert_equal(1, winlist[4].wincol)
+
+ call assert_equal(1, winlist[0].tabnr)
+ call assert_equal(1, winlist[1].tabnr)
+ call assert_equal(2, winlist[2].tabnr)
+ call assert_equal(2, winlist[3].tabnr)
+ call assert_equal(2, winlist[4].tabnr)
+
+ call assert_equal('green', winlist[2].variables.signal)
+ call assert_equal(w4_id, winlist[3].winid)
+ let winfo = w5_id->getwininfo()[0]
+ call assert_equal(2, winfo.tabnr)
+ call assert_equal([], getwininfo(3))
+
+ call settabvar(1, 'space', 'build')
+ let tablist = gettabinfo()
+ call assert_equal(2, len(tablist))
+ call assert_equal(3, len(tablist[1].windows))
+ call assert_equal(2, tablist[1].tabnr)
+ call assert_equal('build', tablist[0].variables.space)
+ call assert_equal(w2_id, tablist[0].windows[0])
+ call assert_equal([], 3->gettabinfo())
+
+ tabonly | only
+
+ lexpr ''
+ lopen
+ copen
+ let winlist = getwininfo()
+ call assert_false(winlist[0].quickfix)
+ call assert_false(winlist[0].loclist)
+ call assert_true(winlist[1].quickfix)
+ call assert_true(winlist[1].loclist)
+ call assert_true(winlist[2].quickfix)
+ call assert_false(winlist[2].loclist)
+ wincmd t | only
endfunction
function Test_get_buf_options()
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index 0bba321ee2..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('..')
@@ -215,3 +215,42 @@ func Test_cd_from_non_existing_dir()
cd -
call assert_equal(saveddir, getcwd())
endfunc
+
+func Test_cd_unknown_dir()
+ call mkdir('Xa')
+ cd Xa
+ call writefile(['text'], 'Xb.txt')
+ edit Xa/Xb.txt
+ let first_buf = bufnr()
+ cd ..
+ edit
+ call assert_equal(first_buf, bufnr())
+ edit Xa/Xb.txt
+ call assert_notequal(first_buf, bufnr())
+
+ bwipe!
+ exe "bwipe! " .. first_buf
+ call delete('Xa', 'rf')
+endfunc
+
+func Test_getcwd_actual_dir()
+ CheckFunction test_autochdir
+ let startdir = getcwd()
+ call mkdir('Xactual')
+ call test_autochdir()
+ set autochdir
+ edit Xactual/file.txt
+ call assert_match('testdir.Xactual$', getcwd())
+ lcd ..
+ call assert_match('testdir$', getcwd())
+ edit
+ call assert_match('testdir.Xactual$', getcwd())
+ call assert_match('testdir$', getcwd(win_getid()))
+
+ set noautochdir
+ bwipe!
+ call chdir(startdir)
+ call delete('Xactual', 'rf')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
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 98340d0ac6..49a5386337 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -428,14 +428,17 @@ func Test_getcompletion()
call assert_equal([], l)
func T(a, c, p)
+ let g:cmdline_compl_params = [a:a, a:c, a:p]
return "oneA\noneB\noneC"
endfunc
command -nargs=1 -complete=custom,T MyCmd
let l = getcompletion('MyCmd ', 'cmdline')
call assert_equal(['oneA', 'oneB', 'oneC'], l)
+ call assert_equal(['', 'MyCmd ', 6], g:cmdline_compl_params)
delcommand MyCmd
delfunc T
+ unlet g:cmdline_compl_params
" For others test if the name is recognized.
let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
@@ -902,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_edit.vim b/src/nvim/testdir/test_edit.vim
index 23ad8dbfc5..fc4e80f0d6 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1294,6 +1294,7 @@ func Test_edit_forbidden()
call assert_fails(':Sandbox', 'E48:')
delcom Sandbox
call assert_equal(['a'], getline(1,'$'))
+
" 2) edit with textlock set
fu! DoIt()
call feedkeys("i\<del>\<esc>", 'tnix')
@@ -1313,6 +1314,7 @@ func Test_edit_forbidden()
catch /^Vim\%((\a\+)\)\=:E117/ " catch E117: unknown function
endtry
au! InsertCharPre
+
" 3) edit when completion is shown
fun! Complete(findstart, base)
if a:findstart
@@ -1330,6 +1332,7 @@ func Test_edit_forbidden()
endtry
delfu Complete
set completefunc=
+
if has("rightleft") && exists("+fkmap")
" 4) 'R' when 'fkmap' and 'revins' is set.
set revins fkmap
@@ -1644,4 +1647,95 @@ func Test_read_invalid()
set encoding=utf-8
endfunc
+" Test for ModeChanged pattern
+func Test_mode_changes()
+ let g:index = 0
+ let g:mode_seq = ['n', 'i', 'n', 'v', 'V', 'i', 'ix', 'i', 'ic', 'i', 'n', 'no', 'n', 'V', 'v', 's', 'n']
+ func! TestMode()
+ call assert_equal(g:mode_seq[g:index], get(v:event, "old_mode"))
+ call assert_equal(g:mode_seq[g:index + 1], get(v:event, "new_mode"))
+ call assert_equal(mode(1), get(v:event, "new_mode"))
+ let g:index += 1
+ endfunc
+
+ au ModeChanged * :call TestMode()
+ let g:n_to_any = 0
+ au ModeChanged n:* let g:n_to_any += 1
+ call feedkeys("i\<esc>vVca\<CR>\<C-X>\<C-L>\<esc>ggdG", 'tnix')
+
+ let g:V_to_v = 0
+ au ModeChanged V:v let g:V_to_v += 1
+ call feedkeys("Vv\<C-G>\<esc>", 'tnix')
+ call assert_equal(len(filter(g:mode_seq[1:], {idx, val -> val == 'n'})), g:n_to_any)
+ call assert_equal(1, g:V_to_v)
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+
+ let g:n_to_i = 0
+ au ModeChanged n:i let g:n_to_i += 1
+ let g:n_to_niI = 0
+ au ModeChanged i:niI let g:n_to_niI += 1
+ let g:niI_to_i = 0
+ au ModeChanged niI:i let g:niI_to_i += 1
+ let g:nany_to_i = 0
+ au ModeChanged n*:i let g:nany_to_i += 1
+ let g:i_to_n = 0
+ au ModeChanged i:n let g:i_to_n += 1
+ let g:nori_to_any = 0
+ au ModeChanged [ni]:* let g:nori_to_any += 1
+ let g:i_to_any = 0
+ au ModeChanged i:* let g:i_to_any += 1
+ let g:index = 0
+ let g:mode_seq = ['n', 'i', 'niI', 'i', 'n']
+ call feedkeys("a\<C-O>l\<esc>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(1, g:n_to_i)
+ call assert_equal(1, g:n_to_niI)
+ call assert_equal(1, g:niI_to_i)
+ call assert_equal(2, g:nany_to_i)
+ call assert_equal(1, g:i_to_n)
+ call assert_equal(2, g:i_to_any)
+ call assert_equal(3, g:nori_to_any)
+
+ if has('terminal')
+ let g:mode_seq += ['c', 'n', 't', 'nt', 'c', 'nt', 'n']
+ call feedkeys(":term\<CR>\<C-W>N:bd!\<CR>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(1, g:n_to_i)
+ call assert_equal(1, g:n_to_niI)
+ call assert_equal(1, g:niI_to_i)
+ call assert_equal(2, g:nany_to_i)
+ call assert_equal(1, g:i_to_n)
+ call assert_equal(2, g:i_to_any)
+ call assert_equal(5, g:nori_to_any)
+ endif
+
+ au! ModeChanged
+ delfunc TestMode
+ unlet! g:mode_seq
+ unlet! g:index
+ unlet! g:n_to_any
+ unlet! g:V_to_v
+ unlet! g:n_to_i
+ unlet! g:n_to_niI
+ unlet! g:niI_to_i
+ unlet! g:nany_to_i
+ unlet! g:i_to_n
+ unlet! g:nori_to_any
+ unlet! g:i_to_any
+endfunc
+
+func Test_recursive_ModeChanged()
+ au! ModeChanged * norm 0u
+ sil! norm 
+ au!
+endfunc
+
+func Test_ModeChanged_starts_visual()
+ " This was triggering ModeChanged before setting VIsual, causing a crash.
+ au! ModeChanged * norm 0u
+ sil! norm 
+
+ au! ModeChanged
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
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_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 1c645ad0f8..92e0559618 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -85,7 +85,7 @@ endfunc
func Test_ex_mode_count_overflow()
" this used to cause a crash
let lines =<< trim END
- call feedkeys("\<Esc>Q\<CR>")
+ call feedkeys("\<Esc>gQ\<CR>")
v9|9silent! vi|333333233333y32333333%O
call writefile(['done'], 'Xdidexmode')
qall!
diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim
index 15ba894dbe..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)
@@ -107,6 +107,18 @@ func Test_win_execute()
call win_gotoid(otherwin)
bwipe!
+
+ " check :lcd in another window does not change directory
+ let curid = win_getid()
+ let curdir = getcwd()
+ split Xother
+ lcd ..
+ " Use :pwd to get the actual current directory
+ let otherdir = execute('pwd')
+ call win_execute(curid, 'lcd testdir')
+ call assert_equal(otherdir, execute('pwd'))
+ bwipe!
+ execute 'cd ' .. curdir
endfunc
func Test_win_execute_update_ruler()
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 18e59bb6b7..dbe0cd8388 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -59,7 +59,7 @@ let s:filename_checks = {
\ 'aml': ['file.aml'],
\ 'ampl': ['file.run'],
\ 'ant': ['build.xml'],
- \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file'],
+ \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'],
\ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'],
\ 'applescript': ['file.scpt'],
\ 'aptconf': ['apt.conf', '/.aptitude/config', 'any/.aptitude/config'],
@@ -117,7 +117,7 @@ let s:filename_checks = {
\ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
\ 'crm': ['file.crm'],
\ 'crontab': ['crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'],
- \ 'cs': ['file.cs'],
+ \ 'cs': ['file.cs', 'file.csx'],
\ 'csc': ['file.csc'],
\ 'csdl': ['file.csdl'],
\ 'csp': ['file.csp', 'file.fdr'],
@@ -142,7 +142,7 @@ let s:filename_checks = {
\ 'desc': ['file.desc'],
\ 'desktop': ['file.desktop', '.directory', 'file.directory'],
\ 'dictconf': ['dict.conf', '.dictrc'],
- \ 'dictdconf': ['dictd.conf'],
+ \ 'dictdconf': ['dictd.conf', 'dictdfile.conf', 'dictd-file.conf'],
\ 'diff': ['file.diff', 'file.rej'],
\ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'],
\ 'dnsmasq': ['/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'],
@@ -180,15 +180,17 @@ let s:filename_checks = {
\ 'fennel': ['file.fnl'],
\ 'fetchmail': ['.fetchmailrc'],
\ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
+ \ 'fish': ['file.fish'],
\ 'focexec': ['file.fex', 'file.focexec'],
- \ 'forth': ['file.fs', 'file.ft', 'file.fth'],
+ \ 'forth': ['file.ft', 'file.fth'],
\ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'],
\ 'fpcmake': ['file.fpc'],
\ 'framescript': ['file.fsl'],
\ 'freebasic': ['file.fb', 'file.bi'],
+ \ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'],
\ 'fstab': ['fstab', 'mtab'],
\ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'],
- \ 'gdb': ['.gdbinit'],
+ \ 'gdb': ['.gdbinit', 'gdbinit'],
\ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'],
\ 'gemtext': ['file.gmi', 'file.gemini'],
@@ -224,6 +226,7 @@ let s:filename_checks = {
\ 'hollywood': ['file.hws'],
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
+ \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
\ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
@@ -337,7 +340,7 @@ let s:filename_checks = {
\ 'msql': ['file.msql'],
\ 'mupad': ['file.mu'],
\ 'mush': ['file.mush'],
- \ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'],
+ \ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'],
\ 'mysql': ['file.mysql'],
\ 'n1ql': ['file.n1ql', 'file.nql'],
\ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'],
@@ -419,6 +422,7 @@ let s:filename_checks = {
\ 'rnc': ['file.rnc'],
\ 'rng': ['file.rng'],
\ 'robots': ['robots.txt'],
+ \ 'routeros': ['file.rsc'],
\ 'rpcgen': ['file.x'],
\ 'rpl': ['file.rpl'],
\ 'rst': ['file.rst'],
@@ -452,6 +456,7 @@ let s:filename_checks = {
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
\ 'slang': ['file.sl'],
\ 'slice': ['file.ice'],
+ \ 'solution': ['file.sln'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
\ 'slpreg': ['/etc/slp.reg', 'any/etc/slp.reg'],
\ 'slpspi': ['/etc/slp.spi', 'any/etc/slp.spi'],
@@ -473,13 +478,14 @@ let s:filename_checks = {
\ 'sqlj': ['file.sqlj'],
\ 'sqr': ['file.sqr', 'file.sqi'],
\ 'squid': ['squid.conf'],
+ \ 'squirrel': ['file.nut'],
\ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
\ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config'],
\ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'],
\ 'st': ['file.st'],
\ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
\ 'stp': ['file.stp'],
- \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers'],
+ \ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
\ 'swift': ['file.swift'],
@@ -498,7 +504,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', '/usr/share/doc/bash-completion/AUTHORS'],
+ \ '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'],
@@ -551,7 +557,7 @@ let s:filename_checks = {
\ 'xhtml': ['file.xhtml', 'file.xht'],
\ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'],
\ 'xmath': ['file.msc', 'file.msf'],
- \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu'],
+ \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
\ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xpm': ['file.xpm'],
@@ -564,6 +570,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'],
@@ -659,6 +666,9 @@ let s:script_checks = {
\ 'yaml': [['%YAML 1.2']],
\ 'pascal': [['#!/path/instantfpc']],
\ 'fennel': [['#!/path/fennel']],
+ \ 'routeros': [['#!/path/rsc']],
+ \ 'fish': [['#!/path/fish']],
+ \ 'forth': [['#!/path/gforth']],
\ }
" Various forms of "env" optional arguments.
@@ -862,6 +872,16 @@ func Test_m_file()
call assert_equal('objc', &filetype)
bwipe!
+ call writefile(['#include <header.h>'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('objc', &filetype)
+ bwipe!
+
+ call writefile(['#define FORTY_TWO'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('objc', &filetype)
+ bwipe!
+
" Octave
call writefile(['# Octave line comment'], 'Xfile.m')
@@ -931,4 +951,97 @@ func Test_xpm_file()
filetype off
endfunc
+func Test_fs_file()
+ filetype on
+
+ call writefile(['looks like F#'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('fsharp', &filetype)
+ bwipe!
+
+ let g:filetype_fs = 'forth'
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+ unlet g:filetype_fs
+
+ " Test dist#ft#FTfs()
+
+ " Forth (Gforth)
+
+ call writefile(['( Forth inline comment )'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['.( Forth displayed inline comment )'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['\ Forth line comment'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ " empty line comment - no space required
+ call writefile(['\'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['\G Forth documentation comment '], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile([': squared ( n -- n^2 )', 'dup * ;'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call delete('Xfile.fs')
+ filetype off
+endfunc
+
+func Test_dep3patch_file()
+ filetype on
+
+ call assert_true(mkdir('debian/patches', 'p'))
+
+ " series files are not patches
+ call writefile(['Description: some awesome patch'], 'debian/patches/series')
+ split debian/patches/series
+ call assert_notequal('dep3patch', &filetype)
+ bwipe!
+
+ " diff/patch files without the right headers should still show up as ft=diff
+ call writefile([], 'debian/patches/foo.diff')
+ split debian/patches/foo.diff
+ call assert_equal('diff', &filetype)
+ bwipe!
+
+ " Files with the right headers are detected as dep3patch, even if they don't
+ " have a diff/patch extension
+ call writefile(['Subject: dep3patches'], 'debian/patches/bar')
+ split debian/patches/bar
+ call assert_equal('dep3patch', &filetype)
+ bwipe!
+
+ " Files in sub-directories are detected
+ call assert_true(mkdir('debian/patches/s390x', 'p'))
+ call writefile(['Subject: dep3patches'], 'debian/patches/s390x/bar')
+ split debian/patches/s390x/bar
+ call assert_equal('dep3patch', &filetype)
+ bwipe!
+
+ " The detection stops when seeing the "header end" marker
+ call writefile(['---', 'Origin: the cloud'], 'debian/patches/baz')
+ split debian/patches/baz
+ call assert_notequal('dep3patch', &filetype)
+ bwipe!
+
+ call delete('debian/patches', 'rf')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
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 d10fad690c..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)
@@ -1592,6 +1603,10 @@ func Test_bufadd_bufload()
endfunc
func Test_readdir()
+ if isdirectory('Xdir')
+ call delete('Xdir', 'rf')
+ endif
+
call mkdir('Xdir')
call writefile([], 'Xdir/foo.txt')
call writefile([], 'Xdir/bar.txt')
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 6fd9477ce9..899eb530ec 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -651,6 +651,23 @@ func Test_1_highlight_Normalgroup_exists()
endif
endfunc
+function Test_no_space_before_xxx()
+ " Note: we need to create this highlight group in the test because it does not exist in Neovim
+ execute('hi StatusLineTermNC ctermfg=green')
+ let l:org_columns = &columns
+ set columns=17
+ let l:hi_StatusLineTermNC = join(split(execute('hi StatusLineTermNC')))
+ call assert_match('StatusLineTermNC xxx', l:hi_StatusLineTermNC)
+ let &columns = l:org_columns
+endfunction
+
+" Test for :highlight command errors
+func Test_highlight_cmd_errors()
+ if has('gui_running') || has('nvim')
+ call assert_fails('hi ' .. repeat('a', 201) .. ' ctermfg=black', 'E1249:')
+ endif
+endfunc
+
" Test for using RGB color values in a highlight group
func Test_xxlast_highlight_RGB_color()
CheckCanRunGui
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index 8a1393a45d..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:<
@@ -112,7 +112,7 @@ func Test_listchars()
" Test lead and trail
normal ggdG
- set listchars=eol:$
+ set listchars=eol:$ " Accommodate Nvim default
set listchars+=lead:>,trail:<,space:x
set list
@@ -142,7 +142,7 @@ func Test_listchars()
" Test multispace
normal ggdG
- set listchars=eol:$
+ set listchars=eol:$ " Accommodate Nvim default
set listchars+=multispace:yYzZ
set list
@@ -286,6 +286,10 @@ func Test_listchars_unicode()
call cursor(1, 1)
call assert_equal(expected, ScreenLines(1, virtcol('$')))
+ set listchars=eol:\\u21d4,space:\\u2423,multispace:≡\\u2262\\U00002263,nbsp:\\U00002260,tab:←↔\\u2192
+ redraw!
+ call assert_equal(expected, ScreenLines(1, virtcol('$')))
+
set listchars+=lead:⇨,trail:⇦
let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
redraw!
@@ -301,7 +305,7 @@ func Test_listchars_invalid()
enew!
set ff=unix
- set listchars=eol:$
+ set listchars=eol:$ " Accommodate Nvim default
set list
set ambiwidth=double
@@ -365,3 +369,138 @@ func Test_listchars_composing()
enew!
set listchars& ff&
endfunction
+
+" Check for the value of the 'listchars' option
+func s:CheckListCharsValue(expected)
+ call assert_equal(a:expected, &listchars)
+ call assert_equal(a:expected, getwinvar(0, '&listchars'))
+endfunc
+
+" Test for using a window local value for 'listchars'
+func Test_listchars_window_local()
+ %bw!
+ set list listchars&
+ let l:default_listchars = &listchars " Accommodate Nvim default
+ new
+ " set a local value for 'listchars'
+ setlocal listchars=tab:+-,eol:#
+ call s:CheckListCharsValue('tab:+-,eol:#')
+ " When local value is reset, global value should be used
+ setlocal listchars=
+ call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default
+ " Use 'setlocal <' to copy global value
+ setlocal listchars=space:.,extends:>
+ setlocal listchars<
+ call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default
+ " Use 'set <' to copy global value
+ setlocal listchars=space:.,extends:>
+ set listchars<
+ call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default
+ " Changing global setting should not change the local setting
+ setlocal listchars=space:.,extends:>
+ setglobal listchars=tab:+-,eol:#
+ call s:CheckListCharsValue('space:.,extends:>')
+ " when split opening a new window, local value should be copied
+ split
+ call s:CheckListCharsValue('space:.,extends:>')
+ " clearing local value in one window should not change the other window
+ set listchars&
+ call s:CheckListCharsValue(l:default_listchars) " Accommodate Nvim default
+ close
+ call s:CheckListCharsValue('space:.,extends:>')
+
+ " use different values for 'listchars' items in two different windows
+ call setline(1, ["\t one two "])
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ split
+ setlocal listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+ split
+ set listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ " changing the global setting should not change the local value
+ setglobal listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ set listchars<
+ call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$')))
+
+ " Using setglobal in a window with local setting should not affect the
+ " window. But should impact other windows using the global setting.
+ enew! | only
+ call setline(1, ["\t one two "])
+ set listchars=tab:[.],lead:#,space:_,trail:.,eol:&
+ split
+ setlocal listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$')))
+
+ " Setting the global setting to the default value should not impact a window
+ " using a local setting.
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ setglobal listchars=eol:$ " Accommodate Nvim default
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$')))
+
+ " Setting the local setting to the default value should not impact a window
+ " using a global setting.
+ set listchars=tab:{.},lead:-,space:=,trail:#,eol:$
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ setlocal listchars=eol:$ " Accommodate Nvim default
+ call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$')))
+
+ " Using set in a window with a local setting should change it to use the
+ " global setting and also impact other windows using the global setting.
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ set listchars=tab:+-+,lead:^,space:>,trail:<,eol:%
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+
+ " Setting invalid value for a local setting should not impact the local and
+ " global settings.
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ let cmd = 'setlocal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x'
+ call assert_fails(cmd, 'E474:')
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+
+ " Setting invalid value for a global setting should not impact the local and
+ " global settings.
+ split
+ setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:#
+ let cmd = 'setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x'
+ call assert_fails(cmd, 'E474:')
+ call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$')))
+ close
+ call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$')))
+
+ " Closing window with local lcs-multispace should not cause a memory leak.
+ setlocal listchars=multispace:---+
+ split
+ call s:CheckListCharsValue('multispace:---+')
+ close
+
+ %bw!
+ set list& listchars&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim
index e0518de3c2..2fda12d8b4 100644
--- a/src/nvim/testdir/test_listlbr.vim
+++ b/src/nvim/testdir/test_listlbr.vim
@@ -43,6 +43,7 @@ endfunc
func Test_linebreak_with_list()
throw 'skipped: Nvim does not support enc=latin1'
+ set listchars=
call s:test_windows('setl ts=4 sbr=+ list listchars=')
call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ")
let lines = s:screen_lines([1, 4], winwidth(0))
@@ -54,6 +55,7 @@ func Test_linebreak_with_list()
\ ]
call s:compare_lines(expect, lines)
call s:close_windows()
+ set listchars&vim
endfunc
func Test_linebreak_with_nolist()
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 15745d5619..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()
@@ -111,3 +111,16 @@ func Test_put_p_indent_visual()
call assert_equal('select that text', getline(2))
bwipe!
endfunc
+
+func Test_multibyte_op_end_mark()
+ new
+ call setline(1, 'тест')
+ normal viwdp
+ call assert_equal([0, 1, 7, 0], getpos("'>"))
+ call assert_equal([0, 1, 7, 0], getpos("']"))
+
+ normal Vyp
+ call assert_equal([0, 1, 2147483647, 0], getpos("'>"))
+ call assert_equal([0, 2, 7, 0], getpos("']"))
+ bwipe!
+ endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 8c6ce63ade..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()
@@ -3653,6 +3653,9 @@ func Xqftick_tests(cchar)
\ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'r')
call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
+ if isdirectory("Xone")
+ call delete("Xone", 'rf')
+ endif
call writefile(["F8:80:L80", "F8:81:L81"], "Xone")
Xfile Xone
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index fd8653a2eb..84a5aca3d5 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -43,6 +43,10 @@ func Test_yank_shows_register()
endfunc
func Test_display_registers()
+ " Disable clipboard
+ let save_clipboard = get(g:, 'clipboard', {})
+ let g:clipboard = {}
+
e file1
e file2
call setline(1, ['foo', 'bar'])
@@ -78,6 +82,7 @@ func Test_display_registers()
\ . ' c ": ls', a)
bwipe!
+ let g:clipboard = save_clipboard
endfunc
func Test_recording_status_in_ex_line()
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..799e6cb57b 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -15,13 +15,13 @@ func Test_sign()
" the icon name when listing signs.
sign define Sign1 text=x
- call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error icon=../../pixmaps/stock_vim_find_help.png')
+ call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search icon=../../pixmaps/stock_vim_find_help.png')
" Test listing signs.
let a=execute('sign list')
call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' .
\ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' .
- \ 'linehl=Error texthl=Title$', a)
+ \ 'linehl=Error texthl=Title culhl=Search$', a)
let a=execute('sign list Sign1')
call assert_equal("\nsign Sign1 text=x ", a)
@@ -126,6 +126,30 @@ func Test_sign()
" call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:')
call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:')
+ " an empty highlight argument for an existing sign clears it
+ sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl
+ let sl = sign_getdefined('SignY')[0]
+ call assert_equal('TextHl', sl.texthl)
+ call assert_equal('CulHl', sl.culhl)
+ call assert_equal('LineHl', sl.linehl)
+
+ sign define SignY texthl= culhl=CulHl linehl=LineHl
+ let sl = sign_getdefined('SignY')[0]
+ call assert_false(has_key(sl, 'texthl'))
+ call assert_equal('CulHl', sl.culhl)
+ call assert_equal('LineHl', sl.linehl)
+
+ sign define SignY linehl=
+ let sl = sign_getdefined('SignY')[0]
+ call assert_false(has_key(sl, 'linehl'))
+ call assert_equal('CulHl', sl.culhl)
+
+ sign define SignY culhl=
+ let sl = sign_getdefined('SignY')[0]
+ call assert_false(has_key(sl, 'culhl'))
+
+ sign undefine SignY
+
" define sign with whitespace
sign define Sign4 text=\ X linehl=Comment
sign undefine Sign4
@@ -392,25 +416,27 @@ func Test_sign_funcs()
call sign_undefine()
" Tests for sign_define()
- let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error'}
- call assert_equal(0, sign_define("sign1", attr))
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error',
+ \ 'culhl': 'Visual'}
+ call assert_equal(0, "sign1"->sign_define(attr))
call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
- \ 'linehl' : 'Search', 'text' : '=>'}], sign_getdefined())
+ \ 'linehl' : 'Search', 'culhl': 'Visual', 'text' : '=>'}],
+ \ sign_getdefined())
" Define a new sign without attributes and then update it
call sign_define("sign2")
let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange',
- \ 'icon' : 'sign2.ico'}
+ \ 'culhl': 'DiffDelete', 'icon' : 'sign2.ico'}
call Sign_define_ignore_error("sign2", attr)
call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
- \ 'linehl' : 'DiffAdd', 'text' : '!!', 'icon' : 'sign2.ico'}],
- \ sign_getdefined("sign2"))
+ \ 'linehl' : 'DiffAdd', 'culhl' : 'DiffDelete', 'text' : '!!',
+ \ 'icon' : 'sign2.ico'}], "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 +460,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 +516,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 +1719,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 +1947,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 +1980,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..20b760ac15 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -137,7 +137,7 @@ func Test_substitute_repeat()
" This caused an invalid memory access.
split Xfile
s/^/x
- call feedkeys("Qsc\<CR>y", 'tx')
+ call feedkeys("gQsc\<CR>y", 'tx')
bwipe!
endfunc
@@ -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_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index c259453b5e..2b6bb8b302 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -421,4 +421,36 @@ func Test_textobj_quote()
close!
endfunc
+" Test for i(, i<, etc. when cursor is in front of a block
+func Test_textobj_find_paren_forward()
+ new
+
+ " i< and a> when cursor is in front of a block
+ call setline(1, '#include <foo.h>')
+ normal 0yi<
+ call assert_equal('foo.h', @")
+ normal 0ya>
+ call assert_equal('<foo.h>', @")
+
+ " 2i(, 3i( in front of a block enters second/third nested '('
+ call setline(1, 'foo (bar (baz (quux)))')
+ normal 0yi)
+ call assert_equal('bar (baz (quux))', @")
+ normal 02yi)
+ call assert_equal('baz (quux)', @")
+ normal 03yi)
+ call assert_equal('quux', @")
+
+ " 3i( in front of a block doesn't enter third but un-nested '('
+ call setline(1, 'foo (bar (baz) (quux))')
+ normal 03di)
+ call assert_equal('foo (bar (baz) (quux))', getline(1))
+ normal 02di)
+ call assert_equal('foo (bar () (quux))', getline(1))
+ normal 0di)
+ call assert_equal('foo ()', getline(1))
+
+ close!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index ceaa5de92b..aae315b2c5 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()
@@ -279,7 +279,7 @@ func Test_ex_mode()
endfunc
let timer = timer_start(40, function('g:Foo'), {'repeat':-1})
" This used to throw error E749.
- exe "normal Qsleep 100m\rvi\r"
+ exe "normal gQsleep 100m\rvi\r"
call timer_stop(timer)
endfunc
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/tui/input.c b/src/nvim/tui/input.c
index 5bb6059fa7..5fec41f9a5 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -114,6 +114,12 @@ static void tinput_done_event(void **argv)
static void tinput_wait_enqueue(void **argv)
{
TermInput *input = argv[0];
+ if (rbuffer_size(input->key_buffer) == 0 && input->paste == 3) {
+ const String keys = { .data = "", .size = 0 };
+ String copy = copy_string(keys);
+ multiqueue_put(main_loop.events, tinput_paste_event, 3,
+ copy.data, copy.size, (intptr_t)input->paste);
+ }
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
const String keys = { .data = buf, .size = len };
if (input->paste) {
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bb75286369..e7a60aca49 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -308,23 +308,39 @@ static void terminfo_start(UI *ui)
// Enable bracketed paste
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
+ int ret;
uv_loop_init(&data->write_loop);
if (data->out_isatty) {
- uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
+ ret = uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
+ if (ret) {
+ ELOG("uv_tty_init failed: %s", uv_strerror(ret));
+ }
#ifdef WIN32
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
+ ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
#else
int retry_count = 10;
// A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
// few times. #12322
- while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR
+ while ((ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO)) == UV_EINTR
&& retry_count > 0) {
retry_count--;
}
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
#endif
} else {
- uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
- uv_pipe_open(&data->output_handle.pipe, data->out_fd);
+ ret = uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
+ if (ret) {
+ ELOG("uv_pipe_init failed: %s", uv_strerror(ret));
+ }
+ ret = uv_pipe_open(&data->output_handle.pipe, data->out_fd);
+ if (ret) {
+ ELOG("uv_pipe_open failed: %s", uv_strerror(ret));
+ }
}
flush_buf(ui);
}
@@ -1086,8 +1102,14 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
// after calling uv_tty_set_mode. So, set the mode of the TTY again here.
// #13073
if (data->is_starting && data->input.in_fd == STDERR_FILENO) {
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ int ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
+ ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
}
#endif
tui_set_mode(ui, (ModeShape)mode_idx);
@@ -2081,8 +2103,11 @@ static void flush_buf(UI *ui)
fwrite(bufs[i].base, bufs[i].len, 1, data->screenshot);
}
} else {
- uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
- bufs, (unsigned)(bufp - bufs), NULL);
+ int ret = uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
+ bufs, (unsigned)(bufp - bufs), NULL);
+ if (ret) {
+ ELOG("uv_write failed: %s", uv_strerror(ret));
+ }
uv_run(&data->write_loop, UV_RUN_DEFAULT);
}
data->bufpos = 0;
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index aad72af025..1aadaf5c9d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -23,7 +23,6 @@
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
-#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
@@ -300,6 +299,44 @@ void ui_busy_stop(void)
}
}
+/// Emit a bell or visualbell as a warning
+///
+/// val is one of the BO_ values, e.g., BO_OPER
+void vim_beep(unsigned val)
+{
+ called_vim_beep = true;
+
+ if (emsg_silent == 0) {
+ if (!((bo_flags & val) || (bo_flags & BO_ALL))) {
+ static int beeps = 0;
+ static uint64_t start_time = 0;
+
+ // Only beep up to three times per half a second,
+ // otherwise a sequence of beeps would freeze Vim.
+ if (start_time == 0 || os_hrtime() - start_time > 500000000u) {
+ beeps = 0;
+ start_time = os_hrtime();
+ }
+ beeps++;
+ if (beeps <= 3) {
+ if (p_vb) {
+ ui_call_visual_bell();
+ } else {
+ ui_call_bell();
+ }
+ }
+ }
+
+ // When 'debug' contains "beep" produce a message. If we are sourcing
+ // a script or executing a function give the user a hint where the beep
+ // comes from.
+ if (vim_strchr(p_debug, 'e') != NULL) {
+ msg_source(HL_ATTR(HLF_W));
+ msg_attr(_("Beep!"), HL_ATTR(HLF_W));
+ }
+ }
+}
+
void ui_attach_impl(UI *ui, uint64_t chanid)
{
if (ui_count == MAX_UI_COUNT) {
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 7eb76abd2c..d18f35a43a 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -93,13 +93,14 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
+#include "nvim/getchar.h"
#include "nvim/lib/kvec.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/os_unix.h"
@@ -922,7 +923,7 @@ static u_header_T *unserialize_uhp(bufinfo_T *bi, const char *file_name)
uhp->uh_time = undo_read_time(bi);
// Unserialize optional fields.
- for (;; ) {
+ for (;;) {
int len = undo_read_byte(bi);
if (len == EOF) {
@@ -1504,7 +1505,7 @@ void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_AT
// Optional header fields.
long last_save_nr = 0;
- for (;; ) {
+ for (;;) {
int len = undo_read_byte(&bi);
if (len == 0 || len == EOF) {
@@ -2621,7 +2622,7 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet)
if (uhp == NULL) {
*msgbuf = NUL;
} else {
- add_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
+ undo_fmt_time(msgbuf, sizeof(msgbuf), uhp->uh_time);
}
{
@@ -2641,6 +2642,29 @@ static void u_undo_end(bool did_undo, bool absolute, bool quiet)
msgbuf);
}
+/// Put the timestamp of an undo header in "buf[buflen]" in a nice format.
+void undo_fmt_time(char_u *buf, size_t buflen, time_t tt)
+{
+ struct tm curtime;
+
+ if (time(NULL) - tt >= 100) {
+ os_localtime_r(&tt, &curtime);
+ if (time(NULL) - tt < (60L * 60L * 12L)) {
+ // within 12 hours
+ (void)strftime((char *)buf, buflen, "%H:%M:%S", &curtime);
+ } else {
+ // longer ago
+ (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", &curtime);
+ }
+ } else {
+ int64_t seconds = time(NULL) - tt;
+ vim_snprintf((char *)buf, buflen,
+ NGETTEXT("%" PRId64 " second ago",
+ "%" PRId64 " seconds ago", (uint32_t)seconds),
+ seconds);
+ }
+}
+
/// u_sync: stop adding to the current entry list
///
/// @param force if true, also sync when no_u_sync is set.
@@ -2683,16 +2707,13 @@ void ex_undolist(exarg_T *eap)
while (uhp != NULL) {
if (uhp->uh_prev.ptr == NULL && uhp->uh_walk != nomark
&& uhp->uh_walk != mark) {
- vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ",
- uhp->uh_seq, changes);
- add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
- uhp->uh_time);
+ vim_snprintf((char *)IObuff, IOSIZE, "%6ld %7d ", uhp->uh_seq, changes);
+ undo_fmt_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), uhp->uh_time);
if (uhp->uh_save_nr > 0) {
while (STRLEN(IObuff) < 33) {
STRCAT(IObuff, " ");
}
- vim_snprintf_add((char *)IObuff, IOSIZE,
- " %3ld", uhp->uh_save_nr);
+ vim_snprintf_add((char *)IObuff, IOSIZE, " %3ld", uhp->uh_save_nr);
}
GA_APPEND(char_u *, &ga, vim_strsave(IObuff));
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 1fcbae8be3..5e2a81795a 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -458,11 +458,11 @@ static const int included_patches[] = {
1466,
1465,
1464,
- // 1463,
+ 1463,
1462,
- // 1461,
- // 1460,
- // 1459,
+ 1461,
+ 1460,
+ 1459,
1458,
1457,
1456,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 726670f082..2f8ddd1e88 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -72,6 +72,8 @@ enum { NUMBUFLEN = 65, };
#define TERM_FOCUS 0x2000 // Terminal focus mode
#define CMDPREVIEW 0x4000 // Showing 'inccommand' command "live" preview.
+#define MODE_MAX_LENGTH 4 // max mode length returned in mode()
+
// all mode bits used for mapping
#define MAP_ALL_MODES (0x3f | SELECTMODE | TERM_FOCUS)
@@ -213,6 +215,11 @@ enum { FOLD_TEXT_LEN = 51, }; //!< buffer size for get_foldtext()
// (vim_strchr() is now in strings.c)
#define STRLEN(s) strlen((char *)(s))
+#ifdef HAVE_STRNLEN
+# define STRNLEN(s, n) strnlen((char *)(s), (size_t)(n))
+#else
+# define STRNLEN(s, n) xstrnlen((char *)(s), (size_t)(n))
+#endif
#define STRCPY(d, s) strcpy((char *)(d), (char *)(s))
#define STRNCPY(d, s, n) strncpy((char *)(d), (char *)(s), (size_t)(n))
#define STRLCPY(d, s, n) xstrlcpy((char *)(d), (char *)(s), (size_t)(n))
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index 4f028fa87f..ba6cfab98b 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -204,40 +204,40 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
} \
} while (0)
switch (schar) {
- // Paired brackets.
+ // Paired brackets.
#define BRACKET(typ, opning, clsing) \
-case opning: \
-case clsing: { \
- ret.type = typ; \
- ret.data.brc.closing = (schar == clsing); \
- break; \
-}
- BRACKET(kExprLexParenthesis, '(', ')')
- BRACKET(kExprLexBracket, '[', ']')
- BRACKET(kExprLexFigureBrace, '{', '}')
+ case opning: \
+ case clsing: { \
+ ret.type = typ; \
+ ret.data.brc.closing = (schar == clsing); \
+ break; \
+ }
+ BRACKET(kExprLexParenthesis, '(', ')')
+ BRACKET(kExprLexBracket, '[', ']')
+ BRACKET(kExprLexFigureBrace, '{', '}')
#undef BRACKET
- // Single character tokens without data.
+ // Single character tokens without data.
#define CHAR(typ, ch) \
-case ch: { \
- ret.type = typ; \
- break; \
-}
- CHAR(kExprLexQuestion, '?')
- CHAR(kExprLexColon, ':')
- CHAR(kExprLexComma, ',')
+ case ch: { \
+ ret.type = typ; \
+ break; \
+ }
+ CHAR(kExprLexQuestion, '?')
+ CHAR(kExprLexColon, ':')
+ CHAR(kExprLexComma, ',')
#undef CHAR
- // Multiplication/division/modulo.
+ // Multiplication/division/modulo.
#define MUL(mul_type, ch) \
-case ch: { \
- ret.type = kExprLexMultiplication; \
- ret.data.mul.type = mul_type; \
- break; \
-}
- MUL(kExprLexMulMul, '*')
- MUL(kExprLexMulDiv, '/')
- MUL(kExprLexMulMod, '%')
+ case ch: { \
+ ret.type = kExprLexMultiplication; \
+ ret.data.mul.type = mul_type; \
+ break; \
+ }
+ MUL(kExprLexMulMul, '*')
+ MUL(kExprLexMulDiv, '/')
+ MUL(kExprLexMulMod, '%')
#undef MUL
#define CHARREG(typ, cond) \
@@ -653,16 +653,16 @@ case ch: { \
// Sign or augmented assignment.
#define CHAR_OR_ASSIGN(ch, ch_type, ass_type) \
-case ch: { \
- if (pline.size > 1 && pline.data[1] == '=') { \
- ret.len++; \
- ret.type = kExprLexAssignment; \
- ret.data.ass.type = ass_type; \
- } else { \
- ret.type = ch_type; \
- } \
- break; \
-}
+ case ch: { \
+ if (pline.size > 1 && pline.data[1] == '=') { \
+ ret.len++; \
+ ret.type = kExprLexAssignment; \
+ ret.data.ass.type = ass_type; \
+ } else { \
+ ret.type = ch_type; \
+ } \
+ break; \
+ }
CHAR_OR_ASSIGN('+', kExprLexPlus, kExprAsgnAdd)
CHAR_OR_ASSIGN('.', kExprLexDot, kExprAsgnConcat)
#undef CHAR_OR_ASSIGN
@@ -811,19 +811,19 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate, const LexExpr
eltkn_type_tab[token.type]);
switch (token.type) {
#define TKNARGS(tkn_type, ...) \
-case tkn_type: { \
- ADDSTR(__VA_ARGS__); \
- break; \
-}
- TKNARGS(kExprLexComparison, "(type=%s,ccs=%s,inv=%i)",
- eltkn_cmp_type_tab[token.data.cmp.type],
- ccs_tab[token.data.cmp.ccs],
- (int)token.data.cmp.inv)
- TKNARGS(kExprLexMultiplication, "(type=%s)",
- eltkn_mul_type_tab[token.data.mul.type])
- TKNARGS(kExprLexAssignment, "(type=%s)",
- expr_asgn_type_tab[token.data.ass.type])
- TKNARGS(kExprLexRegister, "(name=%s)", intchar2str(token.data.reg.name))
+ case tkn_type: { \
+ ADDSTR(__VA_ARGS__); \
+ break; \
+ }
+ TKNARGS(kExprLexComparison, "(type=%s,ccs=%s,inv=%i)",
+ eltkn_cmp_type_tab[token.data.cmp.type],
+ ccs_tab[token.data.cmp.ccs],
+ (int)token.data.cmp.inv)
+ TKNARGS(kExprLexMultiplication, "(type=%s)",
+ eltkn_mul_type_tab[token.data.mul.type])
+ TKNARGS(kExprLexAssignment, "(type=%s)",
+ expr_asgn_type_tab[token.data.ass.type])
+ TKNARGS(kExprLexRegister, "(name=%s)", intchar2str(token.data.reg.name))
case kExprLexDoubleQuotedString:
TKNARGS(kExprLexSingleQuotedString, "(closed=%i)",
(int)token.data.str.closed)
@@ -1036,7 +1036,7 @@ void viml_pexpr_free_ast(ExprAST ast)
ExprASTNode **const cur_node = kv_last(ast_stack);
#ifndef NDEBUG
// Explicitly check for AST recursiveness.
- for (size_t i = 0 ; i < kv_size(ast_stack) - 1 ; i++) {
+ for (size_t i = 0; i < kv_size(ast_stack) - 1; i++) {
assert(*kv_A(ast_stack, i) != *cur_node);
}
#endif
@@ -1540,21 +1540,21 @@ static inline void east_set_error(const ParserState *const pstate, ExprASTError
case kExprNodeComplexIdentifier: \
case kExprNodePlainIdentifier: \
case kExprNodeCurlyBracesIdentifier: { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComplexIdentifier); \
- cur_node->len = 0; \
- cur_node->children = *top_node_p; \
- *top_node_p = cur_node; \
- kvi_push(ast_stack, &cur_node->children->next); \
- ExprASTNode **const new_top_node_p = kv_last(ast_stack); \
- assert(*new_top_node_p == NULL); \
- new_ident_node_code; \
- *new_top_node_p = cur_node; \
- HL_CUR_TOKEN(hl); \
- break; \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComplexIdentifier); \
+ cur_node->len = 0; \
+ cur_node->children = *top_node_p; \
+ *top_node_p = cur_node; \
+ kvi_push(ast_stack, &cur_node->children->next); \
+ ExprASTNode **const new_top_node_p = kv_last(ast_stack); \
+ assert(*new_top_node_p == NULL); \
+ new_ident_node_code; \
+ *new_top_node_p = cur_node; \
+ HL_CUR_TOKEN(hl); \
+ break; \
} \
default: { \
- OP_MISSING; \
- break; \
+ OP_MISSING; \
+ break; \
} \
} \
} while (0)
@@ -1747,19 +1747,19 @@ static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const no
const char *const v_p_start = v_p;
switch (*p) {
#define SINGLE_CHAR_ESC(ch, real_ch) \
-case ch: { \
- *v_p++ = real_ch; \
- p++; \
- break; \
-}
- SINGLE_CHAR_ESC('b', BS)
- SINGLE_CHAR_ESC('e', ESC)
- SINGLE_CHAR_ESC('f', FF)
- SINGLE_CHAR_ESC('n', NL)
- SINGLE_CHAR_ESC('r', CAR)
- SINGLE_CHAR_ESC('t', TAB)
- SINGLE_CHAR_ESC('"', '"')
- SINGLE_CHAR_ESC('\\', '\\')
+ case ch: { \
+ *v_p++ = real_ch; \
+ p++; \
+ break; \
+ }
+ SINGLE_CHAR_ESC('b', BS)
+ SINGLE_CHAR_ESC('e', ESC)
+ SINGLE_CHAR_ESC('f', FF)
+ SINGLE_CHAR_ESC('n', NL)
+ SINGLE_CHAR_ESC('r', CAR)
+ SINGLE_CHAR_ESC('t', TAB)
+ SINGLE_CHAR_ESC('"', '"')
+ SINGLE_CHAR_ESC('\\', '\\')
#undef SINGLE_CHAR_ESC
// Hexadecimal or unicode.
@@ -2141,32 +2141,32 @@ viml_pexpr_parse_process_token:
break;
}
#define SIMPLE_UB_OP(op) \
-case kExprLex##op: { \
- if (want_node == kENodeValue) { \
- /* Value level: assume unary operator. */ \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnary##op); \
- *top_node_p = cur_node; \
- kvi_push(ast_stack, &cur_node->children); \
- HL_CUR_TOKEN(Unary##op); \
- } else { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinary##op); \
- ADD_OP_NODE(cur_node); \
- HL_CUR_TOKEN(Binary##op); \
- } \
- want_node = kENodeValue; \
- break; \
-}
+ case kExprLex##op: { \
+ if (want_node == kENodeValue) { \
+ /* Value level: assume unary operator. */ \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnary##op); \
+ *top_node_p = cur_node; \
+ kvi_push(ast_stack, &cur_node->children); \
+ HL_CUR_TOKEN(Unary##op); \
+ } else { \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinary##op); \
+ ADD_OP_NODE(cur_node); \
+ HL_CUR_TOKEN(Binary##op); \
+ } \
+ want_node = kENodeValue; \
+ break; \
+ }
SIMPLE_UB_OP(Plus)
SIMPLE_UB_OP(Minus)
#undef SIMPLE_UB_OP
#define SIMPLE_B_OP(op, msg) \
-case kExprLex##op: { \
- ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
- HL_CUR_TOKEN(op); \
- ADD_OP_NODE(cur_node); \
- break; \
-}
+ case kExprLex##op: { \
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
+ HL_CUR_TOKEN(op); \
+ ADD_OP_NODE(cur_node); \
+ break; \
+ }
SIMPLE_B_OP(Or, "or operator")
SIMPLE_B_OP(And, "and operator")
#undef SIMPLE_B_OP
@@ -2174,14 +2174,14 @@ case kExprLex##op: { \
ADD_VALUE_IF_MISSING(_("E15: Unexpected multiplication-like operator: %.*s"));
switch (cur_token.data.mul.type) {
#define MUL_OP(lex_op_tail, node_op_tail) \
-case kExprLexMul##lex_op_tail: { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
- HL_CUR_TOKEN(node_op_tail); \
- break; \
-}
- MUL_OP(Mul, Multiplication)
- MUL_OP(Div, Division)
- MUL_OP(Mod, Mod)
+ case kExprLexMul##lex_op_tail: { \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
+ HL_CUR_TOKEN(node_op_tail); \
+ break; \
+ }
+ MUL_OP(Mul, Multiplication)
+ MUL_OP(Div, Division)
+ MUL_OP(Mod, Mod)
#undef MUL_OP
}
ADD_OP_NODE(cur_node);
@@ -2929,11 +2929,11 @@ viml_pexpr_parse_no_paren_closing_error: {}
cur_node->data.ass.type = cur_token.data.ass.type;
switch (cur_token.data.ass.type) {
#define HL_ASGN(asgn, hl) \
-case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
- HL_ASGN(Plain, PlainAssignment)
- HL_ASGN(Add, AssignmentWithAddition)
- HL_ASGN(Subtract, AssignmentWithSubtraction)
- HL_ASGN(Concat, AssignmentWithConcatenation)
+ case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
+ HL_ASGN(Plain, PlainAssignment)
+ HL_ASGN(Add, AssignmentWithAddition)
+ HL_ASGN(Subtract, AssignmentWithSubtraction)
+ HL_ASGN(Concat, AssignmentWithConcatenation)
#undef HL_ASGN
}
ADD_OP_NODE(cur_node);
diff --git a/src/nvim/window.c b/src/nvim/window.c
index ff5b39eb84..c711f462d1 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -30,7 +30,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -224,7 +223,7 @@ newwindow:
beep_flush();
} else {
if (Prenum) { // go to specified window
- for (wp = firstwin; --Prenum > 0; ) {
+ for (wp = firstwin; --Prenum > 0;) {
if (wp->w_next == NULL) {
break;
} else {
@@ -569,7 +568,7 @@ wingotofile:
static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, int64_t Prenum)
{
- size_t len = xstrlcpy((char *)bufp, cmd, bufsize);
+ size_t len = STRLCPY(bufp, cmd, bufsize);
if (Prenum > 0 && len < bufsize) {
vim_snprintf((char *)bufp + len, bufsize - len, "%" PRId64, Prenum);
@@ -1958,8 +1957,8 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
// Set the width/height of this frame.
// Redraw when size or position changes
if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
- || topfr->fr_width != width ||
- topfr->fr_win->w_wincol != col) {
+ || topfr->fr_width != width
+ || topfr->fr_win->w_wincol != col) {
topfr->fr_win->w_winrow = row;
frame_new_height(topfr, height, false, false);
topfr->fr_win->w_wincol = col;
@@ -2229,6 +2228,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`
@@ -2239,7 +2286,7 @@ void close_windows(buf_T *buf, int keep_curwin)
++RedrawingDisabled;
- for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW; ) {
+ for (win_T *wp = firstwin; wp != NULL && !ONE_WINDOW;) {
if (wp->w_buffer == buf && (!keep_curwin || wp != curwin)
&& !(wp->w_closing || wp->w_buffer->b_locked > 0)) {
if (win_close(wp, false) == FAIL) {
@@ -2367,6 +2414,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 +2482,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 {
@@ -2582,7 +2630,7 @@ int win_close(win_T *win, bool free_buf)
* If the cursor goes to the preview or the quickfix window, try
* finding another window to go to.
*/
- for (;; ) {
+ for (;;) {
if (wp->w_next == NULL) {
wp = firstwin;
} else {
@@ -3147,12 +3195,12 @@ static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wf
break;
}
if (topfirst) {
- do{
+ do {
frp = frp->fr_next;
}
while (wfh && frp != NULL && frame_fixed_height(frp));
} else {
- do{
+ do {
frp = frp->fr_prev;
}
while (wfh && frp != NULL && frame_fixed_height(frp));
@@ -3347,12 +3395,12 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw
break;
}
if (leftfirst) {
- do{
+ do {
frp = frp->fr_next;
}
while (wfw && frp != NULL && frame_fixed_width(frp));
} else {
- do{
+ do {
frp = frp->fr_prev;
}
while (wfw && frp != NULL && frame_fixed_width(frp));
@@ -3801,6 +3849,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 +4006,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) {
@@ -4316,7 +4367,7 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count)
* downwards neighbor.
*/
fr = foundfr;
- for (;; ) {
+ for (;;) {
if (fr == tp->tp_topframe) {
goto end;
}
@@ -4334,7 +4385,7 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count)
/*
* Now go downwards to find the bottom or top frame in it.
*/
- for (;; ) {
+ for (;;) {
if (nfr->fr_layout == FR_LEAF) {
foundfr = nfr;
break;
@@ -4399,7 +4450,7 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count)
* right neighbor.
*/
fr = foundfr;
- for (;; ) {
+ for (;;) {
if (fr == tp->tp_topframe) {
goto end;
}
@@ -4417,7 +4468,7 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count)
/*
* Now go downwards to find the leftmost or rightmost frame in it.
*/
- for (;; ) {
+ for (;;) {
if (nfr->fr_layout == FR_LEAF) {
foundfr = nfr;
break;
@@ -4478,6 +4529,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) {
@@ -4523,42 +4578,10 @@ static void win_enter_ext(win_T *const wp, const int flags)
}
changed_line_abv_curs(); // assume cursor position needs updating
- // New directory is either the local directory of the window, tab or NULL.
- char *new_dir = (char *)(curwin->w_localdir
- ? curwin->w_localdir : curtab->tp_localdir);
-
- char cwd[MAXPATHL];
- if (os_dirname((char_u *)cwd, MAXPATHL) != OK) {
- cwd[0] = NUL;
- }
-
- if (new_dir) {
- // Window/tab has a local directory: Save current directory as global
- // (unless that was done already) and change to the local directory.
- if (globaldir == NULL) {
- if (cwd[0] != NUL) {
- globaldir = (char_u *)xstrdup(cwd);
- }
- }
- if (os_chdir(new_dir) == 0) {
- if (!p_acd && pathcmp(new_dir, cwd, -1) != 0) {
- do_autocmd_dirchanged(new_dir, curwin->w_localdir
- ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow);
- }
- shorten_fnames(true);
- }
- } else if (globaldir != NULL) {
- // Window doesn't have a local directory and we are not in the global
- // directory: Change to the global directory.
- if (os_chdir((char *)globaldir) == 0) {
- if (!p_acd && pathcmp((char *)globaldir, cwd, -1) != 0) {
- do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
- }
- }
- XFREE_CLEAR(globaldir);
- shorten_fnames(true);
- }
+ 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);
}
@@ -4592,7 +4615,7 @@ static void win_enter_ext(win_T *const wp, const int flags)
}
// set window width to desired minimal value
- if (curwin->w_width < p_wiw && !curwin->w_p_wfw && !wp->w_floating) {
+ if (curwin->w_width < p_wiw && !curwin->w_p_wfw && !curwin->w_floating) {
win_setwidth((int)p_wiw);
}
@@ -4602,6 +4625,46 @@ static void win_enter_ext(win_T *const wp, const int flags)
do_autochdir();
}
+/// Used after making another window the current one: change directory if needed.
+void fix_current_dir(void)
+{
+ // New directory is either the local directory of the window, tab or NULL.
+ char *new_dir = (char *)(curwin->w_localdir
+ ? curwin->w_localdir : curtab->tp_localdir);
+ char cwd[MAXPATHL];
+ if (os_dirname((char_u *)cwd, MAXPATHL) != OK) {
+ cwd[0] = NUL;
+ }
+
+ if (new_dir) {
+ // Window/tab has a local directory: Save current directory as global
+ // (unless that was done already) and change to the local directory.
+ if (globaldir == NULL) {
+ if (cwd[0] != NUL) {
+ globaldir = (char_u *)xstrdup(cwd);
+ }
+ }
+ if (os_chdir(new_dir) == 0) {
+ if (!p_acd && pathcmp(new_dir, cwd, -1) != 0) {
+ do_autocmd_dirchanged(new_dir, curwin->w_localdir
+ ? kCdScopeWindow : kCdScopeTabpage, kCdCauseWindow);
+ }
+ last_chdir_reason = NULL;
+ shorten_fnames(true);
+ }
+ } else if (globaldir != NULL) {
+ // Window doesn't have a local directory and we are not in the global
+ // directory: Change to the global directory.
+ if (os_chdir((char *)globaldir) == 0) {
+ if (!p_acd && pathcmp((char *)globaldir, cwd, -1) != 0) {
+ do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal, kCdCauseWindow);
+ }
+ }
+ XFREE_CLEAR(globaldir);
+ last_chdir_reason = NULL;
+ shorten_fnames(true);
+ }
+}
/// Jump to the first open window that contains buffer "buf", if one exists.
/// Returns a pointer to the window found, otherwise NULL.
@@ -4750,6 +4813,8 @@ static void win_free(win_T *wp, tabpage_T *tp)
clear_winopt(&wp->w_onebuf_opt);
clear_winopt(&wp->w_allbuf_opt);
+ xfree(wp->w_p_lcs_chars.multispace);
+
vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables
hash_init(&wp->w_vars->dv_hashtab);
unref_var_dict(wp->w_vars);
@@ -5823,8 +5888,8 @@ void scroll_to_fraction(win_T *wp, int prev_height)
// is visible.
if (height > 0
&& (!wp->w_p_scb || wp == curwin)
- && (height < wp->w_buffer->b_ml.ml_line_count ||
- wp->w_topline > 1)) {
+ && (height < wp->w_buffer->b_ml.ml_line_count
+ || wp->w_topline > 1)) {
/*
* Find a value for w_topline that shows the cursor at the same
* relative position in the window as before (more or less).
@@ -6080,7 +6145,7 @@ void command_height(void)
static void frame_add_height(frame_T *frp, int n)
{
frame_new_height(frp, frp->fr_height + n, false, false);
- for (;; ) {
+ for (;;) {
frp = frp->fr_parent;
if (frp == NULL) {
break;
@@ -6624,6 +6689,9 @@ void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, bool no_dis
curwin = save_curwin;
curbuf = curwin->w_buffer;
}
+ // If called by win_execute() and executing the command changed the
+ // directory, it now has to be restored.
+ fix_current_dir();
}
/// Make "buf" the current buffer.
@@ -7003,7 +7071,7 @@ int win_getid(typval_T *argvars)
wp = tp->tp_firstwin;
}
}
- for ( ; wp != NULL; wp = wp->w_next) {
+ for (; wp != NULL; wp = wp->w_next) {
if (--winnr == 0) {
return wp->handle;
}
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
index c06bf41d47..49ce394dc9 100644
--- a/src/uncrustify.cfg
+++ b/src/uncrustify.cfg
@@ -1,4 +1,4 @@
-# Uncrustify-0.73.0-199-0dfafb27
+# Uncrustify-0.74.0
#
# General options
@@ -141,7 +141,7 @@ sp_enum_before_assign = ignore # ignore/add/remove/force/not_defined
# Add or remove space after assignment '=' in enum.
#
# Overrides sp_enum_assign.
-sp_enum_after_assign = ignore # ignore/add/remove/force/not_defined
+sp_enum_after_assign = force # ignore/add/remove/force/not_defined
# Add or remove space around assignment ':' in enum.
sp_enum_colon = ignore # ignore/add/remove/force/not_defined
@@ -149,11 +149,11 @@ sp_enum_colon = ignore # ignore/add/remove/force/not_defined
# Add or remove space around preprocessor '##' concatenation operator.
#
# Default: add
-sp_pp_concat = ignore # ignore/add/remove/force/not_defined
+sp_pp_concat = remove # ignore/add/remove/force/not_defined
# Add or remove space after preprocessor '#' stringify operator.
# Also affects the '#@' charizing operator.
-sp_pp_stringify = ignore # ignore/add/remove/force/not_defined
+sp_pp_stringify = remove # ignore/add/remove/force/not_defined
# Add or remove space before preprocessor '#' stringify operator
# as in '#define x(y) L#y'.
@@ -214,6 +214,10 @@ sp_after_ptr_star_func = remove # ignore/add/remove/force/not_defined
# function prototype or function definition.
sp_after_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between the pointer star '*' and the name of the variable
+# in a function pointer definition.
+sp_ptr_star_func_var = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space after a pointer star '*', if followed by an open
# parenthesis, as in 'void* (*)()'.
sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined
@@ -311,19 +315,33 @@ sp_permit_cpp11_shift = false # true/false
# 'while', etc.).
sp_before_sparen = force # ignore/add/remove/force/not_defined
-# Add or remove space inside '(' and ')' of control statements.
+# Add or remove space inside '(' and ')' of control statements other than
+# 'for'.
sp_inside_sparen = remove # ignore/add/remove/force/not_defined
-# Add or remove space after '(' of control statements.
+# Add or remove space after '(' of control statements other than 'for'.
#
# Overrides sp_inside_sparen.
sp_inside_sparen_open = remove # ignore/add/remove/force/not_defined
-# Add or remove space before ')' of control statements.
+# Add or remove space before ')' of control statements other than 'for'.
#
# Overrides sp_inside_sparen.
sp_inside_sparen_close = ignore # ignore/add/remove/force/not_defined
+# Add or remove space inside '(' and ')' of 'for' statements.
+sp_inside_for = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after '(' of 'for' statements.
+#
+# Overrides sp_inside_for.
+sp_inside_for_open = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before ')' of 'for' statements.
+#
+# Overrides sp_inside_for.
+sp_inside_for_close = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space between '((' or '))' of control statements.
sp_sparen_paren = ignore # ignore/add/remove/force/not_defined
@@ -334,10 +352,10 @@ sp_after_sparen = ignore # ignore/add/remove/force/not_defined
sp_sparen_brace = ignore # ignore/add/remove/force/not_defined
# Add or remove space between 'do' and '{'.
-sp_do_brace_open = ignore # ignore/add/remove/force/not_defined
+sp_do_brace_open = force # ignore/add/remove/force/not_defined
# Add or remove space between '}' and 'while'.
-sp_brace_close_while = ignore # ignore/add/remove/force/not_defined
+sp_brace_close_while = force # ignore/add/remove/force/not_defined
# Add or remove space between 'while' and '('. Overrides sp_before_sparen.
sp_while_paren_open = ignore # ignore/add/remove/force/not_defined
@@ -354,18 +372,18 @@ sp_special_semi = ignore # ignore/add/remove/force/not_defined
# Add or remove space before ';'.
#
# Default: remove
-sp_before_semi = ignore # ignore/add/remove/force/not_defined
+sp_before_semi = remove # ignore/add/remove/force/not_defined
# Add or remove space before ';' in non-empty 'for' statements.
-sp_before_semi_for = ignore # ignore/add/remove/force/not_defined
+sp_before_semi_for = remove # ignore/add/remove/force/not_defined
# Add or remove space before a semicolon of an empty left part of a for
# statement, as in 'for ( <here> ; ; )'.
-sp_before_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+sp_before_semi_for_empty = remove # ignore/add/remove/force/not_defined
# Add or remove space between the semicolons of an empty middle part of a for
# statement, as in 'for ( ; <here> ; )'.
-sp_between_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+sp_between_semi_for_empty = remove # ignore/add/remove/force/not_defined
# Add or remove space after ';', except when followed by a comment.
#
@@ -379,10 +397,10 @@ sp_after_semi_for = force # ignore/add/remove/force/not_defined
# Add or remove space after the final semicolon of an empty part of a for
# statement, as in 'for ( ; ; <here> )'.
-sp_after_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+sp_after_semi_for_empty = remove # ignore/add/remove/force/not_defined
# Add or remove space before '[' (except '[]').
-sp_before_square = ignore # ignore/add/remove/force/not_defined
+sp_before_square = remove # ignore/add/remove/force/not_defined
# Add or remove space before '[' for a variable definition.
#
@@ -393,13 +411,13 @@ sp_before_vardef_square = remove # ignore/add/remove/force/not_defined
sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined
# Add or remove space before '[]'.
-sp_before_squares = ignore # ignore/add/remove/force/not_defined
+sp_before_squares = remove # ignore/add/remove/force/not_defined
# Add or remove space before C++17 structured bindings.
sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined
# Add or remove space inside a non-empty '[' and ']'.
-sp_inside_square = ignore # ignore/add/remove/force/not_defined
+sp_inside_square = remove # ignore/add/remove/force/not_defined
# Add or remove space inside '[]'.
sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined
@@ -592,18 +610,18 @@ sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined
# Add or remove space inside empty function '()'.
# Overrides sp_after_angle unless use_sp_after_angle_always is set to true.
-sp_inside_fparens = ignore # ignore/add/remove/force/not_defined
+sp_inside_fparens = remove # ignore/add/remove/force/not_defined
# Add or remove space inside function '(' and ')'.
-sp_inside_fparen = ignore # ignore/add/remove/force/not_defined
+sp_inside_fparen = remove # ignore/add/remove/force/not_defined
# Add or remove space inside the first parentheses in a function type, as in
# 'void (*x)(...)'.
-sp_inside_tparen = ignore # ignore/add/remove/force/not_defined
+sp_inside_tparen = remove # ignore/add/remove/force/not_defined
# Add or remove space between the ')' and '(' in a function type, as in
# 'void (*x)(...)'.
-sp_after_tparen_close = ignore # ignore/add/remove/force/not_defined
+sp_after_tparen_close = remove # ignore/add/remove/force/not_defined
# Add or remove space between ']' and '(' when part of a function call.
sp_square_fparen = ignore # ignore/add/remove/force/not_defined
@@ -648,8 +666,13 @@ sp_func_class_paren = ignore # ignore/add/remove/force/not_defined
# and '()'.
sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined
+# Add or remove space after 'return'.
+#
+# Default: force
+sp_return = force # ignore/add/remove/force/not_defined
+
# Add or remove space between 'return' and '('.
-sp_return_paren = ignore # ignore/add/remove/force/not_defined
+sp_return_paren = force # ignore/add/remove/force/not_defined
# Add or remove space between 'return' and '{'.
sp_return_brace = ignore # ignore/add/remove/force/not_defined
@@ -714,7 +737,7 @@ sp_else_brace = add # ignore/add/remove/force/not_defined
sp_brace_else = add # ignore/add/remove/force/not_defined
# Add or remove space between '}' and the name of a typedef on the same line.
-sp_brace_typedef = ignore # ignore/add/remove/force/not_defined
+sp_brace_typedef = force # ignore/add/remove/force/not_defined
# Add or remove space before the '{' of a 'catch' statement, if the '{' and
# 'catch' are on the same line, as in 'catch (decl) <here> {'.
@@ -971,11 +994,31 @@ sp_inside_newop_paren_open = ignore # ignore/add/remove/force/not_defined
# Overrides sp_inside_newop_paren.
sp_inside_newop_paren_close = ignore # ignore/add/remove/force/not_defined
-# Add or remove space before a trailing or embedded comment.
-sp_before_tr_emb_cmt = add # ignore/add/remove/force/not_defined
+# Add or remove space before a trailing comment.
+sp_before_tr_cmt = add # ignore/add/remove/force/not_defined
+
+# Number of spaces before a trailing comment.
+sp_num_before_tr_cmt = 2 # unsigned number
+
+# Add or remove space before an embedded comment.
+#
+# Default: force
+sp_before_emb_cmt = force # ignore/add/remove/force/not_defined
+
+# Number of spaces before an embedded comment.
+#
+# Default: 1
+sp_num_before_emb_cmt = 1 # unsigned number
+
+# Add or remove space after an embedded comment.
+#
+# Default: force
+sp_after_emb_cmt = force # ignore/add/remove/force/not_defined
-# Number of spaces before a trailing or embedded comment.
-sp_num_before_tr_emb_cmt = 2 # unsigned number
+# Number of spaces after an embedded comment.
+#
+# Default: 1
+sp_num_after_emb_cmt = 1 # unsigned number
# (Java) Add or remove space between an annotation and the open parenthesis.
sp_annotation_paren = ignore # ignore/add/remove/force/not_defined
@@ -1216,12 +1259,16 @@ indent_sparen_extra = 0 # number
indent_relative_single_line_comments = true # true/false
# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns.
-# It might wise to choose the same value for the option indent_case_brace.
+# It might be wise to choose the same value for the option indent_case_brace.
indent_switch_case = 0 # unsigned number
+# Spaces to indent the body of a 'switch' before any 'case'.
+# Usually the same as indent_columns or indent_switch_case.
+indent_switch_body = 0 # unsigned number
+
# Spaces to indent '{' from 'case'. By default, the brace will appear under
# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK.
-# It might wise to choose the same value for the option indent_switch_case.
+# It might be wise to choose the same value for the option indent_switch_case.
indent_case_brace = 0 # number
# indent 'break' with 'case' from 'switch'.
@@ -1236,13 +1283,31 @@ indent_switch_pp = true # true/false
# Usually 0.
indent_case_shift = 0 # unsigned number
+# Whether to align comments before 'case' with the 'case'.
+#
+# Default: true
+indent_case_comment = true # true/false
+
+# Whether to indent comments not found in first column.
+#
+# Default: true
+indent_comment = true # true/false
+
# Whether to indent comments found in first column.
indent_col1_comment = false # true/false
# Whether to indent multi string literal in first column.
indent_col1_multi_string_literal = false # true/false
-# How to indent goto labels.
+# Align comments on adjacent lines that are this many columns apart or less.
+#
+# Default: 3
+indent_comment_align_thresh = 3 # unsigned number
+
+# Whether to ignore indent for goto labels.
+indent_ignore_label = false # true/false
+
+# How to indent goto labels. Requires indent_ignore_label=false.
#
# >0: Absolute column where 1 is the leftmost column
# <=0: Subtract from brace indent
@@ -1414,7 +1479,7 @@ indent_using_block = true # true/false
# 0: Off (default)
# 1: When the `if_false` is a continuation, indent it under `if_false`
# 2: When the `:` is a continuation, indent it under `?`
-indent_ternary_operator = 2 # unsigned number
+indent_ternary_operator = 0 # unsigned number
# Whether to indent the statements inside ternary operator.
indent_inside_ternary_operator = false # true/false
@@ -1632,7 +1697,7 @@ nl_using_brace = ignore # ignore/add/remove/force/not_defined
nl_brace_brace = ignore # ignore/add/remove/force/not_defined
# Add or remove newline between 'do' and '{'.
-nl_do_brace = ignore # ignore/add/remove/force/not_defined
+nl_do_brace = remove # ignore/add/remove/force/not_defined
# Add or remove newline between '}' and 'while' of 'do' statement.
nl_brace_while = ignore # ignore/add/remove/force/not_defined
@@ -2333,7 +2398,7 @@ pos_arith = ignore # ignore/break/force/lead/trail/join/
pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
# The position of Boolean operators in wrapped expressions.
-pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+pos_bool = lead # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
# The position of comparison operators in wrapped expressions.
pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
@@ -2622,6 +2687,22 @@ align_right_cmt_at_col = 0 # unsigned number
# 0: Don't align (default).
align_func_proto_span = 0 # unsigned number
+# How to consider (or treat) the '*' in the alignment of function prototypes.
+#
+# 0: Part of the type 'void * foo();' (default)
+# 1: Part of the function 'void *foo();'
+# 2: Dangling 'void *foo();'
+# Dangling: the '*' will not be taken into account when aligning.
+align_func_proto_star_style = 0 # unsigned number
+
+# How to consider (or treat) the '&' in the alignment of function prototypes.
+#
+# 0: Part of the type 'long & foo();' (default)
+# 1: Part of the function 'long &foo();'
+# 2: Dangling 'long &foo();'
+# Dangling: the '&' will not be taken into account when aligning.
+align_func_proto_amp_style = 0 # unsigned number
+
# The threshold for aligning function prototypes.
# Use a negative number for absolute thresholds.
#
@@ -3101,6 +3182,9 @@ pp_indent_in_guard = false # true/false
# indented from column 1.
pp_define_at_level = false # true/false
+# Whether to indent '#include' at the brace level.
+pp_include_at_level = false # true/false
+
# Whether to ignore the '#define' body while formatting.
pp_ignore_define_body = false # true/false
@@ -3307,5 +3391,5 @@ set QUESTION REAL_FATTR_CONST
set QUESTION REAL_FATTR_NONNULL_ALL
set QUESTION REAL_FATTR_PURE
set QUESTION REAL_FATTR_WARN_UNUSED_RESULT
-# option(s) with 'not default' value: 69
+# option(s) with 'not default' value: 86
#