aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-format8
-rw-r--r--src/nvim/CMakeLists.txt53
-rw-r--r--src/nvim/api/buffer.c179
-rw-r--r--src/nvim/api/private/defs.h1
-rw-r--r--src/nvim/api/private/helpers.c36
-rw-r--r--src/nvim/api/tabpage.c29
-rw-r--r--src/nvim/api/vim.c34
-rw-r--r--src/nvim/api/window.c33
-rw-r--r--src/nvim/arabic.c18
-rw-r--r--src/nvim/assert.h108
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer.c286
-rw-r--r--src/nvim/buffer_defs.h64
-rw-r--r--src/nvim/charset.c107
-rw-r--r--src/nvim/diff.c68
-rw-r--r--src/nvim/edit.c921
-rw-r--r--src/nvim/edit.h6
-rw-r--r--src/nvim/eval.c2899
-rw-r--r--src/nvim/eval.h46
-rw-r--r--src/nvim/eval/decode.c1116
-rw-r--r--src/nvim/eval/decode.h13
-rw-r--r--src/nvim/eval/encode.c1296
-rw-r--r--src/nvim/eval/encode.h75
-rw-r--r--src/nvim/eval_defs.h84
-rw-r--r--src/nvim/event/process.c6
-rw-r--r--src/nvim/ex_cmds.c348
-rw-r--r--src/nvim/ex_cmds.lua12
-rw-r--r--src/nvim/ex_cmds2.c397
-rw-r--r--src/nvim/ex_docmd.c273
-rw-r--r--src/nvim/ex_docmd.h14
-rw-r--r--src/nvim/ex_eval.c107
-rw-r--r--src/nvim/ex_getln.c163
-rw-r--r--src/nvim/ex_getln.h12
-rw-r--r--src/nvim/farsi.c31
-rw-r--r--src/nvim/file_search.c8
-rw-r--r--src/nvim/fileio.c254
-rw-r--r--src/nvim/fold.c33
-rw-r--r--src/nvim/garray.c19
-rw-r--r--src/nvim/getchar.c192
-rw-r--r--src/nvim/globals.h30
-rw-r--r--src/nvim/hardcopy.c34
-rw-r--r--src/nvim/if_cscope.c18
-rw-r--r--src/nvim/indent.c2
-rw-r--r--src/nvim/indent_c.c13
-rw-r--r--src/nvim/keymap.c178
-rw-r--r--src/nvim/keymap.h10
-rw-r--r--src/nvim/lib/kvec.h1
-rw-r--r--src/nvim/macros.h11
-rw-r--r--src/nvim/main.c32
-rw-r--r--src/nvim/mbyte.c47
-rw-r--r--src/nvim/memfile.c144
-rw-r--r--src/nvim/memline.c14
-rw-r--r--src/nvim/menu.c10
-rw-r--r--src/nvim/message.c302
-rw-r--r--src/nvim/message.h51
-rw-r--r--src/nvim/misc1.c536
-rw-r--r--src/nvim/misc1.h1
-rw-r--r--src/nvim/misc2.c5
-rw-r--r--src/nvim/mouse.c94
-rw-r--r--src/nvim/mouse.h6
-rw-r--r--src/nvim/move.c9
-rw-r--r--src/nvim/msgpack_rpc/helpers.c4
-rw-r--r--src/nvim/msgpack_rpc/remote_ui.c12
-rw-r--r--src/nvim/msgpack_rpc/server.c4
-rw-r--r--src/nvim/normal.c394
-rw-r--r--src/nvim/normal.h15
-rw-r--r--src/nvim/ops.c729
-rw-r--r--src/nvim/ops.h8
-rw-r--r--src/nvim/option.c224
-rw-r--r--src/nvim/option_defs.h67
-rw-r--r--src/nvim/options.lua15
-rw-r--r--src/nvim/os/env.c127
-rw-r--r--src/nvim/os/fs.c104
-rw-r--r--src/nvim/os/fs_defs.h6
-rw-r--r--src/nvim/os/input.c11
-rw-r--r--src/nvim/os/mem.c2
-rw-r--r--src/nvim/os/stdpaths.c15
-rw-r--r--src/nvim/os/win_defs.h5
-rw-r--r--src/nvim/os_unix.c27
-rw-r--r--src/nvim/os_unix.h6
-rw-r--r--src/nvim/path.c372
-rw-r--r--src/nvim/path.h4
-rw-r--r--src/nvim/po/CMakeLists.txt4
-rw-r--r--src/nvim/po/eo.po50
-rw-r--r--src/nvim/po/es.po3
-rw-r--r--src/nvim/po/fr.po160
-rw-r--r--src/nvim/po/it.po502
-rw-r--r--src/nvim/pos.h6
-rw-r--r--src/nvim/quickfix.c367
-rw-r--r--src/nvim/regexp.c25
-rw-r--r--src/nvim/regexp_nfa.c505
-rw-r--r--src/nvim/screen.c142
-rw-r--r--src/nvim/search.c229
-rw-r--r--src/nvim/search.h27
-rw-r--r--src/nvim/shada.c148
-rw-r--r--src/nvim/spell.c14
-rw-r--r--src/nvim/syntax.c171
-rw-r--r--src/nvim/syntax_defs.h4
-rw-r--r--src/nvim/tag.c61
-rw-r--r--src/nvim/tempfile.c138
-rw-r--r--src/nvim/tempfile.h8
-rw-r--r--src/nvim/terminal.c29
-rw-r--r--src/nvim/testdir/Makefile12
-rw-r--r--src/nvim/testdir/runtest.vim25
-rw-r--r--src/nvim/testdir/test17.in26
-rw-r--r--src/nvim/testdir/test49.in4
-rw-r--r--src/nvim/testdir/test49.ok15
-rw-r--r--src/nvim/testdir/test49.vim851
-rw-r--r--src/nvim/testdir/test68.in131
-rw-r--r--src/nvim/testdir/test68.ok77
-rw-r--r--src/nvim/testdir/test88.in99
-rw-r--r--src/nvim/testdir/test88.ok29
-rw-r--r--src/nvim/testdir/test_alot.vim3
-rw-r--r--src/nvim/testdir/test_cursor_func.vim52
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim40
-rw-r--r--src/nvim/testdir/test_marks.in34
-rw-r--r--src/nvim/testdir/test_marks.ok16
-rw-r--r--src/nvim/testdir/test_menu.vim9
-rw-r--r--src/nvim/testdir/test_viml.vim930
-rw-r--r--src/nvim/tui/input.c12
-rw-r--r--src/nvim/tui/tui.c16
-rw-r--r--src/nvim/ugrid.h2
-rw-r--r--src/nvim/ui.c7
-rw-r--r--src/nvim/ui.h3
-rw-r--r--src/nvim/ui_bridge.c11
-rw-r--r--src/nvim/undo.c17
-rw-r--r--src/nvim/version.c642
-rw-r--r--src/nvim/vim.h40
-rw-r--r--src/nvim/window.c67
129 files changed, 11123 insertions, 7689 deletions
diff --git a/src/.clang-format b/src/.clang-format
index 35e545ac4b..5a910ff34b 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -1,4 +1,4 @@
-BasedOnStyle: llvm
+BasedOnStyle: Google
Language: Cpp
ColumnLimit: 80
IndentWidth: 2
@@ -10,3 +10,9 @@ AlignEscapedNewlinesLeft: false
AllowShortFunctionsOnASingleLine: false
SpacesBeforeTrailingComments: 2
PenaltyReturnTypeOnItsOwnLine: 200
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+BinPackParameters: false
+BreakBeforeBinaryOperators: true
+ContinuationIndentWidth: 4
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index ea5125e4e7..6b2ce08d36 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -1,4 +1,5 @@
include(CheckLibraryExists)
+include(CheckCCompilerFlag)
option(USE_GCOV "Enable gcov support" OFF)
@@ -41,25 +42,33 @@ include_directories(${GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR})
-file(MAKE_DIRECTORY ${GENERATED_DIR}/os)
-file(MAKE_DIRECTORY ${GENERATED_DIR}/api)
-file(MAKE_DIRECTORY ${GENERATED_DIR}/api/private)
-file(MAKE_DIRECTORY ${GENERATED_DIR}/msgpack_rpc)
-file(MAKE_DIRECTORY ${GENERATED_DIR}/tui)
-file(MAKE_DIRECTORY ${GENERATED_DIR}/event)
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/os)
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api)
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/api/private)
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/msgpack_rpc)
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/tui)
-file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/event)
-
-file(GLOB NEOVIM_SOURCES *.c os/*.c api/*.c api/private/*.c msgpack_rpc/*.c
- tui/*.c event/*.c)
+
+file(GLOB NEOVIM_SOURCES *.c)
+
+foreach(subdir
+ os
+ api
+ api/private
+ msgpack_rpc
+ tui
+ event
+ eval
+ )
+ file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
+ file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
+ file(GLOB sources ${subdir}/*.c)
+ list(APPEND NEOVIM_SOURCES ${sources})
+endforeach()
+
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
+# Sort file lists to ensure generated files are created in the same order from
+# build to build.
+list(SORT NEOVIM_SOURCES)
+list(SORT NEOVIM_HEADERS)
+
foreach(sfile ${NEOVIM_SOURCES})
get_filename_component(f ${sfile} NAME)
if(${f} MATCHES "^(regexp_nfa.c)$")
@@ -72,23 +81,17 @@ list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove})
# Handle legacy files that don't yet pass -Wconversion.
set(CONV_SOURCES
buffer.c
- charset.c
diff.c
edit.c
eval.c
- ex_cmds2.c
ex_cmds.c
ex_docmd.c
ex_getln.c
fileio.c
- getchar.c
mbyte.c
memline.c
message.c
- misc1.c
ops.c
- path.c
- quickfix.c
regexp.c
screen.c
search.c
@@ -256,8 +259,14 @@ install_helper(TARGETS nvim)
if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
+ check_c_compiler_flag(-fno-sanitize-recover=all SANITIZE_RECOVER_ALL)
+ if(SANITIZE_RECOVER_ALL)
+ set(SANITIZE_RECOVER -fno-sanitize-recover=all) # Clang 3.6+
+ else()
+ set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
+ endif()
set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-sanitize-recover -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
+ set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ")
elseif(CLANG_MSAN)
message(STATUS "Enabling Clang memory sanitizer for nvim.")
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index fa4b8e5f7d..55b535c78c 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -45,14 +45,22 @@ Integer buffer_line_count(Buffer buffer, Error *err)
/// Gets a buffer line
///
+/// @deprecated use buffer_get_lines instead.
+/// for positive indices (including 0) use
+/// "buffer_get_lines(buffer, index, index+1, true)"
+/// for negative indices use
+/// "buffer_get_lines(buffer, index-1, index, true)"
+///
/// @param buffer The buffer handle
/// @param index The line index
/// @param[out] err Details of an error that may have occurred
/// @return The line string
String buffer_get_line(Buffer buffer, Integer index, Error *err)
{
- String rv = {.size = 0};
- Array slice = buffer_get_line_slice(buffer, index, index, true, true, err);
+ String rv = { .size = 0 };
+
+ index = convert_index(index);
+ Array slice = buffer_get_lines(buffer, index, index+1, true, err);
if (!err->set && slice.size) {
rv = slice.items[0].data.string;
@@ -65,6 +73,12 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// Sets a buffer line
///
+/// @deprecated use buffer_set_lines instead.
+/// for positive indices use
+/// "buffer_set_lines(buffer, index, index+1, true, [line])"
+/// for negative indices use
+/// "buffer_set_lines(buffer, index-1, index, true, [line])"
+///
/// @param buffer The buffer handle
/// @param index The line index
/// @param line The new line.
@@ -72,23 +86,34 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
{
Object l = STRING_OBJ(line);
- Array array = {.items = &l, .size = 1};
- buffer_set_line_slice(buffer, index, index, true, true, array, err);
+ Array array = { .items = &l, .size = 1 };
+ index = convert_index(index);
+ buffer_set_lines(buffer, index, index+1, true, array, err);
}
/// Deletes a buffer line
///
+/// @deprecated use buffer_set_lines instead.
+/// for positive indices use
+/// "buffer_set_lines(buffer, index, index+1, true, [])"
+/// for negative indices use
+/// "buffer_set_lines(buffer, index-1, index, true, [])"
/// @param buffer The buffer handle
/// @param index The line index
/// @param[out] err Details of an error that may have occurred
void buffer_del_line(Buffer buffer, Integer index, Error *err)
{
Array array = ARRAY_DICT_INIT;
- buffer_set_line_slice(buffer, index, index, true, true, array, err);
+ index = convert_index(index);
+ buffer_set_lines(buffer, index, index+1, true, array, err);
}
/// Retrieves a line range from the buffer
///
+/// @deprecated use buffer_get_lines(buffer, newstart, newend, false)
+/// where newstart = start + int(not include_start) - int(start < 0)
+/// newend = end + int(include_end) - int(end < 0)
+/// int(bool) = 1 if bool is true else 0
/// @param buffer The buffer handle
/// @param start The first line index
/// @param end The last line index
@@ -103,16 +128,48 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
Boolean include_end,
Error *err)
{
+ start = convert_index(start) + !include_start;
+ end = convert_index(end) + include_end;
+ return buffer_get_lines(buffer, start , end, false, err);
+}
+
+
+/// Retrieves a line range from the buffer
+///
+/// Indexing is zero-based, end-exclusive. Negative indices are interpreted
+/// as length+1+index, i e -1 refers to the index past the end. So to get the
+/// last element set start=-2 and end=-1.
+///
+/// Out-of-bounds indices are clamped to the nearest valid value, unless
+/// `strict_indexing` is set.
+///
+/// @param buffer The buffer handle
+/// @param start The first line index
+/// @param end The last line index (exclusive)
+/// @param strict_indexing whether out-of-bounds should be an error.
+/// @param[out] err Details of an error that may have occurred
+/// @return An array of lines
+ArrayOf(String) buffer_get_lines(Buffer buffer,
+ Integer start,
+ Integer end,
+ Boolean strict_indexing,
+ Error *err)
+{
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
- if (!buf || !inbounds(buf, start)) {
+ if (!buf) {
return rv;
}
- start = normalize_index(buf, start) + (include_start ? 0 : 1);
- include_end = include_end || (end >= buf->b_ml.ml_line_count);
- end = normalize_index(buf, end) + (include_end ? 1 : 0);
+ bool oob = false;
+ start = normalize_index(buf, start, &oob);
+ end = normalize_index(buf, end, &oob);
+
+ if (strict_indexing && oob) {
+ api_set_error(err, Validation, _("Index out of bounds"));
+ return rv;
+ }
if (start >= end) {
// Return 0-length array
@@ -152,8 +209,14 @@ end:
return rv;
}
+
/// Replaces a line range on the buffer
///
+/// @deprecated use buffer_set_lines(buffer, newstart, newend, false, lines)
+/// where newstart = start + int(not include_start) + int(start < 0)
+/// newend = end + int(include_end) + int(end < 0)
+/// int(bool) = 1 if bool is true else 0
+///
/// @param buffer The buffer handle
/// @param start The first line index
/// @param end The last line index
@@ -170,20 +233,52 @@ void buffer_set_line_slice(Buffer buffer,
ArrayOf(String) replacement,
Error *err)
{
+ start = convert_index(start) + !include_start;
+ end = convert_index(end) + include_end;
+ buffer_set_lines(buffer, start, end, false, replacement, err);
+}
+
+
+/// Replaces line range on the buffer
+///
+/// Indexing is zero-based, end-exclusive. Negative indices are interpreted
+/// as length+1+index, i e -1 refers to the index past the end. So to change
+/// or delete the last element set start=-2 and end=-1.
+///
+/// To insert lines at a given index, set both start and end to the same index.
+/// To delete a range of lines, set replacement to an empty array.
+///
+/// Out-of-bounds indices are clamped to the nearest valid value, unless
+/// `strict_indexing` is set.
+///
+/// @param buffer The buffer handle
+/// @param start The first line index
+/// @param end The last line index (exclusive)
+/// @param strict_indexing whether out-of-bounds should be an error.
+/// @param replacement An array of lines to use as replacement
+/// @param[out] err Details of an error that may have occurred
+void buffer_set_lines(Buffer buffer,
+ Integer start,
+ Integer end,
+ Boolean strict_indexing,
+ ArrayOf(String) replacement,
+ Error *err)
+{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return;
}
- if (!inbounds(buf, start)) {
+ bool oob = false;
+ start = normalize_index(buf, start, &oob);
+ end = normalize_index(buf, end, &oob);
+
+ if (strict_indexing && oob) {
api_set_error(err, Validation, _("Index out of bounds"));
return;
}
- start = normalize_index(buf, start) + (include_start ? 0 : 1);
- include_end = include_end || (end >= buf->b_ml.ml_line_count);
- end = normalize_index(buf, end) + (include_end ? 1 : 0);
if (start > end) {
api_set_error(err,
@@ -328,13 +423,16 @@ Object buffer_get_var(Buffer buffer, String name, Error *err)
return dict_get_value(buf->b_vars, name, err);
}
-/// Sets a buffer-scoped (b:) variable. 'nil' value deletes the variable.
+/// Sets a buffer-scoped (b:) variable
///
/// @param buffer The buffer handle
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
-/// @return The old value
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -343,7 +441,27 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
return (Object) OBJECT_INIT;
}
- return dict_set_value(buf->b_vars, name, value, err);
+ return dict_set_value(buf->b_vars, name, value, false, err);
+}
+
+/// Removes a buffer-scoped (b:) variable
+///
+/// @param buffer The buffer handle
+/// @param name The variable name
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
+Object buffer_del_var(Buffer buffer, String name, Error *err)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+
+ if (!buf) {
+ return (Object) OBJECT_INIT;
+ }
+
+ return dict_set_value(buf->b_vars, name, NIL, true, err);
}
/// Gets a buffer option value
@@ -457,6 +575,8 @@ Boolean buffer_is_valid(Buffer buffer)
/// Inserts a sequence of lines to a buffer at a certain index
///
+/// @deprecated use buffer_set_lines(buffer, lnum, lnum, true, lines)
+///
/// @param buffer The buffer handle
/// @param lnum Insert the lines after `lnum`. If negative, it will append
/// to the end of the buffer.
@@ -467,8 +587,9 @@ void buffer_insert(Buffer buffer,
ArrayOf(String) lines,
Error *err)
{
- bool end_start = lnum < 0;
- buffer_set_line_slice(buffer, lnum, lnum, !end_start, end_start, lines, err);
+ // "lnum" will be the index of the line after inserting,
+ // no matter if it is negative or not
+ buffer_set_lines(buffer, lnum, lnum, true, lines, err);
}
/// Return a tuple (row,col) representing the position of the named mark
@@ -632,20 +753,26 @@ static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
}
// Normalizes 0-based indexes to buffer line numbers
-static int64_t normalize_index(buf_T *buf, int64_t index)
+static int64_t normalize_index(buf_T *buf, int64_t index, bool *oob)
{
+ int64_t line_count = buf->b_ml.ml_line_count;
// Fix if < 0
- index = index < 0 ? buf->b_ml.ml_line_count + index : index;
+ index = index < 0 ? line_count + index +1 : index;
+
+ // Check for oob
+ if (index > line_count) {
+ *oob = true;
+ index = line_count;
+ } else if (index < 0) {
+ *oob = true;
+ index = 0;
+ }
// Convert the index to a vim line number
index++;
- // Fix if > line_count
- index = index > buf->b_ml.ml_line_count ? buf->b_ml.ml_line_count : index;
return index;
}
-// Returns true if the 0-indexed `index` is within the 1-indexed buffer bounds.
-static bool inbounds(buf_T *buf, int64_t index)
+static int64_t convert_index(int64_t index)
{
- linenr_T nlines = buf->b_ml.ml_line_count;
- return index >= -nlines && index < nlines;
+ return index < 0 ? index - 1 : index;
}
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index 6c8e324649..fbfa87d5ae 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -99,4 +99,3 @@ struct key_value_pair {
#endif // NVIM_API_PRIVATE_DEFS_H
-
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 7a0b5191d7..db3e499427 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -90,14 +90,17 @@ Object dict_get_value(dict_T *dict, String key, Error *err)
}
/// Set a value in a dict. Objects are recursively expanded into their
-/// vimscript equivalents. Passing 'nil' as value deletes the key.
+/// vimscript equivalents.
///
/// @param dict The vimscript dict
/// @param key The key
/// @param value The new value
+/// @param del Delete key in place of setting it. Argument `value` is ignored in
+/// this case.
/// @param[out] err Details of an error that may have occurred
/// @return the old value, if any
-Object dict_set_value(dict_T *dict, String key, Object value, Error *err)
+Object dict_set_value(dict_T *dict, String key, Object value, bool del,
+ Error *err)
{
Object rv = OBJECT_INIT;
@@ -118,7 +121,7 @@ Object dict_set_value(dict_T *dict, String key, Object value, Error *err)
dictitem_T *di = dict_find(dict, (uint8_t *)key.data, (int)key.size);
- if (value.type == kObjectTypeNil) {
+ if (del) {
// Delete the key
if (di == NULL) {
// Doesn't exist, fail
@@ -397,13 +400,13 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
switch (obj.type) {
case kObjectTypeNil:
- tv->v_type = VAR_NUMBER;
- tv->vval.v_number = 0;
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_special = kSpecialVarNull;
break;
case kObjectTypeBoolean:
- tv->v_type = VAR_NUMBER;
- tv->vval.v_number = obj.data.boolean;
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_special = obj.data.boolean? kSpecialVarTrue: kSpecialVarFalse;
break;
case kObjectTypeBuffer:
@@ -651,6 +654,21 @@ static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup)
}
switch (obj->v_type) {
+ case VAR_SPECIAL:
+ switch (obj->vval.v_special) {
+ case kSpecialVarTrue:
+ case kSpecialVarFalse: {
+ rv.type = kObjectTypeBoolean;
+ rv.data.boolean = (obj->vval.v_special == kSpecialVarTrue);
+ break;
+ }
+ case kSpecialVarNull: {
+ rv.type = kObjectTypeNil;
+ break;
+ }
+ }
+ break;
+
case VAR_STRING:
rv.type = kObjectTypeString;
rv.data.string = cstr_to_string((char *) obj->vval.v_string);
@@ -730,6 +748,10 @@ static Object vim_to_object_rec(typval_T *obj, PMap(ptr_t) *lookup)
}
}
break;
+
+ case VAR_UNKNOWN:
+ case VAR_FUNC:
+ break;
}
return rv;
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 126ee4072d..c8311b0aa0 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -54,13 +54,16 @@ Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
return dict_get_value(tab->tp_vars, name, err);
}
-/// Sets a tab-scoped (t:) variable. 'nil' value deletes the variable.
+/// Sets a tab-scoped (t:) variable
///
/// @param tabpage handle
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
-/// @return The tab page handle
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@@ -69,7 +72,27 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
return (Object) OBJECT_INIT;
}
- return dict_set_value(tab->tp_vars, name, value, err);
+ return dict_set_value(tab->tp_vars, name, value, false, err);
+}
+
+/// Removes a tab-scoped (t:) variable
+///
+/// @param tabpage handle
+/// @param name The variable name
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
+Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
+{
+ tabpage_T *tab = find_tab_by_handle(tabpage, err);
+
+ if (!tab) {
+ return (Object) OBJECT_INIT;
+ }
+
+ return dict_set_value(tab->tp_vars, name, NIL, true, err);
}
/// Gets the current window in a tab page
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 9279f6b469..46ac3c9022 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -116,8 +116,14 @@ String vim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
}
char *ptr = NULL;
- replace_termcodes((char_u *)str.data, (char_u **)&ptr,
- from_part, do_lt, special);
+ // Set 'cpoptions' the way we want it.
+ // FLAG_CPO_BSLASH set - backslashes are *not* treated specially
+ // FLAG_CPO_KEYCODE set - keycodes are *not* reverse-engineered
+ // FLAG_CPO_SPECI unset - <Key> sequences *are* interpreted
+ // The third from end parameter of replace_termcodes() is true so that the
+ // <lt> sequence is recognised - needed for a real backslash.
+ replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr,
+ from_part, do_lt, special, CPO_TO_CPO_FLAGS);
return cstr_as_string(ptr);
}
@@ -291,7 +297,7 @@ void vim_change_directory(String dir, Error *err)
return;
}
- post_chdir(false);
+ post_chdir(kCdScopeGlobal);
try_end(err);
}
@@ -331,15 +337,31 @@ Object vim_get_var(String name, Error *err)
return dict_get_value(&globvardict, name, err);
}
-/// Sets a global variable. Passing 'nil' as value deletes the variable.
+/// Sets a global variable
///
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
-/// @return the old value if any
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
Object vim_set_var(String name, Object value, Error *err)
{
- return dict_set_value(&globvardict, name, value, err);
+ return dict_set_value(&globvardict, name, value, false, err);
+}
+
+/// Removes a global variable
+///
+/// @param name The variable name
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
+Object vim_del_var(String name, Error *err)
+{
+ return dict_set_value(&globvardict, name, NIL, true, err);
}
/// Gets a vim variable
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index aad616c7bf..f644453358 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -57,8 +57,8 @@ void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
{
win_T *win = find_window_by_handle(window, err);
- if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger ||
- pos.items[1].type != kObjectTypeInteger) {
+ if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger
+ || pos.items[1].type != kObjectTypeInteger) {
api_set_error(err,
Validation,
_("Argument \"pos\" must be a [row, col] array"));
@@ -197,13 +197,16 @@ Object window_get_var(Window window, String name, Error *err)
return dict_get_value(win->w_vars, name, err);
}
-/// Sets a window-scoped (w:) variable. 'nil' value deletes the variable.
+/// Sets a window-scoped (w:) variable
///
/// @param window The window handle
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
-/// @return The old value
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
Object window_set_var(Window window, String name, Object value, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@@ -212,7 +215,27 @@ Object window_set_var(Window window, String name, Object value, Error *err)
return (Object) OBJECT_INIT;
}
- return dict_set_value(win->w_vars, name, value, err);
+ return dict_set_value(win->w_vars, name, value, false, err);
+}
+
+/// Removes a window-scoped (w:) variable
+///
+/// @param window The window handle
+/// @param name The variable name
+/// @param[out] err Details of an error that may have occurred
+/// @return The old value or nil if there was no previous value.
+///
+/// @warning It may return nil if there was no previous value
+/// or if previous value was `v:null`.
+Object window_del_var(Window window, String name, Error *err)
+{
+ win_T *win = find_window_by_handle(window, err);
+
+ if (!win) {
+ return (Object) OBJECT_INIT;
+ }
+
+ return dict_set_value(win->w_vars, name, NIL, true, err);
}
/// Gets a window option value
diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c
index b432e12c02..db97bd9dc4 100644
--- a/src/nvim/arabic.c
+++ b/src/nvim/arabic.c
@@ -1367,8 +1367,8 @@ int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1,
int prev_laa = A_firstc_laa(prev_c, prev_c1);
if (curr_laa) {
- if (A_is_valid(prev_c) && !A_is_f(shape_c) && !A_is_s(shape_c) &&
- !prev_laa) {
+ if (A_is_valid(prev_c) && !A_is_f(shape_c) && !A_is_s(shape_c)
+ && !prev_laa) {
curr_c = chg_c_laa2f(curr_laa);
} else {
curr_c = chg_c_laa2i(curr_laa);
@@ -1454,19 +1454,19 @@ static bool A_is_harakat(int c)
// (alphabet/number/punctuation)
static bool A_is_iso(int c)
{
- return (c >= a_HAMZA && c <= a_GHAIN) ||
- (c >= a_TATWEEL && c <= a_HAMZA_BELOW) ||
- c == a_MINI_ALEF;
+ return ((c >= a_HAMZA && c <= a_GHAIN)
+ || (c >= a_TATWEEL && c <= a_HAMZA_BELOW)
+ || c == a_MINI_ALEF);
}
// A_is_formb returns true if 'c' is an Arabic 10646-1 FormB character.
// (alphabet/number/punctuation)
static bool A_is_formb(int c)
{
- return (c >= a_s_FATHATAN && c <= a_s_DAMMATAN) ||
- c == a_s_KASRATAN ||
- (c >= a_s_FATHA && c <= a_f_LAM_ALEF) ||
- c == a_BYTE_ORDER_MARK;
+ return ((c >= a_s_FATHATAN && c <= a_s_DAMMATAN)
+ || c == a_s_KASRATAN
+ || (c >= a_s_FATHA && c <= a_f_LAM_ALEF)
+ || c == a_BYTE_ORDER_MARK);
}
// A_is_ok returns true if 'c' is an Arabic 10646 (8859-6 or Form-B).
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index 3a900aca65..761636305e 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -8,17 +8,32 @@
// defined(__has_feature) && __has_feature(...). Therefore we define Clang's
// __has_feature and __has_extension macro's before referring to them.
#ifndef __has_feature
- #define __has_feature(x) 0
+# define __has_feature(x) 0
#endif
#ifndef __has_extension
- #define __has_extension __has_feature
+# define __has_extension __has_feature
#endif
-/// STATIC_ASSERT(condition, message) - assert at compile time if !cond
+/// @def STATIC_ASSERT
+/// @brief Assert at compile time if condition is not satisfied.
///
-/// example:
-/// STATIC_ASSERT(sizeof(void *) == 8, "need 64-bits mode");
+/// Should be put on its own line, followed by a semicolon.
+///
+/// Example:
+///
+/// STATIC_ASSERT(sizeof(void *) == 8, "Expected 64-bit mode");
+///
+/// @param[in] condition Condition to check, should be an integer constant
+/// expression.
+/// @param[in] message Message which will be given if check fails.
+
+/// @def STATIC_ASSERT_EXPR
+/// @brief Like #STATIC_ASSERT, but can be used where expressions are used.
+///
+/// STATIC_ASSERT_EXPR may be put in brace initializer lists. Error message
+/// given in this case is not very nice with the current implementation though
+/// and `message` argument is ignored.
// define STATIC_ASSERT as C11's _Static_assert whenever either C11 mode is
// detected or the compiler is known to support it. Note that Clang in C99
@@ -29,50 +44,81 @@
// clearer messages we get from _Static_assert, we suppress the warnings
// temporarily.
+#define STATIC_ASSERT_PRAGMA_START
+#define STATIC_ASSERT_PRAGMA_END
+#define STATIC_ASSERT(cond, msg) \
+ do { \
+ STATIC_ASSERT_PRAGMA_START \
+ STATIC_ASSERT_STATEMENT(cond, msg); \
+ STATIC_ASSERT_PRAGMA_END \
+ } while (0)
+
// the easiest case, when the mode is C11 (generic compiler) or Clang
// advertises explicit support for c_static_assert, meaning it won't warn.
#if __STDC_VERSION__ >= 201112L || __has_feature(c_static_assert)
- #define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
+# define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
// if we're dealing with gcc >= 4.6 in C99 mode, we can still use
// _Static_assert but we need to suppress warnings, this is pretty ugly.
#elif (!defined(__clang__) && !defined(__INTEL_COMPILER)) && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
- #define STATIC_ASSERT(cond, msg) \
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-pedantic\"") \
- _Static_assert(cond, msg); \
- _Pragma("GCC diagnostic pop") \
+
+# define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
+
+# undef STATIC_ASSERT_PRAGMA_START
+
+#if __GNUC__ >= 6
+# define STATIC_ASSERT_PRAGMA_START \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
+#else
+# define STATIC_ASSERT_PRAGMA_START \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-pedantic\"")
+#endif
+
+# undef STATIC_ASSERT_PRAGMA_END
+# define STATIC_ASSERT_PRAGMA_END \
+ _Pragma("GCC diagnostic pop") \
// the same goes for clang in C99 mode, but we suppress a different warning
#elif defined(__clang__) && __has_extension(c_static_assert)
- #define STATIC_ASSERT(cond, msg) \
- _Pragma("clang diagnostic push") \
- _Pragma("clang diagnostic ignored \"-Wc11-extensions\"") \
- _Static_assert(cond, msg); \
- _Pragma("clang diagnostic pop") \
+
+# define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
+
+# undef STATIC_ASSERT_PRAGMA_START
+# define STATIC_ASSERT_PRAGMA_START \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wc11-extensions\"") \
+
+# undef STATIC_ASSERT_PRAGMA_END
+# define STATIC_ASSERT_PRAGMA_END \
+ _Pragma("clang diagnostic pop") \
// TODO(aktau): verify that this works, don't have MSVC on hand.
#elif _MSC_VER >= 1600
- #define STATIC_ASSERT(cond, msg) static_assert(cond, msg)
+
+# define STATIC_ASSERT_STATEMENT(cond, msg) static_assert(cond, msg)
// fallback for compilers that don't support _Static_assert or static_assert
// not as pretty but gets the job done. Credit goes to Pádraig Brady and
// contributors.
#else
- #define ASSERT_CONCAT_(a, b) a##b
- #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
- // These can't be used after statements in c89.
- #ifdef __COUNTER__
- #define STATIC_ASSERT(e,m) \
- { enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }; }
- #else
- // This can't be used twice on the same line so ensure if using in headers
- // that the headers are not included twice (by wrapping in #ifndef...#endif)
- // Note it doesn't cause an issue when used on same line of separate modules
- // compiled with gcc -combine -fwhole-program.
- #define STATIC_ASSERT(e,m) \
- { enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }; }
- #endif
+# define STATIC_ASSERT_STATEMENT STATIC_ASSERT_EXPR
+#endif
+
+#define ASSERT_CONCAT_(a, b) a##b
+#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)
+// These can't be used after statements in c89.
+#ifdef __COUNTER__
+# define STATIC_ASSERT_EXPR(e, m) \
+ ((enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1/(!!(e)) }) 0)
+#else
+// This can't be used twice on the same line so ensure if using in headers
+// that the headers are not included twice (by wrapping in #ifndef...#endif)
+// Note it doesn't cause an issue when used on same line of separate modules
+// compiled with gcc -combine -fwhole-program.
+# define STATIC_ASSERT_EXPR(e, m) \
+ ((enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }) 0)
#endif
#endif // NVIM_ASSERT_H
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index aa4a8d8332..8d891effae 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -83,6 +83,7 @@ return {
'TermResponse', -- after setting "v:termresponse"
'TextChanged', -- text was modified
'TextChangedI', -- text was modified in Insert mode
+ 'TextYankPost', -- after a yank or delete was done (y, d, c)
'User', -- user defined autocommand
'VimEnter', -- after starting Vim
'VimLeave', -- before exiting Vim
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 62ab7495da..72716daf0e 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -141,14 +141,21 @@ open_buffer (
/* mark cursor position as being invalid */
curwin->w_valid = 0;
- if (curbuf->b_ffname != NULL
- ) {
+ if (curbuf->b_ffname != NULL) {
+ int old_msg_silent = msg_silent;
+ if (shortmess(SHM_FILEINFO)) {
+ msg_silent = 1;
+ }
+
retval = readfile(curbuf->b_ffname, curbuf->b_fname,
- (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
- flags | READ_NEW);
- /* Help buffer is filtered. */
- if (curbuf->b_help)
+ (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, eap,
+ flags | READ_NEW);
+ msg_silent = old_msg_silent;
+
+ // Help buffer is filtered.
+ if (curbuf->b_help) {
fix_help_buffer();
+ }
} else if (read_stdin) {
int save_bin = curbuf->b_p_bin;
linenr_T line_count;
@@ -257,17 +264,16 @@ open_buffer (
return retval;
}
-/*
- * Return TRUE if "buf" points to a valid buffer (in the buffer list).
- */
-int buf_valid(buf_T *buf)
+/// Check that "buf" points to a valid buffer (in the buffer list).
+bool buf_valid(buf_T *buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_BUFFERS(bp) {
if (bp == buf) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/*
@@ -401,10 +407,9 @@ close_buffer (
buf->b_nwindows = nwindows;
buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
- if (
- win_valid(win) &&
- win->w_buffer == buf)
- win->w_buffer = NULL; /* make sure we don't use the buffer now */
+ if (win_valid(win) && win->w_buffer == buf) {
+ win->w_buffer = NULL; // make sure we don't use the buffer now
+ }
/* Autocommands may have deleted the buffer. */
if (!buf_valid(buf))
@@ -1288,14 +1293,15 @@ void enter_buffer(buf_T *buf)
redraw_later(NOT_VALID);
}
-/*
- * Change to the directory of the current buffer.
- */
+// Change to the directory of the current buffer.
+// Don't do this while still starting up.
void do_autochdir(void)
{
if (p_acd) {
- if (curbuf->b_ffname != NULL && vim_chdirfile(curbuf->b_ffname) == OK) {
- shorten_fnames(TRUE);
+ if (starting == 0
+ && curbuf->b_ffname != NULL
+ && vim_chdirfile(curbuf->b_ffname) == OK) {
+ shorten_fnames(true);
}
}
}
@@ -1333,8 +1339,8 @@ buflist_new (
/* We can use inode numbers when the file exists. Works better
* for hard links. */
FileID file_id;
- bool file_id_valid = (sfname != NULL &&
- os_fileid((char *)sfname, &file_id));
+ bool file_id_valid = (sfname != NULL
+ && os_fileid((char *)sfname, &file_id));
if (ffname != NULL && !(flags & BLN_DUMMY)
&& (buf = buflist_findname_file_id(ffname, &file_id,
file_id_valid)) != NULL) {
@@ -1547,6 +1553,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_ep);
clear_string_option(&buf->b_p_path);
clear_string_option(&buf->b_p_tags);
+ clear_string_option(&buf->b_p_tc);
clear_string_option(&buf->b_p_dict);
clear_string_option(&buf->b_p_tsr);
clear_string_option(&buf->b_p_qe);
@@ -2055,16 +2062,15 @@ void buflist_setfpos(buf_T *const buf, win_T *const win,
}
-/*
- * Return true when "wip" has 'diff' set and the diff is only for another tab
- * page. That's because a diff is local to a tab page.
- */
+/// Check that "wip" has 'diff' set and the diff is only for another tab page.
+/// That's because a diff is local to a tab page.
static bool wininfo_other_tab_diff(wininfo_T *wip)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (wip->wi_opt.wo_diff) {
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- /* return false when it's a window in the current tab page, thus
- * the buffer was in diff mode here */
+ // return false when it's a window in the current tab page, thus
+ // the buffer was in diff mode here
if (wip->wi_win == wp) {
return false;
}
@@ -2189,15 +2195,16 @@ void buflist_list(exarg_T *eap)
len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
buf->b_fnum,
buf->b_p_bl ? ' ' : 'u',
- buf == curbuf ? '%' :
- (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
- buf->b_ml.ml_mfp == NULL ? ' ' :
- (buf->b_nwindows == 0 ? 'h' : 'a'),
+ buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
+ buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'),
!MODIFIABLE(buf) ? '-' : (buf->b_p_ro ? '=' : ' '),
- (buf->b_flags & BF_READERR) ? 'x'
- : (bufIsChanged(buf) ? '+' : ' '),
+ (buf->b_flags & BF_READERR) ? 'x' : (bufIsChanged(buf) ? '+' : ' '),
NameBuff);
+ if (len > IOSIZE - 20) {
+ len = IOSIZE - 20;
+ }
+
/* put "line 999" in column 40 or after the file name */
i = 40 - vim_strsize(IObuff);
do {
@@ -2421,52 +2428,62 @@ void buflist_altfpos(win_T *win)
buflist_setfpos(curbuf, win, win->w_cursor.lnum, win->w_cursor.col, TRUE);
}
-/*
- * Return TRUE if 'ffname' is not the same file as current file.
- * Fname must have a full path (expanded by path_get_absolute_path()).
- */
-int otherfile(char_u *ffname)
+/// Check that "ffname" is not the same file as current file.
+/// Fname must have a full path (expanded by path_get_absolute_path()).
+///
+/// @param ffname full path name to check
+bool otherfile(char_u *ffname)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
return otherfile_buf(curbuf, ffname, NULL, false);
}
-static int otherfile_buf(buf_T *buf, char_u *ffname,
- FileID *file_id_p, bool file_id_valid)
+/// Check that "ffname" is not the same file as the file loaded in "buf".
+/// Fname must have a full path (expanded by path_get_absolute_path()).
+///
+/// @param buf buffer to check
+/// @param ffname full path name to check
+/// @param file_id_p information about the file at "ffname".
+/// @param file_id_valid whether a valid "file_id_p" was passed in.
+static bool otherfile_buf(buf_T *buf, char_u *ffname, FileID *file_id_p,
+ bool file_id_valid)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- /* no name is different */
+ // no name is different
if (ffname == NULL || *ffname == NUL || buf->b_ffname == NULL) {
- return TRUE;
+ return true;
}
if (fnamecmp(ffname, buf->b_ffname) == 0) {
- return FALSE;
+ return false;
}
{
FileID file_id;
- /* If no struct stat given, get it now */
+ // If no struct stat given, get it now
if (file_id_p == NULL) {
file_id_p = &file_id;
file_id_valid = os_fileid((char *)ffname, file_id_p);
}
if (!file_id_valid) {
// file_id not valid, assume files are different.
- return TRUE;
+ return true;
}
- /* Use dev/ino to check if the files are the same, even when the names
- * are different (possible with links). Still need to compare the
- * name above, for when the file doesn't exist yet.
- * Problem: The dev/ino changes when a file is deleted (and created
- * again) and remains the same when renamed/moved. We don't want to
- * stat() each buffer each time, that would be too slow. Get the
- * dev/ino again when they appear to match, but not when they appear
- * to be different: Could skip a buffer when it's actually the same
- * file. */
+ // Use dev/ino to check if the files are the same, even when the names
+ // are different (possible with links). Still need to compare the
+ // name above, for when the file doesn't exist yet.
+ // Problem: The dev/ino changes when a file is deleted (and created
+ // again) and remains the same when renamed/moved. We don't want to
+ // stat() each buffer each time, that would be too slow. Get the
+ // dev/ino again when they appear to match, but not when they appear
+ // to be different: Could skip a buffer when it's actually the same
+ // file.
if (buf_same_file_id(buf, file_id_p)) {
buf_set_file_id(buf);
- if (buf_same_file_id(buf, file_id_p))
- return FALSE;
+ if (buf_same_file_id(buf, file_id_p)) {
+ return false;
+ }
}
}
- return TRUE;
+ return true;
}
// Set file_id for a buffer.
@@ -2483,11 +2500,14 @@ void buf_set_file_id(buf_T *buf)
}
}
-// return TRUE if file_id in buffer "buf" matches with "file_id".
+/// Check that file_id in buffer "buf" matches with "file_id".
+///
+/// @param buf buffer
+/// @param file_id file id
static bool buf_same_file_id(buf_T *buf, FileID *file_id)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return buf->file_id_valid
- && os_fileid_equal(&(buf->file_id), file_id);
+ return buf->file_id_valid && os_fileid_equal(&(buf->file_id), file_id);
}
/*
@@ -2770,23 +2790,28 @@ void maketitle(void)
resettitle();
}
-/*
- * Used for title and icon: Check if "str" differs from "*last". Set "*last"
- * from "str" if it does.
- * Return TRUE when "*last" changed.
- */
-static int ti_change(char_u *str, char_u **last)
+/// Used for title and icon: Check if "str" differs from "*last". Set "*last"
+/// from "str" if it does by freeing the old value of "*last" and duplicating
+/// "str".
+///
+/// @param str desired title string
+/// @param[in,out] last current title string
+//
+/// @return true when "*last" changed.
+static bool ti_change(char_u *str, char_u **last)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
if ((str == NULL) != (*last == NULL)
|| (str != NULL && *last != NULL && STRCMP(str, *last) != 0)) {
xfree(*last);
- if (str == NULL)
+ if (str == NULL) {
*last = NULL;
- else
+ } else {
*last = vim_strsave(str);
- return TRUE;
+ }
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -3014,7 +3039,7 @@ int build_stl_str_hl(
&& item[groupitem[groupdepth]].minwid == 0) {
bool has_normal_items = false;
for (long n = groupitem[groupdepth] + 1; n < curitem; n++) {
- if (item[n].type == Normal) {
+ if (item[n].type == Normal || item[n].type == Highlight) {
has_normal_items = true;
break;
}
@@ -3922,26 +3947,29 @@ void get_rel_pos(win_T *wp, char_u *buf, int buflen)
: (int)(above * 100L / (above + below)));
}
-/*
- * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
- * Return TRUE if it was appended.
- */
-static int
-append_arg_number (
- win_T *wp,
- char_u *buf,
- int buflen,
- int add_file /* Add "file" before the arg number */
-)
+/// Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
+///
+/// @param wp window whose buffers to check
+/// @param[in,out] buf string buffer to add the text to
+/// @param buflen length of the string buffer
+/// @param add_file if true, add "file" before the arg number
+///
+/// @return true if it was appended.
+static bool append_arg_number(win_T *wp, char_u *buf, int buflen, bool add_file)
+ FUNC_ATTR_NONNULL_ALL
{
- char_u *p;
+ // Nothing to do
+ if (ARGCOUNT <= 1) {
+ return false;
+ }
+
+ char_u *p = buf + STRLEN(buf); // go to the end of the buffer
- if (ARGCOUNT <= 1) /* nothing to do */
- return FALSE;
+ // Early out if the string is getting too long
+ if (p - buf + 35 >= buflen) {
+ return false;
+ }
- p = buf + STRLEN(buf); /* go to the end of the buffer */
- if (p - buf + 35 >= buflen) /* getting too long */
- return FALSE;
*p++ = ' ';
*p++ = '(';
if (add_file) {
@@ -3949,9 +3977,10 @@ append_arg_number (
p += 5;
}
vim_snprintf((char *)p, (size_t)(buflen - (p - buf)),
- wp->w_arg_idx_invalid ? "(%d) of %d)"
- : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
- return TRUE;
+ wp->w_arg_idx_invalid
+ ? "(%d) of %d)"
+ : "%d of %d)", wp->w_arg_idx + 1, ARGCOUNT);
+ return true;
}
/*
@@ -4585,11 +4614,16 @@ char_u *buf_spname(buf_T *buf)
return NULL;
}
-/*
- * Find a window for buffer "buf".
- * If found true is returned and "wp" and "tp" are set to the window and tabpage.
- * If not found false is returned.
- */
+/// Find a window for buffer "buf".
+/// If found true is returned and "wp" and "tp" are set to
+/// the window and tabpage.
+/// If not found, false is returned.
+///
+/// @param buf buffer to find a window for
+/// @param[out] wp stores the found window
+/// @param[out] tp stores the found tabpage
+///
+/// @return true if a window was found for the buffer.
bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
{
*wp = NULL;
@@ -5103,50 +5137,54 @@ void set_buflisted(int on)
}
}
-/*
- * Read the file for "buf" again and check if the contents changed.
- * Return TRUE if it changed or this could not be checked.
- */
-int buf_contents_changed(buf_T *buf)
+/// Read the file for "buf" again and check if the contents changed.
+/// Return true if it changed or this could not be checked.
+///
+/// @param buf buffer to check
+///
+/// @return true if the buffer's contents have changed
+bool buf_contents_changed(buf_T *buf)
+ FUNC_ATTR_NONNULL_ALL
{
- buf_T *newbuf;
- int differ = TRUE;
- linenr_T lnum;
- aco_save_T aco;
- exarg_T ea;
+ bool differ = true;
- /* Allocate a buffer without putting it in the buffer list. */
- newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
- if (newbuf == NULL)
- return TRUE;
+ // Allocate a buffer without putting it in the buffer list.
+ buf_T *newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
+ if (newbuf == NULL) {
+ return true;
+ }
- /* Force the 'fileencoding' and 'fileformat' to be equal. */
+ // Force the 'fileencoding' and 'fileformat' to be equal.
+ exarg_T ea;
prep_exarg(&ea, buf);
- /* set curwin/curbuf to buf and save a few things */
+ // set curwin/curbuf to buf and save a few things
+ aco_save_T aco;
aucmd_prepbuf(&aco, newbuf);
if (ml_open(curbuf) == OK
&& readfile(buf->b_ffname, buf->b_fname,
- (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
- &ea, READ_NEW | READ_DUMMY) == OK) {
- /* compare the two files line by line */
+ (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
+ &ea, READ_NEW | READ_DUMMY) == OK) {
+ // compare the two files line by line
if (buf->b_ml.ml_line_count == curbuf->b_ml.ml_line_count) {
- differ = FALSE;
- for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
- if (STRCMP(ml_get_buf(buf, lnum, FALSE), ml_get(lnum)) != 0) {
- differ = TRUE;
+ differ = false;
+ for (linenr_T lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
+ if (STRCMP(ml_get_buf(buf, lnum, false), ml_get(lnum)) != 0) {
+ differ = true;
break;
}
+ }
}
}
xfree(ea.cmd);
- /* restore curwin/curbuf and a few other things */
+ // restore curwin/curbuf and a few other things
aucmd_restbuf(&aco);
- if (curbuf != newbuf) /* safety check */
- wipe_buffer(newbuf, FALSE);
+ if (curbuf != newbuf) { // safety check
+ wipe_buffer(newbuf, false);
+ }
return differ;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 936a14b903..0324f6b88a 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -141,8 +141,8 @@ struct buffblock {
struct buffheader {
buffblock_T bh_first; // first (dummy) block of list
buffblock_T *bh_curr; // buffblock for appending
- int bh_index; // index for reading
- int bh_space; // space in bh_curr for appending
+ size_t bh_index; // index for reading
+ size_t bh_space; // space in bh_curr for appending
};
/*
@@ -533,9 +533,9 @@ struct file_buffer {
/*
* Character table, only used in charset.c for 'iskeyword'
- * 32 bytes of 8 bits: 1 bit per character 0-255.
+ * bitset with 4*64=256 bits: 1 bit per character 0-255.
*/
- char_u b_chartab[32];
+ uint64_t b_chartab[4];
/* Table used for mappings local to a buffer. */
mapblock_T *(b_maphash[256]);
@@ -666,19 +666,21 @@ struct file_buffer {
long b_p_wm_nopaste; ///< b_p_wm saved for paste mode
char_u *b_p_keymap; ///< 'keymap'
- /* local values for options which are normally global */
- char_u *b_p_gp; /* 'grepprg' local value */
- char_u *b_p_mp; /* 'makeprg' local value */
- char_u *b_p_efm; /* 'errorformat' local value */
- char_u *b_p_ep; /* 'equalprg' local value */
- char_u *b_p_path; /* 'path' local value */
- int b_p_ar; /* 'autoread' local value */
- char_u *b_p_tags; /* 'tags' local value */
- char_u *b_p_dict; /* 'dictionary' local value */
- char_u *b_p_tsr; /* 'thesaurus' local value */
- long b_p_ul; /* 'undolevels' local value */
- int b_p_udf; /* 'undofile' */
- char_u *b_p_lw; // 'lispwords' local value
+ // local values for options which are normally global
+ char_u *b_p_gp; ///< 'grepprg' local value
+ char_u *b_p_mp; ///< 'makeprg' local value
+ char_u *b_p_efm; ///< 'errorformat' local value
+ char_u *b_p_ep; ///< 'equalprg' local value
+ char_u *b_p_path; ///< 'path' local value
+ int b_p_ar; ///< 'autoread' local value
+ char_u *b_p_tags; ///< 'tags' local value
+ char_u *b_p_tc; ///< 'tagcase' local value
+ unsigned b_tc_flags; ///< flags for 'tagcase'
+ char_u *b_p_dict; ///< 'dictionary' local value
+ char_u *b_p_tsr; ///< 'thesaurus' local value
+ long b_p_ul; ///< 'undolevels' local value
+ int b_p_udf; ///< 'undofile'
+ char_u *b_p_lw; ///< 'lispwords' local value
/* end of buffer options */
@@ -816,10 +818,12 @@ struct tabpage_S {
was set */
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
- int tp_diff_invalid; /* list of diffs is outdated */
- frame_T *(tp_snapshot[SNAP_COUNT]); /* window layout snapshots */
- dictitem_T tp_winvar; /* variable for "t:" Dictionary */
- dict_T *tp_vars; /* internal variables, local to tab page */
+ int tp_diff_invalid; ///< list of diffs is outdated */
+ frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
+ dictitem_T tp_winvar; ///< variable for "t:" Dictionary
+ dict_T *tp_vars; ///< internal variables, local to tab page
+ char_u *localdir; ///< Absolute path of local directory or
+ ///< NULL
};
/*
@@ -953,16 +957,14 @@ struct window_S {
time through cursupdate() to the
current virtual column */
- /*
- * the next six are used to update the visual part
- */
- char w_old_visual_mode; /* last known VIsual_mode */
- linenr_T w_old_cursor_lnum; /* last known end of visual part */
- colnr_T w_old_cursor_fcol; /* first column for block visual part */
- colnr_T w_old_cursor_lcol; /* last column for block visual part */
- linenr_T w_old_visual_lnum; /* last known start of visual part */
- colnr_T w_old_visual_col; /* last known start of visual part */
- colnr_T w_old_curswant; /* last known value of Curswant */
+ // the next seven are used to update the visual part
+ char w_old_visual_mode; ///< last known VIsual_mode
+ linenr_T w_old_cursor_lnum; ///< last known end of visual part
+ colnr_T w_old_cursor_fcol; ///< first column for block visual part
+ colnr_T w_old_cursor_lcol; ///< last column for block visual part
+ linenr_T w_old_visual_lnum; ///< last known start of visual part
+ colnr_T w_old_visual_col; ///< last known start of visual part
+ colnr_T w_old_curswant; ///< last known value of Curswant
/*
* "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 4e329b5cd8..d0dc7b66fc 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -32,16 +32,16 @@
#endif
-static int chartab_initialized = FALSE;
+static bool chartab_initialized = false;
-// b_chartab[] is an array of 32 bytes, each bit representing one of the
+// b_chartab[] is an array with 256 bits, each bit representing one of the
// characters 0-255.
#define SET_CHARTAB(buf, c) \
- (buf)->b_chartab[(unsigned)(c) >> 3] |= (1 << ((c) & 0x7))
+ (buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f))
#define RESET_CHARTAB(buf, c) \
- (buf)->b_chartab[(unsigned)(c) >> 3] &= ~(1 << ((c) & 0x7))
+ (buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f))
#define GET_CHARTAB(buf, c) \
- ((buf)->b_chartab[(unsigned)(c) >> 3] & (1 << ((c) & 0x7)))
+ ((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
/// Fill chartab[]. Also fills curbuf->b_chartab[] with flags for keyword
/// characters for current buffer.
@@ -69,12 +69,12 @@ static int chartab_initialized = FALSE;
/// an error, OK otherwise.
int init_chartab(void)
{
- return buf_init_chartab(curbuf, TRUE);
+ return buf_init_chartab(curbuf, true);
}
/// Helper for init_chartab
///
-/// @param global FALSE: only set buf->b_chartab[]
+/// @param global false: only set buf->b_chartab[]
///
/// @return FAIL if 'iskeyword', 'isident', 'isfname' or 'isprint' option has
/// an error, OK otherwise.
@@ -84,13 +84,13 @@ int buf_init_chartab(buf_T *buf, int global)
int c2;
char_u *p;
int i;
- int tilde;
- int do_isalpha;
+ bool tilde;
+ bool do_isalpha;
if (global) {
// Set the default size for printable characters:
// From <Space> to '~' is 1 (printable), others are 2 (not printable).
- // This also inits all 'isident' and 'isfname' flags to FALSE.
+ // This also inits all 'isident' and 'isfname' flags to false.
c = 0;
while (c < ' ') {
@@ -133,7 +133,7 @@ int buf_init_chartab(buf_T *buf, int global)
}
}
- // Init word char flags all to FALSE
+ // Init word char flags all to false
memset(buf->b_chartab, 0, (size_t)32);
if (enc_dbcs != 0) {
@@ -169,11 +169,11 @@ int buf_init_chartab(buf_T *buf, int global)
}
while (*p) {
- tilde = FALSE;
- do_isalpha = FALSE;
+ tilde = false;
+ do_isalpha = false;
if ((*p == '^') && (p[1] != NUL)) {
- tilde = TRUE;
+ tilde = true;
++p;
}
@@ -212,7 +212,7 @@ int buf_init_chartab(buf_T *buf, int global)
// standard function isalpha(). This takes care of locale for
// single-byte characters).
if (c == '@') {
- do_isalpha = TRUE;
+ do_isalpha = true;
c = 1;
c2 = 255;
} else {
@@ -231,7 +231,7 @@ int buf_init_chartab(buf_T *buf, int global)
if (i == 0) {
// (re)set ID flag
if (tilde) {
- chartab[c] &= ~CT_ID_CHAR;
+ chartab[c] &= (uint8_t)~CT_ID_CHAR;
} else {
chartab[c] |= CT_ID_CHAR;
}
@@ -244,18 +244,18 @@ int buf_init_chartab(buf_T *buf, int global)
|| (p_altkeymap && (F_isalpha(c) || F_isdigit(c))))
&& !(enc_dbcs && (MB_BYTE2LEN(c) == 2))) {
if (tilde) {
- chartab[c] = (chartab[c] & ~CT_CELL_MASK)
- + ((dy_flags & DY_UHEX) ? 4 : 2);
- chartab[c] &= ~CT_PRINT_CHAR;
+ chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK)
+ + ((dy_flags & DY_UHEX) ? 4 : 2));
+ chartab[c] &= (uint8_t)~CT_PRINT_CHAR;
} else {
- chartab[c] = (chartab[c] & ~CT_CELL_MASK) + 1;
+ chartab[c] = (uint8_t)((chartab[c] & ~CT_CELL_MASK) + 1);
chartab[c] |= CT_PRINT_CHAR;
}
}
} else if (i == 2) {
// (re)set fname flag
if (tilde) {
- chartab[c] &= ~CT_FNAME_CHAR;
+ chartab[c] &= (uint8_t)~CT_FNAME_CHAR;
} else {
chartab[c] |= CT_FNAME_CHAR;
}
@@ -280,7 +280,7 @@ int buf_init_chartab(buf_T *buf, int global)
}
}
}
- chartab_initialized = TRUE;
+ chartab_initialized = true;
return OK;
}
@@ -333,7 +333,8 @@ char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET
{
char_u *res;
char_u *p;
- int l, c;
+ int c;
+ size_t l;
char_u hexbuf[11];
if (has_mbyte) {
@@ -343,7 +344,7 @@ char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET
p = s;
while (*p != NUL) {
- if ((l = (*mb_ptr2len)(p)) > 1) {
+ if ((l = (size_t)(*mb_ptr2len)(p)) > 1) {
c = (*mb_ptr2char)(p);
p += l;
@@ -354,7 +355,7 @@ char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET
len += STRLEN(hexbuf);
}
} else {
- l = byte2cells(*p++);
+ l = (size_t)byte2cells(*p++);
if (l > 0) {
len += l;
@@ -366,14 +367,14 @@ char_u *transstr(char_u *s) FUNC_ATTR_NONNULL_RET
}
res = xmallocz(len);
} else {
- res = xmallocz(vim_strsize(s));
+ res = xmallocz((size_t)vim_strsize(s));
}
*res = NUL;
p = s;
while (*p != NUL) {
- if (has_mbyte && ((l = (*mb_ptr2len)(p)) > 1)) {
+ if (has_mbyte && ((l = (size_t)(*mb_ptr2len)(p)) > 1)) {
c = (*mb_ptr2char)(p);
if (vim_isprintc(c)) {
@@ -477,9 +478,9 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
i += (*mb_ptr2len)(STR_PTR(i));
} else {
if (buf == NULL) {
- GA_CHAR(i) = TOLOWER_LOC(GA_CHAR(i));
+ GA_CHAR(i) = (char_u)TOLOWER_LOC(GA_CHAR(i));
} else {
- buf[i] = TOLOWER_LOC(buf[i]);
+ buf[i] = (char_u)TOLOWER_LOC(buf[i]);
}
++i;
}
@@ -493,7 +494,7 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
// Catch 22: chartab[] can't be initialized before the options are
// initialized, and initializing options may cause transchar() to be called!
-// When chartab_initialized == FALSE don't use chartab[].
+// When chartab_initialized == false don't use chartab[].
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
@@ -518,7 +519,7 @@ char_u* transchar(int c)
if ((!chartab_initialized && (((c >= ' ') && (c <= '~')) || F_ischar(c)))
|| ((c < 256) && vim_isprintc_strict(c))) {
// printable character
- transchar_buf[i] = c;
+ transchar_buf[i] = (char_u)c;
transchar_buf[i + 1] = NUL;
} else {
transchar_nonprint(transchar_buf + i, c);
@@ -564,7 +565,7 @@ void transchar_nonprint(char_u *buf, int c)
// 0x00 - 0x1f and 0x7f
buf[0] = '^';
// DEL displayed as ^?
- buf[1] = c ^ 0x40;
+ buf[1] = (char_u)(c ^ 0x40);
buf[2] = NUL;
} else if (enc_utf8 && (c >= 0x80)) {
@@ -572,12 +573,12 @@ void transchar_nonprint(char_u *buf, int c)
} else if ((c >= ' ' + 0x80) && (c <= '~' + 0x80)) {
// 0xa0 - 0xfe
buf[0] = '|';
- buf[1] = c - 0x80;
+ buf[1] = (char_u)(c - 0x80);
buf[2] = NUL;
} else {
// 0x80 - 0x9f and 0xff
buf[0] = '~';
- buf[1] = (c - 0x80) ^ 0x40;
+ buf[1] = (char_u)((c - 0x80) ^ 0x40);
buf[2] = NUL;
}
}
@@ -592,11 +593,11 @@ void transchar_hex(char_u *buf, int c)
buf[0] = '<';
if (c > 255) {
- buf[++i] = nr2hex((unsigned)c >> 12);
- buf[++i] = nr2hex((unsigned)c >> 8);
+ buf[++i] = (char_u)nr2hex((unsigned)c >> 12);
+ buf[++i] = (char_u)nr2hex((unsigned)c >> 8);
}
- buf[++i] = nr2hex((unsigned)c >> 4);
- buf[++i] = nr2hex((unsigned)c);
+ buf[++i] = (char_u)(nr2hex((unsigned)c >> 4));
+ buf[++i] = (char_u)(nr2hex((unsigned)c));
buf[++i] = '>';
buf[++i] = NUL;
}
@@ -734,9 +735,8 @@ int vim_strnsize(char_u *s, int len)
/// @return Number of characters.
#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) { \
- int ts; \
- ts = (buf)->b_p_ts; \
- return (int)(ts - (col % ts)); \
+ const int ts = (int) (buf)->b_p_ts; \
+ return (ts - (int)(col % ts)); \
} else { \
return ptr2cells(p); \
}
@@ -1137,7 +1137,7 @@ static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
int n;
if ((*s == TAB) && (!wp->w_p_list || lcs_tab1)) {
- n = wp->w_buffer->b_p_ts;
+ n = (int)wp->w_buffer->b_p_ts;
return n - (col % n);
}
n = ptr2cells(s);
@@ -1205,11 +1205,11 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
char_u *line; // start of the line
int incr;
int head;
- int ts = wp->w_buffer->b_p_ts;
+ int ts = (int)wp->w_buffer->b_p_ts;
int c;
vcol = 0;
- line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+ line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, false);
if (pos->col == MAXCOL) {
// continue until the NUL
@@ -1329,7 +1329,7 @@ colnr_T getvcol_nolist(pos_T *posp)
int list_save = curwin->w_p_list;
colnr_T vcol;
- curwin->w_p_list = FALSE;
+ curwin->w_p_list = false;
getvcol(curwin, posp, NULL, &vcol, NULL);
curwin->w_p_list = list_save;
return vcol;
@@ -1358,7 +1358,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
endadd = 0;
// Cannot put the cursor on part of a wide character.
- ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+ ptr = ml_get_buf(wp->w_buffer, pos->lnum, false);
if (pos->col < (colnr_T)STRLEN(ptr)) {
int c = (*mb_ptr2char)(ptr + pos->col);
@@ -1595,7 +1595,7 @@ bool vim_islower(int c)
if (c >= 0x100) {
if (has_mbyte) {
- return iswlower(c);
+ return iswlower((wint_t)c);
}
// islower() can't handle these chars and may crash
@@ -1626,7 +1626,7 @@ bool vim_isupper(int c)
if (c >= 0x100) {
if (has_mbyte) {
- return iswupper(c);
+ return iswupper((wint_t)c);
}
// isupper() can't handle these chars and may crash
@@ -1653,7 +1653,7 @@ int vim_toupper(int c)
if (c >= 0x100) {
if (has_mbyte) {
- return towupper(c);
+ return (int)towupper((wint_t)c);
}
// toupper() can't handle these chars and may crash
@@ -1680,7 +1680,7 @@ int vim_tolower(int c)
if (c >= 0x100) {
if (has_mbyte) {
- return towlower(c);
+ return (int)towlower((wint_t)c);
}
// tolower() can't handle these chars and may crash
@@ -1794,10 +1794,11 @@ bool vim_isblankline(char_u *lbuf)
/// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result.
/// @param maxlen Max length of string to check.
-void vim_str2nr(char_u *start, int *prep, int *len, int what,
- long *nptr, unsigned long *unptr, int maxlen)
+void vim_str2nr(const char_u *const start, int *const prep, int *const len,
+ const int what, long *const nptr, unsigned long *const unptr,
+ const int maxlen)
{
- char_u *ptr = start;
+ const char_u *ptr = start;
int pre = 0; // default is decimal
bool negative = false;
unsigned long un = 0;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 0be8b3c514..4826e70727 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -29,7 +29,6 @@
#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
-#include "nvim/tempfile.h"
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
@@ -658,9 +657,9 @@ void ex_diffupdate(exarg_T *eap)
}
// We need three temp file names.
- char_u *tmp_orig = vim_tempname();
- char_u *tmp_new = vim_tempname();
- char_u *tmp_diff = vim_tempname();
+ char *tmp_orig = (char *) vim_tempname();
+ char *tmp_new = (char *) vim_tempname();
+ char *tmp_diff = (char *) vim_tempname();
if ((tmp_orig == NULL) || (tmp_new == NULL) || (tmp_diff == NULL)) {
goto theend;
@@ -670,11 +669,11 @@ void ex_diffupdate(exarg_T *eap)
// are no differences. Can't use the return value, it's non-zero when
// there are differences.
// May try twice, first with "-a" and then without.
- int io_error = FALSE;
- int ok = FALSE;
+ int io_error = false;
+ bool ok = false;
for (;;) {
- ok = FALSE;
- FILE *fd = mch_fopen((char *)tmp_orig, "w");
+ ok = false;
+ FILE *fd = mch_fopen(tmp_orig, "w");
if (fd == NULL) {
io_error = TRUE;
@@ -683,7 +682,7 @@ void ex_diffupdate(exarg_T *eap)
io_error = TRUE;
}
fclose(fd);
- fd = mch_fopen((char *)tmp_new, "w");
+ fd = mch_fopen(tmp_new, "w");
if (fd == NULL) {
io_error = TRUE;
@@ -693,7 +692,7 @@ void ex_diffupdate(exarg_T *eap)
}
fclose(fd);
diff_file(tmp_orig, tmp_new, tmp_diff);
- fd = mch_fopen((char *)tmp_diff, "r");
+ fd = mch_fopen(tmp_diff, "r");
if (fd == NULL) {
io_error = TRUE;
@@ -712,10 +711,10 @@ void ex_diffupdate(exarg_T *eap)
}
fclose(fd);
}
- os_remove((char *)tmp_diff);
- os_remove((char *)tmp_new);
+ os_remove(tmp_diff);
+ os_remove(tmp_new);
}
- os_remove((char *)tmp_orig);
+ os_remove(tmp_orig);
}
// When using 'diffexpr' break here.
@@ -756,7 +755,7 @@ void ex_diffupdate(exarg_T *eap)
// Write the first buffer to a tempfile.
buf_T *buf = curtab->tp_diffbuf[idx_orig];
- if (diff_write(buf, tmp_orig) == FAIL) {
+ if (diff_write(buf, (char_u *) tmp_orig) == FAIL) {
goto theend;
}
@@ -767,17 +766,17 @@ void ex_diffupdate(exarg_T *eap)
continue; // skip buffer that isn't loaded
}
- if (diff_write(buf, tmp_new) == FAIL) {
+ if (diff_write(buf, (char_u *) tmp_new) == FAIL) {
continue;
}
diff_file(tmp_orig, tmp_new, tmp_diff);
// Read the diff output and add each entry to the diff list.
- diff_read(idx_orig, idx_new, tmp_diff);
- os_remove((char *)tmp_diff);
- os_remove((char *)tmp_new);
+ diff_read(idx_orig, idx_new, (char_u *) tmp_diff);
+ os_remove(tmp_diff);
+ os_remove(tmp_new);
}
- os_remove((char *)tmp_orig);
+ os_remove(tmp_orig);
// force updating cursor position on screen
curwin->w_valid_cursor.lnum = 0;
@@ -795,15 +794,16 @@ theend:
/// @param tmp_orig
/// @param tmp_new
/// @param tmp_diff
-static void diff_file(char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff)
+static void diff_file(const char *const tmp_orig, const char *const tmp_new,
+ const char *const tmp_diff)
{
if (*p_dex != NUL) {
// Use 'diffexpr' to generate the diff file.
eval_diff(tmp_orig, tmp_new, tmp_diff);
} else {
- size_t len = STRLEN(tmp_orig) + STRLEN(tmp_new) + STRLEN(tmp_diff)
- + STRLEN(p_srr) + 27;
- char_u *cmd = xmalloc(len);
+ const size_t len = (strlen(tmp_orig) + strlen(tmp_new) + strlen(tmp_diff)
+ + STRLEN(p_srr) + 27);
+ char *const cmd = xmalloc(len);
/* We don't want $DIFF_OPTIONS to get in the way. */
if (os_getenv("DIFF_OPTIONS")) {
@@ -813,19 +813,17 @@ static void diff_file(char_u *tmp_orig, char_u *tmp_new, char_u *tmp_diff)
/* Build the diff command and execute it. Always use -a, binary
* differences are of no use. Ignore errors, diff returns
* non-zero when differences have been found. */
- vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s %s",
- diff_a_works == FALSE ? "" : "-a ",
+ vim_snprintf(cmd, len, "diff %s%s%s%s%s %s",
+ diff_a_works ? "-a " : "",
"",
(diff_flags & DIFF_IWHITE) ? "-b " : "",
(diff_flags & DIFF_ICASE) ? "-i " : "",
tmp_orig, tmp_new);
- append_redir(cmd, (int)len, p_srr, tmp_diff);
- block_autocmds(); /* Avoid ShellCmdPost stuff */
- (void)call_shell(
- cmd,
- kShellOptFilter | kShellOptSilent | kShellOptDoOut,
- NULL
- );
+ append_redir(cmd, len, (char *) p_srr, tmp_diff);
+ block_autocmds(); // Avoid ShellCmdPost stuff
+ (void)call_shell((char_u *) cmd,
+ kShellOptFilter | kShellOptSilent | kShellOptDoOut,
+ NULL);
unblock_autocmds();
xfree(cmd);
}
@@ -902,9 +900,11 @@ void ex_diffpatch(exarg_T *eap)
if (*p_pex != NUL) {
// Use 'patchexpr' to generate the new file.
#ifdef UNIX
- eval_patch(tmp_orig, fullname != NULL ? fullname : eap->arg, tmp_new);
+ eval_patch((char *) tmp_orig,
+ (char *) (fullname != NULL ? fullname : eap->arg),
+ (char *) tmp_new);
#else
- eval_patch(tmp_orig, eap->arg, tmp_new);
+ eval_patch((char *) tmp_orig, (char *) eap->arg, (char *) tmp_new);
#endif // ifdef UNIX
} else {
// Build the patch command and execute it. Ignore errors. Switch to
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 6313ea2e81..e131da8fe0 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -165,10 +165,6 @@ static int compl_restarting = FALSE; /* don't insert match */
* FALSE the word to be completed must be located. */
static int compl_started = FALSE;
-/* Set when doing something for completion that may call edit() recursively,
- * which is not allowed. */
-static int compl_busy = FALSE;
-
static int compl_matches = 0;
static char_u *compl_pattern = NULL;
static int compl_direction = FORWARD;
@@ -203,7 +199,7 @@ typedef struct insert_state {
int did_restart_edit; // remember if insert mode was restarted
// after a ctrl+o
bool nomove;
- uint8_t *ptr;
+ char_u *ptr;
} InsertState;
@@ -274,8 +270,8 @@ static void insert_enter(InsertState *s)
s->ptr = (char_u *)"i";
}
- set_vim_var_string(VV_INSERTMODE, s->ptr, 1);
- set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
+ set_vim_var_string(VV_INSERTMODE, (char *) s->ptr, 1);
+ set_vim_var_string(VV_CHAR, NULL, -1);
apply_autocmds(EVENT_INSERTENTER, NULL, NULL, false, curbuf);
// Make sure the cursor didn't move. Do call check_cursor_col() in
@@ -887,7 +883,7 @@ static int insert_handle_key(InsertState *s)
case Ctrl_T: // Make indent one shiftwidth greater.
if (s->c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS) {
- if (has_compl_option(false)) {
+ if (check_compl_option(false)) {
insert_do_complete(s);
}
break;
@@ -1102,7 +1098,7 @@ static int insert_handle_key(InsertState *s)
case Ctrl_K: // digraph or keyword completion
if (ctrl_x_mode == CTRL_X_DICTIONARY) {
- if (has_compl_option(true)) {
+ if (check_compl_option(true)) {
insert_do_complete(s);
}
break;
@@ -1264,30 +1260,28 @@ static void insert_do_cindent(InsertState *s)
}
}
-/*
- * edit(): Start inserting text.
- *
- * "cmdchar" can be:
- * 'i' normal insert command
- * 'a' normal append command
- * 'R' replace command
- * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
- * but still only one <CR> is inserted. The <Esc> is not used for redo.
- * 'g' "gI" command.
- * 'V' "gR" command for Virtual Replace mode.
- * 'v' "gr" command for single character Virtual Replace mode.
- *
- * This function is not called recursively. For CTRL-O commands, it returns
- * and lets the caller handle the Normal-mode command.
- *
- * Return TRUE if a CTRL-O command caused the return (insert mode pending).
- */
-int
-edit (
- int cmdchar,
- int startln, /* if set, insert at start of line */
- long count
-)
+/// edit(): Start inserting text.
+///
+/// "cmdchar" can be:
+/// 'i' normal insert command
+/// 'a' normal append command
+/// 'R' replace command
+/// 'r' "r<CR>" command: insert one <CR>.
+/// Note: count can be > 1, for redo, but still only one <CR> is inserted.
+/// <Esc> is not used for redo.
+/// 'g' "gI" command.
+/// 'V' "gR" command for Virtual Replace mode.
+/// 'v' "gr" command for single character Virtual Replace mode.
+///
+/// This function is not called recursively. For CTRL-O commands, it returns
+/// and lets the caller handle the Normal-mode command.
+///
+/// @param cmdchar command that started the insert
+/// @param startln if true, insert at start of line
+/// @param count repeat count for the command
+///
+/// @return true if a CTRL-O command caused the return (insert mode pending).
+bool edit(int cmdchar, bool startln, long count)
{
if (curbuf->terminal) {
if (ex_normal_busy) {
@@ -1365,6 +1359,9 @@ ins_redraw (
update_screen(0);
}
if (has_event(EVENT_CURSORMOVEDI)) {
+ // Make sure curswant is correct, an autocommand may call
+ // getcurpos()
+ update_curswant();
apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, false, curbuf);
}
if (curwin->w_p_cole > 0) {
@@ -1795,33 +1792,37 @@ void backspace_until_column(int col)
}
}
-/*
- * Like del_char(), but make sure not to go before column "limit_col".
- * Only matters when there are composing characters.
- * Return TRUE when something was deleted.
- */
-static int del_char_after_col(int limit_col)
+/// Like del_char(), but make sure not to go before column "limit_col".
+/// Only matters when there are composing characters.
+///
+/// @param limit_col only delete the character if it is after this column
+//
+/// @return true when something was deleted.
+static bool del_char_after_col(int limit_col)
{
if (enc_utf8 && limit_col >= 0) {
colnr_T ecol = curwin->w_cursor.col + 1;
- /* Make sure the cursor is at the start of a character, but
- * skip forward again when going too far back because of a
- * composing character. */
+ // Make sure the cursor is at the start of a character, but
+ // skip forward again when going too far back because of a
+ // composing character.
mb_adjust_cursor();
while (curwin->w_cursor.col < (colnr_T)limit_col) {
int l = utf_ptr2len(get_cursor_pos_ptr());
- if (l == 0) /* end of line */
+ if (l == 0) { // end of line
break;
+ }
curwin->w_cursor.col += l;
}
- if (*get_cursor_pos_ptr() == NUL || curwin->w_cursor.col == ecol)
- return FALSE;
- del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE);
- } else
- (void)del_char(FALSE);
- return TRUE;
+ if (*get_cursor_pos_ptr() == NUL || curwin->w_cursor.col == ecol) {
+ return false;
+ }
+ del_bytes(ecol - curwin->w_cursor.col, false, true);
+ } else {
+ del_char(false);
+ }
+ return true;
}
/*
@@ -1846,47 +1847,48 @@ static void ins_ctrl_x(void)
}
}
-/*
- * Return TRUE if the 'dict' or 'tsr' option can be used.
- */
-static int has_compl_option(int dict_opt)
+/// Check that the "dict" or "tsr" option can be used.
+///
+/// @param dict_opt check "dict" when true, "tsr" when false.
+static bool check_compl_option(bool dict_opt)
{
- if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
- && !curwin->w_p_spell
- )
+ if (dict_opt
+ ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
: (*curbuf->b_p_tsr == NUL && *p_tsr == NUL)) {
ctrl_x_mode = 0;
edit_submode = NULL;
msg_attr(dict_opt ? (char_u *)_("'dictionary' option is empty")
- : (char_u *)_("'thesaurus' option is empty"),
- hl_attr(HLF_E));
+ : (char_u *)_("'thesaurus' option is empty"), hl_attr(HLF_E));
if (emsg_silent == 0) {
vim_beep(BO_COMPL);
setcursor();
ui_flush();
os_delay(2000L, false);
}
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
-/*
- * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
- * This depends on the current mode.
- */
-int vim_is_ctrl_x_key(int c)
+/// Check that the character "c" a valid key to go to or keep us in CTRL-X mode?
+/// This depends on the current mode.
+///
+/// @param c character to check
+bool vim_is_ctrl_x_key(int c)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
- /* Always allow ^R - let it's results then be checked */
- if (c == Ctrl_R)
- return TRUE;
+ // Always allow ^R - let its results then be checked
+ if (c == Ctrl_R) {
+ return true;
+ }
- /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
- if (ins_compl_pum_key(c))
- return TRUE;
+ // Accept <PageUp> and <PageDown> if the popup menu is visible.
+ if (ins_compl_pum_key(c)) {
+ return true;
+ }
switch (ctrl_x_mode) {
- case 0: /* Not in any CTRL-X mode */
+ case 0: // Not in any CTRL-X mode
return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
case CTRL_X_NOT_DEFINED_YET:
return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
@@ -1924,35 +1926,37 @@ int vim_is_ctrl_x_key(int c)
return (c == Ctrl_P || c == Ctrl_N);
}
EMSG(_(e_internal));
- return FALSE;
+ return false;
}
-/*
- * Return TRUE when character "c" is part of the item currently being
- * completed. Used to decide whether to abandon complete mode when the menu
- * is visible.
- */
-static int ins_compl_accept_char(int c)
+/// Check that character "c" is part of the item currently being
+/// completed. Used to decide whether to abandon complete mode when the menu
+/// is visible.
+///
+/// @param c character to check
+static bool ins_compl_accept_char(int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (ctrl_x_mode & CTRL_X_WANT_IDENT)
- /* When expanding an identifier only accept identifier chars. */
+ if (ctrl_x_mode & CTRL_X_WANT_IDENT) {
+ // When expanding an identifier only accept identifier chars.
return vim_isIDc(c);
+ }
switch (ctrl_x_mode) {
case CTRL_X_FILES:
- /* When expanding file name only accept file name chars. But not
- * path separators, so that "proto/<Tab>" expands files in
- * "proto", not "proto/" as a whole */
+ // When expanding file name only accept file name chars. But not
+ // path separators, so that "proto/<Tab>" expands files in
+ // "proto", not "proto/" as a whole
return vim_isfilec(c) && !vim_ispathsep(c);
case CTRL_X_CMDLINE:
case CTRL_X_OMNI:
- /* Command line and Omni completion can work with just about any
- * printable character, but do stop at white space. */
+ // Command line and Omni completion can work with just about any
+ // printable character, but do stop at white space.
return vim_isprintc(c) && !ascii_iswhite(c);
case CTRL_X_WHOLE_LINE:
- /* For while line completion a space can be part of the line. */
+ // For while line completion a space can be part of the line.
return vim_isprintc(c);
}
return vim_iswordc(c);
@@ -2197,15 +2201,19 @@ ins_compl_add (
return OK;
}
-/*
- * Return TRUE if "str[len]" matches with match->cp_str, considering
- * match->cp_icase.
- */
-static int ins_compl_equal(compl_T *match, char_u *str, int len)
+/// Check that "str[len]" matches with "match->cp_str", considering
+/// "match->cp_icase".
+///
+/// @param match completion match
+/// @param str character string to check
+/// @param len lenth of "str"
+static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- if (match->cp_icase)
- return STRNICMP(match->cp_str, str, (size_t)len) == 0;
- return STRNCMP(match->cp_str, str, (size_t)len) == 0;
+ if (match->cp_icase) {
+ return STRNICMP(match->cp_str, str, len) == 0;
+ }
+ return STRNCMP(match->cp_str, str, len) == 0;
}
/*
@@ -2314,6 +2322,22 @@ static int ins_compl_make_cyclic(void)
return count;
}
+
+// Set variables that store noselect and noinsert behavior from the
+// 'completeopt' value.
+void completeopt_was_set(void)
+{
+ compl_no_insert = false;
+ compl_no_select = false;
+ if (strstr((char *)p_cot, "noselect") != NULL) {
+ compl_no_select = true;
+ }
+ if (strstr((char *)p_cot, "noinsert") != NULL) {
+ compl_no_insert = true;
+ }
+}
+
+
/*
* Start completion for the complete() function.
* "startcol" is where the matched text starts (1 is first column).
@@ -2353,13 +2377,13 @@ void set_completion(colnr_T startcol, list_T *list)
int save_w_wrow = curwin->w_wrow;
compl_curr_match = compl_first_match;
- if (compl_no_insert) {
+ if (compl_no_insert || compl_no_select) {
ins_complete(K_DOWN, false);
- } else {
- ins_complete(Ctrl_N, false);
if (compl_no_select) {
- ins_complete(Ctrl_P, false);
+ ins_complete(K_UP, false);
}
+ } else {
+ ins_complete(Ctrl_N, false);
}
// Lazily show the popup menu, unless we got interrupted.
@@ -2403,44 +2427,33 @@ static void ins_compl_del_pum(void)
}
}
-/*
- * Return TRUE if the popup menu should be displayed.
- */
-static int pum_wanted(void)
+/// Check if the popup menu should be displayed.
+static bool pum_wanted(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- /* 'completeopt' must contain "menu" or "menuone" */
- if (vim_strchr(p_cot, 'm') == NULL)
- return FALSE;
-
- /* The display looks bad on a B&W display. */
- if (t_colors < 8
- )
- return FALSE;
- return TRUE;
+ // "completeopt" must contain "menu" or "menuone"
+ return vim_strchr(p_cot, 'm') != NULL;
}
-/*
- * Return TRUE if there are two or more matches to be shown in the popup menu.
- * One if 'completopt' contains "menuone".
- */
-static int pum_enough_matches(void)
+/// Check that there are two or more matches to be shown in the popup menu.
+/// One if "completopt" contains "menuone".
+static bool pum_enough_matches(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- compl_T *compl;
- int i;
-
- /* Don't display the popup menu if there are no matches or there is only
- * one (ignoring the original text). */
- compl = compl_first_match;
- i = 0;
+ // Don't display the popup menu if there are no matches or there is only
+ // one (ignoring the original text).
+ compl_T *comp = compl_first_match;
+ int i = 0;
do {
- if (compl == NULL
- || ((compl->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2))
+ if (comp == NULL || ((comp->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2)) {
break;
- compl = compl->cp_next;
- } while (compl != compl_first_match);
+ }
+ comp = comp->cp_next;
+ } while (comp != compl_first_match);
- if (strstr((char *)p_cot, "menuone") != NULL)
+ if (strstr((char *)p_cot, "menuone") != NULL) {
return i >= 1;
+ }
return i >= 2;
}
@@ -2871,10 +2884,9 @@ static void ins_compl_clear(void)
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
}
-/*
- * Return TRUE when Insert completion is active.
- */
-int ins_compl_active(void)
+/// Check that Insert completion is active.
+bool ins_compl_active(void)
+ FUNC_ATTR_PURE
{
return compl_started;
}
@@ -2918,14 +2930,13 @@ static int ins_compl_bs(void)
return NUL;
}
-/*
- * Return TRUE when we need to find matches again, ins_compl_restart() is to
- * be called.
- */
-static int ins_compl_need_restart(void)
+/// Check that we need to find matches again, ins_compl_restart() is to
+/// be called.
+static bool ins_compl_need_restart(void)
+ FUNC_ATTR_PURE
{
- /* Return TRUE if we didn't complete finding matches or when the
- * 'completefunc' returned "always" in the "refresh" dictionary item. */
+ // Return true if we didn't complete finding matches or when the
+ // "completefunc" returned "always" in the "refresh" dictionary item.
return compl_was_interrupted
|| ((ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
&& compl_opt_refresh_always);
@@ -3073,16 +3084,16 @@ static void ins_compl_addfrommatch(void)
ins_compl_addleader(c);
}
-/*
- * Prepare for Insert mode completion, or stop it.
- * Called just after typing a character in Insert mode.
- * Returns TRUE when the character is not to be inserted;
- */
-static int ins_compl_prep(int c)
+/// Prepare for Insert mode completion, or stop it.
+/// Called just after typing a character in Insert mode.
+///
+/// @param c character that was typed
+///
+/// @return true when the character is not to be inserted;
+static bool ins_compl_prep(int c)
{
- char_u *ptr;
- int want_cindent;
- int retval = FALSE;
+ char_u *ptr;
+ bool retval = false;
/* Forget any previous 'special' messages if this is actually
* a ^X mode key - bar ^R, in which case we wait to see what it gives us.
@@ -3092,8 +3103,10 @@ static int ins_compl_prep(int c)
/* Ignore end of Select mode mapping and mouse scroll buttons. */
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT)
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
+ || c == K_FOCUSGAINED || c == K_FOCUSLOST) {
return retval;
+ }
/* Set "compl_get_longest" when finding the first matches. */
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
@@ -3103,17 +3116,6 @@ static int ins_compl_prep(int c)
}
- if (strstr((char *)p_cot, "noselect") != NULL) {
- compl_no_insert = FALSE;
- compl_no_select = TRUE;
- } else if (strstr((char *)p_cot, "noinsert") != NULL) {
- compl_no_insert = TRUE;
- compl_no_select = FALSE;
- } else {
- compl_no_insert = FALSE;
- compl_no_select = FALSE;
- }
-
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) {
/*
* We have just typed CTRL-X and aren't quite sure which CTRL-X mode
@@ -3247,11 +3249,9 @@ static int ins_compl_prep(int c)
ins_compl_fixRedoBufForLeader(ptr);
}
- want_cindent = (can_cindent && cindent_on());
- /*
- * When completing whole lines: fix indent for 'cindent'.
- * Otherwise, break line if it's too long.
- */
+ bool want_cindent = (can_cindent && cindent_on());
+ // When completing whole lines: fix indent for 'cindent'.
+ // Otherwise, break line if it's too long.
if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
/* re-indent the current line */
if (want_cindent) {
@@ -3271,22 +3271,24 @@ static int ins_compl_prep(int c)
inc_cursor();
}
- /* If the popup menu is displayed pressing CTRL-Y means accepting
- * the selection without inserting anything. When
- * compl_enter_selects is set the Enter key does the same. */
+ // If the popup menu is displayed pressing CTRL-Y means accepting
+ // the selection without inserting anything. When
+ // compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
- && pum_visible())
- retval = TRUE;
+ && pum_visible()) {
+ retval = true;
+ }
/* CTRL-E means completion is Ended, go back to the typed text. */
if (c == Ctrl_E) {
ins_compl_delete();
- if (compl_leader != NULL)
+ if (compl_leader != NULL) {
ins_bytes(compl_leader + ins_compl_len());
- else if (compl_first_match != NULL)
+ } else if (compl_first_match != NULL) {
ins_bytes(compl_orig_text + ins_compl_len());
- retval = TRUE;
+ }
+ retval = true;
}
auto_format(FALSE, TRUE);
@@ -3304,6 +3306,12 @@ static int ins_compl_prep(int c)
showmode();
}
+ // Avoid the popup menu remains displayed when leaving the
+ // command line window.
+ if (c == Ctrl_C && cmdwin_type != 0) {
+ update_screen(0);
+ }
+
/*
* Indent now if a key was typed that is in 'cinkeys'.
*/
@@ -4245,22 +4253,22 @@ void ins_compl_check_keys(int frequency)
static int ins_compl_key2dir(int c)
{
if (c == Ctrl_P || c == Ctrl_L
- || (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP
- || c == K_S_UP || c == K_UP)))
+ || c == K_PAGEUP || c == K_KPAGEUP
+ || c == K_S_UP || c == K_UP) {
return BACKWARD;
+ }
return FORWARD;
}
-/*
- * Return TRUE for keys that are used for completion only when the popup menu
- * is visible.
- */
-static int ins_compl_pum_key(int c)
+/// Check that "c" is a valid completion key only while the popup menu is shown
+///
+/// @param c character to check
+static bool ins_compl_pum_key(int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
- || c == K_PAGEDOWN || c == K_KPAGEDOWN || c ==
- K_S_DOWN
- || c == K_UP || c == K_DOWN);
+ || c == K_PAGEDOWN || c == K_KPAGEDOWN
+ || c == K_S_DOWN || c == K_UP || c == K_DOWN);
}
/*
@@ -4280,11 +4288,12 @@ static int ins_compl_key2count(int c)
return 1;
}
-/*
- * Return TRUE if completion with "c" should insert the match, FALSE if only
- * to change the currently selected completion.
- */
-static int ins_compl_use_match(int c)
+/// Check that completion with "c" should insert the match, false if only
+/// to change the currently selected completion.
+///
+/// @param c character to check
+static bool ins_compl_use_match(int c)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (c) {
case K_UP:
@@ -4295,9 +4304,9 @@ static int ins_compl_use_match(int c)
case K_PAGEUP:
case K_KPAGEUP:
case K_S_UP:
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/*
@@ -4421,11 +4430,10 @@ static int ins_complete(int c, bool enable_pum)
prefix = (char_u *)"";
STRCPY((char *)compl_pattern, prefix);
(void)quote_meta(compl_pattern + STRLEN(prefix),
- line + compl_col, compl_length);
- } else if (--startcol < 0 ||
- !vim_iswordp(mb_prevptr(line, line + startcol + 1))
- ) {
- /* Match any word of at least two chars */
+ line + compl_col, compl_length);
+ } else if (--startcol < 0
+ || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
+ // Match any word of at least two chars
compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
compl_col += curs_col;
compl_length = 0;
@@ -6313,18 +6321,22 @@ char_u *get_last_insert_save(void)
return s;
}
-/*
- * Check the word in front of the cursor for an abbreviation.
- * Called when the non-id character "c" has been entered.
- * When an abbreviation is recognized it is removed from the text and
- * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
- */
-static int echeck_abbr(int c)
+/// Check the word in front of the cursor for an abbreviation.
+/// Called when the non-id character "c" has been entered.
+/// When an abbreviation is recognized it is removed from the text and
+/// the replacement string is inserted in typebuf.tb_buf[], followed by "c".
+///
+/// @param c character
+///
+/// @return true if the word is a known abbreviation.
+static bool echeck_abbr(int c)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- /* Don't check for abbreviation in paste mode, when disabled and just
- * after moving around with cursor keys. */
- if (p_paste || no_abbr || arrow_used)
- return FALSE;
+ // Don't check for abbreviation in paste mode, when disabled and just
+ // after moving around with cursor keys.
+ if (p_paste || no_abbr || arrow_used) {
+ return false;
+ }
return check_abbr(c, get_cursor_line_ptr(), curwin->w_cursor.col,
curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
@@ -6560,13 +6572,11 @@ static void replace_do_bs(int limit_col)
(void)del_char_after_col(limit_col);
}
-/*
- * Return TRUE if C-indenting is on.
- */
-static int cindent_on(void) {
- return !p_paste && (curbuf->b_p_cin
- || *curbuf->b_p_inde != NUL
- );
+/// Check that C-indenting is on.
+static bool cindent_on(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL);
}
/*
@@ -6596,32 +6606,33 @@ void fix_indent(void) {
do_c_expr_indent();
}
-/*
- * return TRUE if 'cinkeys' contains the key "keytyped",
- * when == '*': Only if key is preceded with '*' (indent before insert)
- * when == '!': Only if key is preceded with '!' (don't insert)
- * when == ' ': Only if key is not preceded with '*'(indent afterwards)
- *
- * "keytyped" can have a few special values:
- * KEY_OPEN_FORW
- * KEY_OPEN_BACK
- * KEY_COMPLETE just finished completion.
- *
- * If line_is_empty is TRUE accept keys with '0' before them.
- */
-int in_cinkeys(int keytyped, int when, int line_is_empty)
+/// Check that "cinkeys" contains the key "keytyped",
+/// when == '*': Only if key is preceded with '*' (indent before insert)
+/// when == '!': Only if key is preceded with '!' (don't insert)
+/// when == ' ': Only if key is not preceded with '*' (indent afterwards)
+///
+/// "keytyped" can have a few special values:
+/// KEY_OPEN_FORW :
+/// KEY_OPEN_BACK :
+/// KEY_COMPLETE : Just finished completion.
+///
+/// @param keytyped key that was typed
+/// @param when condition on when to perform the check
+/// @param line_is_empty when true, accept keys with '0' before them.
+bool in_cinkeys(int keytyped, int when, bool line_is_empty)
{
- char_u *look;
+ char_u *look;
int try_match;
int try_match_word;
- char_u *p;
- char_u *line;
+ char_u *p;
+ char_u *line;
int icase;
int i;
- if (keytyped == NUL)
- /* Can happen with CTRL-Y and CTRL-E on a short line. */
- return FALSE;
+ if (keytyped == NUL) {
+ // Can happen with CTRL-Y and CTRL-E on a short line.
+ return false;
+ }
if (*curbuf->b_p_inde != NUL)
look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
@@ -6637,68 +6648,64 @@ int in_cinkeys(int keytyped, int when, int line_is_empty)
case '!': try_match = (*look == '!'); break;
default: try_match = (*look != '*'); break;
}
- if (*look == '*' || *look == '!')
- ++look;
+ if (*look == '*' || *look == '!') {
+ look++;
+ }
- /*
- * If there is a '0', only accept a match if the line is empty.
- * But may still match when typing last char of a word.
- */
+ // If there is a '0', only accept a match if the line is empty.
+ // But may still match when typing last char of a word.
if (*look == '0') {
try_match_word = try_match;
- if (!line_is_empty)
- try_match = FALSE;
- ++look;
- } else
- try_match_word = FALSE;
+ if (!line_is_empty) {
+ try_match = false;
+ }
+ look++;
+ } else {
+ try_match_word = false;
+ }
- /*
- * does it look like a control character?
- */
- if (*look == '^'
- && look[1] >= '?' && look[1] <= '_'
- ) {
- if (try_match && keytyped == Ctrl_chr(look[1]))
- return TRUE;
+ // Does it look like a control character?
+ if (*look == '^' && look[1] >= '?' && look[1] <= '_') {
+ if (try_match && keytyped == Ctrl_chr(look[1])) {
+ return true;
+ }
look += 2;
- }
- /*
- * 'o' means "o" command, open forward.
- * 'O' means "O" command, open backward.
- */
- else if (*look == 'o') {
- if (try_match && keytyped == KEY_OPEN_FORW)
- return TRUE;
- ++look;
+
+ // 'o' means "o" command, open forward.
+ // 'O' means "O" command, open backward.
+ } else if (*look == 'o') {
+ if (try_match && keytyped == KEY_OPEN_FORW) {
+ return true;
+ }
+ look++;
} else if (*look == 'O') {
- if (try_match && keytyped == KEY_OPEN_BACK)
- return TRUE;
- ++look;
- }
- /*
- * 'e' means to check for "else" at start of line and just before the
- * cursor.
- */
- else if (*look == 'e') {
+ if (try_match && keytyped == KEY_OPEN_BACK) {
+ return true;
+ }
+ look++;
+
+ // 'e' means to check for "else" at start of line and just before the
+ // cursor.
+ } else if (*look == 'e') {
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
p = get_cursor_line_ptr();
- if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
- STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
- return TRUE;
+ if (skipwhite(p) == p + curwin->w_cursor.col - 4
+ && STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
+ return true;
+ }
}
- ++look;
- }
- /*
- * ':' only causes an indent if it is at the end of a label or case
- * statement, or when it was before typing the ':' (to fix
- * class::method for C++).
- */
- else if (*look == ':') {
+ look++;
+
+ // ':' only causes an indent if it is at the end of a label or case
+ // statement, or when it was before typing the ':' (to fix
+ // class::method for C++).
+ } else if (*look == ':') {
if (try_match && keytyped == ':') {
p = get_cursor_line_ptr();
- if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel())
- return TRUE;
- /* Need to get the line again after cin_islabel(). */
+ if (cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel()) {
+ return true;
+ }
+ // Need to get the line again after cin_islabel().
p = get_cursor_line_ptr();
if (curwin->w_cursor.col > 2
&& p[curwin->w_cursor.col - 1] == ':'
@@ -6708,28 +6715,27 @@ int in_cinkeys(int keytyped, int when, int line_is_empty)
|| cin_islabel());
p = get_cursor_line_ptr();
p[curwin->w_cursor.col - 1] = ':';
- if (i)
- return TRUE;
+ if (i) {
+ return true;
+ }
}
}
- ++look;
- }
- /*
- * Is it a key in <>, maybe?
- */
- else if (*look == '<') {
+ look++;
+
+ // Is it a key in <>, maybe?
+ } else if (*look == '<') {
if (try_match) {
- /*
- * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
- * <:> and <!> so that people can re-indent on o, O, e, 0, <,
- * >, *, : and ! keys if they really really want to.
- */
+ // make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
+ // <:> and <!> so that people can re-indent on o, O, e, 0, <,
+ // >, *, : and ! keys if they really really want to.
if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
- && keytyped == look[1])
- return TRUE;
+ && keytyped == look[1]) {
+ return true;
+ }
- if (keytyped == get_special_key_code(look + 1))
- return TRUE;
+ if (keytyped == get_special_key_code(look + 1)) {
+ return true;
+ }
}
while (*look && *look != '>')
look++;
@@ -6800,18 +6806,18 @@ int in_cinkeys(int keytyped, int when, int line_is_empty)
(int)(curwin->w_cursor.col - (p - look)))
match = FALSE;
}
- if (match)
- return TRUE;
+ if (match) {
+ return true;
+ }
}
look = p;
- }
- /*
- * ok, it's a boring generic character.
- */
- else {
- if (try_match && *look == keytyped)
- return TRUE;
- ++look;
+
+ // Ok, it's a boring generic character.
+ } else {
+ if (try_match && *look == keytyped) {
+ return true;
+ }
+ look++;
}
/*
@@ -6819,7 +6825,7 @@ int in_cinkeys(int keytyped, int when, int line_is_empty)
*/
look = skip_to_option_part(look);
}
- return FALSE;
+ return false;
}
/*
@@ -7046,27 +7052,24 @@ static void ins_ctrl_hat(void)
status_redraw_curbuf();
}
-/*
- * Handle ESC in insert mode.
- * Returns TRUE when leaving insert mode, FALSE when going to repeat the
- * insert.
- */
-static int
-ins_esc (
- long *count,
- int cmdchar,
- int nomove /* don't move cursor */
-)
+/// Handle ESC in insert mode.
+///
+/// @param[in,out] count repeat count of the insert command
+/// @param cmdchar command that started the insert
+/// @param nomove when true, don't move the cursor
+///
+/// @return true when leaving insert mode, false when repeating the insert.
+static bool ins_esc(long *count, int cmdchar, bool nomove)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- int temp;
- static int disabled_redraw = FALSE;
+ static bool disabled_redraw = false;
check_spell_redraw();
- temp = curwin->w_cursor.col;
+ int temp = curwin->w_cursor.col;
if (disabled_redraw) {
- --RedrawingDisabled;
- disabled_redraw = FALSE;
+ RedrawingDisabled--;
+ disabled_redraw = false;
}
if (!arrow_used) {
/*
@@ -7096,9 +7099,10 @@ ins_esc (
if (cmdchar == 'r' || cmdchar == 'v') {
stuffRedoReadbuff(ESC_STR); // No ESC in redo buffer
}
- ++RedrawingDisabled;
- disabled_redraw = TRUE;
- return FALSE; /* repeat the insert */
+ RedrawingDisabled++;
+ disabled_redraw = true;
+ // Repeat the insert
+ return false;
}
stop_insert(&curwin->w_cursor, TRUE, nomove);
undisplay_dollar();
@@ -7148,16 +7152,15 @@ ins_esc (
setmouse();
ui_cursor_shape(); /* may show different cursor shape */
- /*
- * When recording or for CTRL-O, need to display the new mode.
- * Otherwise remove the mode message.
- */
- if (Recording || restart_edit != NUL)
+ // When recording or for CTRL-O, need to display the new mode.
+ // Otherwise remove the mode message.
+ if (Recording || restart_edit != NUL) {
showmode();
- else if (p_smd)
+ } else if (p_smd) {
MSG("");
-
- return TRUE; /* exit Insert mode */
+ }
+ // Exit Insert mode
+ return true;
}
/*
@@ -7195,14 +7198,16 @@ static void ins_ctrl_(void)
showmode();
}
-/*
- * If 'keymodel' contains "startsel", may start selection.
- * Returns TRUE when a CTRL-O and other keys stuffed.
- */
-static int ins_start_select(int c)
+/// If 'keymodel' contains "startsel", may start selection.
+///
+/// @param c character to check
+//
+/// @return true when a CTRL-O and other keys stuffed.
+static bool ins_start_select(int c)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
if (!km_startsel) {
- return FALSE;
+ return false;
}
switch (c) {
case K_KHOME:
@@ -7213,32 +7218,27 @@ static int ins_start_select(int c)
case K_KPAGEDOWN:
if (!(mod_mask & MOD_MASK_SHIFT))
break;
- /* FALLTHROUGH */
+ // FALLTHROUGH
case K_S_LEFT:
case K_S_RIGHT:
case K_S_UP:
case K_S_DOWN:
case K_S_END:
case K_S_HOME:
- /* Start selection right away, the cursor can move with
- * CTRL-O when beyond the end of the line. */
+ // Start selection right away, the cursor can move with
+ // CTRL-O when beyond the end of the line.
start_selection();
- /* Execute the key in (insert) Select mode. */
+ // Execute the key in (insert) Select mode.
stuffcharReadbuff(Ctrl_O);
if (mod_mask) {
- char_u buf[4];
-
- buf[0] = K_SPECIAL;
- buf[1] = KS_MODIFIER;
- buf[2] = mod_mask;
- buf[3] = NUL;
+ char_u buf[4] = { K_SPECIAL, KS_MODIFIER, mod_mask, NUL };
stuffReadbuff(buf);
}
stuffcharReadbuff(c);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -7252,15 +7252,15 @@ static void ins_insert(int replaceState)
return;
}
- set_vim_var_string(VV_INSERTMODE,
- (char_u *)((State & REPLACE_FLAG) ? "i" :
- replaceState == VREPLACE ? "v" :
- "r"), 1);
- apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf);
- if (State & REPLACE_FLAG)
+ set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" :
+ replaceState == VREPLACE ? "v" :
+ "r"), 1);
+ apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, false, curbuf);
+ if (State & REPLACE_FLAG) {
State = INSERT | (State & LANGMAP);
- else
+ } else {
State = replaceState | (State & LANGMAP);
+ }
AppendCharToRedobuff(K_INS);
showmode();
ui_cursor_shape(); /* may show different cursor shape */
@@ -7362,18 +7362,23 @@ static void ins_bs_one(colnr_T *vcolp)
(void)del_char(FALSE);
}
-/*
- * Handle Backspace, delete-word and delete-line in Insert mode.
- * Return TRUE when backspace was actually used.
- */
-static int ins_bs(int c, int mode, int *inserted_space_p)
+/// Handle Backspace, delete-word and delete-line in Insert mode.
+///
+/// @param c charcter that was typed
+/// @param mode backspace mode to use
+/// @param[in,out] inserted_space_p whether a space was the last
+// character inserted
+///
+/// @return true when backspace was actually used.
+static bool ins_bs(int c, int mode, int *inserted_space_p)
+ FUNC_ATTR_NONNULL_ARG(3)
{
linenr_T lnum;
int cc;
int temp = 0; /* init for GCC */
colnr_T save_col;
colnr_T mincol;
- int did_backspace = FALSE;
+ bool did_backspace = false;
int in_indent;
int oldState;
int cpc[MAX_MCO]; /* composing characters */
@@ -7384,43 +7389,43 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
* can't backup past starting point unless 'backspace' > 1
* can backup to a previous line if 'backspace' == 0
*/
- if ( bufempty()
- || (
- !revins_on &&
- ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
- || (!can_bs(BS_START)
- && (arrow_used
- || (curwin->w_cursor.lnum == Insstart_orig.lnum
- && curwin->w_cursor.col <= Insstart_orig.col)))
- || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
- && curwin->w_cursor.col <= ai_col)
- || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) {
+ if (bufempty()
+ || (!revins_on
+ && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
+ || (!can_bs(BS_START)
+ && (arrow_used
+ || (curwin->w_cursor.lnum == Insstart_orig.lnum
+ && curwin->w_cursor.col <= Insstart_orig.col)))
+ || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
+ && curwin->w_cursor.col <= ai_col)
+ || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) {
vim_beep(BO_BS);
return false;
}
- if (stop_arrow() == FAIL)
- return FALSE;
+ if (stop_arrow() == FAIL) {
+ return false;
+ }
in_indent = inindent(0);
- if (in_indent)
- can_cindent = FALSE;
- end_comment_pending = NUL; /* After BS, don't auto-end comment */
- if (revins_on) /* put cursor after last inserted char */
+ if (in_indent) {
+ can_cindent = false;
+ }
+ end_comment_pending = NUL; // After BS, don't auto-end comment
+ if (revins_on) { // put cursor after last inserted char
inc_cursor();
-
- /* Virtualedit:
- * BACKSPACE_CHAR eats a virtual space
- * BACKSPACE_WORD eats all coladd
- * BACKSPACE_LINE eats all coladd and keeps going
- */
+ }
+ // Virtualedit:
+ // BACKSPACE_CHAR eats a virtual space
+ // BACKSPACE_WORD eats all coladd
+ // BACKSPACE_LINE eats all coladd and keeps going
if (curwin->w_cursor.coladd > 0) {
if (mode == BACKSPACE_CHAR) {
- --curwin->w_cursor.coladd;
- return TRUE;
+ curwin->w_cursor.coladd--;
+ return true;
}
if (mode == BACKSPACE_WORD) {
curwin->w_cursor.coladd = 0;
- return TRUE;
+ return true;
}
curwin->w_cursor.coladd = 0;
}
@@ -7432,10 +7437,10 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
lnum = Insstart.lnum;
if (curwin->w_cursor.lnum == lnum || revins_on) {
if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
- (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) {
- return FALSE;
+ (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) {
+ return false;
}
- --Insstart.lnum;
+ Insstart.lnum--;
Insstart.col = MAXCOL;
}
/*
@@ -7639,14 +7644,14 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
if (revins_on && gchar_cursor() == NUL)
break;
}
- /* Just a single backspace?: */
- if (mode == BACKSPACE_CHAR)
+ // Just a single backspace?:
+ if (mode == BACKSPACE_CHAR) {
break;
- } while (
- revins_on ||
- (curwin->w_cursor.col > mincol
- && (curwin->w_cursor.lnum != Insstart_orig.lnum
- || curwin->w_cursor.col != Insstart_orig.col)));
+ }
+ } while (revins_on
+ || (curwin->w_cursor.col > mincol
+ && (curwin->w_cursor.lnum != Insstart_orig.lnum
+ || curwin->w_cursor.col != Insstart_orig.col)));
}
did_backspace = true;
}
@@ -7677,12 +7682,12 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1)
dollar_vcol = curwin->w_virtcol;
- /* When deleting a char the cursor line must never be in a closed fold.
- * E.g., when 'foldmethod' is indent and deleting the first non-white
- * char before a Tab. */
- if (did_backspace)
+ // When deleting a char the cursor line must never be in a closed fold.
+ // E.g., when 'foldmethod' is indent and deleting the first non-white
+ // char before a Tab.
+ if (did_backspace) {
foldOpenCursor();
-
+ }
return did_backspace;
}
@@ -7748,6 +7753,8 @@ static void ins_mousescroll(int dir)
(long)(curwin->w_botline - curwin->w_topline));
else
scroll_redraw(dir, 3L);
+ } else {
+ mouse_scroll_horiz(dir);
}
did_scroll = TRUE;
}
@@ -8001,35 +8008,37 @@ static void ins_pagedown(void)
}
}
-/*
- * Handle TAB in Insert or Replace mode.
- * Return TRUE when the TAB needs to be inserted like a normal character.
- */
-static int ins_tab(void)
+/// Handle TAB in Insert or Replace mode.
+///
+/// @return true when the TAB needs to be inserted like a normal character.
+static bool ins_tab(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
- int ind;
int i;
int temp;
- if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
+ if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) {
Insstart_blank_vcol = get_nolist_virtcol();
- if (echeck_abbr(TAB + ABBR_OFF))
- return FALSE;
+ }
+ if (echeck_abbr(TAB + ABBR_OFF)) {
+ return false;
+ }
- ind = inindent(0);
- if (ind)
- can_cindent = FALSE;
+ int ind = inindent(0);
+ if (ind) {
+ can_cindent = false;
+ }
- /*
- * When nothing special, insert TAB like a normal character
- */
+ // When nothing special, insert TAB like a normal character
if (!curbuf->b_p_et
&& !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf))
- && get_sts_value() == 0)
- return TRUE;
+ && get_sts_value() == 0) {
+ return true;
+ }
- if (stop_arrow() == FAIL)
- return TRUE;
+ if (stop_arrow() == FAIL) {
+ return true;
+ }
did_ai = FALSE;
did_si = FALSE;
@@ -8037,12 +8046,13 @@ static int ins_tab(void)
can_si_back = FALSE;
AppendToRedobuff((char_u *)"\t");
- if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
+ if (p_sta && ind) { // insert tab in indent, use "shiftwidth"
temp = get_sw_value(curbuf);
- else if (curbuf->b_p_sts != 0) /* use 'softtabstop' when set */
+ } else if (curbuf->b_p_sts != 0) { // use "softtabstop" when set
temp = get_sts_value();
- else /* otherwise use 'tabstop' */
+ } else { // otherwise use "tabstop"
temp = (int)curbuf->b_p_ts;
+ }
temp -= get_nolist_virtcol() % temp;
/*
@@ -8182,21 +8192,20 @@ static int ins_tab(void)
curwin->w_p_list = save_list;
}
- return FALSE;
+ return false;
}
-/*
- * Handle CR or NL in insert mode.
- * Return TRUE when it can't undo.
- */
-static int ins_eol(int c)
+/// Handle CR or NL in insert mode.
+///
+/// @return true when it can't undo.
+static bool ins_eol(int c)
{
- int i;
-
- if (echeck_abbr(c + ABBR_OFF))
- return FALSE;
- if (stop_arrow() == FAIL)
- return TRUE;
+ if (echeck_abbr(c + ABBR_OFF)) {
+ return false;
+ }
+ if (stop_arrow() == FAIL) {
+ return true;
+ }
undisplay_dollar();
/*
@@ -8229,9 +8238,9 @@ static int ins_eol(int c)
curwin->w_cursor.col += (colnr_T)STRLEN(get_cursor_pos_ptr());
AppendToRedobuff(NL_STR);
- i = open_line(FORWARD,
- has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
- 0, old_indent);
+ bool i = open_line(FORWARD,
+ has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0,
+ old_indent);
old_indent = 0;
can_cindent = TRUE;
/* When inserting a line the cursor line must never be in a closed fold. */
@@ -8485,22 +8494,22 @@ static colnr_T get_nolist_virtcol(void)
*/
static char_u *do_insert_char_pre(int c)
{
- char_u buf[MB_MAXBYTES + 1];
+ char buf[MB_MAXBYTES + 1];
// Return quickly when there is nothing to do.
if (!has_event(EVENT_INSERTCHARPRE)) {
return NULL;
}
if (has_mbyte) {
- buf[(*mb_char2bytes)(c, buf)] = NUL;
+ buf[(*mb_char2bytes)(c, (char_u *) buf)] = NUL;
} else {
buf[0] = c;
buf[1] = NUL;
}
- /* Lock the text to avoid weird things from happening. */
- ++textlock;
- set_vim_var_string(VV_CHAR, buf, -1); /* set v:char */
+ // Lock the text to avoid weird things from happening.
+ textlock++;
+ set_vim_var_string(VV_CHAR, buf, -1);
char_u *res = NULL;
if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL, FALSE, curbuf)) {
@@ -8511,8 +8520,8 @@ static char_u *do_insert_char_pre(int c)
res = vim_strsave(get_vim_var_str(VV_CHAR));
}
- set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
- --textlock;
+ set_vim_var_string(VV_CHAR, NULL, -1);
+ textlock--;
return res;
}
diff --git a/src/nvim/edit.h b/src/nvim/edit.h
index 0289b2c3a6..0d61f26bcc 100644
--- a/src/nvim/edit.h
+++ b/src/nvim/edit.h
@@ -36,12 +36,6 @@ typedef int (*IndentGetter)(void);
#define INSCHAR_NO_FEX 8 /* don't use 'formatexpr' */
#define INSCHAR_COM_LIST 16 /* format comments with list/2nd line indent */
-/* direction for nv_mousescroll() and ins_mousescroll() */
-#define MSCR_DOWN 0 /* DOWN must be FALSE */
-#define MSCR_UP 1
-#define MSCR_LEFT -1
-#define MSCR_RIGHT -2
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "edit.h.generated.h"
#endif
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 31175773f0..201a71facb 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -66,13 +66,14 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/tempfile.h"
#include "nvim/ui.h"
#include "nvim/mouse.h"
#include "nvim/terminal.h"
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/window.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/decode.h"
#include "nvim/os/os.h"
#include "nvim/event/libuv_process.h"
#include "nvim/event/pty_process.h"
@@ -87,7 +88,6 @@
#include "nvim/os/dl.h"
#include "nvim/os/input.h"
#include "nvim/event/loop.h"
-#include "nvim/lib/kvec.h"
#include "nvim/lib/queue.h"
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
@@ -142,13 +142,6 @@ typedef struct lval_S {
char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
} lval_T;
-/// Structure defining state for read_from_list()
-typedef struct {
- const listitem_T *li; ///< Item currently read.
- size_t offset; ///< Byte offset inside the read item.
- size_t li_length; ///< Length of the string inside the read item.
-} ListReaderState;
-
static char *e_letunexp = N_("E18: Unexpected characters in :let");
static char *e_listidx = N_("E684: list index out of range: %" PRId64);
@@ -160,6 +153,7 @@ static char *e_listdictarg = N_(
static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary");
static char *e_listreq = N_("E714: List required");
static char *e_dictreq = N_("E715: Dictionary required");
+static char *e_strreq = N_("E114: String required");
static char *e_toomanyarg = N_("E118: Too many arguments for function: %s");
static char *e_dictkey = N_("E716: Key not present in Dictionary: %s");
static char *e_funcexts = N_(
@@ -173,6 +167,7 @@ static char *e_illvar = N_("E461: Illegal variable name: %s");
static char *e_float_as_string = N_("E806: using Float as a String");
static char_u * const empty_string = (char_u *)"";
+static char_u * const namespace_char = (char_u *)"abglstvw";
static dictitem_T globvars_var; /* variable used for g: */
#define globvarht globvardict.dv_hashtab
@@ -183,17 +178,7 @@ static dictitem_T globvars_var; /* variable used for g: */
*/
static hashtab_T compat_hashtab;
-/*
- * When recursively copying lists and dicts we need to remember which ones we
- * have done to avoid endless recursiveness. This unique ID is used for that.
- * The last bit is used for previous_funccal, ignored when comparing.
- */
-static int current_copyID = 0;
-#define COPYID_INC 2
-#define COPYID_MASK (~0x1)
-
-/// Abort conversion to string after a recursion error.
-static bool did_echo_string_emsg = false;
+hashtab_T func_hashtab;
/*
* Array to hold the hashtab with variables local to each sourced script.
@@ -296,93 +281,112 @@ typedef enum {
#define VV_RO 2 /* read-only */
#define VV_RO_SBX 4 /* read-only in the sandbox */
-#define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}, {0}
+#define VV(idx, name, type, flags) \
+ [idx] = { \
+ .vv_name = name, \
+ .vv_di = { \
+ .di_tv = { .v_type = type }, \
+ .di_flags = 0, \
+ }, \
+ .vv_filler = { 0 }, \
+ .vv_flags = flags, \
+ }
// 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 variable, without v: */
- dictitem_T vv_di; /* value and name for key */
- char vv_filler[16]; /* space for LONGEST name below!!! */
- char vv_flags; /* VV_COMPAT, VV_RO, VV_RO_SBX */
-} vimvars[VV_LEN] =
-{
- /*
- * The order here must match the VV_ defines in eval.h!
- * Initializing a union does not work, leave tv.vval empty to get zero's.
- */
- { VV_NAME("count", VAR_NUMBER), VV_COMPAT+VV_RO },
- { VV_NAME("count1", VAR_NUMBER), VV_RO },
- { VV_NAME("prevcount", VAR_NUMBER), VV_RO },
- { VV_NAME("errmsg", VAR_STRING), VV_COMPAT },
- { VV_NAME("warningmsg", VAR_STRING), 0 },
- { VV_NAME("statusmsg", VAR_STRING), 0 },
- { VV_NAME("shell_error", VAR_NUMBER), VV_COMPAT+VV_RO },
- { VV_NAME("this_session", VAR_STRING), VV_COMPAT },
- { VV_NAME("version", VAR_NUMBER), VV_COMPAT+VV_RO },
- { VV_NAME("lnum", VAR_NUMBER), VV_RO_SBX },
- { VV_NAME("termresponse", VAR_STRING), VV_RO },
- { VV_NAME("fname", VAR_STRING), VV_RO },
- { VV_NAME("lang", VAR_STRING), VV_RO },
- { VV_NAME("lc_time", VAR_STRING), VV_RO },
- { VV_NAME("ctype", VAR_STRING), VV_RO },
- { VV_NAME("charconvert_from", VAR_STRING), VV_RO },
- { VV_NAME("charconvert_to", VAR_STRING), VV_RO },
- { VV_NAME("fname_in", VAR_STRING), VV_RO },
- { VV_NAME("fname_out", VAR_STRING), VV_RO },
- { VV_NAME("fname_new", VAR_STRING), VV_RO },
- { VV_NAME("fname_diff", VAR_STRING), VV_RO },
- { VV_NAME("cmdarg", VAR_STRING), VV_RO },
- { VV_NAME("foldstart", VAR_NUMBER), VV_RO_SBX },
- { VV_NAME("foldend", VAR_NUMBER), VV_RO_SBX },
- { VV_NAME("folddashes", VAR_STRING), VV_RO_SBX },
- { VV_NAME("foldlevel", VAR_NUMBER), VV_RO_SBX },
- { VV_NAME("progname", VAR_STRING), VV_RO },
- { VV_NAME("servername", VAR_STRING), VV_RO },
- { VV_NAME("dying", VAR_NUMBER), VV_RO },
- { VV_NAME("exception", VAR_STRING), VV_RO },
- { VV_NAME("throwpoint", VAR_STRING), VV_RO },
- { VV_NAME("register", VAR_STRING), VV_RO },
- { VV_NAME("cmdbang", VAR_NUMBER), VV_RO },
- { VV_NAME("insertmode", VAR_STRING), VV_RO },
- { VV_NAME("val", VAR_UNKNOWN), VV_RO },
- { VV_NAME("key", VAR_UNKNOWN), VV_RO },
- { VV_NAME("profiling", VAR_NUMBER), VV_RO },
- { VV_NAME("fcs_reason", VAR_STRING), VV_RO },
- { VV_NAME("fcs_choice", VAR_STRING), 0 },
- { VV_NAME("beval_bufnr", VAR_NUMBER), VV_RO },
- { VV_NAME("beval_winnr", VAR_NUMBER), VV_RO },
- { VV_NAME("beval_lnum", VAR_NUMBER), VV_RO },
- { VV_NAME("beval_col", VAR_NUMBER), VV_RO },
- { VV_NAME("beval_text", VAR_STRING), VV_RO },
- { VV_NAME("scrollstart", VAR_STRING), 0 },
- { VV_NAME("swapname", VAR_STRING), VV_RO },
- { VV_NAME("swapchoice", VAR_STRING), 0 },
- { VV_NAME("swapcommand", VAR_STRING), VV_RO },
- { VV_NAME("char", VAR_STRING), 0 },
- { VV_NAME("mouse_win", VAR_NUMBER), 0 },
- { VV_NAME("mouse_lnum", VAR_NUMBER), 0 },
- { VV_NAME("mouse_col", VAR_NUMBER), 0 },
- { VV_NAME("operator", VAR_STRING), VV_RO },
- { VV_NAME("searchforward", VAR_NUMBER), 0 },
- { VV_NAME("hlsearch", VAR_NUMBER), 0 },
- { VV_NAME("oldfiles", VAR_LIST), 0 },
- { VV_NAME("windowid", VAR_NUMBER), VV_RO },
- { VV_NAME("progpath", VAR_STRING), VV_RO },
- { VV_NAME("command_output", VAR_STRING), 0 },
- { VV_NAME("completed_item", VAR_DICT), VV_RO },
- { VV_NAME("option_new", VAR_STRING), VV_RO },
- { VV_NAME("option_old", VAR_STRING), VV_RO },
- { VV_NAME("option_type", VAR_STRING), VV_RO },
- { VV_NAME("errors", VAR_LIST), 0 },
- { VV_NAME("msgpack_types", VAR_DICT), VV_RO },
+ char *vv_name; ///< Name of the variable, without v:.
+ dictitem_T vv_di; ///< Value of the variable, with name.
+ char vv_filler[16]; ///< Space for longest name from below.
+ char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
+} vimvars[] =
+{
+ // VV_ tails differing from upcased string literals:
+ // VV_CC_FROM "charconvert_from"
+ // VV_CC_TO "charconvert_to"
+ // VV_SEND_SERVER "servername"
+ // VV_REG "register"
+ // VV_OP "operator"
+ VV(VV_COUNT, "count", VAR_NUMBER, VV_COMPAT+VV_RO),
+ VV(VV_COUNT1, "count1", VAR_NUMBER, VV_RO),
+ VV(VV_PREVCOUNT, "prevcount", VAR_NUMBER, VV_RO),
+ VV(VV_ERRMSG, "errmsg", VAR_STRING, VV_COMPAT),
+ VV(VV_WARNINGMSG, "warningmsg", VAR_STRING, 0),
+ VV(VV_STATUSMSG, "statusmsg", VAR_STRING, 0),
+ VV(VV_SHELL_ERROR, "shell_error", VAR_NUMBER, VV_COMPAT+VV_RO),
+ VV(VV_THIS_SESSION, "this_session", VAR_STRING, VV_COMPAT),
+ 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_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_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_COMMAND_OUTPUT, "command_output", VAR_STRING, 0),
+ 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_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
+ VV(VV_EVENT, "event", VAR_DICT, VV_RO),
+ VV(VV_FALSE, "false", VAR_SPECIAL, VV_RO),
+ VV(VV_TRUE, "true", VAR_SPECIAL, VV_RO),
+ VV(VV_NULL, "null", VAR_SPECIAL, VV_RO),
+ VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
+ VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
};
+#undef VV
/* shorthand */
#define vv_type vv_di.di_tv.v_type
#define vv_nr vv_di.di_tv.vval.v_number
+#define vv_special vv_di.di_tv.vval.v_special
#define vv_float vv_di.di_tv.vval.v_float
#define vv_str vv_di.di_tv.vval.v_string
#define vv_list vv_di.di_tv.vval.v_list
@@ -416,29 +420,6 @@ typedef struct dict_watcher {
bool busy; // prevent recursion if the dict is changed in the callback
} DictWatcher;
-/// Structure representing current VimL to messagepack conversion state
-typedef struct {
- enum {
- kMPConvDict, ///< Convert dict_T *dictionary.
- kMPConvList, ///< Convert list_T *list.
- kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
- } type;
- union {
- struct {
- dict_T *dict; ///< Currently converted dictionary.
- hashitem_T *hi; ///< Currently converted dictionary item.
- size_t todo; ///< Amount of items left to process.
- } d; ///< State of dictionary conversion.
- struct {
- list_T *list; ///< Currently converted list.
- listitem_T *li; ///< Currently converted list item.
- } l; ///< State of list or generic mapping conversion.
- } data; ///< Data to convert.
-} MPConvStackVal;
-
-/// Stack used to convert VimL values to messagepack.
-typedef kvec_t(MPConvStackVal) MPConvStack;
-
typedef struct {
TerminalJobData *data;
ufunc_T *callback;
@@ -457,17 +438,6 @@ typedef struct {
static uint64_t current_job_id = 1;
static PMap(uint64_t) *jobs = NULL;
-typedef enum {
- kMPNil,
- kMPBoolean,
- kMPInteger,
- kMPFloat,
- kMPString,
- kMPBinary,
- kMPArray,
- kMPMap,
- kMPExt,
-} MessagePackType;
static const char *const msgpack_type_names[] = {
[kMPNil] = "nil",
[kMPBoolean] = "boolean",
@@ -479,7 +449,7 @@ static const char *const msgpack_type_names[] = {
[kMPMap] = "map",
[kMPExt] = "ext",
};
-static const list_T *msgpack_type_lists[] = {
+const list_T *eval_msgpack_type_lists[] = {
[kMPNil] = NULL,
[kMPBoolean] = NULL,
[kMPInteger] = NULL,
@@ -496,8 +466,9 @@ static const list_T *msgpack_type_lists[] = {
*/
void eval_init(void)
{
+ vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+
jobs = pmap_new(uint64_t)();
- int i;
struct vimvar *p;
init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
@@ -506,7 +477,7 @@ void eval_init(void)
hash_init(&compat_hashtab);
hash_init(&func_hashtab);
- for (i = 0; i < VV_LEN; ++i) {
+ for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
p = &vimvars[i];
STRCPY(p->vv_di.di_key, p->vv_name);
if (p->vv_flags & VV_RO)
@@ -535,7 +506,7 @@ void eval_init(void)
.v_type = VAR_LIST,
.vval = { .v_list = type_list, },
};
- msgpack_type_lists[i] = type_list;
+ eval_msgpack_type_lists[i] = type_list;
if (dict_add(msgpack_types_dict, di) == FAIL) {
// There must not be duplicate items in this dictionary by definition.
assert(false);
@@ -545,10 +516,19 @@ void eval_init(void)
set_vim_var_dict(VV_MSGPACK_TYPES, msgpack_types_dict);
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+
+ dict_T *v_event = dict_alloc();
+ v_event->dv_lock = VAR_FIXED;
+ set_vim_var_dict(VV_EVENT, v_event);
set_vim_var_list(VV_ERRORS, list_alloc());
set_vim_var_nr(VV_SEARCHFORWARD, 1L);
set_vim_var_nr(VV_HLSEARCH, 1L);
- set_reg_var(0); /* default for v:register is not 0 but '"' */
+
+ set_vim_var_special(VV_FALSE, kSpecialVarFalse);
+ set_vim_var_special(VV_TRUE, kSpecialVarTrue);
+ set_vim_var_special(VV_NULL, kSpecialVarNull);
+
+ set_reg_var(0); // default for v:register is not 0 but '"'
}
#if defined(EXITFREE)
@@ -556,7 +536,7 @@ void eval_clear(void)
{
struct vimvar *p;
- for (int i = 0; i < VV_LEN; ++i) {
+ for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
p = &vimvars[i];
if (p->vv_di.di_tv.v_type == VAR_STRING) {
xfree(p->vv_str);
@@ -791,45 +771,50 @@ void var_redir_stop(void)
redir_varname = NULL;
}
-int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, char_u *fname_to)
+int eval_charconvert(const char *const enc_from, const char *const enc_to,
+ const char *const fname_from, const char *const fname_to)
{
- int err = FALSE;
+ int err = false;
set_vim_var_string(VV_CC_FROM, enc_from, -1);
set_vim_var_string(VV_CC_TO, enc_to, -1);
set_vim_var_string(VV_FNAME_IN, fname_from, -1);
set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
- if (eval_to_bool(p_ccv, &err, NULL, FALSE))
- err = TRUE;
+ if (eval_to_bool(p_ccv, &err, NULL, false)) {
+ err = true;
+ }
set_vim_var_string(VV_CC_FROM, NULL, -1);
set_vim_var_string(VV_CC_TO, NULL, -1);
set_vim_var_string(VV_FNAME_IN, NULL, -1);
set_vim_var_string(VV_FNAME_OUT, NULL, -1);
- if (err)
+ if (err) {
return FAIL;
+ }
return OK;
}
-int eval_printexpr(char_u *fname, char_u *args)
+int eval_printexpr(const char *const fname, const char *const args)
{
- int err = FALSE;
+ int err = false;
set_vim_var_string(VV_FNAME_IN, fname, -1);
set_vim_var_string(VV_CMDARG, args, -1);
- if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
- err = TRUE;
+ if (eval_to_bool(p_pexpr, &err, NULL, false)) {
+ err = true;
+ }
set_vim_var_string(VV_FNAME_IN, NULL, -1);
set_vim_var_string(VV_CMDARG, NULL, -1);
if (err) {
- os_remove((char *)fname);
+ os_remove(fname);
return FAIL;
}
return OK;
}
-void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile)
+void eval_diff(const char *const origfile, const char *const newfile,
+ const char *const outfile)
{
int err = FALSE;
@@ -842,7 +827,8 @@ void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile)
set_vim_var_string(VV_FNAME_OUT, NULL, -1);
}
-void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile)
+void eval_patch(const char *const origfile, const char *const difffile,
+ const char *const outfile)
{
int err;
@@ -1726,7 +1712,7 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first)
} else {
int c;
- char_u *s = (char_u *) echo_string(&tv, NULL);
+ char_u *s = (char_u *) encode_tv2echo(&tv, NULL);
c = *arg;
*arg = NUL;
list_one_var_a((char_u *)"",
@@ -2280,8 +2266,8 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, true, false) == OK) {
if ((di == NULL
- || (!var_check_ro(di->di_flags, lp->ll_name, false) &&
- !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
+ || (!var_check_ro(di->di_flags, lp->ll_name, false)
+ && !tv_check_lock(di->di_tv.v_lock, lp->ll_name, false)))
&& tv_op(&tv, rettv, op) == OK) {
set_var(lp->ll_name, &tv, false);
}
@@ -2410,11 +2396,12 @@ static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
char_u numbuf[NUMBUFLEN];
char_u *s;
- /* Can't do anything with a Funcref or a Dict on the right. */
+ // Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
switch (tv1->v_type) {
case VAR_DICT:
case VAR_FUNC:
+ case VAR_SPECIAL:
break;
case VAR_LIST:
@@ -2482,6 +2469,9 @@ static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
tv1->vval.v_float -= f;
}
return OK;
+
+ case VAR_UNKNOWN:
+ assert(false);
}
}
@@ -3119,6 +3109,15 @@ static void item_lock(typval_T *tv, int deep, int lock)
}
}
}
+ break;
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_SPECIAL:
+ break;
+ case VAR_UNKNOWN:
+ assert(false);
}
--recurse;
}
@@ -3197,7 +3196,7 @@ char_u *get_user_var_name(expand_T *xp, int idx)
static size_t bdone;
static size_t wdone;
static size_t tdone;
- static int vidx;
+ static size_t vidx;
static hashitem_T *hi;
hashtab_T *ht;
@@ -3259,9 +3258,10 @@ char_u *get_user_var_name(expand_T *xp, int idx)
return cat_prefix_varname('t', hi->hi_key);
}
- /* v: variables */
- if (vidx < VV_LEN)
+ // v: variables
+ if (vidx < ARRAY_SIZE(vimvars)) {
return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
+ }
xfree(varnamebuf);
varnamebuf = NULL;
@@ -4010,12 +4010,22 @@ eval6 (
* When either side is a float the result is a float.
*/
if (use_float) {
- if (op == '*')
+ if (op == '*') {
f1 = f1 * f2;
- else if (op == '/') {
- /* We rely on the floating point library to handle divide
- * by zero to result in "inf" and not a crash. */
- f1 = f2 != 0 ? f1 / f2 : INFINITY;
+ } else if (op == '/') {
+ // Division by zero triggers error from AddressSanitizer
+ f1 = (f2 == 0
+ ? (
+#ifdef NAN
+ f1 == 0
+ ? NAN
+ :
+#endif
+ (f1 > 0
+ ? INFINITY
+ : -INFINITY)
+ )
+ : f1 / f2);
} else {
EMSG(_("E804: Cannot use '%' with Float"));
return FAIL;
@@ -4141,7 +4151,7 @@ static int eval7(
if (get_float) {
float_T f;
- *arg += string2float(*arg, &f);
+ *arg += string2float((char *) *arg, &f);
if (evaluate) {
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f;
@@ -4330,14 +4340,37 @@ eval_index (
char_u *s;
char_u *key = NULL;
- if (rettv->v_type == VAR_FUNC) {
- if (verbose)
- EMSG(_("E695: Cannot index a Funcref"));
- return FAIL;
- } else if (rettv->v_type == VAR_FLOAT) {
- if (verbose)
- EMSG(_(e_float_as_string));
- return FAIL;
+ switch (rettv->v_type) {
+ case VAR_FUNC: {
+ if (verbose) {
+ EMSG(_("E695: Cannot index a Funcref"));
+ }
+ return FAIL;
+ }
+ case VAR_FLOAT: {
+ if (verbose) {
+ EMSG(_(e_float_as_string));
+ }
+ return FAIL;
+ }
+ case VAR_SPECIAL: {
+ if (verbose) {
+ EMSG(_("E909: Cannot index a special variable"));
+ }
+ return FAIL;
+ }
+ case VAR_UNKNOWN: {
+ if (evaluate) {
+ return FAIL;
+ }
+ // fallthrough
+ }
+ case VAR_STRING:
+ case VAR_NUMBER:
+ case VAR_LIST:
+ case VAR_DICT: {
+ break;
+ }
}
init_tv(&var1);
@@ -4528,6 +4561,11 @@ eval_index (
*rettv = var1;
}
break;
+ case VAR_SPECIAL:
+ case VAR_FUNC:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ break; // Not evaluating, skipping over subscript
}
}
@@ -4702,13 +4740,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
++name;
break;
- /* Special key, e.g.: "\<C-W>" */
- case '<': extra = trans_special(&p, name, TRUE);
+ // Special key, e.g.: "\<C-W>"
+ case '<':
+ extra = trans_special((const char_u **) &p, STRLEN(p), name, true);
if (extra != 0) {
name += extra;
break;
}
- /* FALLTHROUGH */
+ // FALLTHROUGH
default: MB_COPY_CHAR(p, name);
break;
@@ -5072,10 +5111,18 @@ tv_equal (
s1 = get_tv_string_buf(tv1, buf1);
s2 = get_tv_string_buf(tv2, buf2);
return (ic ? mb_stricmp(s1, s2) : STRCMP(s1, s2)) == 0;
+
+ case VAR_SPECIAL:
+ return tv1->vval.v_special == tv2->vval.v_special;
+
+ case VAR_UNKNOWN:
+ // VAR_UNKNOWN can be the result of an invalid expression, let’s say it does
+ // not equal anything, not even self.
+ return false;
}
- EMSG2(_(e_intern2), "tv_equal()");
- return TRUE;
+ assert(false);
+ return false;
}
/*
@@ -5476,9 +5523,10 @@ static int list_join_inner(garray_T *const gap, list_T *const l,
for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) {
char *s;
size_t len;
- s = echo_string(&item->li_tv, &len);
- if (s == NULL)
+ s = encode_tv2echo(&item->li_tv, &len);
+ if (s == NULL) {
return FAIL;
+ }
sumlen += (int) len;
@@ -5486,9 +5534,6 @@ static int list_join_inner(garray_T *const gap, list_T *const l,
p->tofree = p->s = (char_u *) s;
line_breakcheck();
- if (did_echo_string_emsg) { // recursion error, bail out
- break;
- }
}
/* Allocate result buffer with its total size, avoid re-allocation and
@@ -5540,6 +5585,22 @@ static int list_join(garray_T *const gap, list_T *const l,
return retval;
}
+/// Get next (unique) copy ID
+///
+/// Used for traversing nested structures e.g. when serializing them or garbage
+/// collecting.
+int get_copyID(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // CopyID for recursively traversing lists and dicts
+ //
+ // This value is needed to avoid endless recursiveness. Last bit is used for
+ // previous_funccal and normally ignored when comparing.
+ static int current_copyID = 0;
+ current_copyID += COPYID_INC;
+ return current_copyID;
+}
+
/*
* Garbage collection for lists and dictionaries.
*
@@ -5575,8 +5636,7 @@ bool garbage_collect(void)
// We advance by two because we add one for items referenced through
// previous_funccal.
- current_copyID += COPYID_INC;
- int copyID = current_copyID;
+ const int copyID = get_copyID();
// 1. Go through all accessible variables and mark all lists and dicts
// with copyID.
@@ -5921,6 +5981,15 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
}
break;
}
+
+ case VAR_FUNC:
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ break;
+ }
}
return abort;
}
@@ -6007,6 +6076,27 @@ static void rettv_dict_alloc(typval_T *rettv)
++d->dv_refcount;
}
+/// Clear all the keys of a Dictionary. "d" remains a valid empty Dictionary.
+///
+/// @param d The Dictionary to clear
+void dict_clear(dict_T *d)
+ FUNC_ATTR_NONNULL_ALL
+{
+ hash_lock(&d->dv_hashtab);
+ assert(d->dv_hashtab.ht_locked > 0);
+
+ size_t todo = d->dv_hashtab.ht_used;
+ for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ dictitem_free(HI2DI(hi));
+ hash_remove(&d->dv_hashtab, hi);
+ todo--;
+ }
+ }
+
+ hash_unlock(&d->dv_hashtab);
+}
+
/*
* Unreference a Dictionary: decrement the reference count and free it when it
@@ -6248,6 +6338,24 @@ int dict_add_list(dict_T *d, char *key, list_T *list)
return OK;
}
+/// Set all existing keys in "dict" as read-only.
+///
+/// This does not protect against adding new keys to the Dictionary.
+///
+/// @param dict The dict whose keys should be frozen
+void dict_set_keys_readonly(dict_T *dict)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t todo = dict->dv_hashtab.ht_used;
+ for (hashitem_T *hi = dict->dv_hashtab.ht_array; todo > 0 ; hi++) {
+ if (HASHITEM_EMPTY(hi)) {
+ continue;
+ }
+ todo--;
+ HI2DI(hi)->di_flags |= DI_FLAGS_RO | DI_FLAGS_FIX;
+ }
+}
+
/*
* Get the number of items in a Dictionary.
*/
@@ -6473,580 +6581,22 @@ failret:
return OK;
}
-#define CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \
- do { \
- if ((val)->copyID_attr == copyID) { \
- CONV_RECURSE((val), conv_type); \
- } \
- (val)->copyID_attr = copyID; \
- } while (0)
-
-/// Define functions which convert VimL value to something else
-///
-/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const
-/// tv)` which returns OK or FAIL and helper functions.
+/// Convert the string to a floating point number
///
-/// @param firstargtype Type of the first argument. It will be used to return
-/// the results.
-/// @param firstargname Name of the first argument.
-/// @param name Name of the target converter.
-#define DEFINE_VIML_CONV_FUNCTIONS(scope, name, firstargtype, firstargname) \
-static int name##_convert_one_value(firstargtype firstargname, \
- MPConvStack *const mpstack, \
- typval_T *const tv, \
- const int copyID, \
- const char *const objname) \
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- switch (tv->v_type) { \
- case VAR_STRING: { \
- CONV_STRING(tv->vval.v_string, STRLEN(tv->vval.v_string)); \
- break; \
- } \
- case VAR_NUMBER: { \
- CONV_NUMBER(tv->vval.v_number); \
- break; \
- } \
- case VAR_FLOAT: { \
- CONV_FLOAT(tv->vval.v_float); \
- break; \
- } \
- case VAR_FUNC: { \
- CONV_FUNC(tv->vval.v_string); \
- break; \
- } \
- case VAR_LIST: { \
- if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
- CONV_EMPTY_LIST(); \
- break; \
- } \
- CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, kMPConvList); \
- CONV_LIST_START(tv->vval.v_list); \
- kv_push( \
- MPConvStackVal, \
- *mpstack, \
- ((MPConvStackVal) { \
- .type = kMPConvList, \
- .data = { \
- .l = { \
- .list = tv->vval.v_list, \
- .li = tv->vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case VAR_DICT: { \
- if (tv->vval.v_dict == NULL \
- || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \
- CONV_EMPTY_DICT(); \
- break; \
- } \
- const dictitem_T *type_di; \
- const dictitem_T *val_di; \
- if (CONV_ALLOW_SPECIAL \
- && tv->vval.v_dict->dv_hashtab.ht_used == 2 \
- && (type_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_TYPE", -1)) != NULL \
- && type_di->di_tv.v_type == VAR_LIST \
- && (val_di = dict_find((dict_T *) tv->vval.v_dict, \
- (char_u *) "_VAL", -1)) != NULL) { \
- size_t i; \
- for (i = 0; i < ARRAY_SIZE(msgpack_type_lists); i++) { \
- if (type_di->di_tv.vval.v_list == msgpack_type_lists[i]) { \
- break; \
- } \
- } \
- if (i == ARRAY_SIZE(msgpack_type_lists)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- switch ((MessagePackType) i) { \
- case kMPNil: { \
- CONV_SPECIAL_NIL(); \
- break; \
- } \
- case kMPBoolean: { \
- if (val_di->di_tv.v_type != VAR_NUMBER) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_SPECIAL_BOOL(val_di->di_tv.vval.v_number); \
- break; \
- } \
- case kMPInteger: { \
- const list_T *val_list; \
- varnumber_T sign; \
- varnumber_T highest_bits; \
- varnumber_T high_bits; \
- varnumber_T low_bits; \
- /* List of 4 integers; first is signed (should be 1 or -1, but */ \
- /* this is not checked), second is unsigned and have at most */ \
- /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \
- /* bits is not checked), other unsigned and have at most 31 */ \
- /* non-zero bits (number of bits is not checked).*/ \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 4 \
- || val_list->lv_first->li_tv.v_type != VAR_NUMBER \
- || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \
- || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \
- || (highest_bits = \
- val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \
- || (high_bits = \
- val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \
- || val_list->lv_last->li_tv.v_type != VAR_NUMBER \
- || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \
- | (uint64_t) (((uint64_t) high_bits) << 31) \
- | (uint64_t) low_bits); \
- if (sign > 0) { \
- CONV_UNSIGNED_NUMBER(number); \
- } else { \
- CONV_NUMBER(-number); \
- } \
- break; \
- } \
- case kMPFloat: { \
- if (val_di->di_tv.v_type != VAR_FLOAT) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_FLOAT(val_di->di_tv.vval.v_float); \
- break; \
- } \
- case kMPString: \
- case kMPBinary: { \
- const bool is_string = ((MessagePackType) i == kMPString); \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!vim_list_to_buf(val_di->di_tv.vval.v_list, &len, &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- if (is_string) { \
- CONV_STR_STRING(buf, len); \
- } else { \
- CONV_STRING(buf, len); \
- } \
- xfree(buf); \
- break; \
- } \
- case kMPArray: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, \
- kMPConvList); \
- CONV_LIST_START(val_di->di_tv.vval.v_list); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvList, \
- .data = { \
- .l = { \
- .list = val_di->di_tv.vval.v_list, \
- .li = val_di->di_tv.vval.v_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPMap: { \
- if (val_di->di_tv.v_type != VAR_LIST) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- if (val_di->di_tv.vval.v_list == NULL) { \
- CONV_EMPTY_DICT(); \
- break; \
- } \
- list_T *const val_list = val_di->di_tv.vval.v_list; \
- for (const listitem_T *li = val_list->lv_first; li != NULL; \
- li = li->li_next) { \
- if (li->li_tv.v_type != VAR_LIST \
- || li->li_tv.vval.v_list->lv_len != 2) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- } \
- CHECK_SELF_REFERENCE(val_list, lv_copyID, kMPConvPairs); \
- CONV_SPECIAL_MAP_START(val_list); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvPairs, \
- .data = { \
- .l = { \
- .list = val_list, \
- .li = val_list->lv_first, \
- }, \
- }, \
- })); \
- break; \
- } \
- case kMPExt: { \
- const list_T *val_list; \
- varnumber_T type; \
- if (val_di->di_tv.v_type != VAR_LIST \
- || (val_list = val_di->di_tv.vval.v_list) == NULL \
- || val_list->lv_len != 2 \
- || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \
- || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \
- || type < INT8_MIN \
- || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- size_t len; \
- char *buf; \
- if (!vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \
- &len, &buf)) { \
- goto name##_convert_one_value_regular_dict; \
- } \
- CONV_EXT_STRING(buf, len, type); \
- xfree(buf); \
- break; \
- } \
- } \
- break; \
- } \
-name##_convert_one_value_regular_dict: \
- CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, kMPConvDict); \
- CONV_DICT_START(tv->vval.v_dict); \
- kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
- .type = kMPConvDict, \
- .data = { \
- .d = { \
- .dict = tv->vval.v_dict, \
- .hi = tv->vval.v_dict->dv_hashtab.ht_array, \
- .todo = tv->vval.v_dict->dv_hashtab.ht_used, \
- }, \
- }, \
- })); \
- break; \
- } \
- default: { \
- EMSG2(_(e_intern2), #name "_convert_one_value()"); \
- return FAIL; \
- } \
- } \
- return OK; \
-} \
-\
-scope int vim_to_##name(firstargtype firstargname, typval_T *const tv, \
- const char *const objname) \
- FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- current_copyID += COPYID_INC; \
- const int copyID = current_copyID; \
- MPConvStack mpstack; \
- kv_init(mpstack); \
- if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
- == FAIL) { \
- goto vim_to_msgpack_error_ret; \
- } \
- while (kv_size(mpstack)) { \
- MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \
- typval_T *cur_tv = NULL; \
- switch (cur_mpsv->type) { \
- case kMPConvDict: { \
- if (!cur_mpsv->data.d.todo) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
- CONV_DICT_END(cur_mpsv->data.d.dict); \
- continue; \
- } else if (cur_mpsv->data.d.todo \
- != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \
- CONV_DICT_BETWEEN_ITEMS(cur_mpsv->data.d.dict); \
- } \
- while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \
- cur_mpsv->data.d.hi++; \
- } \
- dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \
- cur_mpsv->data.d.todo--; \
- cur_mpsv->data.d.hi++; \
- CONV_STR_STRING(&di->di_key[0], STRLEN(&di->di_key[0])); \
- CONV_DICT_AFTER_KEY(cur_mpsv->data.d.dict); \
- cur_tv = &di->di_tv; \
- break; \
- } \
- case kMPConvList: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- CONV_LIST_END(cur_mpsv->data.l.list); \
- continue; \
- } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
- CONV_LIST_BETWEEN_ITEMS(cur_mpsv->data.l.list); \
- } \
- cur_tv = &cur_mpsv->data.l.li->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
- } \
- case kMPConvPairs: { \
- if (cur_mpsv->data.l.li == NULL) { \
- (void) kv_pop(mpstack); \
- cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
- continue; \
- } \
- const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
- if (name##_convert_one_value(firstargname, &mpstack, \
- &kv_pair->lv_first->li_tv, copyID, \
- objname) == FAIL) { \
- goto vim_to_msgpack_error_ret; \
- } \
- cur_tv = &kv_pair->lv_last->li_tv; \
- cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
- break; \
- } \
- } \
- if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
- objname) == FAIL) { \
- goto vim_to_msgpack_error_ret; \
- } \
- } \
- kv_destroy(mpstack); \
- return OK; \
-vim_to_msgpack_error_ret: \
- kv_destroy(mpstack); \
- return FAIL; \
-}
-
-#define CONV_STRING(buf, len) \
- do { \
- const char *const buf_ = (const char *) buf; \
- if (buf == NULL) { \
- ga_concat(gap, (char_u *) "''"); \
- } else { \
- const size_t len_ = (len); \
- size_t num_quotes = 0; \
- for (size_t i = 0; i < len_; i++) { \
- if (buf_[i] == '\'') { \
- num_quotes++; \
- } \
- } \
- ga_grow(gap, 2 + len_ + num_quotes); \
- ga_append(gap, '\''); \
- for (size_t i = 0; i < len_; i++) { \
- if (buf_[i] == '\'') { \
- num_quotes++; \
- ga_append(gap, '\''); \
- } \
- ga_append(gap, buf_[i]); \
- } \
- ga_append(gap, '\''); \
- } \
- } while (0)
-
-#define CONV_STR_STRING(buf, len) \
- CONV_STRING(buf, len)
-
-#define CONV_EXT_STRING(buf, len, type)
-
-#define CONV_NUMBER(num) \
- do { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, NUMBUFLEN - 1, "%" PRId64, (int64_t) (num)); \
- ga_concat(gap, (char_u *) numbuf); \
- } while (0)
-
-#define CONV_FLOAT(flt) \
- do { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, NUMBUFLEN - 1, "%g", (flt)); \
- ga_concat(gap, (char_u *) numbuf); \
- } while (0)
-
-#define CONV_FUNC(fun) \
- do { \
- ga_concat(gap, (char_u *) "function("); \
- CONV_STRING(fun, STRLEN(fun)); \
- ga_append(gap, ')'); \
- } while (0)
-
-#define CONV_EMPTY_LIST() \
- ga_concat(gap, (char_u *) "[]")
-
-#define CONV_LIST_START(lst) \
- ga_append(gap, '[')
-
-#define CONV_EMPTY_DICT() \
- ga_concat(gap, (char_u *) "{}")
-
-#define CONV_SPECIAL_NIL()
-
-#define CONV_SPECIAL_BOOL(num)
-
-#define CONV_UNSIGNED_NUMBER(num)
-
-#define CONV_SPECIAL_MAP_START(lst)
-
-#define CONV_DICT_START(dct) \
- ga_append(gap, '{')
-
-#define CONV_DICT_END(dct) \
- ga_append(gap, '}')
-
-#define CONV_DICT_AFTER_KEY(dct) \
- ga_concat(gap, (char_u *) ": ")
-
-#define CONV_DICT_BETWEEN_ITEMS(dct) \
- ga_concat(gap, (char_u *) ", ")
-
-#define CONV_LIST_END(lst) \
- ga_append(gap, ']')
-
-#define CONV_LIST_BETWEEN_ITEMS(lst) \
- CONV_DICT_BETWEEN_ITEMS(NULL)
-
-#define CONV_RECURSE(val, conv_type) \
- do { \
- if (!did_echo_string_emsg) { \
- /* Only give this message once for a recursive call to avoid */ \
- /* flooding the user with errors. */ \
- did_echo_string_emsg = true; \
- EMSG(_("E724: unable to correctly dump variable " \
- "with self-referencing container")); \
- } \
- char ebuf[NUMBUFLEN + 7]; \
- size_t backref = 0; \
- for (; backref < kv_size(*mpstack); backref++) { \
- const MPConvStackVal mpval = kv_a(MPConvStackVal, *mpstack, backref); \
- if (mpval.type == conv_type) { \
- if (conv_type == kMPConvDict) { \
- if ((void *) mpval.data.d.dict == (void *) (val)) { \
- break; \
- } \
- } else if (conv_type == kMPConvList) { \
- if ((void *) mpval.data.l.list == (void *) (val)) { \
- break; \
- } \
- } \
- } \
- } \
- vim_snprintf(ebuf, NUMBUFLEN + 6, "{E724@%zu}", backref); \
- ga_concat(gap, (char_u *) &ebuf[0]); \
- return OK; \
- } while (0)
-
-#define CONV_ALLOW_SPECIAL false
-
-DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap)
-
-#undef CONV_RECURSE
-#define CONV_RECURSE(val, conv_type) \
- do { \
- char ebuf[NUMBUFLEN + 7]; \
- size_t backref = 0; \
- for (; backref < kv_size(*mpstack); backref++) { \
- const MPConvStackVal mpval = kv_a(MPConvStackVal, *mpstack, backref); \
- if (mpval.type == conv_type) { \
- if (conv_type == kMPConvDict) { \
- if ((void *) mpval.data.d.dict == (void *) val) { \
- break; \
- } \
- } else if (conv_type == kMPConvList) { \
- if ((void *) mpval.data.l.list == (void *) val) { \
- break; \
- } \
- } \
- } \
- } \
- if (conv_type == kMPConvDict) { \
- vim_snprintf(ebuf, NUMBUFLEN + 6, "{...@%zu}", backref); \
- } else { \
- vim_snprintf(ebuf, NUMBUFLEN + 6, "[...@%zu]", backref); \
- } \
- ga_concat(gap, (char_u *) &ebuf[0]); \
- return OK; \
- } while (0)
-
-DEFINE_VIML_CONV_FUNCTIONS(static, echo, garray_T *const, gap)
-
-#undef CONV_STRING
-#undef CONV_STR_STRING
-#undef CONV_EXT_STRING
-#undef CONV_NUMBER
-#undef CONV_FLOAT
-#undef CONV_FUNC
-#undef CONV_EMPTY_LIST
-#undef CONV_LIST_START
-#undef CONV_EMPTY_DICT
-#undef CONV_SPECIAL_NIL
-#undef CONV_SPECIAL_BOOL
-#undef CONV_UNSIGNED_NUMBER
-#undef CONV_SPECIAL_MAP_START
-#undef CONV_DICT_START
-#undef CONV_DICT_END
-#undef CONV_DICT_AFTER_KEY
-#undef CONV_DICT_BETWEEN_ITEMS
-#undef CONV_LIST_END
-#undef CONV_LIST_BETWEEN_ITEMS
-#undef CONV_RECURSE
-#undef CONV_ALLOW_SPECIAL
-
-/// Return a string with the string representation of a variable.
-/// Puts quotes around strings, so that they can be parsed back by eval().
+/// This uses strtod(). setlocale(LC_NUMERIC, "C") has been used earlier to
+/// make sure this always uses a decimal point.
///
-/// @param[in] tv typval_T to convert.
-/// @param[out] len Location where length of the result will be saved.
+/// @param[in] text String to convert.
+/// @param[out] ret_value Location where conversion result is saved.
///
-/// @return String representation of the variable or NULL.
-static char *tv2string(typval_T *tv, size_t *len)
- FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_MALLOC
-{
- garray_T ga;
- ga_init(&ga, (int)sizeof(char), 80);
- vim_to_string(&ga, tv, "tv2string() argument");
- did_echo_string_emsg = false;
- if (len != NULL) {
- *len = (size_t) ga.ga_len;
- }
- ga_append(&ga, '\0');
- return (char *) ga.ga_data;
-}
-
-/// Return a string with the string representation of a variable.
-/// Does not put quotes around strings, as ":echo" displays values.
-///
-/// @param[in] tv typval_T to convert.
-/// @param[out] len Location where length of the result will be saved.
-///
-/// @return String representation of the variable or NULL.
-static char *echo_string(typval_T *tv, size_t *len)
- FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_MALLOC
-{
- garray_T ga;
- ga_init(&ga, (int)sizeof(char), 80);
- if (tv->v_type == VAR_STRING || tv->v_type == VAR_FUNC) {
- if (tv->vval.v_string != NULL) {
- ga_concat(&ga, tv->vval.v_string);
- }
- } else {
- vim_to_echo(&ga, tv, ":echo argument");
- did_echo_string_emsg = false;
- }
- if (len != NULL) {
- *len = (size_t) ga.ga_len;
- }
- ga_append(&ga, '\0');
- return (char *) ga.ga_data;
-}
-
-/*
- * Convert the string "text" to a floating point number.
- * This uses strtod(). setlocale(LC_NUMERIC, "C") has been used to make sure
- * this always uses a decimal point.
- * Returns the length of the text that was consumed.
- */
-static int
-string2float (
- char_u *text,
- float_T *value /* result stored here */
-)
+/// @return Length of the text that was consumed.
+size_t string2float(const char *const text, float_T *const ret_value)
+ FUNC_ATTR_NONNULL_ALL
{
- char *s = (char *)text;
- float_T f;
+ char *s = NULL;
- f = strtod(s, &s);
- *value = f;
- return (int)((char_u *)s - text);
+ *ret_value = strtod(text, &s);
+ return (size_t) (s - text);
}
/// Get the value of an environment variable.
@@ -7106,7 +6656,7 @@ static struct fst {
} functions[] =
{
{ "abs", 1, 1, f_abs },
- { "acos", 1, 1, f_acos }, // WJMc
+ { "acos", 1, 1, f_acos }, // WJMc
{ "add", 2, 2, f_add },
{ "and", 2, 2, f_and },
{ "append", 2, 2, f_append },
@@ -7116,6 +6666,7 @@ static struct fst {
{ "argv", 0, 1, f_argv },
{ "asin", 1, 1, f_asin }, // WJMc
{ "assert_equal", 2, 3, f_assert_equal },
+ { "assert_exception", 1, 2, f_assert_exception },
{ "assert_false", 1, 2, f_assert_false },
{ "assert_true", 1, 2, f_assert_true },
{ "atan", 1, 1, f_atan },
@@ -7123,9 +6674,9 @@ static struct fst {
{ "browse", 4, 4, f_browse },
{ "browsedir", 2, 2, f_browsedir },
{ "bufexists", 1, 1, f_bufexists },
- { "buffer_exists", 1, 1, f_bufexists }, // obsolete
- { "buffer_name", 1, 1, f_bufname }, // obsolete
- { "buffer_number", 1, 1, f_bufnr }, // obsolete
+ { "buffer_exists", 1, 1, f_bufexists }, // obsolete
+ { "buffer_name", 1, 1, f_bufname }, // obsolete
+ { "buffer_number", 1, 1, f_bufnr }, // obsolete
{ "buflisted", 1, 1, f_buflisted },
{ "bufloaded", 1, 1, f_bufloaded },
{ "bufname", 1, 1, f_bufname },
@@ -7152,7 +6703,7 @@ static struct fst {
{ "cscope_connection", 0, 3, f_cscope_connection },
{ "cursor", 1, 3, f_cursor },
{ "deepcopy", 1, 2, f_deepcopy },
- { "delete", 1, 1, f_delete },
+ { "delete", 1, 2, f_delete },
{ "dictwatcheradd", 3, 3, f_dictwatcheradd },
{ "dictwatcherdel", 3, 3, f_dictwatcherdel },
{ "did_filetype", 0, 0, f_did_filetype },
@@ -7169,7 +6720,7 @@ static struct fst {
{ "expand", 1, 3, f_expand },
{ "extend", 2, 3, f_extend },
{ "feedkeys", 1, 2, f_feedkeys },
- { "file_readable", 1, 1, f_filereadable }, // obsolete
+ { "file_readable", 1, 1, f_filereadable }, // obsolete
{ "filereadable", 1, 1, f_filereadable },
{ "filewritable", 1, 1, f_filewritable },
{ "filter", 2, 2, f_filter },
@@ -7199,7 +6750,7 @@ static struct fst {
{ "getcmdtype", 0, 0, f_getcmdtype },
{ "getcmdwintype", 0, 0, f_getcmdwintype },
{ "getcurpos", 0, 0, f_getcurpos },
- { "getcwd", 0, 0, f_getcwd },
+ { "getcwd", 0, 2, f_getcwd },
{ "getfontname", 0, 1, f_getfontname },
{ "getfperm", 1, 1, f_getfperm },
{ "getfsize", 1, 1, f_getfsize },
@@ -7223,7 +6774,7 @@ static struct fst {
{ "globpath", 2, 5, f_globpath },
{ "has", 1, 1, f_has },
{ "has_key", 2, 2, f_has_key },
- { "haslocaldir", 0, 0, f_haslocaldir },
+ { "haslocaldir", 0, 2, f_haslocaldir },
{ "hasmapto", 1, 3, f_hasmapto },
{ "highlightID", 1, 1, f_hlID }, // obsolete
{ "highlight_exists", 1, 1, f_hlexists }, // obsolete
@@ -7256,6 +6807,8 @@ static struct fst {
{ "jobstop", 1, 1, f_jobstop },
{ "jobwait", 1, 2, f_jobwait },
{ "join", 1, 2, f_join },
+ { "json_decode", 1, 1, f_json_decode },
+ { "json_encode", 1, 1, f_json_encode },
{ "keys", 1, 1, f_keys },
{ "last_buffer_nr", 0, 0, f_last_buffer_nr }, // obsolete
{ "len", 1, 1, f_len },
@@ -7290,13 +6843,14 @@ static struct fst {
{ "pathshorten", 1, 1, f_pathshorten },
{ "pow", 2, 2, f_pow },
{ "prevnonblank", 1, 1, f_prevnonblank },
- { "printf", 2, 19, f_printf },
+ { "printf", 2, MAX_FUNC_ARGS, f_printf },
{ "pumvisible", 0, 0, f_pumvisible },
{ "py3eval", 1, 1, f_py3eval },
{ "pyeval", 1, 1, f_pyeval },
{ "range", 1, 3, f_range },
{ "readfile", 1, 3, f_readfile },
{ "reltime", 0, 2, f_reltime },
+ { "reltimefloat", 1, 1, f_reltimefloat },
{ "reltimestr", 1, 1, f_reltimestr },
{ "remove", 2, 3, f_remove },
{ "rename", 2, 2, f_rename },
@@ -7304,8 +6858,8 @@ static struct fst {
{ "resolve", 1, 1, f_resolve },
{ "reverse", 1, 1, f_reverse },
{ "round", 1, 1, f_round },
- { "rpcnotify", 2, 64, f_rpcnotify },
- { "rpcrequest", 2, 64, f_rpcrequest },
+ { "rpcnotify", 2, MAX_FUNC_ARGS, f_rpcnotify },
+ { "rpcrequest", 2, MAX_FUNC_ARGS, f_rpcrequest },
{ "rpcstart", 1, 2, f_rpcstart },
{ "rpcstop", 1, 1, f_rpcstop },
{ "screenattr", 2, 2, f_screenattr },
@@ -7396,6 +6950,7 @@ static struct fst {
{ "winrestview", 1, 1, f_winrestview },
{ "winsaveview", 0, 0, f_winsaveview },
{ "winwidth", 1, 1, f_winwidth },
+ { "wordcount", 0, 0, f_wordcount },
{ "writefile", 2, 3, f_writefile },
{ "xor", 2, 2, f_xor },
};
@@ -8030,19 +7585,19 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
char_u *tofree;
if (opt_msg_tv->v_type != VAR_UNKNOWN) {
- tofree = (char_u *) tv2string(opt_msg_tv, NULL);
+ tofree = (char_u *) encode_tv2string(opt_msg_tv, NULL);
ga_concat(gap, tofree);
xfree(tofree);
} else {
ga_concat(gap, (char_u *)"Expected ");
if (exp_str == NULL) {
- tofree = (char_u *) tv2string(exp_tv, NULL);
+ tofree = (char_u *) encode_tv2string(exp_tv, NULL);
ga_concat(gap, tofree);
xfree(tofree);
} else {
ga_concat(gap, exp_str);
}
- tofree = (char_u *) tv2string(got_tv, NULL);
+ tofree = (char_u *) encode_tv2string(got_tv, NULL);
ga_concat(gap, (char_u *)" but got ");
ga_concat(gap, tofree);
xfree(tofree);
@@ -8076,17 +7631,43 @@ static void f_assert_equal(typval_T *argvars, typval_T *rettv)
}
}
+/// "assert_exception(string[, msg])" function
+static void f_assert_exception(typval_T *argvars, typval_T *rettv)
+{
+ garray_T ga;
+
+ char *error = (char *)get_tv_string_chk(&argvars[0]);
+ if (vimvars[VV_EXCEPTION].vv_str == NULL) {
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (char_u *)"v:exception is not set");
+ assert_error(&ga);
+ ga_clear(&ga);
+ } else if (strstr((char *)vimvars[VV_EXCEPTION].vv_str, error) == NULL) {
+ prepare_assert_error(&ga);
+ fill_assert_error(&ga, &argvars[1], NULL, &argvars[0],
+ &vimvars[VV_EXCEPTION].vv_tv);
+ assert_error(&ga);
+ ga_clear(&ga);
+ }
+}
+
// Common for assert_true() and assert_false().
-static void assert_bool(typval_T *argvars, bool isTrue)
+static void assert_bool(typval_T *argvars, bool is_true)
{
int error = (int)false;
garray_T ga;
- if (argvars[0].v_type != VAR_NUMBER ||
- (get_tv_number_chk(&argvars[0], &error) == 0) == isTrue || error) {
+ if ((argvars[0].v_type != VAR_NUMBER
+ || (get_tv_number_chk(&argvars[0], &error) == 0) == is_true
+ || error)
+ && (argvars[0].v_type != VAR_SPECIAL
+ || (argvars[0].vval.v_special
+ != (SpecialVarValue) (is_true
+ ? kSpecialVarTrue
+ : kSpecialVarFalse)))) {
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[1],
- (char_u *)(isTrue ? "True" : "False"),
+ (char_u *)(is_true ? "True" : "False"),
NULL, &argvars[0]);
assert_error(&ga);
ga_clear(&ga);
@@ -8748,16 +8329,17 @@ static void f_cscope_connection(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = cs_connection(num, dbpath, prepend);
}
-/*
- * "cursor(lnum, col)" function
- *
- * Moves the cursor to the specified line and column.
- * Returns 0 when the position could be set, -1 otherwise.
- */
+/// "cursor(lnum, col)" function, or
+/// "cursor(list)"
+///
+/// Moves the cursor to the specified line and column.
+///
+/// @returns 0 when the position could be set, -1 otherwise.
static void f_cursor(typval_T *argvars, typval_T *rettv)
{
long line, col;
long coladd = 0;
+ bool set_curswant = true;
rettv->vval.v_number = -1;
if (argvars[1].v_type == VAR_UNKNOWN) {
@@ -8765,37 +8347,44 @@ static void f_cursor(typval_T *argvars, typval_T *rettv)
colnr_T curswant = -1;
if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL) {
+ EMSG(_(e_invarg));
return;
}
+
line = pos.lnum;
col = pos.col;
coladd = pos.coladd;
if (curswant >= 0) {
curwin->w_curswant = curswant - 1;
+ set_curswant = false;
}
} else {
line = get_tv_lnum(argvars);
col = get_tv_number_chk(&argvars[1], NULL);
- if (argvars[2].v_type != VAR_UNKNOWN)
+ if (argvars[2].v_type != VAR_UNKNOWN) {
coladd = get_tv_number_chk(&argvars[2], NULL);
+ }
}
if (line < 0 || col < 0
- || coladd < 0
- )
- return; /* type error; errmsg already given */
- if (line > 0)
+ || coladd < 0) {
+ return; // type error; errmsg already given
+ }
+ if (line > 0) {
curwin->w_cursor.lnum = line;
- if (col > 0)
+ }
+ if (col > 0) {
curwin->w_cursor.col = col - 1;
+ }
curwin->w_cursor.coladd = coladd;
- /* Make sure the cursor is in a valid position. */
+ // Make sure the cursor is in a valid position.
check_cursor();
- /* Correct cursor for multi-byte character. */
- if (has_mbyte)
+ // Correct cursor for multi-byte character.
+ if (has_mbyte) {
mb_adjust_cursor();
+ }
- curwin->w_set_curswant = TRUE;
+ curwin->w_set_curswant = set_curswant;
rettv->vval.v_number = 0;
}
@@ -8808,25 +8397,51 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN)
noref = get_tv_number_chk(&argvars[1], NULL);
- if (noref < 0 || noref > 1)
+ if (noref < 0 || noref > 1) {
EMSG(_(e_invarg));
- else {
- current_copyID += COPYID_INC;
+ } else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
- ? current_copyID
+ ? get_copyID()
: 0));
}
}
-/*
- * "delete()" function
- */
+// "delete()" function
static void f_delete(typval_T *argvars, typval_T *rettv)
{
- if (check_restricted() || check_secure())
- rettv->vval.v_number = -1;
- else
- rettv->vval.v_number = os_remove((char *)get_tv_string(&argvars[0]));
+ char_u nbuf[NUMBUFLEN];
+ char_u *name;
+ char_u *flags;
+
+ rettv->vval.v_number = -1;
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ name = get_tv_string(&argvars[0]);
+ if (name == NULL || *name == NUL) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ if (argvars[1].v_type != VAR_UNKNOWN) {
+ flags = get_tv_string_buf(&argvars[1], nbuf);
+ } else {
+ flags = (char_u *)"";
+ }
+
+ if (*flags == NUL) {
+ // delete a file
+ rettv->vval.v_number = os_remove((char *)name) == 0 ? 0 : -1;
+ } else if (STRCMP(flags, "d") == 0) {
+ // delete an empty directory
+ rettv->vval.v_number = os_rmdir((char *)name) == 0 ? 0 : -1;
+ } else if (STRCMP(flags, "rf") == 0) {
+ // delete a directory recursively
+ rettv->vval.v_number = delete_recursive(name);
+ } else {
+ EMSG2(_(e_invexpr2), flags);
+ }
}
// dictwatcheradd(dict, key, funcref) function
@@ -9003,7 +8618,7 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv)
*/
static void f_empty(typval_T *argvars, typval_T *rettv)
{
- int n;
+ bool n = true;
switch (argvars[0].v_type) {
case VAR_STRING:
@@ -9025,9 +8640,12 @@ static void f_empty(typval_T *argvars, typval_T *rettv)
n = argvars[0].vval.v_dict == NULL
|| argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
break;
- default:
- EMSG2(_(e_intern2), "f_empty()");
- n = 0;
+ case VAR_SPECIAL:
+ n = argvars[0].vval.v_special != kSpecialVarTrue;
+ break;
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "f_empty(UNKNOWN)");
+ break;
}
rettv->vval.v_number = n;
@@ -9082,7 +8700,11 @@ static void f_eventhandler(typval_T *argvars, typval_T *rettv)
*/
static void f_executable(typval_T *argvars, typval_T *rettv)
{
- rettv->vval.v_number = os_can_exe(get_tv_string(&argvars[0]), NULL);
+ char_u *name = get_tv_string(&argvars[0]);
+
+ // Check in $PATH and also check directly if there is a directory name
+ rettv->vval.v_number = os_can_exe(name, NULL, true)
+ || (gettail_dir(name) != name && os_can_exe(name, NULL, false));
}
/// "exepath()" function
@@ -9091,7 +8713,7 @@ static void f_exepath(typval_T *argvars, typval_T *rettv)
char_u *arg = get_tv_string(&argvars[0]);
char_u *path = NULL;
- (void)os_can_exe(arg, &path);
+ (void)os_can_exe(arg, &path, true);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = path;
@@ -10199,22 +9821,130 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string[0] = cmdwin_type;
}
-/*
- * "getcwd()" function
- */
+/// `getcwd([{win}[, {tab}]])` function
+///
+/// Every scope not specified implies the currently selected scope object.
+///
+/// @pre The arguments must be of type number.
+/// @pre There may not be more than two arguments.
+/// @pre An argument may not be -1 if preceding arguments are not all -1.
+///
+/// @post The return value will be a string.
static void f_getcwd(typval_T *argvars, typval_T *rettv)
{
- char_u *cwd;
+ // Possible scope of working directory to return.
+ CdScope scope = MIN_CD_SCOPE;
+
+ // 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.
+ [kCdScopeTab ] = 0, // Number of tab to look at.
+ };
+
+ char_u *cwd = NULL; // Current working directory to print
+ char_u *from = NULL; // The original string to copy
+
+ tabpage_T *tp = curtab; // The tabpage to look at.
+ win_T *win = curwin; // The window to look at.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
+
+ // Pre-conditions and scope extraction together
+ for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) {
+ // If there is no argument there are no more scopes after it, break out.
+ if (argvars[i].v_type == VAR_UNKNOWN) {
+ break;
+ }
+ if (argvars[i].v_type != VAR_NUMBER) {
+ EMSG(_(e_invarg));
+ return;
+ }
+ scope_number[i] = argvars[i].vval.v_number;
+ // The scope is the current iteration step.
+ scope = i;
+ // It is an error for the scope number to be less than `-1`.
+ if (scope_number[i] < -1) {
+ EMSG(_(e_invarg));
+ return;
+ }
+ }
+
+ // Normalize scope, the number of the new scope will be 0.
+ if (scope_number[scope] < 0) {
+ // Arguments to `getcwd` always end at second-highest scope, so scope will
+ // always be <= `MAX_CD_SCOPE`.
+ scope++;
+ }
+
+ // Find the tabpage by number
+ if (scope_number[kCdScopeTab] == -1) {
+ tp = NULL;
+ } else if (scope_number[kCdScopeTab] > 0) {
+ tp = find_tabpage(scope_number[kCdScopeTab]);
+ if (!tp) {
+ EMSG(_("E5000: Cannot find tab number."));
+ return;
+ }
+ }
+
+ // Find the window in `tp` by number, `NULL` if none.
+ if (scope_number[kCdScopeWindow] == -1) {
+ win = NULL;
+ } else if (scope_number[kCdScopeWindow] >= 0) {
+ if (!tp) {
+ EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
+ return;
+ }
+
+ if (scope_number[kCdScopeWindow] > 0) {
+ win = find_win_by_nr(&argvars[0], curtab);
+ if (!win) {
+ EMSG(_("E5002: Cannot find window number."));
+ return;
+ }
+ }
+ }
+
cwd = xmalloc(MAXPATHL);
- if (os_dirname(cwd, MAXPATHL) != FAIL) {
- rettv->vval.v_string = vim_strsave(cwd);
+
+ switch (scope) {
+ case kCdScopeWindow:
+ assert(win);
+ from = win->w_localdir;
+ if (from) {
+ break;
+ }
+ case kCdScopeTab: // FALLTHROUGH
+ assert(tp);
+ from = tp->localdir;
+ if (from) {
+ break;
+ }
+ case kCdScopeGlobal: // FALLTHROUGH
+ // The `globaldir` variable is not always set.
+ if (globaldir) {
+ from = globaldir;
+ } else {
+ // We have to copy the OS path directly into output string.
+ if (os_dirname(cwd, MAXPATHL) == FAIL) {
+ EMSG(_("E41: Could not display path."));
+ goto end;
+ }
+ }
+ break;
+ }
+
+ if (from) {
+ xstrlcpy((char *)cwd, (char *)from, MAXPATHL);
+ }
+
+ rettv->vval.v_string = vim_strsave(cwd);
#ifdef BACKSLASH_IN_FILENAME
- slash_adjust(rettv->vval.v_string);
+ slash_adjust(rettv->vval.v_string);
#endif
- }
+end:
xfree(cwd);
}
@@ -10465,6 +10195,7 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
list_append_number(l,
(fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
if (getcurpos) {
+ update_curswant();
list_append_number(l, curwin->w_curswant == MAXCOL
? (varnumber_T)MAXCOL
: (varnumber_T)curwin->w_curswant + 1);
@@ -10537,9 +10268,10 @@ static void f_getreg(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_LIST;
rettv->vval.v_list =
get_reg_contents(regname, (arg2 ? kGRegExprSrc : 0) | kGRegList);
- if (rettv->vval.v_list != NULL) {
- rettv->vval.v_list->lv_refcount++;
+ if (rettv->vval.v_list == NULL) {
+ rettv->vval.v_list = list_alloc();
}
+ rettv->vval.v_list->lv_refcount++;
} else {
rettv->v_type = VAR_STRING;
rettv->vval.v_string = get_reg_contents(regname, arg2 ? kGRegExprSrc : 0);
@@ -10553,8 +10285,6 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv)
{
char_u *strregname;
int regname;
- char_u buf[NUMBUFLEN + 2];
- long reglen = 0;
if (argvars[0].v_type != VAR_UNKNOWN) {
strregname = get_tv_string_chk(&argvars[0]);
@@ -10571,18 +10301,13 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv)
if (regname == 0)
regname = '"';
- buf[0] = NUL;
- buf[1] = NUL;
- switch (get_reg_type(regname, &reglen)) {
- case MLINE: buf[0] = 'V'; break;
- case MCHAR: buf[0] = 'v'; break;
- case MBLOCK:
- buf[0] = Ctrl_V;
- sprintf((char *)buf + 1, "%" PRId64, (int64_t)(reglen + 1));
- break;
- }
+ colnr_T reglen = 0;
+ char buf[NUMBUFLEN + 2];
+ MotionType reg_type = get_reg_type(regname, &reglen);
+ format_reg_type(reg_type, reglen, buf, ARRAY_SIZE(buf));
+
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = vim_strsave(buf);
+ rettv->vval.v_string = (char_u *)xstrdup(buf);
}
/*
@@ -10959,6 +10684,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)
"tablineat",
"tag_binary",
"tag_old_static",
+ "termguicolors",
"termresponse",
"textobjects",
"title",
@@ -11040,12 +10766,103 @@ static void f_has_key(typval_T *argvars, typval_T *rettv)
get_tv_string(&argvars[1]), -1) != NULL;
}
-/*
- * "haslocaldir()" function
- */
+/// `haslocaldir([{win}[, {tab}]])` function
+///
+/// Returns `1` if the scope object has a local directory, `0` otherwise. If a
+/// scope object is not specified the current one is implied. This function
+/// share a lot of code with `f_getcwd`.
+///
+/// @pre The arguments must be of type number.
+/// @pre There may not be more than two arguments.
+/// @pre An argument may not be -1 if preceding arguments are not all -1.
+///
+/// @post The return value will be either the number `1` or `0`.
static void f_haslocaldir(typval_T *argvars, typval_T *rettv)
{
- rettv->vval.v_number = (curwin->w_localdir != NULL);
+ // Possible scope of working directory to return.
+ CdScope scope = MIN_CD_SCOPE;
+
+ // 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.
+ [kCdScopeTab ] = 0, // Number of tab to look at.
+ };
+
+ tabpage_T *tp = curtab; // The tabpage to look at.
+ win_T *win = curwin; // The window to look at.
+
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ // Pre-conditions and scope extraction together
+ for (int i = MIN_CD_SCOPE; i < MAX_CD_SCOPE; i++) {
+ if (argvars[i].v_type == VAR_UNKNOWN) {
+ break;
+ }
+ if (argvars[i].v_type != VAR_NUMBER) {
+ EMSG(_(e_invarg));
+ return;
+ }
+ scope_number[i] = argvars[i].vval.v_number;
+ // The scope is the current iteration step.
+ scope = i;
+ if (scope_number[i] < -1) {
+ EMSG(_(e_invarg));
+ return;
+ }
+ }
+
+ // Normalize scope, the number of the new scope will be 0.
+ if (scope_number[scope] < 0) {
+ // Arguments to `haslocaldir` always end at second-highest scope, so scope
+ // will always be <= `MAX_CD_SCOPE`.
+ scope++;
+ }
+
+ // Find the tabpage by number
+ if (scope_number[kCdScopeTab] == -1) {
+ tp = NULL;
+ } else if (scope_number[kCdScopeTab] > 0) {
+ tp = find_tabpage(scope_number[kCdScopeTab]);
+ if (!tp) {
+ EMSG(_("5000: Cannot find tab number."));
+ return;
+ }
+ }
+
+ // Find the window in `tp` by number, `NULL` if none.
+ if (scope_number[kCdScopeWindow] == -1) {
+ win = NULL;
+ } else if (scope_number[kCdScopeWindow] >= 0) {
+ if (!tp) {
+ EMSG(_("E5001: Higher scope cannot be -1 if lower scope is >= 0."));
+ return;
+ }
+
+ if (scope_number[kCdScopeWindow] > 0) {
+ win = find_win_by_nr(&argvars[0], curtab);
+ if (!win) {
+ EMSG(_("E5002: Cannot find window number."));
+ return;
+ }
+ }
+ }
+
+ switch (scope) {
+ case kCdScopeWindow:
+ assert(win);
+ rettv->vval.v_number = win->w_localdir ? 1 : 0;
+ break;
+ case kCdScopeTab:
+ assert(tp);
+ rettv->vval.v_number = tp->localdir ? 1 : 0;
+ break;
+ case kCdScopeGlobal:
+ // The global scope never has a local directory
+ rettv->vval.v_number = 0;
+ break;
+ }
}
/*
@@ -11078,21 +10895,22 @@ static void f_hasmapto(typval_T *argvars, typval_T *rettv)
*/
static void f_histadd(typval_T *argvars, typval_T *rettv)
{
- int histype;
+ HistoryType histype;
char_u *str;
char_u buf[NUMBUFLEN];
- rettv->vval.v_number = FALSE;
- if (check_restricted() || check_secure())
+ rettv->vval.v_number = false;
+ if (check_restricted() || check_secure()) {
return;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- histype = str != NULL ? get_histtype(str) : -1;
- if (histype >= 0) {
+ }
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ histype = str != NULL ? get_histtype(str, STRLEN(str), false) : HIST_INVALID;
+ if (histype != HIST_INVALID) {
str = get_tv_string_buf(&argvars[1], buf);
if (*str != NUL) {
init_history();
- add_to_history(histype, str, FALSE, NUL);
- rettv->vval.v_number = TRUE;
+ add_to_history(histype, str, false, NUL);
+ rettv->vval.v_number = true;
return;
}
}
@@ -11107,20 +10925,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv)
char_u buf[NUMBUFLEN];
char_u *str;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- if (str == NULL)
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ if (str == NULL) {
n = 0;
- else if (argvars[1].v_type == VAR_UNKNOWN)
- /* only one argument: clear entire history */
- n = clr_history(get_histtype(str));
- else if (argvars[1].v_type == VAR_NUMBER)
- /* index given: remove that entry */
- n = del_history_idx(get_histtype(str),
- (int)get_tv_number(&argvars[1]));
- else
- /* string given: remove all matching entries */
- n = del_history_entry(get_histtype(str),
- get_tv_string_buf(&argvars[1], buf));
+ } else if (argvars[1].v_type == VAR_UNKNOWN) {
+ // only one argument: clear entire history
+ n = clr_history(get_histtype(str, STRLEN(str), false));
+ } else if (argvars[1].v_type == VAR_NUMBER) {
+ // index given: remove that entry
+ n = del_history_idx(get_histtype(str, STRLEN(str), false),
+ (int) get_tv_number(&argvars[1]));
+ } else {
+ // string given: remove all matching entries
+ n = del_history_entry(get_histtype(str, STRLEN(str), false),
+ get_tv_string_buf(&argvars[1], buf));
+ }
rettv->vval.v_number = n;
}
@@ -11129,20 +10948,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv)
*/
static void f_histget(typval_T *argvars, typval_T *rettv)
{
- int type;
+ HistoryType type;
int idx;
char_u *str;
- str = get_tv_string_chk(&argvars[0]); /* NULL on type error */
- if (str == NULL)
+ str = get_tv_string_chk(&argvars[0]); // NULL on type error
+ if (str == NULL) {
rettv->vval.v_string = NULL;
- else {
- type = get_histtype(str);
- if (argvars[1].v_type == VAR_UNKNOWN)
+ } else {
+ type = get_histtype(str, STRLEN(str), false);
+ if (argvars[1].v_type == VAR_UNKNOWN) {
idx = get_history_idx(type);
- else
+ } else {
idx = (int)get_tv_number_chk(&argvars[1], NULL);
- /* -1 on type error */
+ }
+ // -1 on type error
rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
}
rettv->v_type = VAR_STRING;
@@ -11157,11 +10977,13 @@ static void f_histnr(typval_T *argvars, typval_T *rettv)
char_u *history = get_tv_string_chk(&argvars[0]);
- i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
- if (i >= HIST_CMD && i < HIST_COUNT)
+ i = history == NULL ? HIST_CMD - 1 : get_histtype(history, STRLEN(history),
+ false);
+ if (i != HIST_INVALID) {
i = get_history_idx(i);
- else
+ } else {
i = -1;
+ }
rettv->vval.v_number = i;
}
@@ -11797,7 +11619,7 @@ static char **tv_to_argv(typval_T *cmd_tv, char **cmd)
assert(argl->lv_first);
const char_u *exe = get_tv_string_chk(&argl->lv_first->li_tv);
- if (!exe || !os_can_exe(exe, NULL)) {
+ if (!exe || !os_can_exe(exe, NULL, true)) {
// String is not executable
if (exe) {
EMSG2(e_jobexe, exe);
@@ -12053,6 +11875,47 @@ static void f_join(typval_T *argvars, typval_T *rettv)
rettv->vval.v_string = NULL;
}
+/// json_decode() function
+static void f_json_decode(typval_T *argvars, typval_T *rettv)
+{
+ char numbuf[NUMBUFLEN];
+ char *s = NULL;
+ char *tofree = NULL;
+ size_t len;
+ if (argvars[0].v_type == VAR_LIST) {
+ if (!encode_vim_list_to_buf(argvars[0].vval.v_list, &len, &s)) {
+ EMSG(_("E474: Failed to convert list to string"));
+ return;
+ }
+ tofree = s;
+ if (s == NULL) {
+ assert(len == 0);
+ s = "";
+ }
+ } else {
+ s = (char *) get_tv_string_buf_chk(&argvars[0], (char_u *) numbuf);
+ if (s) {
+ len = strlen(s);
+ } else {
+ return;
+ }
+ }
+ if (json_decode_string(s, len, rettv) == FAIL) {
+ emsgf(_("E474: Failed to parse %.*s"), (int) len, s);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+ }
+ assert(rettv->v_type != VAR_UNKNOWN);
+ xfree(tofree);
+}
+
+/// json_encode() function
+static void f_json_encode(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (char_u *) encode_tv2json(&argvars[0], NULL);
+}
+
/*
* "keys()" function
*/
@@ -12094,7 +11957,10 @@ static void f_len(typval_T *argvars, typval_T *rettv)
case VAR_DICT:
rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
break;
- default:
+ case VAR_UNKNOWN:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_FUNC:
EMSG(_("E701: Invalid type for len()"));
break;
}
@@ -12254,8 +12120,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
mode = get_map_mode(&which, 0);
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
- rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
+ keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false,
+ CPO_TO_CPO_FLAGS);
+ rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local);
xfree(keys_buf);
if (!get_dict) {
@@ -12417,9 +12284,10 @@ static void find_some_match(typval_T *argvars, typval_T *rettv, int type)
break;
}
xfree(tofree);
- tofree = str = (char_u *) echo_string(&li->li_tv, NULL);
- if (str == NULL)
+ tofree = str = (char_u *) encode_tv2echo(&li->li_tv, NULL);
+ if (str == NULL) {
break;
+ }
}
match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
@@ -12817,289 +12685,6 @@ static void f_mode(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_STRING;
}
-/// Msgpack callback for writing to readfile()-style list
-static int msgpack_list_write(void *data, const char *buf, size_t len)
-{
- if (len == 0) {
- return 0;
- }
- list_T *const list = (list_T *) data;
- const char *const end = buf + len;
- const char *line_end = buf;
- if (list->lv_last == NULL) {
- list_append_string(list, NULL, 0);
- }
- listitem_T *li = list->lv_last;
- do {
- const char *line_start = line_end;
- line_end = xmemscan(line_start, NL, end - line_start);
- if (line_end == line_start) {
- list_append_allocated_string(list, NULL);
- } else {
- const size_t line_length = line_end - line_start;
- char *str;
- if (li == NULL) {
- str = xmemdupz(line_start, line_length);
- } else {
- const size_t li_len = (li->li_tv.vval.v_string == NULL
- ? 0
- : STRLEN(li->li_tv.vval.v_string));
- li->li_tv.vval.v_string = xrealloc(li->li_tv.vval.v_string,
- li_len + line_length + 1);
- str = (char *) li->li_tv.vval.v_string + li_len;
- memmove(str, line_start, line_length);
- str[line_length] = 0;
- }
- for (size_t i = 0; i < line_length; i++) {
- if (str[i] == NUL) {
- str[i] = NL;
- }
- }
- if (li == NULL) {
- list_append_allocated_string(list, str);
- } else {
- li = NULL;
- }
- if (line_end == end - 1) {
- list_append_allocated_string(list, NULL);
- }
- }
- line_end++;
- } while (line_end < end);
- return 0;
-}
-
-/// Convert readfile()-style list to a char * buffer with length
-///
-/// @param[in] list Converted list.
-/// @param[out] ret_len Resulting buffer length.
-/// @param[out] ret_buf Allocated buffer with the result or NULL if ret_len is
-/// zero.
-///
-/// @return true in case of success, false in case of failure.
-static inline bool vim_list_to_buf(const list_T *const list,
- size_t *const ret_len, char **const ret_buf)
- FUNC_ATTR_NONNULL_ARG(2,3) FUNC_ATTR_WARN_UNUSED_RESULT
-{
- size_t len = 0;
- if (list != NULL) {
- for (const listitem_T *li = list->lv_first;
- li != NULL;
- li = li->li_next) {
- if (li->li_tv.v_type != VAR_STRING) {
- return false;
- }
- len++;
- if (li->li_tv.vval.v_string != 0) {
- len += STRLEN(li->li_tv.vval.v_string);
- }
- }
- if (len) {
- len--;
- }
- }
- *ret_len = len;
- if (len == 0) {
- *ret_buf = NULL;
- return true;
- }
- ListReaderState lrstate = init_lrstate(list);
- char *const buf = xmalloc(len);
- size_t read_bytes;
- if (read_from_list(&lrstate, buf, len, &read_bytes) != OK) {
- assert(false);
- }
- assert(len == read_bytes);
- *ret_buf = buf;
- return true;
-}
-
-/// Show a error message when converting to msgpack value
-///
-/// @param[in] msg Error message to dump. Must contain exactly two %s that
-/// will be replaced with what was being dumped: first with
-/// something like “F†or “function argumentâ€, second with path
-/// to the failed value.
-/// @param[in] mpstack Path to the failed value.
-/// @param[in] objname Dumped object name.
-///
-/// @return FAIL.
-static int conv_error(const char *const msg, const MPConvStack *const mpstack,
- const char *const objname)
- FUNC_ATTR_NONNULL_ALL
-{
- garray_T msg_ga;
- ga_init(&msg_ga, (int)sizeof(char), 80);
- char *const key_msg = _("key %s");
- char *const key_pair_msg = _("key %s at index %i from special map");
- char *const idx_msg = _("index %i");
- for (size_t i = 0; i < kv_size(*mpstack); i++) {
- if (i != 0) {
- ga_concat(&msg_ga, (char_u *) ", ");
- }
- MPConvStackVal v = kv_A(*mpstack, i);
- switch (v.type) {
- case kMPConvDict: {
- typval_T key_tv = {
- .v_type = VAR_STRING,
- .vval = { .v_string = (v.data.d.hi == NULL
- ? v.data.d.dict->dv_hashtab.ht_array
- : (v.data.d.hi - 1))->hi_key },
- };
- char *const key = tv2string(&key_tv, NULL);
- vim_snprintf((char *) IObuff, IOSIZE, key_msg, key);
- xfree(key);
- ga_concat(&msg_ga, IObuff);
- break;
- }
- case kMPConvPairs:
- case kMPConvList: {
- int idx = 0;
- const listitem_T *li;
- for (li = v.data.l.list->lv_first;
- li != NULL && li->li_next != v.data.l.li;
- li = li->li_next) {
- idx++;
- }
- if (v.type == kMPConvList
- || li == NULL
- || (li->li_tv.v_type != VAR_LIST
- && li->li_tv.vval.v_list->lv_len <= 0)) {
- vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx);
- ga_concat(&msg_ga, IObuff);
- } else {
- typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv;
- char *const key = echo_string(&key_tv, NULL);
- vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
- xfree(key);
- ga_concat(&msg_ga, IObuff);
- }
- break;
- }
- }
- }
- EMSG3(msg, objname, (kv_size(*mpstack) == 0
- ? _("itself")
- : (char *) msg_ga.ga_data));
- ga_clear(&msg_ga);
- return FAIL;
-}
-
-#define CONV_STRING(buf, len) \
- do { \
- if (buf == NULL) { \
- msgpack_pack_bin(packer, 0); \
- } else { \
- const size_t len_ = (len); \
- msgpack_pack_bin(packer, len_); \
- msgpack_pack_bin_body(packer, buf, len_); \
- } \
- } while (0)
-
-#define CONV_STR_STRING(buf, len) \
- do { \
- if (buf == NULL) { \
- msgpack_pack_str(packer, 0); \
- } else { \
- const size_t len_ = (len); \
- msgpack_pack_str(packer, len_); \
- msgpack_pack_str_body(packer, buf, len_); \
- } \
- } while (0)
-
-#define CONV_EXT_STRING(buf, len, type) \
- do { \
- if (buf == NULL) { \
- msgpack_pack_ext(packer, 0, type); \
- } else { \
- const size_t len_ = (len); \
- msgpack_pack_ext(packer, len_, (int8_t) type); \
- msgpack_pack_ext_body(packer, buf, len_); \
- } \
- } while (0)
-
-#define CONV_NUMBER(num) \
- msgpack_pack_int64(packer, (int64_t) (num))
-
-#define CONV_FLOAT(flt) \
- msgpack_pack_double(packer, (double) (flt))
-
-#define CONV_FUNC(fun) \
- return conv_error(_("E951: Error while dumping %s, %s: " \
- "attempt to dump function reference"), \
- mpstack, objname)
-
-#define CONV_EMPTY_LIST() \
- msgpack_pack_array(packer, 0)
-
-#define CONV_LIST_START(lst) \
- msgpack_pack_array(packer, (lst)->lv_len)
-
-#define CONV_EMPTY_DICT() \
- msgpack_pack_map(packer, 0)
-
-#define CONV_SPECIAL_NIL() \
- msgpack_pack_nil(packer)
-
-#define CONV_SPECIAL_BOOL(num) \
- do { \
- if ((num)) { \
- msgpack_pack_true(packer); \
- } else { \
- msgpack_pack_false(packer); \
- } \
- } while (0)
-
-#define CONV_UNSIGNED_NUMBER(num) \
- msgpack_pack_uint64(packer, (num))
-
-#define CONV_SPECIAL_MAP_START(lst) \
- msgpack_pack_map(packer, (lst)->lv_len)
-
-#define CONV_DICT_START(dct) \
- msgpack_pack_map(packer, (dct)->dv_hashtab.ht_used)
-
-#define CONV_DICT_END(dct)
-
-#define CONV_DICT_AFTER_KEY(dct)
-
-#define CONV_DICT_BETWEEN_ITEMS(dct)
-
-#define CONV_LIST_END(lst)
-
-#define CONV_LIST_BETWEEN_ITEMS(lst)
-
-#define CONV_RECURSE(val, conv_type) \
- return conv_error(_("E952: Unable to dump %s: " \
- "container references itself in %s"), \
- mpstack, objname)
-
-#define CONV_ALLOW_SPECIAL true
-
-DEFINE_VIML_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
-
-#undef CONV_STRING
-#undef CONV_STR_STRING
-#undef CONV_EXT_STRING
-#undef CONV_NUMBER
-#undef CONV_FLOAT
-#undef CONV_FUNC
-#undef CONV_EMPTY_LIST
-#undef CONV_LIST_START
-#undef CONV_EMPTY_DICT
-#undef CONV_SPECIAL_NIL
-#undef CONV_SPECIAL_BOOL
-#undef CONV_UNSIGNED_NUMBER
-#undef CONV_SPECIAL_MAP_START
-#undef CONV_DICT_START
-#undef CONV_DICT_END
-#undef CONV_DICT_AFTER_KEY
-#undef CONV_DICT_BETWEEN_ITEMS
-#undef CONV_LIST_END
-#undef CONV_LIST_BETWEEN_ITEMS
-#undef CONV_RECURSE
-#undef CONV_ALLOW_SPECIAL
-
/// "msgpackdump()" function
static void f_msgpackdump(typval_T *argvars, typval_T *rettv)
FUNC_ATTR_NONNULL_ALL
@@ -13113,7 +12698,7 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv)
if (list == NULL) {
return;
}
- msgpack_packer *lpacker = msgpack_packer_new(ret_list, &msgpack_list_write);
+ msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write);
const char *const msg = _("msgpackdump() argument, index %i");
// Assume that translation will not take more then 4 times more space
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
@@ -13121,307 +12706,13 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv)
for (listitem_T *li = list->lv_first; li != NULL; li = li->li_next) {
vim_snprintf(msgbuf, sizeof(msgbuf), (char *) msg, idx);
idx++;
- if (vim_to_msgpack(lpacker, &li->li_tv, msgbuf) == FAIL) {
+ if (encode_vim_to_msgpack(lpacker, &li->li_tv, msgbuf) == FAIL) {
break;
}
}
msgpack_packer_free(lpacker);
}
-/// Read bytes from list
-///
-/// @param[in,out] state Structure describing position in list from which
-/// reading should start. Is updated to reflect position
-/// at which reading ended.
-/// @param[out] buf Buffer to write to.
-/// @param[in] nbuf Buffer length.
-/// @param[out] read_bytes Is set to amount of bytes read.
-///
-/// @return OK when reading was finished, FAIL in case of error (i.e. list item
-/// was not a string), NOTDONE if reading was successfull, but there are
-/// more bytes to read.
-static int read_from_list(ListReaderState *const state, char *const buf,
- const size_t nbuf, size_t *const read_bytes)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
- char *const buf_end = buf + nbuf;
- char *p = buf;
- while (p < buf_end) {
- for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
- const char ch = state->li->li_tv.vval.v_string[state->offset++];
- *p++ = (ch == NL ? NUL : ch);
- }
- if (p < buf_end) {
- state->li = state->li->li_next;
- if (state->li == NULL) {
- *read_bytes = (size_t) (p - buf);
- return OK;
- }
- *p++ = NL;
- if (state->li->li_tv.v_type != VAR_STRING) {
- *read_bytes = (size_t) (p - buf);
- return FAIL;
- }
- state->offset = 0;
- state->li_length = (state->li->li_tv.vval.v_string == NULL
- ? 0
- : STRLEN(state->li->li_tv.vval.v_string));
- }
- }
- *read_bytes = nbuf;
- return (state->offset < state->li_length || state->li->li_next != NULL
- ? NOTDONE
- : OK);
-}
-
-/// Initialize ListReaderState structure
-static inline ListReaderState init_lrstate(const list_T *const list)
- FUNC_ATTR_NONNULL_ALL
-{
- return (ListReaderState) {
- .li = list->lv_first,
- .offset = 0,
- .li_length = (list->lv_first->li_tv.vval.v_string == NULL
- ? 0
- : STRLEN(list->lv_first->li_tv.vval.v_string)),
- };
-}
-
-/// Convert msgpack object to a VimL one
-int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
-#define INIT_SPECIAL_DICT(tv, type, val) \
- do { \
- dict_T *const dict = dict_alloc(); \
- dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE"); \
- type_di->di_tv.v_type = VAR_LIST; \
- type_di->di_tv.v_lock = 0; \
- type_di->di_tv.vval.v_list = (list_T *) msgpack_type_lists[type]; \
- type_di->di_tv.vval.v_list->lv_refcount++; \
- dict_add(dict, type_di); \
- dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL"); \
- val_di->di_tv = val; \
- dict_add(dict, val_di); \
- tv->v_type = VAR_DICT; \
- dict->dv_refcount++; \
- tv->vval.v_dict = dict; \
- } while (0)
- switch (mobj.type) {
- case MSGPACK_OBJECT_NIL: {
- INIT_SPECIAL_DICT(rettv, kMPNil, ((typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = 0,
- .vval = { .v_number = 0 },
- }));
- break;
- }
- case MSGPACK_OBJECT_BOOLEAN: {
- INIT_SPECIAL_DICT(rettv, kMPBoolean,
- ((typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = 0,
- .vval = {
- .v_number = (varnumber_T) mobj.via.boolean,
- },
- }));
- break;
- }
- case MSGPACK_OBJECT_POSITIVE_INTEGER: {
- if (mobj.via.u64 <= VARNUMBER_MAX) {
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = 0,
- .vval = { .v_number = (varnumber_T) mobj.via.u64 },
- };
- } else {
- list_T *const list = list_alloc();
- list->lv_refcount++;
- INIT_SPECIAL_DICT(rettv, kMPInteger,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- uint64_t n = mobj.via.u64;
- list_append_number(list, 1);
- list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
- list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
- list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
- }
- break;
- }
- case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
- if (mobj.via.i64 >= VARNUMBER_MIN) {
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = 0,
- .vval = { .v_number = (varnumber_T) mobj.via.i64 },
- };
- } else {
- list_T *const list = list_alloc();
- list->lv_refcount++;
- INIT_SPECIAL_DICT(rettv, kMPInteger,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- uint64_t n = -((uint64_t) mobj.via.i64);
- list_append_number(list, -1);
- list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
- list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
- list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
- }
- break;
- }
- case MSGPACK_OBJECT_FLOAT: {
- *rettv = (typval_T) {
- .v_type = VAR_FLOAT,
- .v_lock = 0,
- .vval = { .v_float = mobj.via.f64 },
- };
- break;
- }
- case MSGPACK_OBJECT_STR: {
- list_T *const list = list_alloc();
- list->lv_refcount++;
- INIT_SPECIAL_DICT(rettv, kMPString,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- if (msgpack_list_write((void *) list, mobj.via.str.ptr, mobj.via.str.size)
- == -1) {
- return FAIL;
- }
- break;
- }
- case MSGPACK_OBJECT_BIN: {
- if (memchr(mobj.via.bin.ptr, NUL, mobj.via.bin.size) == NULL) {
- *rettv = (typval_T) {
- .v_type = VAR_STRING,
- .v_lock = 0,
- .vval = { .v_string = xmemdupz(mobj.via.bin.ptr, mobj.via.bin.size) },
- };
- break;
- }
- list_T *const list = list_alloc();
- list->lv_refcount++;
- INIT_SPECIAL_DICT(rettv, kMPBinary,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- if (msgpack_list_write((void *) list, mobj.via.bin.ptr, mobj.via.bin.size)
- == -1) {
- return FAIL;
- }
- break;
- }
- case MSGPACK_OBJECT_ARRAY: {
- list_T *const list = list_alloc();
- list->lv_refcount++;
- *rettv = (typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- };
- for (size_t i = 0; i < mobj.via.array.size; i++) {
- listitem_T *const li = listitem_alloc();
- li->li_tv.v_type = VAR_UNKNOWN;
- list_append(list, li);
- if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
- return FAIL;
- }
- }
- break;
- }
- case MSGPACK_OBJECT_MAP: {
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
- || mobj.via.map.ptr[i].key.via.str.size == 0
- || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
- mobj.via.map.ptr[i].key.via.str.size) != NULL) {
- goto msgpack_to_vim_generic_map;
- }
- }
- dict_T *const dict = dict_alloc();
- dict->dv_refcount++;
- *rettv = (typval_T) {
- .v_type = VAR_DICT,
- .v_lock = 0,
- .vval = { .v_dict = dict },
- };
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
- + mobj.via.map.ptr[i].key.via.str.size);
- memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
- mobj.via.map.ptr[i].key.via.str.size);
- di->di_tv.v_type = VAR_UNKNOWN;
- if (dict_add(dict, di) == FAIL) {
- // Duplicate key: fallback to generic map
- clear_tv(rettv);
- xfree(di);
- goto msgpack_to_vim_generic_map;
- }
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
- return FAIL;
- }
- }
- break;
-msgpack_to_vim_generic_map: {}
- list_T *const list = list_alloc();
- list->lv_refcount++;
- INIT_SPECIAL_DICT(rettv, kMPMap,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- list_T *const kv_pair = list_alloc();
- list_append_list(list, kv_pair);
- listitem_T *const key_li = listitem_alloc();
- key_li->li_tv.v_type = VAR_UNKNOWN;
- list_append(kv_pair, key_li);
- listitem_T *const val_li = listitem_alloc();
- val_li->li_tv.v_type = VAR_UNKNOWN;
- list_append(kv_pair, val_li);
- if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
- return FAIL;
- }
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) {
- return FAIL;
- }
- }
- break;
- }
- case MSGPACK_OBJECT_EXT: {
- list_T *const list = list_alloc();
- list->lv_refcount++;
- list_append_number(list, mobj.via.ext.type);
- list_T *const ext_val_list = list_alloc();
- list_append_list(list, ext_val_list);
- INIT_SPECIAL_DICT(rettv, kMPExt,
- ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = 0,
- .vval = { .v_list = list },
- }));
- if (msgpack_list_write((void *) ext_val_list, mobj.via.ext.ptr,
- mobj.via.ext.size) == -1) {
- return FAIL;
- }
- break;
- }
- }
-#undef INIT_SPECIAL_DICT
- return OK;
-}
-
/// "msgpackparse" function
static void f_msgpackparse(typval_T *argvars, typval_T *rettv)
FUNC_ATTR_NONNULL_ALL
@@ -13439,7 +12730,7 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv)
EMSG2(_(e_invarg2), "List item is not a string");
return;
}
- ListReaderState lrstate = init_lrstate(list);
+ ListReaderState lrstate = encode_init_lrstate(list);
msgpack_unpacker *const unpacker = msgpack_unpacker_new(IOSIZE);
if (unpacker == NULL) {
EMSG(_(e_outofmem));
@@ -13453,7 +12744,7 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv)
goto f_msgpackparse_exit;
}
size_t read_bytes;
- const int rlret = read_from_list(
+ const int rlret = encode_read_from_list(
&lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE, &read_bytes);
if (rlret == FAIL) {
EMSG2(_(e_invarg2), "List item is not a string");
@@ -14282,14 +13573,14 @@ static void f_reverse(typval_T *argvars, typval_T *rettv)
}
}
-#define SP_NOMOVE 0x01 /* don't move cursor */
-#define SP_REPEAT 0x02 /* repeat to find outer pair */
-#define SP_RETCOUNT 0x04 /* return matchcount */
-#define SP_SETPCMARK 0x08 /* set previous context mark */
-#define SP_START 0x10 /* accept match at start position */
-#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
-#define SP_END 0x40 /* leave cursor at end of match */
-
+#define SP_NOMOVE 0x01 ///< don't move cursor
+#define SP_REPEAT 0x02 ///< repeat to find outer pair
+#define SP_RETCOUNT 0x04 ///< return matchcount
+#define SP_SETPCMARK 0x08 ///< set previous context mark
+#define SP_START 0x10 ///< accept match at start position
+#define SP_SUBPAT 0x20 ///< return nr of matching sub-pattern
+#define SP_END 0x40 ///< leave cursor at end of match
+#define SP_COLUMN 0x80 ///< start at cursor column
/*
* Get flags for a search function.
@@ -14315,13 +13606,14 @@ static int get_search_arg(typval_T *varp, int *flagsp)
default: mask = 0;
if (flagsp != NULL)
switch (*flags) {
- case 'c': mask = SP_START; break;
- case 'e': mask = SP_END; break;
- case 'm': mask = SP_RETCOUNT; break;
- case 'n': mask = SP_NOMOVE; break;
- case 'p': mask = SP_SUBPAT; break;
- case 'r': mask = SP_REPEAT; break;
- case 's': mask = SP_SETPCMARK; break;
+ case 'c': mask = SP_START; break;
+ case 'e': mask = SP_END; break;
+ case 'm': mask = SP_RETCOUNT; break;
+ case 'n': mask = SP_NOMOVE; break;
+ case 'p': mask = SP_SUBPAT; break;
+ case 'r': mask = SP_REPEAT; break;
+ case 's': mask = SP_SETPCMARK; break;
+ case 'z': mask = SP_COLUMN; break;
}
if (mask == 0) {
EMSG2(_(e_invarg2), flags);
@@ -14337,9 +13629,7 @@ static int get_search_arg(typval_T *varp, int *flagsp)
return dir;
}
-/*
- * Shared by search() and searchpos() functions
- */
+// Shared by search() and searchpos() functions.
static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
{
int flags;
@@ -14360,10 +13650,15 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
if (dir == 0)
goto theend;
flags = *flagsp;
- if (flags & SP_START)
+ if (flags & SP_START) {
options |= SEARCH_START;
- if (flags & SP_END)
+ }
+ if (flags & SP_END) {
options |= SEARCH_END;
+ }
+ if (flags & SP_COLUMN) {
+ options |= SEARCH_COL;
+ }
/* Optional arguments: line number to stop searching and timeout. */
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
@@ -15228,43 +14523,51 @@ static void f_setline(typval_T *argvars, typval_T *rettv)
/// replace its content or create a new one.
/// @param[in] title_arg New list title. Defaults to caller function name.
/// @param[out] rettv Return value: 0 in case of success, -1 otherwise.
-static void set_qf_ll_list(win_T *wp, typval_T *list_arg, typval_T *action_arg,
- typval_T *title_arg, typval_T *rettv)
- FUNC_ATTR_NONNULL_ARG(2, 3, 4, 5)
+static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ARG(2, 3)
{
- char_u *act;
- int action = ' ';
char_u *title = NULL;
-
+ int action = ' ';
rettv->vval.v_number = -1;
- if (list_arg->v_type != VAR_LIST)
+ typval_T *list_arg = &args[0];
+ if (list_arg->v_type != VAR_LIST) {
EMSG(_(e_listreq));
- else {
- list_T *l = list_arg->vval.v_list;
+ return;
+ }
- if (action_arg->v_type != VAR_UNKNOWN) {
- act = get_tv_string_chk(action_arg);
- if (act == NULL)
- return; /* type error; errmsg already given */
- if (*act == 'a' || *act == 'r')
- action = *act;
- }
+ typval_T *action_arg = &args[1];
+ if (action_arg->v_type == VAR_UNKNOWN) {
+ // Option argument was not given.
+ goto skip_args;
+ } else if (action_arg->v_type != VAR_STRING) {
+ EMSG(_(e_strreq));
+ return;
+ }
+ char_u *act = get_tv_string_chk(action_arg);
+ if (*act == 'a' || *act == 'r') {
+ action = *act;
+ }
- if (title_arg->v_type != VAR_UNKNOWN) {
- title = get_tv_string_chk(title_arg);
- if (!title) {
- return; // type error; errmsg already given
- }
- }
+ typval_T *title_arg = &args[2];
+ if (title_arg->v_type == VAR_UNKNOWN) {
+ // Option argument was not given.
+ goto skip_args;
+ }
+ title = get_tv_string_chk(title_arg);
+ if (!title) {
+ // Type error. Error already printed by get_tv_string_chk().
+ return;
+ }
- if (!title) {
- title = (char_u*)(wp ? "setloclist()" : "setqflist()");
- }
+skip_args:
+ if (!title) {
+ title = (char_u*)(wp ? "setloclist()" : "setqflist()");
+ }
- if (l && set_errorlist(wp, l, action, title) == OK) {
- rettv->vval.v_number = 0;
- }
+ list_T *l = list_arg->vval.v_list;
+ if (l && set_errorlist(wp, l, action, title) == OK) {
+ rettv->vval.v_number = 0;
}
}
@@ -15279,7 +14582,7 @@ static void f_setloclist(typval_T *argvars, typval_T *rettv)
win = find_win_by_nr(&argvars[0], NULL);
if (win != NULL) {
- set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
+ set_qf_ll_list(win, &argvars[1], rettv);
}
}
@@ -15388,25 +14691,30 @@ static void f_setpos(typval_T *argvars, typval_T *rettv)
name = get_tv_string_chk(argvars);
if (name != NULL) {
if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK) {
- if (--pos.col < 0)
+ if (--pos.col < 0) {
pos.col = 0;
+ }
if (name[0] == '.' && name[1] == NUL) {
- /* set cursor */
+ // set cursor
if (fnum == curbuf->b_fnum) {
curwin->w_cursor = pos;
if (curswant >= 0) {
curwin->w_curswant = curswant - 1;
+ curwin->w_set_curswant = false;
}
check_cursor();
rettv->vval.v_number = 0;
- } else
+ } else {
EMSG(_(e_invarg));
+ }
} else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
- /* set mark */
- if (setmark_pos(name[1], &pos, fnum) == OK)
+ // set mark
+ if (setmark_pos(name[1], &pos, fnum) == OK) {
rettv->vval.v_number = 0;
- } else
+ }
+ } else {
EMSG(_(e_invarg));
+ }
}
}
}
@@ -15416,7 +14724,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv)
*/
static void f_setqflist(typval_T *argvars, typval_T *rettv)
{
- set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
+ set_qf_ll_list(NULL, argvars, rettv);
}
/*
@@ -15428,11 +14736,11 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
char_u *strregname;
char_u *stropt;
bool append = false;
- char_u yank_type;
+ MotionType yank_type;
long block_len;
block_len = -1;
- yank_type = MAUTO;
+ yank_type = kMTUnknown;
strregname = get_tv_string_chk(argvars);
rettv->vval.v_number = 1; /* FAIL is default */
@@ -15449,17 +14757,17 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
return; /* type error */
for (; *stropt != NUL; ++stropt)
switch (*stropt) {
- case 'a': case 'A': /* append */
+ case 'a': case 'A': // append
append = true;
break;
- case 'v': case 'c': /* character-wise selection */
- yank_type = MCHAR;
+ case 'v': case 'c': // character-wise selection
+ yank_type = kMTCharWise;
break;
- case 'V': case 'l': /* line-wise selection */
- yank_type = MLINE;
+ case 'V': case 'l': // line-wise selection
+ yank_type = kMTLineWise;
break;
- case 'b': case Ctrl_V: /* block-wise selection */
- yank_type = MBLOCK;
+ case 'b': case Ctrl_V: // block-wise selection
+ yank_type = kMTBlockWise;
if (ascii_isdigit(stropt[1])) {
++stropt;
block_len = getdigits_long(&stropt) - 1;
@@ -15685,6 +14993,8 @@ typedef struct {
static int item_compare_ic;
static bool item_compare_numeric;
+static bool item_compare_numbers;
+static bool item_compare_float;
static char_u *item_compare_func;
static dict_T *item_compare_selfdict;
static int item_compare_func_err;
@@ -15706,9 +15016,24 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
si2 = (sortItem_T *)s2;
typval_T *tv1 = &si1->item->li_tv;
typval_T *tv2 = &si2->item->li_tv;
- // tv2string() puts quotes around a string and allocates memory. Don't do
- // that for string variables. Use a single quote when comparing with a
- // non-string to do what the docs promise.
+
+ if (item_compare_numbers) {
+ long v1 = get_tv_number(tv1);
+ long v2 = get_tv_number(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+
+ if (item_compare_float) {
+ float_T v1 = get_tv_float(tv1);
+ float_T v2 = get_tv_float(tv2);
+
+ return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
+ }
+
+ // encode_tv2string() puts quotes around a string and allocates memory. Don't
+ // do that for string variables. Use a single quote when comparing with
+ // a non-string to do what the docs promise.
if (tv1->v_type == VAR_STRING) {
if (tv2->v_type != VAR_STRING || item_compare_numeric) {
p1 = (char_u *)"'";
@@ -15716,7 +15041,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
p1 = tv1->vval.v_string;
}
} else {
- tofree1 = p1 = (char_u *) tv2string(tv1, NULL);
+ tofree1 = p1 = (char_u *) encode_tv2string(tv1, NULL);
}
if (tv2->v_type == VAR_STRING) {
if (tv1->v_type != VAR_STRING || item_compare_numeric) {
@@ -15725,7 +15050,7 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)
p2 = tv2->vval.v_string;
}
} else {
- tofree2 = p2 = (char_u *) tv2string(tv2, NULL);
+ tofree2 = p2 = (char_u *) encode_tv2string(tv2, NULL);
}
if (p1 == NULL)
p1 = (char_u *)"";
@@ -15834,12 +15159,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
l = argvars[0].vval.v_list;
- if (l == NULL ||
- tv_check_lock(l->lv_lock,
- (char_u *)(sort
- ? N_("sort() argument")
- : N_("uniq() argument")),
- true)) {
+ if (l == NULL
+ || tv_check_lock(l->lv_lock,
+ (char_u *)(sort
+ ? N_("sort() argument")
+ : N_("uniq() argument")),
+ true)) {
return;
}
rettv->vval.v_list = l;
@@ -15852,6 +15177,8 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
item_compare_ic = FALSE;
item_compare_numeric = false;
+ item_compare_numbers = false;
+ item_compare_float = false;
item_compare_func = NULL;
item_compare_selfdict = NULL;
@@ -15873,6 +15200,12 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
if (STRCMP(item_compare_func, "n") == 0) {
item_compare_func = NULL;
item_compare_numeric = true;
+ } else if (STRCMP(item_compare_func, "N") == 0) {
+ item_compare_func = NULL;
+ item_compare_numbers = true;
+ } else if (STRCMP(item_compare_func, "f") == 0) {
+ item_compare_func = NULL;
+ item_compare_float = true;
} else if (STRCMP(item_compare_func, "i") == 0) {
item_compare_func = NULL;
item_compare_ic = TRUE;
@@ -15977,6 +15310,21 @@ static void f_uniq(typval_T *argvars, typval_T *rettv)
do_sort_uniq(argvars, rettv, false);
}
+//
+// "reltimefloat()" function
+//
+static void f_reltimefloat(typval_T *argvars , typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ proftime_T tm;
+
+ rettv->v_type = VAR_FLOAT;
+ rettv->vval.v_float = 0;
+ if (list2proftime(&argvars[0], &tm) == OK) {
+ rettv->vval.v_float = ((float_T)tm) / 1000000000;
+ }
+}
+
/*
* "soundfold({word})" function
*/
@@ -16161,7 +15509,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv)
if (*p == '+')
p = skipwhite(p + 1);
- (void)string2float(p, &rettv->vval.v_float);
+ (void) string2float((char *) p, &rettv->vval.v_float);
rettv->v_type = VAR_FLOAT;
}
@@ -16292,7 +15640,7 @@ static void f_stridx(typval_T *argvars, typval_T *rettv)
static void f_string(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *) tv2string(&argvars[0], NULL);
+ rettv->vval.v_string = (char_u *) encode_tv2string(&argvars[0], NULL);
}
/*
@@ -17025,9 +16373,9 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
// Save the job id and pid in b:terminal_job_{id,pid}
Error err;
dict_set_value(curbuf->b_vars, cstr_as_string("terminal_job_id"),
- INTEGER_OBJ(rettv->vval.v_number), &err);
+ INTEGER_OBJ(rettv->vval.v_number), false, &err);
dict_set_value(curbuf->b_vars, cstr_as_string("terminal_job_pid"),
- INTEGER_OBJ(pid), &err);
+ INTEGER_OBJ(pid), false, &err);
Terminal *term = terminal_open(topts);
data->term = term;
@@ -17213,16 +16561,33 @@ static void f_trunc(typval_T *argvars, typval_T *rettv)
*/
static void f_type(typval_T *argvars, typval_T *rettv)
{
- int n;
+ int n = -1;
switch (argvars[0].v_type) {
- case VAR_NUMBER: n = 0; break;
- case VAR_STRING: n = 1; break;
- case VAR_FUNC: n = 2; break;
- case VAR_LIST: n = 3; break;
- case VAR_DICT: n = 4; break;
- case VAR_FLOAT: n = 5; break;
- default: EMSG2(_(e_intern2), "f_type()"); n = 0; break;
+ case VAR_NUMBER: n = 0; break;
+ case VAR_STRING: n = 1; break;
+ case VAR_FUNC: n = 2; break;
+ case VAR_LIST: n = 3; break;
+ case VAR_DICT: n = 4; break;
+ case VAR_FLOAT: n = 5; break;
+ case VAR_SPECIAL: {
+ switch (argvars[0].vval.v_special) {
+ case kSpecialVarTrue:
+ case kSpecialVarFalse: {
+ n = 6;
+ break;
+ }
+ case kSpecialVarNull: {
+ n = 7;
+ break;
+ }
+ }
+ break;
+ }
+ case VAR_UNKNOWN: {
+ EMSG2(_(e_intern2), "f_type(UNKNOWN)");
+ break;
+ }
}
rettv->vval.v_number = n;
}
@@ -17574,6 +16939,13 @@ static void f_winwidth(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = wp->w_width;
}
+/// "wordcount()" function
+static void f_wordcount(typval_T *argvars, typval_T *rettv)
+{
+ rettv_dict_alloc(rettv);
+ cursor_pos_info(rettv->vval.v_dict);
+}
+
/// "writefile()" function
static void f_writefile(typval_T *argvars, typval_T *rettv)
{
@@ -17801,21 +17173,28 @@ static int get_env_len(char_u **arg)
return len;
}
-/*
- * Get the length of the name of a function or internal variable.
- * "arg" is advanced to the first non-white character after the name.
- * Return 0 if something is wrong.
- */
-static int get_id_len(char_u **arg)
-{
- char_u *p;
+// Get the length of the name of a function or internal variable.
+// "arg" is advanced to the first non-white character after the name.
+// Return 0 if something is wrong.
+static int get_id_len(char_u **arg) {
+ char_u *p;
int len;
- /* Find the end of the name. */
- for (p = *arg; eval_isnamec(*p); ++p)
- ;
- if (p == *arg) /* no name found */
+ // Find the end of the name.
+ for (p = *arg; eval_isnamec(*p); p++) {
+ if (*p == ':') {
+ // "s:" is start of "s:var", but "n:" is not and can be used in
+ // slice "[n:]". Also "xx:" is not a namespace.
+ len = (int)(p - *arg);
+ if (len > 1
+ || (len == 1 && vim_strchr(namespace_char, **arg) == NULL)) {
+ break;
+ }
+ }
+ }
+ if (p == *arg) { // no name found
return 0;
+ }
len = (int)(p - *arg);
*arg = skipwhite(p);
@@ -17886,28 +17265,29 @@ static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose)
return len;
}
-/*
- * Find the end of a variable or function name, taking care of magic braces.
- * If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the
- * start and end of the first magic braces item.
- * "flags" can have FNE_INCL_BR and FNE_CHECK_START.
- * Return a pointer to just after the name. Equal to "arg" if there is no
- * valid name.
- */
-static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags)
+// Find the end of a variable or function name, taking care of magic braces.
+// If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the
+// start and end of the first magic braces item.
+// "flags" can have FNE_INCL_BR and FNE_CHECK_START.
+// Return a pointer to just after the name. Equal to "arg" if there is no
+// valid name.
+static char_u *find_name_end(char_u *arg, char_u **expr_start,
+ char_u **expr_end, int flags)
{
int mb_nest = 0;
int br_nest = 0;
- char_u *p;
+ char_u *p;
+ int len;
if (expr_start != NULL) {
*expr_start = NULL;
*expr_end = NULL;
}
- /* Quick check for valid starting character. */
- if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{')
+ // Quick check for valid starting character.
+ if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{') {
return arg;
+ }
for (p = arg; *p != NUL
&& (eval_isnamec(*p)
@@ -17922,30 +17302,44 @@ static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end
if (*p == NUL)
break;
} else if (*p == '"') {
- /* skip over "str\"ing" to avoid counting [ and ] inside it. */
- for (p = p + 1; *p != NUL && *p != '"'; mb_ptr_adv(p))
- if (*p == '\\' && p[1] != NUL)
+ // skip over "str\"ing" to avoid counting [ and ] inside it.
+ for (p = p + 1; *p != NUL && *p != '"'; mb_ptr_adv(p)) {
+ if (*p == '\\' && p[1] != NUL) {
++p;
- if (*p == NUL)
+ }
+ }
+ if (*p == NUL) {
+ break;
+ }
+ } else if (br_nest == 0 && mb_nest == 0 && *p == ':') {
+ // "s:" is start of "s:var", but "n:" is not and can be used in
+ // slice "[n:]". Also "xx:" is not a namespace. But {ns}: is. */
+ len = (int)(p - arg);
+ if ((len > 1 && p[-1] != '}')
+ || (len == 1 && vim_strchr(namespace_char, *arg) == NULL)) {
break;
+ }
}
if (mb_nest == 0) {
- if (*p == '[')
+ if (*p == '[') {
++br_nest;
- else if (*p == ']')
+ } else if (*p == ']') {
--br_nest;
+ }
}
if (br_nest == 0) {
if (*p == '{') {
mb_nest++;
- if (expr_start != NULL && *expr_start == NULL)
+ if (expr_start != NULL && *expr_start == NULL) {
*expr_start = p;
+ }
} else if (*p == '}') {
mb_nest--;
- if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL)
+ if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL) {
*expr_end = p;
+ }
}
}
}
@@ -18027,14 +17421,6 @@ static int eval_isnamec1(int c)
}
/*
- * Set number v: variable to "val".
- */
-void set_vim_var_nr(int idx, long val)
-{
- vimvars[idx].vv_nr = val;
-}
-
-/*
* Get number v: variable value.
*/
long get_vim_var_nr(int idx) FUNC_ATTR_PURE
@@ -18071,11 +17457,11 @@ dict_T *get_vim_var_dict(int idx) FUNC_ATTR_PURE
*/
void set_vim_var_char(int c)
{
- char_u buf[MB_MAXBYTES + 1];
+ char buf[MB_MAXBYTES + 1];
- if (has_mbyte)
- buf[(*mb_char2bytes)(c, buf)] = NUL;
- else {
+ if (has_mbyte) {
+ buf[(*mb_char2bytes)(c, (char_u *) buf)] = NUL;
+ } else {
buf[0] = c;
buf[1] = NUL;
}
@@ -18094,56 +17480,70 @@ void set_vcount(long count, long count1, int set_prevcount)
vimvars[VV_COUNT1].vv_nr = count1;
}
-/*
- * Set string v: variable to a copy of "val".
- */
-void set_vim_var_string (
- int idx,
- char_u *val,
- int len /* length of "val" to use or -1 (whole string) */
-)
+/// Set number v: variable to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_nr(const VimVarIndex idx, const varnumber_T val)
{
- /* Need to do this (at least) once, since we can't initialize a union.
- * Will always be invoked when "v:progname" is set. */
- vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+ vimvars[idx].vv_nr = val;
+}
+
+/// Set special v: variable to the given value
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to.
+void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
+{
+ vimvars[idx].vv_special = val;
+}
+/// Set string v: variable to the given string
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in] val Value to set to. Will be copied.
+/// @param[in] len Legth of that value or -1 in which case strlen() will be
+/// used.
+void set_vim_var_string(const VimVarIndex idx, const char *const val,
+ const ptrdiff_t len)
+{
xfree(vimvars[idx].vv_str);
- if (val == NULL)
+ if (val == NULL) {
vimvars[idx].vv_str = NULL;
- else if (len == -1)
- vimvars[idx].vv_str = vim_strsave(val);
- else
- vimvars[idx].vv_str = vim_strnsave(val, len);
+ } else if (len == -1) {
+ vimvars[idx].vv_str = (char_u *) xstrdup(val);
+ } else {
+ vimvars[idx].vv_str = (char_u *) xstrndup(val, (size_t) len);
+ }
}
-/*
- * Set List v: variable to "val".
- */
-void set_vim_var_list(int idx, list_T *val)
+/// Set list v: variable to the given list
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in,out] val Value to set to. Reference count will be incremented.
+void set_vim_var_list(const VimVarIndex idx, list_T *const val)
{
list_unref(vimvars[idx].vv_list);
vimvars[idx].vv_list = val;
- if (val != NULL)
- ++val->lv_refcount;
+ if (val != NULL) {
+ val->lv_refcount++;
+ }
}
-/// Set Dictionary v: variable to "val".
-void set_vim_var_dict(int idx, dict_T *val)
+/// Set Dictionary v: variable to the given dictionary
+///
+/// @param[in] idx Index of variable to set.
+/// @param[in,out] val Value to set to. Reference count will be incremented.
+/// Also keys of the dictionary will be made read-only.
+void set_vim_var_dict(const VimVarIndex idx, dict_T *const val)
{
dict_unref(vimvars[idx].vv_dict);
vimvars[idx].vv_dict = val;
if (val != NULL) {
- ++val->dv_refcount;
+ val->dv_refcount++;
// Set readonly
- size_t todo = val->dv_hashtab.ht_used;
- for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) {
- if (HASHITEM_EMPTY(hi)) {
- continue;
- }
- --todo;
- HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- }
+ dict_set_keys_readonly(val);
}
}
@@ -18152,15 +17552,17 @@ void set_vim_var_dict(int idx, dict_T *val)
*/
void set_reg_var(int c)
{
- char_u regname;
+ char regname;
- if (c == 0 || c == ' ')
+ if (c == 0 || c == ' ') {
regname = '"';
- else
+ } else {
regname = c;
- /* Avoid free/alloc when the value is already right. */
- if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
+ }
+ // Avoid free/alloc when the value is already right.
+ if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c) {
set_vim_var_string(VV_REG, &regname, 1);
+ }
}
/*
@@ -18390,25 +17792,23 @@ void free_tv(typval_T *varp)
{
if (varp != NULL) {
switch (varp->v_type) {
- case VAR_FUNC:
- func_unref(varp->vval.v_string);
- /*FALLTHROUGH*/
- case VAR_STRING:
- xfree(varp->vval.v_string);
- break;
- case VAR_LIST:
- list_unref(varp->vval.v_list);
- break;
- case VAR_DICT:
- dict_unref(varp->vval.v_dict);
- break;
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_UNKNOWN:
- break;
- default:
- EMSG2(_(e_intern2), "free_tv()");
- break;
+ case VAR_FUNC:
+ func_unref(varp->vval.v_string);
+ // FALLTHROUGH
+ case VAR_STRING:
+ xfree(varp->vval.v_string);
+ break;
+ case VAR_LIST:
+ list_unref(varp->vval.v_list);
+ break;
+ case VAR_DICT:
+ dict_unref(varp->vval.v_dict);
+ break;
+ case VAR_SPECIAL:
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ break;
}
xfree(varp);
}
@@ -18446,10 +17846,11 @@ void clear_tv(typval_T *varp)
case VAR_FLOAT:
varp->vval.v_float = 0.0;
break;
+ case VAR_SPECIAL:
+ varp->vval.v_special = kSpecialVarFalse;
+ break;
case VAR_UNKNOWN:
break;
- default:
- EMSG2(_(e_intern2), "clear_tv()");
}
varp->v_lock = 0;
}
@@ -18504,8 +17905,19 @@ long get_tv_number_chk(typval_T *varp, int *denote)
case VAR_DICT:
EMSG(_("E728: Using a Dictionary as a Number"));
break;
- default:
- EMSG2(_(e_intern2), "get_tv_number()");
+ case VAR_SPECIAL:
+ switch (varp->vval.v_special) {
+ case kSpecialVarTrue: {
+ return 1;
+ }
+ case kSpecialVarFalse:
+ case kSpecialVarNull: {
+ return 0;
+ }
+ }
+ break;
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "get_tv_number(UNKNOWN)");
break;
}
if (denote == NULL) {
@@ -18517,6 +17929,33 @@ long get_tv_number_chk(typval_T *varp, int *denote)
return n;
}
+static float_T get_tv_float(typval_T *varp)
+{
+ switch (varp->v_type) {
+ case VAR_NUMBER:
+ return (float_T)(varp->vval.v_number);
+ case VAR_FLOAT:
+ return varp->vval.v_float;
+ break;
+ case VAR_FUNC:
+ EMSG(_("E891: Using a Funcref as a Float"));
+ break;
+ case VAR_STRING:
+ EMSG(_("E892: Using a String as a Float"));
+ break;
+ case VAR_LIST:
+ EMSG(_("E893: Using a List as a Float"));
+ break;
+ case VAR_DICT:
+ EMSG(_("E894: Using a Dictionary as a Float"));
+ break;
+ default:
+ EMSG2(_(e_intern2), "get_tv_float()");
+ break;
+ }
+ return 0;
+}
+
/*
* Get the lnum from the first argument.
* Also accepts ".", "$", etc., but that only works for the current buffer.
@@ -18610,8 +18049,11 @@ static char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf)
if (varp->vval.v_string != NULL)
return varp->vval.v_string;
return (char_u *)"";
- default:
- EMSG2(_(e_intern2), "get_tv_string_buf()");
+ case VAR_SPECIAL:
+ STRCPY(buf, encode_special_var_names[varp->vval.v_special]);
+ return buf;
+ case VAR_UNKNOWN:
+ EMSG(_("E908: using an invalid value as a String"));
break;
}
return NULL;
@@ -18681,6 +18123,25 @@ static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, in
return HI2DI(hi);
}
+// Get function call environment based on backtrace debug level
+static funccall_T *get_funccal(void)
+{
+ funccall_T *funccal = current_funccal;
+ if (debug_backtrace_level > 0) {
+ for (int i = 0; i < debug_backtrace_level; i++) {
+ funccall_T *temp_funccal = funccal->caller;
+ if (temp_funccal) {
+ funccal = temp_funccal;
+ } else {
+ // backtrace level overflow. reset to max
+ debug_backtrace_level = i;
+ }
+ }
+ }
+
+ return funccal;
+}
+
// Find the dict and hashtable used for a variable name. Set "varname" to the
// start of name without ':'.
static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
@@ -18705,7 +18166,11 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
return &compat_hashtab;
}
- *d = current_funccal ? &current_funccal->l_vars : &globvardict;
+ if (current_funccal == NULL) {
+ *d = &globvardict;
+ } else {
+ *d = &get_funccal()->l_vars; // l: variable
+ }
goto end;
}
@@ -18727,9 +18192,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
} else if (*name == 'v') { // v: variable
*d = &vimvardict;
} else if (*name == 'a' && current_funccal != NULL) { // function argument
- *d = &current_funccal->l_avars;
+ *d = &get_funccal()->l_avars;
} else if (*name == 'l' && current_funccal != NULL) { // local variable
- *d = &current_funccal->l_vars;
+ *d = &get_funccal()->l_vars;
} else if (*name == 's' // script variable
&& current_SID > 0 && current_SID <= ga_scripts.ga_len) {
*d = &SCRIPT_SV(current_SID)->sv_dict;
@@ -18882,7 +18347,7 @@ static void delete_var(hashtab_T *ht, hashitem_T *hi)
*/
static void list_one_var(dictitem_T *v, char_u *prefix, int *first)
{
- char_u *s = (char_u *) echo_string(&v->di_tv, NULL);
+ char_u *s = (char_u *) encode_tv2echo(&v->di_tv, NULL);
list_one_var_a(prefix, v->di_key, v->di_tv.v_type,
s == NULL ? (char_u *)"" : s, first);
xfree(s);
@@ -19159,42 +18624,34 @@ void copy_tv(typval_T *from, typval_T *to)
{
to->v_type = from->v_type;
to->v_lock = 0;
+ memmove(&to->vval, &from->vval, sizeof(to->vval));
switch (from->v_type) {
- case VAR_NUMBER:
- to->vval.v_number = from->vval.v_number;
- break;
- case VAR_FLOAT:
- to->vval.v_float = from->vval.v_float;
- break;
- case VAR_STRING:
- case VAR_FUNC:
- if (from->vval.v_string == NULL)
- to->vval.v_string = NULL;
- else {
- to->vval.v_string = vim_strsave(from->vval.v_string);
- if (from->v_type == VAR_FUNC)
- func_ref(to->vval.v_string);
- }
- break;
- case VAR_LIST:
- if (from->vval.v_list == NULL)
- to->vval.v_list = NULL;
- else {
- to->vval.v_list = from->vval.v_list;
- ++to->vval.v_list->lv_refcount;
- }
- break;
- case VAR_DICT:
- if (from->vval.v_dict == NULL)
- to->vval.v_dict = NULL;
- else {
- to->vval.v_dict = from->vval.v_dict;
- ++to->vval.v_dict->dv_refcount;
- }
- break;
- default:
- EMSG2(_(e_intern2), "copy_tv()");
- break;
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_SPECIAL:
+ break;
+ case VAR_STRING:
+ case VAR_FUNC:
+ if (from->vval.v_string != NULL) {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC) {
+ func_ref(to->vval.v_string);
+ }
+ }
+ break;
+ case VAR_LIST:
+ if (from->vval.v_list != NULL) {
+ to->vval.v_list->lv_refcount++;
+ }
+ break;
+ case VAR_DICT:
+ if (from->vval.v_dict != NULL) {
+ to->vval.v_dict->dv_refcount++;
+ }
+ break;
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "copy_tv(UNKNOWN)");
+ break;
}
}
@@ -19234,6 +18691,7 @@ int var_item_copy(const vimconv_T *const conv,
case VAR_NUMBER:
case VAR_FLOAT:
case VAR_FUNC:
+ case VAR_SPECIAL:
copy_tv(from, to);
break;
case VAR_STRING:
@@ -19280,8 +18738,8 @@ int var_item_copy(const vimconv_T *const conv,
if (to->vval.v_dict == NULL)
ret = FAIL;
break;
- default:
- EMSG2(_(e_intern2), "var_item_copy()");
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "var_item_copy(UNKNOWN)");
ret = FAIL;
}
--recurse;
@@ -19336,7 +18794,7 @@ void ex_echo(exarg_T *eap)
}
} else if (eap->cmdidx == CMD_echo)
msg_puts_attr((char_u *)" ", echo_attr);
- char_u *tofree = p = (char_u *) echo_string(&rettv, NULL);
+ char_u *tofree = p = (char_u *) encode_tv2echo(&rettv, NULL);
if (p != NULL) {
for (; *p != NUL && !got_int; ++p) {
if (*p == '\n' || *p == '\r' || *p == TAB) {
@@ -19871,9 +19329,10 @@ void ex_function(exarg_T *eap)
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
|| (p[0] == 'i'
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
- && (!ASCII_ISALPHA(p[2]) ||
- (p[2] == 's'))))))
+ && (!ASCII_ISALPHA(p[2])
+ || (p[2] == 's')))))) {
skip_until = vim_strsave((char_u *)".");
+ }
// Check for ":python <<EOF", ":lua <<EOF", etc.
arg = skipwhite(skiptowhite(p));
@@ -20140,11 +19599,12 @@ trans_function_name (
*pp = end;
} else {
if (!skip && !(flags & TFN_QUIET) && (fdp == NULL
- || lv.ll_dict == NULL ||
- fdp->fd_newkey == NULL))
+ || lv.ll_dict == NULL
+ || fdp->fd_newkey == NULL)) {
EMSG(_(e_funcref));
- else
+ } else {
*pp = end;
+ }
name = NULL;
}
goto theend;
@@ -20950,15 +20410,22 @@ call_user_func (
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 1;
- // need space for function name + ("function " + 3) or "[number]"
+ // need space for new sourcing_name:
+ // * save_sourcing_name
+ // * "["number"].." or "function "
+ // * "<SNR>" + fp->uf_name - 3
+ // * terminating NUL
size_t len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
- + STRLEN(fp->uf_name) + 20;
+ + STRLEN(fp->uf_name) + 27;
sourcing_name = xmalloc(len);
{
if (save_sourcing_name != NULL
&& STRNCMP(save_sourcing_name, "function ", 9) == 0) {
- vim_snprintf((char *)sourcing_name, len, "%s[%zu]..",
- save_sourcing_name, save_sourcing_lnum);
+ vim_snprintf((char *)sourcing_name,
+ len,
+ "%s[%" PRId64 "]..",
+ save_sourcing_name,
+ (int64_t)save_sourcing_lnum);
} else {
STRCPY(sourcing_name, "function ");
}
@@ -20981,10 +20448,10 @@ call_user_func (
msg_outnum((long)argvars[i].vval.v_number);
} else {
// Do not want errors such as E724 here.
- ++emsg_off;
- char_u *s = (char_u *) tv2string(&argvars[i], NULL);
+ emsg_off++;
+ char_u *s = (char_u *) encode_tv2string(&argvars[i], NULL);
char_u *tofree = s;
- --emsg_off;
+ emsg_off--;
if (s != NULL) {
if (vim_strsize(s) > MSG_BUF_CLEN) {
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
@@ -21037,9 +20504,9 @@ call_user_func (
--RedrawingDisabled;
- /* when the function was aborted because of an error, return -1 */
- if ((did_emsg &&
- (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) {
+ // when the function was aborted because of an error, return -1
+ if ((did_emsg
+ && (fp->uf_flags & FC_ABORT)) || rettv->v_type == VAR_UNKNOWN) {
clear_tv(rettv);
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = -1;
@@ -21075,10 +20542,10 @@ call_user_func (
// The value may be very long. Skip the middle part, so that we
// have some idea how it starts and ends. smsg() would always
// truncate it at the end. Don't want errors such as E724 here.
- ++emsg_off;
- char_u *s = (char_u *) tv2string(fc->rettv, NULL);
+ emsg_off++;
+ char_u *s = (char_u *) encode_tv2string(fc->rettv, NULL);
char_u *tofree = s;
- --emsg_off;
+ emsg_off--;
if (s != NULL) {
if (vim_strsize(s) > MSG_BUF_CLEN) {
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
@@ -21349,7 +20816,7 @@ char_u *get_return_cmd(void *rettv)
char_u *tofree = NULL;
if (rettv != NULL) {
- tofree = s = (char_u *) echo_string((typval_T *) rettv, NULL);
+ tofree = s = (char_u *) encode_tv2echo((typval_T *) rettv, NULL);
}
if (s == NULL) {
s = (char_u *)"";
@@ -21928,7 +21395,15 @@ repeat:
}
if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S') {
+ // vim_strsave_shellescape() needs a NUL terminated string.
+ c = (*fnamep)[*fnamelen];
+ if (c != NUL) {
+ (*fnamep)[*fnamelen] = NUL;
+ }
p = vim_strsave_shellescape(*fnamep, false, false);
+ if (c != NUL) {
+ (*fnamep)[*fnamelen] = c;
+ }
xfree(*bufp);
*bufp = *fnamep = p;
*fnamelen = STRLEN(p);
@@ -22224,7 +21699,7 @@ static void on_process_exit(Process *proc, int status, void *d)
TerminalJobData *data = d;
if (data->term && !data->exited) {
data->exited = true;
- char msg[22];
+ char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status);
terminal_close(data->term, msg);
}
@@ -22249,6 +21724,18 @@ static void term_resize(uint16_t width, uint16_t height, void *d)
pty_process_resize(&data->proc.pty, width, height);
}
+static inline void term_delayed_free(void **argv)
+{
+ TerminalJobData *j = argv[0];
+ if (j->in.pending_reqs || j->out.pending_reqs || j->err.pending_reqs) {
+ queue_put(j->events, term_delayed_free, 1, j);
+ return;
+ }
+
+ terminal_destroy(j->term);
+ term_job_data_decref(j);
+}
+
static void term_close(void *d)
{
TerminalJobData *data = d;
@@ -22256,8 +21743,7 @@ static void term_close(void *d)
data->exited = true;
process_stop((Process *)&data->proc);
}
- terminal_destroy(data->term);
- term_job_data_decref(d);
+ queue_put(data->events, term_delayed_free, 1, data);
}
static void term_job_data_decref(TerminalJobData *data)
@@ -22504,4 +21990,3 @@ static bool is_watched(dict_T *d)
{
return d && !QUEUE_EMPTY(&d->watchers);
}
-
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 79a1341d98..d6800afd52 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -1,12 +1,17 @@
#ifndef NVIM_EVAL_H
#define NVIM_EVAL_H
-#include <msgpack.h>
-
#include "nvim/profile.h"
+#include "nvim/hashtab.h" // For hashtab_T
+#include "nvim/garray.h" // For garray_T
+#include "nvim/buffer_defs.h" // For scid_T
+#include "nvim/ex_cmds_defs.h" // For exarg_T
+
+#define COPYID_INC 2
+#define COPYID_MASK (~0x1)
// All user-defined functions are found in this hashtable.
-EXTERN hashtab_T func_hashtab;
+extern hashtab_T func_hashtab;
// Structure to hold info for a user function.
typedef struct ufunc ufunc_T;
@@ -46,8 +51,8 @@ EXTERN ufunc_T dumuf;
#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf)))
#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
-/* Defines for Vim variables. These must match vimvars[] in eval.c! */
-enum {
+/// Defines for Vim variables
+typedef enum {
VV_COUNT,
VV_COUNT1,
VV_PREVCOUNT,
@@ -113,15 +118,36 @@ enum {
VV_OPTION_TYPE,
VV_ERRORS,
VV_MSGPACK_TYPES,
- VV_LEN, /* number of v: vars */
-};
+ VV_EVENT,
+ VV_FALSE,
+ VV_TRUE,
+ VV_NULL,
+ VV__NULL_LIST, // List with NULL value. For test purposes only.
+ VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
+} VimVarIndex;
+
+/// All recognized msgpack types
+typedef enum {
+ kMPNil,
+ kMPBoolean,
+ kMPInteger,
+ kMPFloat,
+ kMPString,
+ kMPBinary,
+ kMPArray,
+ kMPMap,
+ kMPExt,
+#define LAST_MSGPACK_TYPE kMPExt
+} MessagePackType;
+
+/// Array mapping values from MessagePackType to corresponding list pointers
+extern const list_T *eval_msgpack_type_lists[LAST_MSGPACK_TYPE + 1];
+
+#undef LAST_MSGPACK_TYPE
/// Maximum number of function arguments
#define MAX_FUNC_ARGS 20
-int vim_to_msgpack(msgpack_packer *const, typval_T *const,
- const char *const objname);
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval.h.generated.h"
#endif
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
new file mode 100644
index 0000000000..0774ef515f
--- /dev/null
+++ b/src/nvim/eval/decode.c
@@ -0,0 +1,1116 @@
+#include <stddef.h>
+
+#include <msgpack.h>
+
+#include "nvim/eval_defs.h"
+#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
+#include "nvim/ascii.h"
+#include "nvim/message.h"
+#include "nvim/charset.h" // vim_str2nr
+#include "nvim/lib/kvec.h"
+#include "nvim/vim.h" // OK, FAIL
+
+/// Helper structure for container_struct
+typedef struct {
+ size_t stack_index; ///< Index of current container in stack.
+ list_T *special_val; ///< _VAL key contents for special maps.
+ ///< When container is not a special dictionary it is
+ ///< NULL.
+ const char *s; ///< Location where container starts.
+ typval_T container; ///< Container. Either VAR_LIST, VAR_DICT or VAR_LIST
+ ///< which is _VAL from special dictionary.
+} ContainerStackItem;
+
+/// Helper structure for values struct
+typedef struct {
+ bool is_special_string; ///< Indicates that current value is a special
+ ///< dictionary with string.
+ bool didcomma; ///< True if previous token was comma.
+ bool didcolon; ///< True if previous token was colon.
+ typval_T val; ///< Actual value.
+} ValuesStackItem;
+
+/// Vector containing values not yet saved in any container
+typedef kvec_t(ValuesStackItem) ValuesStack;
+
+/// Vector containing containers, each next container is located inside previous
+typedef kvec_t(ContainerStackItem) ContainerStack;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/decode.c.generated.h"
+#endif
+
+/// Create special dictionary
+///
+/// @param[out] rettv Location where created dictionary will be saved.
+/// @param[in] type Type of the dictionary.
+/// @param[in] val Value associated with the _VAL key.
+static inline void create_special_dict(typval_T *const rettv,
+ const MessagePackType type,
+ typval_T val)
+ FUNC_ATTR_NONNULL_ALL
+{
+ dict_T *const dict = dict_alloc();
+ dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE");
+ type_di->di_tv.v_type = VAR_LIST;
+ type_di->di_tv.v_lock = VAR_UNLOCKED;
+ type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type];
+ type_di->di_tv.vval.v_list->lv_refcount++;
+ dict_add(dict, type_di);
+ dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL");
+ val_di->di_tv = val;
+ dict_add(dict, val_di);
+ dict->dv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_dict = dict },
+ };
+}
+
+#define DICT_LEN(dict) (dict)->dv_hashtab.ht_used
+
+/// Helper function used for working with stack vectors used by JSON decoder
+///
+/// @param[in,out] obj New object. Will either be put into the stack (and,
+/// probably, also inside container) or freed.
+/// @param[out] stack Object stack.
+/// @param[out] container_stack Container objects stack.
+/// @param[in,out] pp Position in string which is currently being parsed. Used
+/// for error reporting and is also set when decoding is
+/// restarted due to the necessity of converting regular
+/// dictionary to a special map.
+/// @param[out] next_map_special Is set to true when dictionary needs to be
+/// converted to a special map, otherwise not
+/// touched. Indicates that decoding has been
+/// restarted.
+/// @param[out] didcomma True if previous token was comma. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+/// @param[out] didcolon True if previous token was colon. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+///
+/// @return OK in case of success, FAIL in case of error.
+static inline int json_decoder_pop(ValuesStackItem obj,
+ ValuesStack *const stack,
+ ContainerStack *const container_stack,
+ const char **const pp,
+ bool *const next_map_special,
+ bool *const didcomma,
+ bool *const didcolon)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (kv_size(*container_stack) == 0) {
+ kv_push(ValuesStackItem, *stack, obj);
+ return OK;
+ }
+ ContainerStackItem last_container = kv_last(*container_stack);
+ const char *val_location = *pp;
+ if (obj.val.v_type == last_container.container.v_type
+ // vval.v_list and vval.v_dict should have the same size and offset
+ && ((void *) obj.val.vval.v_list
+ == (void *) last_container.container.vval.v_list)) {
+ (void) kv_pop(*container_stack);
+ val_location = last_container.s;
+ last_container = kv_last(*container_stack);
+ }
+ if (last_container.container.v_type == VAR_LIST) {
+ if (last_container.container.vval.v_list->lv_len != 0
+ && !obj.didcomma) {
+ EMSG2(_("E474: Expected comma before list item: %s"), val_location);
+ clear_tv(&obj.val);
+ return FAIL;
+ }
+ assert(last_container.special_val == NULL);
+ listitem_T *obj_li = listitem_alloc();
+ obj_li->li_tv = obj.val;
+ list_append(last_container.container.vval.v_list, obj_li);
+ } else if (last_container.stack_index == kv_size(*stack) - 2) {
+ if (!obj.didcolon) {
+ EMSG2(_("E474: Expected colon before dictionary value: %s"),
+ val_location);
+ clear_tv(&obj.val);
+ return FAIL;
+ }
+ ValuesStackItem key = kv_pop(*stack);
+ if (last_container.special_val == NULL) {
+ // These cases should have already been handled.
+ assert(!(key.is_special_string
+ || key.val.vval.v_string == NULL
+ || *key.val.vval.v_string == NUL));
+ dictitem_T *obj_di = dictitem_alloc(key.val.vval.v_string);
+ clear_tv(&key.val);
+ if (dict_add(last_container.container.vval.v_dict, obj_di)
+ == FAIL) {
+ assert(false);
+ }
+ obj_di->di_tv = obj.val;
+ } else {
+ list_T *const kv_pair = list_alloc();
+ list_append_list(last_container.special_val, kv_pair);
+ listitem_T *const key_li = listitem_alloc();
+ key_li->li_tv = key.val;
+ list_append(kv_pair, key_li);
+ listitem_T *const val_li = listitem_alloc();
+ val_li->li_tv = obj.val;
+ list_append(kv_pair, val_li);
+ }
+ } else {
+ // Object with key only
+ if (!obj.is_special_string && obj.val.v_type != VAR_STRING) {
+ EMSG2(_("E474: Expected string key: %s"), *pp);
+ clear_tv(&obj.val);
+ return FAIL;
+ } else if (!obj.didcomma
+ && (last_container.special_val == NULL
+ && (DICT_LEN(last_container.container.vval.v_dict) != 0))) {
+ EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location);
+ clear_tv(&obj.val);
+ return FAIL;
+ }
+ // Handle empty key and key represented as special dictionary
+ if (last_container.special_val == NULL
+ && (obj.is_special_string
+ || obj.val.vval.v_string == NULL
+ || *obj.val.vval.v_string == NUL
+ || dict_find(last_container.container.vval.v_dict,
+ obj.val.vval.v_string, -1))) {
+ clear_tv(&obj.val);
+
+ // Restart
+ (void) kv_pop(*container_stack);
+ ValuesStackItem last_container_val =
+ kv_A(*stack, last_container.stack_index);
+ while (kv_size(*stack) > last_container.stack_index) {
+ clear_tv(&(kv_pop(*stack).val));
+ }
+ *pp = last_container.s;
+ *didcomma = last_container_val.didcomma;
+ *didcolon = last_container_val.didcolon;
+ *next_map_special = true;
+ return OK;
+ }
+ kv_push(ValuesStackItem, *stack, obj);
+ }
+ return OK;
+}
+
+#define LENP(p, e) \
+ ((int) ((e) - (p))), (p)
+#define OBJ(obj_tv, is_sp_string, didcomma_, didcolon_) \
+ ((ValuesStackItem) { \
+ .is_special_string = (is_sp_string), \
+ .val = (obj_tv), \
+ .didcomma = (didcomma_), \
+ .didcolon = (didcolon_), \
+ })
+
+#define POP(obj_tv, is_sp_string) \
+ do { \
+ if (json_decoder_pop(OBJ(obj_tv, is_sp_string, *didcomma, *didcolon), \
+ stack, container_stack, \
+ &p, next_map_special, didcomma, didcolon) \
+ == FAIL) { \
+ goto parse_json_string_fail; \
+ } \
+ if (*next_map_special) { \
+ goto parse_json_string_ret; \
+ } \
+ } while (0)
+
+/// Parse JSON double-quoted string
+///
+/// @param[in] conv Defines conversion necessary to convert UTF-8 string to
+/// &encoding.
+/// @param[in] buf Buffer being converted.
+/// @param[in] buf_len Length of the buffer.
+/// @param[in,out] pp Pointer to the start of the string. Must point to '"'.
+/// Is advanced to the closing '"'. Also see
+/// json_decoder_pop(), it may set pp to another location
+/// and alter next_map_special, didcomma and didcolon.
+/// @param[out] stack Object stack.
+/// @param[out] container_stack Container objects stack.
+/// @param[out] next_map_special Is set to true when dictionary is converted
+/// to a special map, otherwise not touched.
+/// @param[out] didcomma True if previous token was comma. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+/// @param[out] didcolon True if previous token was colon. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+///
+/// @return OK in case of success, FAIL in case of error.
+static inline int parse_json_string(vimconv_T *const conv,
+ const char *const buf, const size_t buf_len,
+ const char **const pp,
+ ValuesStack *const stack,
+ ContainerStack *const container_stack,
+ bool *const next_map_special,
+ bool *const didcomma,
+ bool *const didcolon)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+{
+ const char *const e = buf + buf_len;
+ const char *p = *pp;
+ size_t len = 0;
+ const char *const s = ++p;
+ int ret = OK;
+ while (p < e && *p != '"') {
+ if (*p == '\\') {
+ p++;
+ if (p == e) {
+ emsgf(_("E474: Unfinished escape sequence: %.*s"),
+ (int) buf_len, buf);
+ goto parse_json_string_fail;
+ }
+ switch (*p) {
+ case 'u': {
+ if (p + 4 >= e) {
+ emsgf(_("E474: Unfinished unicode escape sequence: %.*s"),
+ (int) buf_len, buf);
+ goto parse_json_string_fail;
+ } else if (!ascii_isxdigit(p[1])
+ || !ascii_isxdigit(p[2])
+ || !ascii_isxdigit(p[3])
+ || !ascii_isxdigit(p[4])) {
+ emsgf(_("E474: Expected four hex digits after \\u: %.*s"),
+ LENP(p - 1, e));
+ goto parse_json_string_fail;
+ }
+ // One UTF-8 character below U+10000 can take up to 3 bytes,
+ // above up to 6, but they are encoded using two \u escapes.
+ len += 3;
+ p += 5;
+ break;
+ }
+ case '\\':
+ case '/':
+ case '"':
+ case 't':
+ case 'b':
+ case 'n':
+ case 'r':
+ case 'f': {
+ len++;
+ p++;
+ break;
+ }
+ default: {
+ emsgf(_("E474: Unknown escape sequence: %.*s"), LENP(p - 1, e));
+ goto parse_json_string_fail;
+ }
+ }
+ } else {
+ uint8_t p_byte = (uint8_t) *p;
+ // unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ if (p_byte < 0x20) {
+ emsgf(_("E474: ASCII control characters cannot be present "
+ "inside string: %.*s"), LENP(p, e));
+ goto parse_json_string_fail;
+ }
+ const int ch = utf_ptr2char((char_u *) p);
+ // All characters above U+007F are encoded using two or more bytes
+ // and thus cannot possibly be equal to *p. But utf_ptr2char({0xFF,
+ // 0}) will return 0xFF, even though 0xFF cannot start any UTF-8
+ // code point at all.
+ //
+ // The only exception is U+00C3 which is represented as 0xC3 0x83.
+ if (ch >= 0x80 && p_byte == ch
+ && !(ch == 0xC3 && p + 1 < e && (uint8_t) p[1] == 0x83)) {
+ emsgf(_("E474: Only UTF-8 strings allowed: %.*s"), LENP(p, e));
+ goto parse_json_string_fail;
+ } else if (ch > 0x10FFFF) {
+ emsgf(_("E474: Only UTF-8 code points up to U+10FFFF "
+ "are allowed to appear unescaped: %.*s"), LENP(p, e));
+ goto parse_json_string_fail;
+ }
+ const size_t ch_len = (size_t) utf_char2len(ch);
+ assert(ch_len == (size_t) (ch ? utf_ptr2len((char_u *) p) : 1));
+ len += ch_len;
+ p += ch_len;
+ }
+ }
+ if (p == e || *p != '"') {
+ emsgf(_("E474: Expected string end: %.*s"), (int) buf_len, buf);
+ goto parse_json_string_fail;
+ }
+ if (len == 0) {
+ POP(((typval_T) {
+ .v_type = VAR_STRING,
+ .vval = { .v_string = NULL },
+ }), false);
+ goto parse_json_string_ret;
+ }
+ char *str = xmalloc(len + 1);
+ int fst_in_pair = 0;
+ char *str_end = str;
+ bool hasnul = false;
+#define PUT_FST_IN_PAIR(fst_in_pair, str_end) \
+ do { \
+ if (fst_in_pair != 0) { \
+ str_end += utf_char2bytes(fst_in_pair, (char_u *) str_end); \
+ fst_in_pair = 0; \
+ } \
+ } while (0)
+ for (const char *t = s; t < p; t++) {
+ if (t[0] != '\\' || t[1] != 'u') {
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+ }
+ if (*t == '\\') {
+ t++;
+ switch (*t) {
+ case 'u': {
+ const char ubuf[] = { t[1], t[2], t[3], t[4] };
+ t += 4;
+ unsigned long ch;
+ vim_str2nr((char_u *) ubuf, NULL, NULL,
+ STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4);
+ if (ch == 0) {
+ hasnul = true;
+ }
+ if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+ fst_in_pair = (int) ch;
+ } else if (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END
+ && fst_in_pair != 0) {
+ const int full_char = (
+ (int) (ch - SURROGATE_LO_START)
+ + ((fst_in_pair - SURROGATE_HI_START) << 10)
+ + SURROGATE_FIRST_CHAR);
+ str_end += utf_char2bytes(full_char, (char_u *) str_end);
+ fst_in_pair = 0;
+ } else {
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+ str_end += utf_char2bytes((int) ch, (char_u *) str_end);
+ }
+ break;
+ }
+ case '\\':
+ case '/':
+ case '"':
+ case 't':
+ case 'b':
+ case 'n':
+ case 'r':
+ case 'f': {
+ static const char escapes[] = {
+ ['\\'] = '\\',
+ ['/'] = '/',
+ ['"'] = '"',
+ ['t'] = TAB,
+ ['b'] = BS,
+ ['n'] = NL,
+ ['r'] = CAR,
+ ['f'] = FF,
+ };
+ *str_end++ = escapes[(int) *t];
+ break;
+ }
+ default: {
+ assert(false);
+ }
+ }
+ } else {
+ *str_end++ = *t;
+ }
+ }
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+#undef PUT_FST_IN_PAIR
+ if (conv->vc_type != CONV_NONE) {
+ size_t str_len = (size_t) (str_end - str);
+ char *const new_str = (char *) string_convert(conv, (char_u *) str,
+ &str_len);
+ if (new_str == NULL) {
+ emsgf(_("E474: Failed to convert string \"%.*s\" from UTF-8"),
+ (int) str_len, str);
+ xfree(str);
+ goto parse_json_string_fail;
+ }
+ xfree(str);
+ str = new_str;
+ str_end = new_str + str_len;
+ }
+ if (hasnul) {
+ typval_T obj;
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(&obj, kMPString, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ if (encode_list_write((void *) list, str, (size_t) (str_end - str))
+ == -1) {
+ clear_tv(&obj);
+ goto parse_json_string_fail;
+ }
+ xfree(str);
+ POP(obj, true);
+ } else {
+ *str_end = NUL;
+ POP(((typval_T) {
+ .v_type = VAR_STRING,
+ .vval = { .v_string = (char_u *) str },
+ }), false);
+ }
+ goto parse_json_string_ret;
+parse_json_string_fail:
+ ret = FAIL;
+parse_json_string_ret:
+ *pp = p;
+ return ret;
+}
+
+#undef POP
+
+/// Parse JSON number: both floating-point and integer
+///
+/// Number format: `-?\d+(?:.\d+)?(?:[eE][+-]?\d+)?`.
+///
+/// @param[in] buf Buffer being converted.
+/// @param[in] buf_len Length of the buffer.
+/// @param[in,out] pp Pointer to the start of the number. Must point to
+/// a digit or a minus sign. Is advanced to the last
+/// character of the number. Also see json_decoder_pop(), it
+/// may set pp to another location and alter
+/// next_map_special, didcomma and didcolon.
+/// @param[out] stack Object stack.
+/// @param[out] container_stack Container objects stack.
+/// @param[out] next_map_special Is set to true when dictionary is converted
+/// to a special map, otherwise not touched.
+/// @param[out] didcomma True if previous token was comma. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+/// @param[out] didcolon True if previous token was colon. Is set to recorded
+/// value when decoder is restarted, otherwise unused.
+///
+/// @return OK in case of success, FAIL in case of error.
+static inline int parse_json_number(const char *const buf, const size_t buf_len,
+ const char **const pp,
+ ValuesStack *const stack,
+ ContainerStack *const container_stack,
+ bool *const next_map_special,
+ bool *const didcomma,
+ bool *const didcolon)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
+{
+ const char *const e = buf + buf_len;
+ const char *p = *pp;
+ int ret = OK;
+ const char *const s = p;
+ const char *ints = NULL;
+ const char *fracs = NULL;
+ const char *exps = NULL;
+ const char *exps_s = NULL;
+ if (*p == '-') {
+ p++;
+ }
+ ints = p;
+ if (p >= e) {
+ goto parse_json_number_check;
+ }
+ while (p < e && ascii_isdigit(*p)) {
+ p++;
+ }
+ if (p != ints + 1 && *ints == '0') {
+ emsgf(_("E474: Leading zeroes are not allowed: %.*s"), LENP(s, e));
+ goto parse_json_number_fail;
+ }
+ if (p >= e || p == ints) {
+ goto parse_json_number_check;
+ }
+ if (*p == '.') {
+ p++;
+ fracs = p;
+ while (p < e && ascii_isdigit(*p)) {
+ p++;
+ }
+ if (p >= e || p == fracs) {
+ goto parse_json_number_check;
+ }
+ }
+ if (*p == 'e' || *p == 'E') {
+ p++;
+ exps_s = p;
+ if (p < e && (*p == '-' || *p == '+')) {
+ p++;
+ }
+ exps = p;
+ while (p < e && ascii_isdigit(*p)) {
+ p++;
+ }
+ }
+parse_json_number_check:
+ if (p == ints) {
+ emsgf(_("E474: Missing number after minus sign: %.*s"), LENP(s, e));
+ goto parse_json_number_fail;
+ } else if (p == fracs || exps_s == fracs + 1) {
+ emsgf(_("E474: Missing number after decimal dot: %.*s"), LENP(s, e));
+ goto parse_json_number_fail;
+ } else if (p == exps) {
+ emsgf(_("E474: Missing exponent: %.*s"), LENP(s, e));
+ goto parse_json_number_fail;
+ }
+ typval_T tv = {
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ };
+ const size_t exp_num_len = (size_t) (p - s);
+ if (fracs || exps) {
+ // Convert floating-point number
+ const size_t num_len = string2float(s, &tv.vval.v_float);
+ if (exp_num_len != num_len) {
+ emsgf(_("E685: internal error: while converting number \"%.*s\" "
+ "to float string2float consumed %zu bytes in place of %zu"),
+ (int) exp_num_len, s, num_len, exp_num_len);
+ }
+ tv.v_type = VAR_FLOAT;
+ } else {
+ // Convert integer
+ long nr;
+ int num_len;
+ vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s));
+ if ((int) exp_num_len != num_len) {
+ emsgf(_("E685: internal error: while converting number \"%.*s\" "
+ "to integer vim_str2nr consumed %i bytes in place of %zu"),
+ (int) exp_num_len, s, num_len, exp_num_len);
+ }
+ tv.vval.v_number = (varnumber_T) nr;
+ }
+ if (json_decoder_pop(OBJ(tv, false, *didcomma, *didcolon),
+ stack, container_stack,
+ &p, next_map_special, didcomma, didcolon) == FAIL) {
+ goto parse_json_number_fail;
+ }
+ if (*next_map_special) {
+ goto parse_json_number_ret;
+ }
+ p--;
+ goto parse_json_number_ret;
+parse_json_number_fail:
+ ret = FAIL;
+parse_json_number_ret:
+ *pp = p;
+ return ret;
+}
+
+#define POP(obj_tv, is_sp_string) \
+ do { \
+ if (json_decoder_pop(OBJ(obj_tv, is_sp_string, didcomma, didcolon), \
+ &stack, &container_stack, \
+ &p, &next_map_special, &didcomma, &didcolon) \
+ == FAIL) { \
+ goto json_decode_string_fail; \
+ } \
+ if (next_map_special) { \
+ goto json_decode_string_cycle_start; \
+ } \
+ } while (0)
+
+/// Convert JSON string into VimL object
+///
+/// @param[in] buf String to convert. UTF-8 encoding is assumed.
+/// @param[in] buf_len Length of the string.
+/// @param[out] rettv Location where to save results.
+///
+/// @return OK in case of success, FAIL otherwise.
+int json_decode_string(const char *const buf, const size_t buf_len,
+ typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const char *p = buf;
+ const char *const e = buf + buf_len;
+ while (p < e && (*p == ' ' || *p == TAB || *p == NL || *p == CAR)) {
+ p++;
+ }
+ if (p == e) {
+ EMSG(_("E474: Attempt to decode a blank string"));
+ return FAIL;
+ }
+ vimconv_T conv = { .vc_type = CONV_NONE };
+ convert_setup(&conv, (char_u *) "utf-8", p_enc);
+ conv.vc_fail = true;
+ int ret = OK;
+ ValuesStack stack;
+ kv_init(stack);
+ ContainerStack container_stack;
+ kv_init(container_stack);
+ rettv->v_type = VAR_UNKNOWN;
+ bool didcomma = false;
+ bool didcolon = false;
+ bool next_map_special = false;
+ for (; p < e; p++) {
+json_decode_string_cycle_start:
+ assert(*p == '{' || next_map_special == false);
+ switch (*p) {
+ case '}':
+ case ']': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: No container to close: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (*p == '}' && last_container.container.v_type != VAR_DICT) {
+ emsgf(_("E474: Closing list with curly bracket: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (*p == ']' && last_container.container.v_type != VAR_LIST) {
+ emsgf(_("E474: Closing dictionary with square bracket: %.*s"),
+ LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcomma) {
+ emsgf(_("E474: Trailing comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Expected value after colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.stack_index != kv_size(stack) - 1) {
+ assert(last_container.stack_index < kv_size(stack) - 1);
+ emsgf(_("E474: Expected value: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ if (kv_size(stack) == 1) {
+ p++;
+ (void) kv_pop(container_stack);
+ goto json_decode_string_after_cycle;
+ } else {
+ if (json_decoder_pop(kv_pop(stack), &stack, &container_stack, &p,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
+ goto json_decode_string_fail;
+ }
+ assert(!next_map_special);
+ break;
+ }
+ }
+ case ',': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: Comma not inside container: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (didcomma) {
+ emsgf(_("E474: Duplicate comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Comma after colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.container.v_type == VAR_DICT
+ && last_container.stack_index != kv_size(stack) - 1) {
+ emsgf(_("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)
+ : (last_container.container.vval.v_list->lv_len == 0))
+ : (last_container.special_val->lv_len == 0)) {
+ emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ didcomma = true;
+ continue;
+ }
+ case ':': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: Colon not inside container: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (last_container.container.v_type != VAR_DICT) {
+ emsgf(_("E474: Using colon not in dictionary: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.stack_index != kv_size(stack) - 2) {
+ emsgf(_("E474: Unexpected colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcomma) {
+ emsgf(_("E474: Colon after comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Duplicate colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ didcolon = true;
+ continue;
+ }
+ case ' ':
+ case TAB:
+ case NL:
+ case CAR: {
+ continue;
+ }
+ case 'n': {
+ if ((p + 3) >= e || strncmp(p + 1, "ull", 3) != 0) {
+ emsgf(_("E474: Expected null: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ p += 3;
+ POP(((typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarNull },
+ }), false);
+ break;
+ }
+ case 't': {
+ if ((p + 3) >= e || strncmp(p + 1, "rue", 3) != 0) {
+ emsgf(_("E474: Expected true: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ p += 3;
+ POP(((typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarTrue },
+ }), false);
+ break;
+ }
+ case 'f': {
+ if ((p + 4) >= e || strncmp(p + 1, "alse", 4) != 0) {
+ emsgf(_("E474: Expected false: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ p += 4;
+ POP(((typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarFalse },
+ }), false);
+ break;
+ }
+ case '"': {
+ if (parse_json_string(&conv, buf, buf_len, &p, &stack, &container_stack,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
+ // Error message was already given
+ goto json_decode_string_fail;
+ }
+ if (next_map_special) {
+ goto json_decode_string_cycle_start;
+ }
+ break;
+ }
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ if (parse_json_number(buf, buf_len, &p, &stack, &container_stack,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
+ // Error message was already given
+ goto json_decode_string_fail;
+ }
+ if (next_map_special) {
+ goto json_decode_string_cycle_start;
+ }
+ break;
+ }
+ case '[': {
+ list_T *list = list_alloc();
+ list->lv_refcount++;
+ typval_T tv = {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ };
+ kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) {
+ .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = NULL,
+ }));
+ kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon));
+ break;
+ }
+ case '{': {
+ typval_T tv;
+ list_T *val_list = NULL;
+ if (next_map_special) {
+ next_map_special = false;
+ val_list = list_alloc();
+ val_list->lv_refcount++;
+ create_special_dict(&tv, kMPMap, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = val_list },
+ }));
+ } else {
+ dict_T *dict = dict_alloc();
+ dict->dv_refcount++;
+ tv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_dict = dict },
+ };
+ }
+ kv_push(ContainerStackItem, container_stack, ((ContainerStackItem) {
+ .stack_index = kv_size(stack),
+ .s = p,
+ .container = tv,
+ .special_val = val_list,
+ }));
+ kv_push(ValuesStackItem, stack, OBJ(tv, false, didcomma, didcolon));
+ break;
+ }
+ default: {
+ emsgf(_("E474: Unidentified byte: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ }
+ didcomma = false;
+ didcolon = false;
+ if (kv_size(container_stack) == 0) {
+ p++;
+ break;
+ }
+ }
+json_decode_string_after_cycle:
+ for (; p < e; p++) {
+ switch (*p) {
+ case NL:
+ case ' ':
+ case TAB:
+ case CAR: {
+ break;
+ }
+ default: {
+ emsgf(_("E474: Trailing characters: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ }
+ }
+ if (kv_size(stack) == 1 && kv_size(container_stack) == 0) {
+ *rettv = kv_pop(stack).val;
+ goto json_decode_string_ret;
+ }
+ emsgf(_("E474: Unexpected end of input: %.*s"), (int) buf_len, buf);
+json_decode_string_fail:
+ ret = FAIL;
+ while (kv_size(stack)) {
+ clear_tv(&(kv_pop(stack).val));
+ }
+json_decode_string_ret:
+ kv_destroy(stack);
+ kv_destroy(container_stack);
+ return ret;
+}
+
+#undef LENP
+#undef POP
+
+#undef OBJ
+
+#undef DICT_LEN
+
+/// Convert msgpack object to a VimL one
+int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ switch (mobj.type) {
+ case MSGPACK_OBJECT_NIL: {
+ *rettv = (typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarNull },
+ };
+ break;
+ }
+ case MSGPACK_OBJECT_BOOLEAN: {
+ *rettv = (typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = {
+ .v_special = mobj.via.boolean ? kSpecialVarTrue : kSpecialVarFalse
+ },
+ };
+ break;
+ }
+ case MSGPACK_OBJECT_POSITIVE_INTEGER: {
+ if (mobj.via.u64 <= VARNUMBER_MAX) {
+ *rettv = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_number = (varnumber_T) mobj.via.u64 },
+ };
+ } else {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(rettv, kMPInteger, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = mobj.via.u64;
+ list_append_number(list, 1);
+ list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
+ list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
+ list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
+ if (mobj.via.i64 >= VARNUMBER_MIN) {
+ *rettv = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_number = (varnumber_T) mobj.via.i64 },
+ };
+ } else {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(rettv, kMPInteger, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = -((uint64_t) mobj.via.i64);
+ list_append_number(list, -1);
+ list_append_number(list, (varnumber_T) ((n >> 62) & 0x3));
+ list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF));
+ list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF));
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_FLOAT: {
+ *rettv = (typval_T) {
+ .v_type = VAR_FLOAT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_float = mobj.via.f64 },
+ };
+ break;
+ }
+ case MSGPACK_OBJECT_STR: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(rettv, kMPString, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ if (encode_list_write((void *) list, mobj.via.str.ptr, mobj.via.str.size)
+ == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_BIN: {
+ if (memchr(mobj.via.bin.ptr, NUL, mobj.via.bin.size) == NULL) {
+ *rettv = (typval_T) {
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_string = xmemdupz(mobj.via.bin.ptr, mobj.via.bin.size) },
+ };
+ break;
+ }
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(rettv, kMPBinary, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ if (encode_list_write((void *) list, mobj.via.bin.ptr, mobj.via.bin.size)
+ == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_ARRAY: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ };
+ for (size_t i = 0; i < mobj.via.array.size; i++) {
+ listitem_T *const li = listitem_alloc();
+ li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(list, li);
+ if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_MAP: {
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
+ || mobj.via.map.ptr[i].key.via.str.size == 0
+ || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
+ mobj.via.map.ptr[i].key.via.str.size) != NULL) {
+ goto msgpack_to_vim_generic_map;
+ }
+ }
+ dict_T *const dict = dict_alloc();
+ dict->dv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_dict = dict },
+ };
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
+ + mobj.via.map.ptr[i].key.via.str.size);
+ memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
+ mobj.via.map.ptr[i].key.via.str.size);
+ di->di_tv.v_type = VAR_UNKNOWN;
+ if (dict_add(dict, di) == FAIL) {
+ // Duplicate key: fallback to generic map
+ clear_tv(rettv);
+ xfree(di);
+ goto msgpack_to_vim_generic_map;
+ }
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+msgpack_to_vim_generic_map: {}
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ create_special_dict(rettv, kMPMap, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ list_T *const kv_pair = list_alloc();
+ list_append_list(list, kv_pair);
+ listitem_T *const key_li = listitem_alloc();
+ key_li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(kv_pair, key_li);
+ listitem_T *const val_li = listitem_alloc();
+ val_li->li_tv.v_type = VAR_UNKNOWN;
+ list_append(kv_pair, val_li);
+ if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_li->li_tv) == FAIL) {
+ return FAIL;
+ }
+ }
+ break;
+ }
+ case MSGPACK_OBJECT_EXT: {
+ list_T *const list = list_alloc();
+ list->lv_refcount++;
+ list_append_number(list, mobj.via.ext.type);
+ list_T *const ext_val_list = list_alloc();
+ list_append_list(list, ext_val_list);
+ create_special_dict(rettv, kMPExt, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ if (encode_list_write((void *) ext_val_list, mobj.via.ext.ptr,
+ mobj.via.ext.size) == -1) {
+ return FAIL;
+ }
+ break;
+ }
+ }
+ return OK;
+}
diff --git a/src/nvim/eval/decode.h b/src/nvim/eval/decode.h
new file mode 100644
index 0000000000..5c25a64f7a
--- /dev/null
+++ b/src/nvim/eval/decode.h
@@ -0,0 +1,13 @@
+#ifndef NVIM_EVAL_DECODE_H
+#define NVIM_EVAL_DECODE_H
+
+#include <stddef.h>
+
+#include <msgpack.h>
+
+#include "nvim/eval_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/decode.h.generated.h"
+#endif
+#endif // NVIM_EVAL_DECODE_H
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
new file mode 100644
index 0000000000..c651a50be9
--- /dev/null
+++ b/src/nvim/eval/encode.c
@@ -0,0 +1,1296 @@
+/// @file encode.c
+///
+/// File containing functions for encoding and decoding VimL values.
+///
+/// Split out from eval.c.
+
+#include <msgpack.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <math.h>
+
+#include "nvim/eval/encode.h"
+#include "nvim/buffer_defs.h" // vimconv_T
+#include "nvim/eval.h"
+#include "nvim/eval_defs.h"
+#include "nvim/garray.h"
+#include "nvim/mbyte.h"
+#include "nvim/message.h"
+#include "nvim/memory.h"
+#include "nvim/charset.h" // vim_isprintc()
+#include "nvim/macros.h"
+#include "nvim/ascii.h"
+#include "nvim/vim.h" // For _()
+#include "nvim/lib/kvec.h"
+
+#define ga_concat(a, b) ga_concat(a, (char_u *)b)
+#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))
+#define string_convert(a, b, c) \
+ ((char *)string_convert((vimconv_T *)a, (char_u *)b, c))
+#define convert_setup(vcp, from, to) \
+ (convert_setup(vcp, (char_u *)from, (char_u *)to))
+
+/// Structure representing current VimL to messagepack conversion state
+typedef struct {
+ enum {
+ kMPConvDict, ///< Convert dict_T *dictionary.
+ kMPConvList, ///< Convert list_T *list.
+ kMPConvPairs, ///< Convert mapping represented as a list_T* of pairs.
+ } type;
+ union {
+ struct {
+ dict_T *dict; ///< Currently converted dictionary.
+ hashitem_T *hi; ///< Currently converted dictionary item.
+ size_t todo; ///< Amount of items left to process.
+ } d; ///< State of dictionary conversion.
+ struct {
+ list_T *list; ///< Currently converted list.
+ listitem_T *li; ///< Currently converted list item.
+ } l; ///< State of list or generic mapping conversion.
+ } data; ///< Data to convert.
+} MPConvStackVal;
+
+/// Stack used to convert VimL values to messagepack.
+typedef kvec_t(MPConvStackVal) MPConvStack;
+
+const char *const encode_special_var_names[] = {
+ [kSpecialVarNull] = "null",
+ [kSpecialVarTrue] = "true",
+ [kSpecialVarFalse] = "false",
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/encode.c.generated.h"
+#endif
+
+/// Msgpack callback for writing to readfile()-style list
+int encode_list_write(void *data, const char *buf, size_t len)
+{
+ if (len == 0) {
+ return 0;
+ }
+ list_T *const list = (list_T *) data;
+ const char *const end = buf + len;
+ const char *line_end = buf;
+ listitem_T *li = list->lv_last;
+
+ // Continue the last list element
+ if (li != NULL) {
+ line_end = xmemscan(buf, NL, len);
+ if (line_end != buf) {
+ const size_t line_length = (size_t)(line_end - buf);
+ char *str = (char *)li->li_tv.vval.v_string;
+ const size_t li_len = (str == NULL ? 0 : strlen(str));
+ li->li_tv.vval.v_string = xrealloc(str, li_len + line_length + 1);
+ str = (char *)li->li_tv.vval.v_string + li_len;
+ memcpy(str, buf, line_length);
+ str[line_length] = 0;
+ memchrsub(str, NUL, NL, line_length);
+ }
+ line_end++;
+ }
+
+ while (line_end < end) {
+ const char *line_start = line_end;
+ line_end = xmemscan(line_start, NL, (size_t) (end - line_start));
+ char *str = NULL;
+ if (line_end != line_start) {
+ const size_t line_length = (size_t)(line_end - line_start);
+ str = xmemdupz(line_start, line_length);
+ memchrsub(str, NUL, NL, line_length);
+ }
+ list_append_allocated_string(list, str);
+ line_end++;
+ }
+ if (line_end == end) {
+ list_append_allocated_string(list, NULL);
+ }
+ return 0;
+}
+
+/// Abort conversion to string after a recursion error.
+static bool did_echo_string_emsg = false;
+
+/// Show a error message when converting to msgpack value
+///
+/// @param[in] msg Error message to dump. Must contain exactly two %s that
+/// will be replaced with what was being dumped: first with
+/// something like “F†or “function argumentâ€, second with path
+/// to the failed value.
+/// @param[in] mpstack Path to the failed value.
+/// @param[in] objname Dumped object name.
+///
+/// @return FAIL.
+static int conv_error(const char *const msg, const MPConvStack *const mpstack,
+ const char *const objname)
+ FUNC_ATTR_NONNULL_ALL
+{
+ garray_T msg_ga;
+ ga_init(&msg_ga, (int)sizeof(char), 80);
+ char *const key_msg = _("key %s");
+ char *const key_pair_msg = _("key %s at index %i from special map");
+ char *const idx_msg = _("index %i");
+ for (size_t i = 0; i < kv_size(*mpstack); i++) {
+ if (i != 0) {
+ ga_concat(&msg_ga, ", ");
+ }
+ MPConvStackVal v = kv_A(*mpstack, i);
+ switch (v.type) {
+ case kMPConvDict: {
+ typval_T key_tv = {
+ .v_type = VAR_STRING,
+ .vval = { .v_string = (v.data.d.hi == NULL
+ ? v.data.d.dict->dv_hashtab.ht_array
+ : (v.data.d.hi - 1))->hi_key },
+ };
+ char *const key = encode_tv2string(&key_tv, NULL);
+ vim_snprintf((char *) IObuff, IOSIZE, key_msg, key);
+ xfree(key);
+ ga_concat(&msg_ga, IObuff);
+ break;
+ }
+ case kMPConvPairs:
+ case kMPConvList: {
+ int idx = 0;
+ const listitem_T *li;
+ for (li = v.data.l.list->lv_first;
+ li != NULL && li->li_next != v.data.l.li;
+ li = li->li_next) {
+ idx++;
+ }
+ if (v.type == kMPConvList
+ || li == NULL
+ || (li->li_tv.v_type != VAR_LIST
+ && li->li_tv.vval.v_list->lv_len <= 0)) {
+ vim_snprintf((char *) IObuff, IOSIZE, idx_msg, idx);
+ ga_concat(&msg_ga, IObuff);
+ } else {
+ typval_T key_tv = li->li_tv.vval.v_list->lv_first->li_tv;
+ char *const key = encode_tv2echo(&key_tv, NULL);
+ vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
+ xfree(key);
+ ga_concat(&msg_ga, IObuff);
+ }
+ break;
+ }
+ }
+ }
+ EMSG3(msg, objname, (kv_size(*mpstack) == 0
+ ? _("itself")
+ : (char *) msg_ga.ga_data));
+ ga_clear(&msg_ga);
+ return FAIL;
+}
+
+/// Convert readfile()-style list to a char * buffer with length
+///
+/// @param[in] list Converted list.
+/// @param[out] ret_len Resulting buffer length.
+/// @param[out] ret_buf Allocated buffer with the result or NULL if ret_len is
+/// zero.
+///
+/// @return true in case of success, false in case of failure.
+bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
+ char **const ret_buf)
+ FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ size_t len = 0;
+ if (list != NULL) {
+ for (const listitem_T *li = list->lv_first;
+ li != NULL;
+ li = li->li_next) {
+ if (li->li_tv.v_type != VAR_STRING) {
+ return false;
+ }
+ len++;
+ if (li->li_tv.vval.v_string != 0) {
+ len += STRLEN(li->li_tv.vval.v_string);
+ }
+ }
+ if (len) {
+ len--;
+ }
+ }
+ *ret_len = len;
+ if (len == 0) {
+ *ret_buf = NULL;
+ return true;
+ }
+ ListReaderState lrstate = encode_init_lrstate(list);
+ char *const buf = xmalloc(len);
+ size_t read_bytes;
+ if (encode_read_from_list(&lrstate, buf, len, &read_bytes) != OK) {
+ assert(false);
+ }
+ assert(len == read_bytes);
+ *ret_buf = buf;
+ return true;
+}
+
+/// Read bytes from list
+///
+/// @param[in,out] state Structure describing position in list from which
+/// reading should start. Is updated to reflect position
+/// at which reading ended.
+/// @param[out] buf Buffer to write to.
+/// @param[in] nbuf Buffer length.
+/// @param[out] read_bytes Is set to amount of bytes read.
+///
+/// @return OK when reading was finished, FAIL in case of error (i.e. list item
+/// was not a string), NOTDONE if reading was successfull, but there are
+/// more bytes to read.
+int encode_read_from_list(ListReaderState *const state, char *const buf,
+ const size_t nbuf, size_t *const read_bytes)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ char *const buf_end = buf + nbuf;
+ char *p = buf;
+ while (p < buf_end) {
+ for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
+ const char ch = (char) state->li->li_tv.vval.v_string[state->offset++];
+ *p++ = (char) ((char) ch == (char) NL ? (char) NUL : (char) ch);
+ }
+ if (p < buf_end) {
+ state->li = state->li->li_next;
+ if (state->li == NULL) {
+ *read_bytes = (size_t) (p - buf);
+ return OK;
+ }
+ *p++ = NL;
+ if (state->li->li_tv.v_type != VAR_STRING) {
+ *read_bytes = (size_t) (p - buf);
+ return FAIL;
+ }
+ state->offset = 0;
+ state->li_length = (state->li->li_tv.vval.v_string == NULL
+ ? 0
+ : STRLEN(state->li->li_tv.vval.v_string));
+ }
+ }
+ *read_bytes = nbuf;
+ return (state->offset < state->li_length || state->li->li_next != NULL
+ ? NOTDONE
+ : OK);
+}
+
+/// Code for checking whether container references itself
+///
+/// @param[in,out] val Container to check.
+/// @param copyID_attr Name of the container attribute that holds copyID.
+/// After checking whether value of this attribute is
+/// copyID (variable) it is set to copyID.
+#define CHECK_SELF_REFERENCE(val, copyID_attr, conv_type) \
+ do { \
+ if ((val)->copyID_attr == copyID) { \
+ CONV_RECURSE((val), conv_type); \
+ } \
+ (val)->copyID_attr = copyID; \
+ } while (0)
+
+#define TV_STRLEN(tv) \
+ (tv->vval.v_string == NULL ? 0 : STRLEN(tv->vval.v_string))
+
+/// Define functions which convert VimL value to something else
+///
+/// Creates function `vim_to_{name}(firstargtype firstargname, typval_T *const
+/// tv)` which returns OK or FAIL and helper functions.
+///
+/// @param firstargtype Type of the first argument. It will be used to return
+/// the results.
+/// @param firstargname Name of the first argument.
+/// @param name Name of the target converter.
+#define DEFINE_VIML_CONV_FUNCTIONS(scope, name, firstargtype, firstargname) \
+static int name##_convert_one_value(firstargtype firstargname, \
+ MPConvStack *const mpstack, \
+ typval_T *const tv, \
+ const int copyID, \
+ const char *const objname) \
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
+{ \
+ switch (tv->v_type) { \
+ case VAR_STRING: { \
+ CONV_STRING(tv->vval.v_string, TV_STRLEN(tv)); \
+ break; \
+ } \
+ case VAR_NUMBER: { \
+ CONV_NUMBER(tv->vval.v_number); \
+ break; \
+ } \
+ case VAR_FLOAT: { \
+ CONV_FLOAT(tv->vval.v_float); \
+ break; \
+ } \
+ case VAR_FUNC: { \
+ CONV_FUNC(tv->vval.v_string); \
+ break; \
+ } \
+ case VAR_LIST: { \
+ if (tv->vval.v_list == NULL || tv->vval.v_list->lv_len == 0) { \
+ CONV_EMPTY_LIST(); \
+ break; \
+ } \
+ CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, kMPConvList); \
+ CONV_LIST_START(tv->vval.v_list); \
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
+ .type = kMPConvList, \
+ .data = { \
+ .l = { \
+ .list = tv->vval.v_list, \
+ .li = tv->vval.v_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case VAR_SPECIAL: { \
+ switch (tv->vval.v_special) { \
+ case kSpecialVarNull: { \
+ CONV_NIL(); \
+ break; \
+ } \
+ case kSpecialVarTrue: \
+ case kSpecialVarFalse: { \
+ CONV_BOOL(tv->vval.v_special == kSpecialVarTrue); \
+ break; \
+ } \
+ } \
+ break; \
+ } \
+ case VAR_DICT: { \
+ if (tv->vval.v_dict == NULL \
+ || tv->vval.v_dict->dv_hashtab.ht_used == 0) { \
+ CONV_EMPTY_DICT(); \
+ break; \
+ } \
+ const dictitem_T *type_di; \
+ const dictitem_T *val_di; \
+ if (CONV_ALLOW_SPECIAL \
+ && tv->vval.v_dict->dv_hashtab.ht_used == 2 \
+ && (type_di = dict_find((dict_T *) tv->vval.v_dict, \
+ (char_u *) "_TYPE", -1)) != NULL \
+ && type_di->di_tv.v_type == VAR_LIST \
+ && (val_di = dict_find((dict_T *) tv->vval.v_dict, \
+ (char_u *) "_VAL", -1)) != NULL) { \
+ size_t i; \
+ for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { \
+ if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { \
+ break; \
+ } \
+ } \
+ if (i == ARRAY_SIZE(eval_msgpack_type_lists)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ switch ((MessagePackType) i) { \
+ case kMPNil: { \
+ CONV_NIL(); \
+ break; \
+ } \
+ case kMPBoolean: { \
+ if (val_di->di_tv.v_type != VAR_NUMBER) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ CONV_BOOL(val_di->di_tv.vval.v_number); \
+ break; \
+ } \
+ case kMPInteger: { \
+ const list_T *val_list; \
+ varnumber_T sign; \
+ varnumber_T highest_bits; \
+ varnumber_T high_bits; \
+ varnumber_T low_bits; \
+ /* List of 4 integers; first is signed (should be 1 or -1, but */ \
+ /* this is not checked), second is unsigned and have at most */ \
+ /* one (sign is -1) or two (sign is 1) non-zero bits (number of */ \
+ /* bits is not checked), other unsigned and have at most 31 */ \
+ /* non-zero bits (number of bits is not checked).*/ \
+ if (val_di->di_tv.v_type != VAR_LIST \
+ || (val_list = val_di->di_tv.vval.v_list) == NULL \
+ || val_list->lv_len != 4 \
+ || val_list->lv_first->li_tv.v_type != VAR_NUMBER \
+ || (sign = val_list->lv_first->li_tv.vval.v_number) == 0 \
+ || val_list->lv_first->li_next->li_tv.v_type != VAR_NUMBER \
+ || (highest_bits = \
+ val_list->lv_first->li_next->li_tv.vval.v_number) < 0 \
+ || val_list->lv_last->li_prev->li_tv.v_type != VAR_NUMBER \
+ || (high_bits = \
+ val_list->lv_last->li_prev->li_tv.vval.v_number) < 0 \
+ || val_list->lv_last->li_tv.v_type != VAR_NUMBER \
+ || (low_bits = val_list->lv_last->li_tv.vval.v_number) < 0) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ uint64_t number = ((uint64_t) (((uint64_t) highest_bits) << 62) \
+ | (uint64_t) (((uint64_t) high_bits) << 31) \
+ | (uint64_t) low_bits); \
+ if (sign > 0) { \
+ CONV_UNSIGNED_NUMBER(number); \
+ } else { \
+ CONV_NUMBER(-number); \
+ } \
+ break; \
+ } \
+ case kMPFloat: { \
+ if (val_di->di_tv.v_type != VAR_FLOAT) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ CONV_FLOAT(val_di->di_tv.vval.v_float); \
+ break; \
+ } \
+ case kMPString: \
+ case kMPBinary: { \
+ const bool is_string = ((MessagePackType) i == kMPString); \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ size_t len; \
+ char *buf; \
+ if (!encode_vim_list_to_buf(val_di->di_tv.vval.v_list, &len, \
+ &buf)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ if (is_string) { \
+ CONV_STR_STRING(buf, len); \
+ } else { \
+ CONV_STRING(buf, len); \
+ } \
+ xfree(buf); \
+ break; \
+ } \
+ case kMPArray: { \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ CHECK_SELF_REFERENCE(val_di->di_tv.vval.v_list, lv_copyID, \
+ kMPConvList); \
+ CONV_LIST_START(val_di->di_tv.vval.v_list); \
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
+ .type = kMPConvList, \
+ .data = { \
+ .l = { \
+ .list = val_di->di_tv.vval.v_list, \
+ .li = val_di->di_tv.vval.v_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case kMPMap: { \
+ if (val_di->di_tv.v_type != VAR_LIST) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ list_T *const val_list = val_di->di_tv.vval.v_list; \
+ if (val_list == NULL || val_list->lv_len == 0) { \
+ CONV_EMPTY_DICT(); \
+ break; \
+ } \
+ for (const listitem_T *li = val_list->lv_first; li != NULL; \
+ li = li->li_next) { \
+ if (li->li_tv.v_type != VAR_LIST \
+ || li->li_tv.vval.v_list->lv_len != 2) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ } \
+ CHECK_SELF_REFERENCE(val_list, lv_copyID, kMPConvPairs); \
+ CONV_DICT_START(val_list->lv_len); \
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
+ .type = kMPConvPairs, \
+ .data = { \
+ .l = { \
+ .list = val_list, \
+ .li = val_list->lv_first, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case kMPExt: { \
+ const list_T *val_list; \
+ varnumber_T type; \
+ if (val_di->di_tv.v_type != VAR_LIST \
+ || (val_list = val_di->di_tv.vval.v_list) == NULL \
+ || val_list->lv_len != 2 \
+ || (val_list->lv_first->li_tv.v_type != VAR_NUMBER) \
+ || (type = val_list->lv_first->li_tv.vval.v_number) > INT8_MAX \
+ || type < INT8_MIN \
+ || (val_list->lv_last->li_tv.v_type != VAR_LIST)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ size_t len; \
+ char *buf; \
+ if (!encode_vim_list_to_buf(val_list->lv_last->li_tv.vval.v_list, \
+ &len, &buf)) { \
+ goto name##_convert_one_value_regular_dict; \
+ } \
+ CONV_EXT_STRING(buf, len, type); \
+ xfree(buf); \
+ break; \
+ } \
+ } \
+ break; \
+ } \
+name##_convert_one_value_regular_dict: \
+ CHECK_SELF_REFERENCE(tv->vval.v_dict, dv_copyID, kMPConvDict); \
+ CONV_DICT_START(tv->vval.v_dict->dv_hashtab.ht_used); \
+ kv_push(MPConvStackVal, *mpstack, ((MPConvStackVal) { \
+ .type = kMPConvDict, \
+ .data = { \
+ .d = { \
+ .dict = tv->vval.v_dict, \
+ .hi = tv->vval.v_dict->dv_hashtab.ht_array, \
+ .todo = tv->vval.v_dict->dv_hashtab.ht_used, \
+ }, \
+ }, \
+ })); \
+ break; \
+ } \
+ case VAR_UNKNOWN: { \
+ EMSG2(_(e_intern2), #name "_convert_one_value()"); \
+ return FAIL; \
+ } \
+ } \
+ return OK; \
+} \
+\
+scope int encode_vim_to_##name(firstargtype firstargname, typval_T *const tv, \
+ const char *const objname) \
+ FUNC_ATTR_WARN_UNUSED_RESULT \
+{ \
+ const int copyID = get_copyID(); \
+ MPConvStack mpstack; \
+ kv_init(mpstack); \
+ if (name##_convert_one_value(firstargname, &mpstack, tv, copyID, objname) \
+ == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ while (kv_size(mpstack)) { \
+ MPConvStackVal *cur_mpsv = &kv_A(mpstack, kv_size(mpstack) - 1); \
+ typval_T *cur_tv = NULL; \
+ switch (cur_mpsv->type) { \
+ case kMPConvDict: { \
+ if (!cur_mpsv->data.d.todo) { \
+ (void) kv_pop(mpstack); \
+ cur_mpsv->data.d.dict->dv_copyID = copyID - 1; \
+ CONV_DICT_END(); \
+ continue; \
+ } else if (cur_mpsv->data.d.todo \
+ != cur_mpsv->data.d.dict->dv_hashtab.ht_used) { \
+ CONV_DICT_BETWEEN_ITEMS(); \
+ } \
+ while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { \
+ cur_mpsv->data.d.hi++; \
+ } \
+ dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); \
+ cur_mpsv->data.d.todo--; \
+ cur_mpsv->data.d.hi++; \
+ CONV_STR_STRING(&di->di_key[0], STRLEN(&di->di_key[0])); \
+ CONV_DICT_AFTER_KEY(); \
+ cur_tv = &di->di_tv; \
+ break; \
+ } \
+ case kMPConvList: { \
+ if (cur_mpsv->data.l.li == NULL) { \
+ (void) kv_pop(mpstack); \
+ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
+ CONV_LIST_END(cur_mpsv->data.l.list); \
+ continue; \
+ } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
+ CONV_LIST_BETWEEN_ITEMS(); \
+ } \
+ cur_tv = &cur_mpsv->data.l.li->li_tv; \
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
+ break; \
+ } \
+ case kMPConvPairs: { \
+ if (cur_mpsv->data.l.li == NULL) { \
+ (void) kv_pop(mpstack); \
+ cur_mpsv->data.l.list->lv_copyID = copyID - 1; \
+ CONV_DICT_END(); \
+ continue; \
+ } else if (cur_mpsv->data.l.li != cur_mpsv->data.l.list->lv_first) { \
+ CONV_DICT_BETWEEN_ITEMS(); \
+ } \
+ const list_T *const kv_pair = cur_mpsv->data.l.li->li_tv.vval.v_list; \
+ CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair); \
+ if (name##_convert_one_value(firstargname, &mpstack, \
+ &kv_pair->lv_first->li_tv, copyID, \
+ objname) == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ CONV_DICT_AFTER_KEY(); \
+ cur_tv = &kv_pair->lv_last->li_tv; \
+ cur_mpsv->data.l.li = cur_mpsv->data.l.li->li_next; \
+ break; \
+ } \
+ } \
+ assert(cur_tv != NULL); \
+ if (name##_convert_one_value(firstargname, &mpstack, cur_tv, copyID, \
+ objname) == FAIL) { \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ } \
+ kv_destroy(mpstack); \
+ return OK; \
+encode_vim_to_##name##_error_ret: \
+ kv_destroy(mpstack); \
+ return FAIL; \
+}
+
+#define CONV_STRING(buf, len) \
+ do { \
+ const char *const buf_ = (const char *) buf; \
+ if (buf == NULL) { \
+ ga_concat(gap, "''"); \
+ } else { \
+ const size_t len_ = (len); \
+ ga_grow(gap, (int) (2 + len_ + memcnt(buf_, '\'', len_))); \
+ ga_append(gap, '\''); \
+ for (size_t i = 0; i < len_; i++) { \
+ if (buf_[i] == '\'') { \
+ ga_append(gap, '\''); \
+ } \
+ ga_append(gap, buf_[i]); \
+ } \
+ ga_append(gap, '\''); \
+ } \
+ } while (0)
+
+#define CONV_STR_STRING(buf, len) \
+ CONV_STRING(buf, len)
+
+#define CONV_EXT_STRING(buf, len, type)
+
+#define CONV_NUMBER(num) \
+ do { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t) (num)); \
+ ga_concat(gap, numbuf); \
+ } while (0)
+
+#define CONV_FLOAT(flt) \
+ do { \
+ const float_T flt_ = (flt); \
+ switch (fpclassify(flt_)) { \
+ case FP_NAN: { \
+ ga_concat(gap, (char_u *) "str2float('nan')"); \
+ break; \
+ } \
+ case FP_INFINITE: { \
+ if (flt_ < 0) { \
+ ga_append(gap, '-'); \
+ } \
+ ga_concat(gap, (char_u *) "str2float('inf')"); \
+ break; \
+ } \
+ default: { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
+ ga_concat(gap, (char_u *) numbuf); \
+ } \
+ } \
+ } while (0)
+
+#define CONV_FUNC(fun) \
+ do { \
+ ga_concat(gap, "function("); \
+ CONV_STRING(fun, STRLEN(fun)); \
+ ga_append(gap, ')'); \
+ } while (0)
+
+#define CONV_EMPTY_LIST() \
+ ga_concat(gap, "[]")
+
+#define CONV_LIST_START(lst) \
+ ga_append(gap, '[')
+
+#define CONV_EMPTY_DICT() \
+ ga_concat(gap, "{}")
+
+#define CONV_NIL() \
+ ga_concat(gap, "v:null")
+
+#define CONV_BOOL(num) \
+ ga_concat(gap, ((num)? "v:true": "v:false"))
+
+#define CONV_UNSIGNED_NUMBER(num)
+
+#define CONV_DICT_START(len) \
+ ga_append(gap, '{')
+
+#define CONV_DICT_END() \
+ ga_append(gap, '}')
+
+#define CONV_DICT_AFTER_KEY() \
+ ga_concat(gap, ": ")
+
+#define CONV_DICT_BETWEEN_ITEMS() \
+ ga_concat(gap, ", ")
+
+#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair)
+
+#define CONV_LIST_END(lst) \
+ ga_append(gap, ']')
+
+#define CONV_LIST_BETWEEN_ITEMS() \
+ CONV_DICT_BETWEEN_ITEMS()
+
+#define CONV_RECURSE(val, conv_type) \
+ do { \
+ if (!did_echo_string_emsg) { \
+ /* Only give this message once for a recursive call to avoid */ \
+ /* flooding the user with errors. */ \
+ did_echo_string_emsg = true; \
+ EMSG(_("E724: unable to correctly dump variable " \
+ "with self-referencing container")); \
+ } \
+ char ebuf[NUMBUFLEN + 7]; \
+ size_t backref = 0; \
+ for (; backref < kv_size(*mpstack); backref++) { \
+ const MPConvStackVal mpval = kv_A(*mpstack, backref); \
+ if (mpval.type == conv_type) { \
+ if (conv_type == kMPConvDict) { \
+ if ((void *) mpval.data.d.dict == (void *) (val)) { \
+ break; \
+ } \
+ } else if (conv_type == kMPConvList) { \
+ if ((void *) mpval.data.l.list == (void *) (val)) { \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{E724@%zu}", backref); \
+ ga_concat(gap, &ebuf[0]); \
+ return OK; \
+ } while (0)
+
+#define CONV_ALLOW_SPECIAL false
+
+DEFINE_VIML_CONV_FUNCTIONS(static, string, garray_T *const, gap)
+
+#undef CONV_RECURSE
+#define CONV_RECURSE(val, conv_type) \
+ do { \
+ char ebuf[NUMBUFLEN + 7]; \
+ size_t backref = 0; \
+ for (; backref < kv_size(*mpstack); backref++) { \
+ const MPConvStackVal mpval = kv_A(*mpstack, backref); \
+ if (mpval.type == conv_type) { \
+ if (conv_type == kMPConvDict) { \
+ if ((void *) mpval.data.d.dict == (void *) val) { \
+ break; \
+ } \
+ } else if (conv_type == kMPConvList) { \
+ if ((void *) mpval.data.l.list == (void *) val) { \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ if (conv_type == kMPConvDict) { \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{...@%zu}", backref); \
+ } else { \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "[...@%zu]", backref); \
+ } \
+ ga_concat(gap, &ebuf[0]); \
+ return OK; \
+ } while (0)
+
+DEFINE_VIML_CONV_FUNCTIONS(, echo, garray_T *const, gap)
+
+#undef CONV_RECURSE
+#define CONV_RECURSE(val, conv_type) \
+ do { \
+ if (!did_echo_string_emsg) { \
+ /* Only give this message once for a recursive call to avoid */ \
+ /* flooding the user with errors. */ \
+ did_echo_string_emsg = true; \
+ EMSG(_("E724: unable to correctly dump variable " \
+ "with self-referencing container")); \
+ } \
+ return OK; \
+ } while (0)
+
+#undef CONV_ALLOW_SPECIAL
+#define CONV_ALLOW_SPECIAL true
+
+#undef CONV_NIL
+#define CONV_NIL() \
+ ga_concat(gap, "null")
+
+#undef CONV_BOOL
+#define CONV_BOOL(num) \
+ ga_concat(gap, ((num)? "true": "false"))
+
+#undef CONV_UNSIGNED_NUMBER
+#define CONV_UNSIGNED_NUMBER(num) \
+ do { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \
+ ga_concat(gap, numbuf); \
+ } while (0)
+
+#undef CONV_FLOAT
+#define CONV_FLOAT(flt) \
+ do { \
+ const float_T flt_ = (flt); \
+ switch (fpclassify(flt_)) { \
+ case FP_NAN: { \
+ EMSG(_("E474: Unable to represent NaN value in JSON")); \
+ return FAIL; \
+ } \
+ case FP_INFINITE: { \
+ 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, (char_u *) numbuf); \
+ break; \
+ } \
+ } \
+ } while (0)
+
+/// Last used p_enc value
+///
+/// Generic pointer: it is not used as a string, only pointer comparisons are
+/// performed. Must not be freed.
+static const void *last_p_enc = NULL;
+
+/// Conversion setup for converting from last_p_enc to UTF-8
+static vimconv_T p_enc_conv = {
+ .vc_type = CONV_NONE,
+};
+
+/// Escape sequences used in JSON
+static const char escapes[][3] = {
+ [BS] = "\\b",
+ [TAB] = "\\t",
+ [NL] = "\\n",
+ [CAR] = "\\r",
+ ['"'] = "\\\"",
+ ['\\'] = "\\\\",
+ [FF] = "\\f",
+};
+
+static const char xdigits[] = "0123456789ABCDEF";
+
+/// Convert given string to JSON string
+///
+/// @param[out] gap Garray where result will be saved.
+/// @param[in] buf Converted string.
+/// @param[in] len Converted string length.
+///
+/// @return OK in case of success, FAIL otherwise.
+static inline int convert_to_json_string(garray_T *const gap,
+ const char *const buf,
+ const size_t len)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_ALWAYS_INLINE
+{
+ const char *utf_buf = buf;
+ if (utf_buf == NULL) {
+ ga_concat(gap, "\"\"");
+ } else {
+ size_t utf_len = len;
+ char *tofree = NULL;
+ if (last_p_enc != (const void *) p_enc) {
+ p_enc_conv.vc_type = CONV_NONE;
+ convert_setup(&p_enc_conv, p_enc, "utf-8");
+ p_enc_conv.vc_fail = true;
+ last_p_enc = p_enc;
+ }
+ if (p_enc_conv.vc_type != CONV_NONE) {
+ tofree = string_convert(&p_enc_conv, buf, &utf_len);
+ if (tofree == NULL) {
+ emsgf(_("E474: Failed to convert string \"%.*s\" to UTF-8"),
+ utf_len, utf_buf);
+ return FAIL;
+ }
+ utf_buf = tofree;
+ }
+ size_t str_len = 0;
+ // Encode character as \u0000 if
+ // 1. It is an ASCII control character (0x0 .. 0x1F, 0x7F).
+ // 2. &encoding is not UTF-8 and code point is above 0x7F.
+ // 3. &encoding is UTF-8 and code point is not printable according to
+ // utf_printable().
+ // This is done to make it possible to :echo values when &encoding is not
+ // UTF-8.
+#define ENCODE_RAW(p_enc_conv, ch) \
+ (ch >= 0x20 && (p_enc_conv.vc_type == CONV_NONE \
+ ? utf_printable(ch) \
+ : ch < 0x7F))
+ 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));
+ assert(shift > 0);
+ i += shift;
+ switch (ch) {
+ case BS:
+ case TAB:
+ case NL:
+ case FF:
+ case CAR:
+ case '"':
+ case '\\': {
+ str_len += 2;
+ break;
+ }
+ default: {
+ if (ch > 0x7F && shift == 1) {
+ emsgf(_("E474: String \"%.*s\" contains byte that does not start "
+ "any UTF-8 character"),
+ utf_len - (i - shift), utf_buf + i - shift);
+ xfree(tofree);
+ return FAIL;
+ } else if ((SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END)
+ || (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END)) {
+ emsgf(_("E474: UTF-8 string contains code point which belongs "
+ "to a surrogate pair: %.*s"),
+ utf_len - (i - shift), utf_buf + i - shift);
+ xfree(tofree);
+ return FAIL;
+ } else if (ENCODE_RAW(p_enc_conv, ch)) {
+ str_len += shift;
+ } else {
+ str_len += ((sizeof("\\u1234") - 1)
+ * (size_t) (1 + (ch >= SURROGATE_FIRST_CHAR)));
+ }
+ break;
+ }
+ }
+ }
+ 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 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));
+ switch (ch) {
+ case BS:
+ case TAB:
+ case NL:
+ case FF:
+ case CAR:
+ case '"':
+ case '\\': {
+ ga_concat_len(gap, escapes[ch], 2);
+ break;
+ }
+ default: {
+ if (ENCODE_RAW(p_enc_conv, ch)) {
+ ga_concat_len(gap, utf_buf + i, shift);
+ } else if (ch < SURROGATE_FIRST_CHAR) {
+ ga_concat_len(gap, ((const char[]) {
+ '\\', 'u',
+ xdigits[(ch >> (4 * 3)) & 0xF],
+ xdigits[(ch >> (4 * 2)) & 0xF],
+ xdigits[(ch >> (4 * 1)) & 0xF],
+ xdigits[(ch >> (4 * 0)) & 0xF],
+ }), sizeof("\\u1234") - 1);
+ } else {
+ const int tmp = ch - SURROGATE_FIRST_CHAR;
+ const int hi = SURROGATE_HI_START + ((tmp >> 10) & ((1 << 10) - 1));
+ const int lo = SURROGATE_LO_END + ((tmp >> 0) & ((1 << 10) - 1));
+ ga_concat_len(gap, ((const char[]) {
+ '\\', 'u',
+ xdigits[(hi >> (4 * 3)) & 0xF],
+ xdigits[(hi >> (4 * 2)) & 0xF],
+ xdigits[(hi >> (4 * 1)) & 0xF],
+ xdigits[(hi >> (4 * 0)) & 0xF],
+ '\\', 'u',
+ xdigits[(lo >> (4 * 3)) & 0xF],
+ xdigits[(lo >> (4 * 2)) & 0xF],
+ xdigits[(lo >> (4 * 1)) & 0xF],
+ xdigits[(lo >> (4 * 0)) & 0xF],
+ }), (sizeof("\\u1234") - 1) * 2);
+ }
+ break;
+ }
+ }
+ i += shift;
+ }
+ ga_append(gap, '"');
+ xfree(tofree);
+ }
+ return OK;
+}
+
+#undef CONV_STRING
+#define CONV_STRING(buf, len) \
+ do { \
+ if (convert_to_json_string(gap, (const char *) (buf), (len)) != OK) { \
+ return FAIL; \
+ } \
+ } while (0)
+
+#undef CONV_EXT_STRING
+#define CONV_EXT_STRING(buf, len, type) \
+ do { \
+ xfree(buf); \
+ EMSG(_("E474: Unable to convert EXT string to JSON")); \
+ return FAIL; \
+ } while (0)
+
+#undef CONV_FUNC
+#define CONV_FUNC(fun) \
+ return conv_error(_("E474: Error while dumping %s, %s: " \
+ "attempt to dump function reference"), \
+ mpstack, objname)
+
+/// Check whether given key can be used in json_encode()
+///
+/// @param[in] tv Key to check.
+static inline bool check_json_key(const typval_T *const tv)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+ FUNC_ATTR_ALWAYS_INLINE
+{
+ if (tv->v_type == VAR_STRING) {
+ return true;
+ }
+ if (tv->v_type != VAR_DICT) {
+ return false;
+ }
+ const dict_T *const spdict = tv->vval.v_dict;
+ if (spdict->dv_hashtab.ht_used != 2) {
+ return false;
+ }
+ const dictitem_T *type_di;
+ const dictitem_T *val_di;
+ if ((type_di = dict_find((dict_T *) spdict, (char_u *) "_TYPE", -1)) == NULL
+ || type_di->di_tv.v_type != VAR_LIST
+ || (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
+ && type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary])
+ || (val_di = dict_find((dict_T *) spdict, (char_u *) "_VAL", -1)) == NULL
+ || val_di->di_tv.v_type != VAR_LIST) {
+ return false;
+ }
+ if (val_di->di_tv.vval.v_list == NULL) {
+ return true;
+ }
+ for (const listitem_T *li = val_di->di_tv.vval.v_list->lv_first;
+ li != NULL; li = li->li_next) {
+ if (li->li_tv.v_type != VAR_STRING) {
+ return false;
+ }
+ }
+ return true;
+}
+
+#undef CONV_SPECIAL_DICT_KEY_CHECK
+#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair) \
+ do { \
+ if (!check_json_key(&kv_pair->lv_first->li_tv)) { \
+ EMSG(_("E474: Invalid key in special dictionary")); \
+ goto encode_vim_to_##name##_error_ret; \
+ } \
+ } while (0)
+
+DEFINE_VIML_CONV_FUNCTIONS(static, json, garray_T *const, gap)
+
+#undef CONV_STRING
+#undef CONV_STR_STRING
+#undef CONV_EXT_STRING
+#undef CONV_NUMBER
+#undef CONV_FLOAT
+#undef CONV_FUNC
+#undef CONV_EMPTY_LIST
+#undef CONV_LIST_START
+#undef CONV_EMPTY_DICT
+#undef CONV_NIL
+#undef CONV_BOOL
+#undef CONV_UNSIGNED_NUMBER
+#undef CONV_DICT_START
+#undef CONV_DICT_END
+#undef CONV_DICT_AFTER_KEY
+#undef CONV_DICT_BETWEEN_ITEMS
+#undef CONV_SPECIAL_DICT_KEY_CHECK
+#undef CONV_LIST_END
+#undef CONV_LIST_BETWEEN_ITEMS
+#undef CONV_RECURSE
+#undef CONV_ALLOW_SPECIAL
+
+/// Return a string with the string representation of a variable.
+/// Puts quotes around strings, so that they can be parsed back by eval().
+///
+/// @param[in] tv typval_T to convert.
+/// @param[out] len Location where length of the result will be saved.
+///
+/// @return String representation of the variable or NULL.
+char *encode_tv2string(typval_T *tv, size_t *len)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_MALLOC
+{
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 80);
+ encode_vim_to_string(&ga, tv, "encode_tv2string() argument");
+ did_echo_string_emsg = false;
+ if (len != NULL) {
+ *len = (size_t) ga.ga_len;
+ }
+ ga_append(&ga, '\0');
+ return (char *) ga.ga_data;
+}
+
+/// Return a string with the string representation of a variable.
+/// Does not put quotes around strings, as ":echo" displays values.
+///
+/// @param[in] tv typval_T to convert.
+/// @param[out] len Location where length of the result will be saved.
+///
+/// @return String representation of the variable or NULL.
+char *encode_tv2echo(typval_T *tv, size_t *len)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_MALLOC
+{
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 80);
+ if (tv->v_type == VAR_STRING || tv->v_type == VAR_FUNC) {
+ if (tv->vval.v_string != NULL) {
+ ga_concat(&ga, tv->vval.v_string);
+ }
+ } else {
+ encode_vim_to_echo(&ga, tv, ":echo argument");
+ }
+ if (len != NULL) {
+ *len = (size_t) ga.ga_len;
+ }
+ ga_append(&ga, '\0');
+ return (char *) ga.ga_data;
+}
+
+/// Return a string with the string representation of a variable.
+/// Puts quotes around strings, so that they can be parsed back by eval().
+///
+/// @param[in] tv typval_T to convert.
+/// @param[out] len Location where length of the result will be saved.
+///
+/// @return String representation of the variable or NULL.
+char *encode_tv2json(typval_T *tv, size_t *len)
+ FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_MALLOC
+{
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char), 80);
+ encode_vim_to_json(&ga, tv, "encode_tv2json() argument");
+ did_echo_string_emsg = false;
+ if (len != NULL) {
+ *len = (size_t) ga.ga_len;
+ }
+ ga_append(&ga, '\0');
+ return (char *) ga.ga_data;
+}
+
+#define CONV_STRING(buf, len) \
+ do { \
+ if (buf == NULL) { \
+ msgpack_pack_bin(packer, 0); \
+ } else { \
+ const size_t len_ = (len); \
+ msgpack_pack_bin(packer, len_); \
+ msgpack_pack_bin_body(packer, buf, len_); \
+ } \
+ } while (0)
+
+#define CONV_STR_STRING(buf, len) \
+ do { \
+ if (buf == NULL) { \
+ msgpack_pack_str(packer, 0); \
+ } else { \
+ const size_t len_ = (len); \
+ msgpack_pack_str(packer, len_); \
+ msgpack_pack_str_body(packer, buf, len_); \
+ } \
+ } while (0)
+
+#define CONV_EXT_STRING(buf, len, type) \
+ do { \
+ if (buf == NULL) { \
+ msgpack_pack_ext(packer, 0, (int8_t) type); \
+ } else { \
+ const size_t len_ = (len); \
+ msgpack_pack_ext(packer, len_, (int8_t) type); \
+ msgpack_pack_ext_body(packer, buf, len_); \
+ } \
+ } while (0)
+
+#define CONV_NUMBER(num) \
+ msgpack_pack_int64(packer, (int64_t) (num))
+
+#define CONV_FLOAT(flt) \
+ msgpack_pack_double(packer, (double) (flt))
+
+#define CONV_FUNC(fun) \
+ return conv_error(_("E951: Error while dumping %s, %s: " \
+ "attempt to dump function reference"), \
+ mpstack, objname)
+
+#define CONV_EMPTY_LIST() \
+ msgpack_pack_array(packer, 0)
+
+#define CONV_LIST_START(lst) \
+ msgpack_pack_array(packer, (size_t) (lst)->lv_len)
+
+#define CONV_EMPTY_DICT() \
+ msgpack_pack_map(packer, 0)
+
+#define CONV_NIL() \
+ msgpack_pack_nil(packer)
+
+#define CONV_BOOL(num) \
+ do { \
+ if ((num)) { \
+ msgpack_pack_true(packer); \
+ } else { \
+ msgpack_pack_false(packer); \
+ } \
+ } while (0)
+
+#define CONV_UNSIGNED_NUMBER(num) \
+ msgpack_pack_uint64(packer, (num))
+
+#define CONV_DICT_START(len) \
+ msgpack_pack_map(packer, (size_t) (len))
+
+#define CONV_DICT_END()
+
+#define CONV_DICT_AFTER_KEY()
+
+#define CONV_DICT_BETWEEN_ITEMS()
+
+#define CONV_SPECIAL_DICT_KEY_CHECK(name, kv_pair)
+
+#define CONV_LIST_END(lst)
+
+#define CONV_LIST_BETWEEN_ITEMS()
+
+#define CONV_RECURSE(val, conv_type) \
+ return conv_error(_("E952: Unable to dump %s: " \
+ "container references itself in %s"), \
+ mpstack, objname)
+
+#define CONV_ALLOW_SPECIAL true
+
+DEFINE_VIML_CONV_FUNCTIONS(, msgpack, msgpack_packer *const, packer)
+
+#undef CONV_STRING
+#undef CONV_STR_STRING
+#undef CONV_EXT_STRING
+#undef CONV_NUMBER
+#undef CONV_FLOAT
+#undef CONV_FUNC
+#undef CONV_EMPTY_LIST
+#undef CONV_LIST_START
+#undef CONV_EMPTY_DICT
+#undef CONV_NIL
+#undef CONV_BOOL
+#undef CONV_UNSIGNED_NUMBER
+#undef CONV_DICT_START
+#undef CONV_DICT_END
+#undef CONV_DICT_AFTER_KEY
+#undef CONV_DICT_BETWEEN_ITEMS
+#undef CONV_SPECIAL_DICT_KEY_CHECK
+#undef CONV_LIST_END
+#undef CONV_LIST_BETWEEN_ITEMS
+#undef CONV_RECURSE
+#undef CONV_ALLOW_SPECIAL
diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h
new file mode 100644
index 0000000000..9bc665253b
--- /dev/null
+++ b/src/nvim/eval/encode.h
@@ -0,0 +1,75 @@
+#ifndef NVIM_EVAL_ENCODE_H
+#define NVIM_EVAL_ENCODE_H
+
+#include <stddef.h>
+
+#include <msgpack.h>
+
+#include "nvim/eval.h"
+#include "nvim/garray.h"
+#include "nvim/vim.h" // For STRLEN
+
+/// Convert VimL value to msgpack string
+///
+/// @param[out] packer Packer to save results in.
+/// @param[in] tv Dumped value.
+/// @param[in] objname Object name, used for error message.
+///
+/// @return OK in case of success, FAIL otherwise.
+int encode_vim_to_msgpack(msgpack_packer *const packer,
+ typval_T *const tv,
+ const char *const objname);
+
+/// Convert VimL value to :echo output
+///
+/// @param[out] packer Packer to save results in.
+/// @param[in] tv Dumped value.
+/// @param[in] objname Object name, used for error message.
+///
+/// @return OK in case of success, FAIL otherwise.
+int encode_vim_to_echo(garray_T *const packer,
+ typval_T *const tv,
+ const char *const objname);
+
+/// Structure defining state for read_from_list()
+typedef struct {
+ const listitem_T *li; ///< Item currently read.
+ size_t offset; ///< Byte offset inside the read item.
+ size_t li_length; ///< Length of the string inside the read item.
+} ListReaderState;
+
+/// Initialize ListReaderState structure
+static inline ListReaderState encode_init_lrstate(const list_T *const list)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return (ListReaderState) {
+ .li = list->lv_first,
+ .offset = 0,
+ .li_length = (list->lv_first->li_tv.vval.v_string == NULL
+ ? 0
+ : STRLEN(list->lv_first->li_tv.vval.v_string)),
+ };
+}
+
+/// Array mapping values from SpecialVarValue enum to names
+extern const char *const encode_special_var_names[];
+
+/// First codepoint in high surrogates block
+#define SURROGATE_HI_START 0xD800
+
+/// Last codepoint in high surrogates block
+#define SURROGATE_HI_END 0xDBFF
+
+/// First codepoint in low surrogates block
+#define SURROGATE_LO_START 0xDC00
+
+/// Last codepoint in low surrogates block
+#define SURROGATE_LO_END 0xDFFF
+
+/// First character that needs to be encoded as surrogate pair
+#define SURROGATE_FIRST_CHAR 0x10000
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "eval/encode.h.generated.h"
+#endif
+#endif // NVIM_EVAL_ENCODE_H
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index cdad1f3197..8ffc0c98ce 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -16,39 +16,52 @@ typedef double float_T;
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
-/*
- * Structure to hold an internal variable without a name.
- */
+/// Special variable values
+typedef enum {
+ kSpecialVarFalse, ///< v:false
+ kSpecialVarTrue, ///< v:true
+ kSpecialVarNull, ///< v:null
+} SpecialVarValue;
+
+/// Variable lock status for typval_T.v_lock
+typedef enum {
+ VAR_UNLOCKED = 0, ///< Not locked.
+ VAR_LOCKED, ///< User lock, can be unlocked.
+ VAR_FIXED, ///< Locked forever.
+} VarLockStatus;
+
+/// VimL variable types, for use in typval_T.v_type
+typedef enum {
+ VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
+ VAR_NUMBER, ///< Number, .v_number is used.
+ VAR_STRING, ///< String, .v_string is used.
+ VAR_FUNC, ///< Function referene, .v_string is used for function name.
+ VAR_LIST, ///< List, .v_list is used.
+ VAR_DICT, ///< Dictionary, .v_dict is used.
+ VAR_FLOAT, ///< Floating-point value, .v_float is used.
+ VAR_SPECIAL, ///< Special value (true, false, null), .v_special
+ ///< is used.
+} VarType;
+
+/// Structure that holds an internal variable value
typedef struct {
- char v_type; /* see below: VAR_NUMBER, VAR_STRING, etc. */
- char v_lock; /* see below: VAR_LOCKED, VAR_FIXED */
+ VarType v_type; ///< Variable type.
+ VarLockStatus v_lock; ///< Variable lock status.
union {
- varnumber_T v_number; /* number value */
- float_T v_float; /* floating number value */
- char_u *v_string; /* string value (can be NULL!) */
- list_T *v_list; /* list value (can be NULL!) */
- dict_T *v_dict; /* dict value (can be NULL!) */
- } vval;
+ varnumber_T v_number; ///< Number, for VAR_NUMBER.
+ SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
+ float_T v_float; ///< Floating-point number, for VAR_FLOAT.
+ char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
+ list_T *v_list; ///< List for VAR_LIST, can be NULL.
+ dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
+ } vval; ///< Actual value.
} typval_T;
-/* Values for "v_type". */
-#define VAR_UNKNOWN 0
-#define VAR_NUMBER 1 /* "v_number" is used */
-#define VAR_STRING 2 /* "v_string" is used */
-#define VAR_FUNC 3 /* "v_string" is function name */
-#define VAR_LIST 4 /* "v_list" is used */
-#define VAR_DICT 5 /* "v_dict" is used */
-#define VAR_FLOAT 6 /* "v_float" is used */
-
/* Values for "dv_scope". */
#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
allowed to mask existing functions */
-/* Values for "v_lock". */
-#define VAR_LOCKED 1 /* locked with lock(), can use unlock() */
-#define VAR_FIXED 2 /* locked forever */
-
/*
* Structure to hold an item of a list: an internal variable without a name.
*/
@@ -107,19 +120,18 @@ typedef struct dictitem_S dictitem_T;
#define DI_FLAGS_LOCK 8 // "di_flags" value: locked variable
#define DI_FLAGS_ALLOC 16 // "di_flags" value: separately allocated
-/*
- * Structure to hold info about a Dictionary.
- */
+/// Structure representing a Dictionary
struct dictvar_S {
- char dv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
- char dv_scope; /* zero, VAR_SCOPE, VAR_DEF_SCOPE */
- int dv_refcount; /* reference count */
- int dv_copyID; /* ID used by deepcopy() */
- hashtab_T dv_hashtab; /* hashtab that refers to the items */
- dict_T *dv_copydict; /* copied dict used by deepcopy() */
- dict_T *dv_used_next; /* next dict in used dicts list */
- dict_T *dv_used_prev; /* previous dict in used dicts list */
- QUEUE watchers; // dictionary key watchers set by user code
+ VarLockStatus dv_lock; ///< Whole dictionary lock status.
+ char dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
+ ///< dictionary represents a scope (i.e. g:, l: …).
+ int dv_refcount; ///< Reference count.
+ int dv_copyID; ///< ID used when recursivery traversing a value.
+ hashtab_T dv_hashtab; ///< Hashtab containing all items.
+ dict_T *dv_copydict; ///< Copied dict used by deepcopy().
+ dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
+ dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
+ QUEUE watchers; ///< Dictionary key watchers set by user code.
};
// structure used for explicit stack while garbage collecting hash tables
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index e6012595fd..9bb62891c7 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -187,9 +187,9 @@ int process_wait(Process *proc, int ms, Queue *events) FUNC_ATTR_NONNULL_ARG(1)
// being freed) before we have a chance to get the status.
proc->refcount++;
LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, ms,
- // Until...
- got_int || // interrupted by the user
- proc->refcount == 1); // job exited
+ // Until...
+ got_int // interrupted by the user
+ || proc->refcount == 1); // job exited
// we'll assume that a user frantically hitting interrupt doesn't like
// the current job. Signal that it has to be killed.
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index ad21e71c51..86f1a16216 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3,6 +3,7 @@
*/
#include <assert.h>
+#include <float.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
@@ -50,7 +51,6 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/tempfile.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/window.h"
@@ -274,17 +274,26 @@ static int linelen(int *has_tab)
static char_u *sortbuf1;
static char_u *sortbuf2;
-static int sort_ic; /* ignore case */
-static int sort_nr; /* sort on number */
-static int sort_rx; /* sort on regex instead of skipping it */
+static int sort_ic; ///< ignore case
+static int sort_nr; ///< sort on number
+static int sort_rx; ///< sort on regex instead of skipping it
+static int sort_flt; ///< sort on floating number
-static int sort_abort; /* flag to indicate if sorting has been interrupted */
+static int sort_abort; ///< flag to indicate if sorting has been interrupted
-/* Struct to store info to be sorted. */
+/// Struct to store info to be sorted.
typedef struct {
- linenr_T lnum; /* line number */
- long start_col_nr; /* starting column number or number */
- long end_col_nr; /* ending column number */
+ linenr_T lnum; ///< line number
+ long start_col_nr; ///< starting column number or number
+ long end_col_nr; ///< ending column number
+ union {
+ struct {
+ long start_col_nr; ///< starting column number
+ long end_col_nr; ///< ending column number
+ } line;
+ long value; ///< value if sorting by integer
+ float_T value_flt; ///< value if sorting by float
+ } st_u;
} sorti_T;
@@ -303,21 +312,26 @@ static int sort_compare(const void *s1, const void *s2)
if (got_int)
sort_abort = TRUE;
- /* When sorting numbers "start_col_nr" is the number, not the column
- * number. */
- if (sort_nr)
- result = l1.start_col_nr == l2.start_col_nr ? 0
- : l1.start_col_nr > l2.start_col_nr ? 1 : -1;
- else {
- /* We need to copy one line into "sortbuf1", because there is no
- * guarantee that the first pointer becomes invalid when obtaining the
- * second one. */
- STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.start_col_nr,
- l1.end_col_nr - l1.start_col_nr + 1);
- sortbuf1[l1.end_col_nr - l1.start_col_nr] = 0;
- STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.start_col_nr,
- l2.end_col_nr - l2.start_col_nr + 1);
- sortbuf2[l2.end_col_nr - l2.start_col_nr] = 0;
+ // When sorting numbers "start_col_nr" is the number, not the column
+ // number.
+ if (sort_nr) {
+ result = l1.st_u.value == l2.st_u.value
+ ? 0 : l1.st_u.value > l2.st_u.value
+ ? 1 : -1;
+ } else if (sort_flt) {
+ result = l1.st_u.value_flt == l2.st_u.value_flt
+ ? 0 : l1.st_u.value_flt > l2.st_u.value_flt
+ ? 1 : -1;
+ } else {
+ // We need to copy one line into "sortbuf1", because there is no
+ // guarantee that the first pointer becomes invalid when obtaining the
+ // second one.
+ STRNCPY(sortbuf1, ml_get(l1.lnum) + l1.st_u.line.start_col_nr,
+ l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr + 1);
+ sortbuf1[l1.st_u.line.end_col_nr - l1.st_u.line.start_col_nr] = 0;
+ STRNCPY(sortbuf2, ml_get(l2.lnum) + l2.st_u.line.start_col_nr,
+ l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr + 1);
+ sortbuf2[l2.st_u.line.end_col_nr - l2.st_u.line.start_col_nr] = 0;
result = sort_ic ? STRICMP(sortbuf1, sortbuf2)
: STRCMP(sortbuf1, sortbuf2);
@@ -361,7 +375,7 @@ void ex_sort(exarg_T *eap)
regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
- sort_abort = sort_ic = sort_rx = sort_nr = 0;
+ sort_abort = sort_ic = sort_rx = sort_nr = sort_flt = 0;
size_t format_found = 0;
for (p = eap->arg; *p != NUL; ++p) {
@@ -371,7 +385,10 @@ void ex_sort(exarg_T *eap)
} else if (*p == 'r') {
sort_rx = true;
} else if (*p == 'n') {
- sort_nr = 2;
+ sort_nr = 1;
+ format_found++;
+ } else if (*p == 'f') {
+ sort_flt = 1;
format_found++;
} else if (*p == 'b') {
sort_what = STR2NR_BIN + STR2NR_FORCE;
@@ -424,7 +441,8 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
- // From here on "sort_nr" is used as a flag for any number sorting.
+ // From here on "sort_nr" is used as a flag for any integer number
+ // sorting.
sort_nr += sort_what;
// Make an array with all line numbers. This avoids having to copy all
@@ -453,7 +471,7 @@ void ex_sort(exarg_T *eap)
end_col = 0;
}
- if (sort_nr) {
+ if (sort_nr || sort_flt) {
// Make sure vim_str2nr doesn't read any digits past the end
// of the match, by temporarily terminating the string there
s2 = s + end_col;
@@ -461,29 +479,42 @@ void ex_sort(exarg_T *eap)
*s2 = NUL;
// Sorting on number: Store the number itself.
p = s + start_col;
- if (sort_what & STR2NR_HEX) {
- s = skiptohex(p);
- } else if (sort_what & STR2NR_BIN) {
- s = (char_u*) skiptobin((char*) p);
- } else {
- s = skiptodigit(p);
- }
- if (s > p && s[-1] == '-') {
- // include preceding negative sign
- s--;
- }
- if (*s == NUL) {
- // empty line should sort before any number
- nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
+ if (sort_nr) {
+ if (sort_what & STR2NR_HEX) {
+ s = skiptohex(p);
+ } else if (sort_what & STR2NR_BIN) {
+ s = (char_u *)skiptobin((char *)p);
+ } else {
+ s = skiptodigit(p);
+ }
+ if (s > p && s[-1] == '-') {
+ s--; // include preceding negative sign
+ }
+ if (*s == NUL) {
+ // empty line should sort before any number
+ nrs[lnum - eap->line1].st_u.value = -MAXLNUM;
+ } else {
+ vim_str2nr(s, NULL, NULL, sort_what,
+ &nrs[lnum - eap->line1].st_u.value, NULL, 0);
+ }
} else {
- vim_str2nr(s, NULL, NULL, sort_what,
- &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
+ s = skipwhite(p);
+ if (*s == '+') {
+ s = skipwhite(s + 1);
+ }
+
+ if (*s == NUL) {
+ // empty line should sort before any number
+ nrs[lnum - eap->line1].st_u.value_flt = -DBL_MAX;
+ } else {
+ nrs[lnum - eap->line1].st_u.value_flt = strtod((char *)s, NULL);
+ }
}
*s2 = c;
} else {
// Store the column to sort at.
- nrs[lnum - eap->line1].start_col_nr = start_col;
- nrs[lnum - eap->line1].end_col_nr = end_col;
+ nrs[lnum - eap->line1].st_u.line.start_col_nr = start_col;
+ nrs[lnum - eap->line1].st_u.line.end_col_nr = end_col;
}
nrs[lnum - eap->line1].lnum = lnum;
@@ -619,13 +650,13 @@ void ex_retab(exarg_T *eap)
num_tabs += num_spaces / new_ts;
num_spaces -= (num_spaces / new_ts) * new_ts;
}
- if (curbuf->b_p_et || got_tab ||
- (num_spaces + num_tabs < len)) {
- if (did_undo == FALSE) {
- did_undo = TRUE;
+ if (curbuf->b_p_et || got_tab
+ || (num_spaces + num_tabs < len)) {
+ if (did_undo == false) {
+ did_undo = true;
if (u_save((linenr_T)(lnum - 1),
- (linenr_T)(lnum + 1)) == FAIL) {
- new_line = NULL; /* flag out-of-memory */
+ (linenr_T)(lnum + 1)) == FAIL) {
+ new_line = NULL; // flag out-of-memory
break;
}
}
@@ -1326,15 +1357,17 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
#endif
size_t len = STRLEN(cmd) + 1; // At least enough space for cmd + NULL.
-
+
len += is_fish_shell ? sizeof("begin; ""; end") - 1
: sizeof("("")") - 1;
- if (itmp != NULL)
+ if (itmp != NULL) {
len += STRLEN(itmp) + sizeof(" { "" < "" } ") - 1;
- if (otmp != NULL)
+ }
+ if (otmp != NULL) {
len += STRLEN(otmp) + STRLEN(p_srr) + 2; // two extra spaces (" "),
- char_u *buf = xmalloc(len);
+ }
+ char *const buf = xmalloc(len);
#if defined(UNIX)
// Put delimiters around the command (for concatenated commands) when
@@ -1342,19 +1375,19 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
if (itmp != NULL || otmp != NULL) {
char *fmt = is_fish_shell ? "begin; %s; end"
: "(%s)";
- vim_snprintf((char *)buf, len, fmt, (char *)cmd);
+ vim_snprintf(buf, len, fmt, (char *)cmd);
} else {
- STRCPY(buf, cmd);
+ strncpy(buf, (char *) cmd, len);
}
if (itmp != NULL) {
- STRCAT(buf, " < ");
- STRCAT(buf, itmp);
+ strncat(buf, " < ", len);
+ strncat(buf, (char *) itmp, len);
}
#else
// For shells that don't understand braces around commands, at least allow
// the use of commands in a pipe.
- STRCPY(buf, cmd);
+ strncpy(buf, cmd, len);
if (itmp != NULL) {
char_u *p;
@@ -1362,55 +1395,56 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
// Don't do this when 'shellquote' is not empty, otherwise the
// redirection would be inside the quotes.
if (*p_shq == NUL) {
- p = vim_strchr(buf, '|');
- if (p != NULL)
+ p = strchr(buf, '|');
+ if (p != NULL) {
*p = NUL;
+ }
}
- STRCAT(buf, " < ");
- STRCAT(buf, itmp);
+ strncat(buf, " < ", len);
+ strncat(buf, (char *) itmp, len);
if (*p_shq == NUL) {
- p = vim_strchr(cmd, '|');
+ p = strchr(cmd, '|');
if (p != NULL) {
- STRCAT(buf, " "); // Insert a space before the '|' for DOS
- STRCAT(buf, p);
+ strncat(buf, " ", len); // Insert a space before the '|' for DOS
+ strncat(buf, p, len);
}
}
}
#endif
- if (otmp != NULL)
- append_redir(buf, (int)len, p_srr, otmp);
-
- return buf;
+ if (otmp != NULL) {
+ append_redir(buf, len, (char *) p_srr, (char *) otmp);
+ }
+ return (char_u *) buf;
}
-/*
- * Append output redirection for file "fname" to the end of string buffer
- * "buf[buflen]"
- * Works with the 'shellredir' and 'shellpipe' options.
- * The caller should make sure that there is enough room:
- * STRLEN(opt) + STRLEN(fname) + 3
- */
-void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname)
+/// Append output redirection for the given file to the end of the buffer
+///
+/// @param[out] buf Buffer to append to.
+/// @param[in] buflen Buffer length.
+/// @param[in] opt Separator or format string to append: will append
+/// `printf(' ' . opt, fname)` if `%s` is found in `opt` or
+/// a space, opt, a space and then fname if `%s` is not found
+/// there.
+/// @param[in] fname File name to append.
+void append_redir(char *const buf, const size_t buflen,
+ const char *const opt, const char *const fname)
{
- char_u *p;
- char_u *end;
-
- end = buf + STRLEN(buf);
- /* find "%s" */
- for (p = opt; (p = vim_strchr(p, '%')) != NULL; ++p) {
- if (p[1] == 's') /* found %s */
+ char *const end = buf + strlen(buf);
+ // find "%s"
+ const char *p = opt;
+ for (; (p = strchr(p, '%')) != NULL; p++) {
+ if (p[1] == 's') { // found %s
break;
- if (p[1] == '%') /* skip %% */
- ++p;
+ } else if (p[1] == '%') { // skip %%
+ p++;
+ }
}
if (p != NULL) {
- *end = ' '; /* not really needed? Not with sh, ksh or bash */
- vim_snprintf((char *)end + 1, (size_t)(buflen - (end + 1 - buf)),
- (char *)opt, (char *)fname);
- } else
- vim_snprintf((char *)end, (size_t)(buflen - (end - buf)),
- " %s %s",
- (char *)opt, (char *)fname);
+ *end = ' '; // not really needed? Not with sh, ksh or bash
+ vim_snprintf(end + 1, (size_t) (buflen - (end + 1 - buf)), opt, fname);
+ } else {
+ vim_snprintf(end, (size_t) (buflen - (end - buf)), " %s %s", opt, fname);
+ }
}
void print_line_no_prefix(linenr_T lnum, int use_number, int list)
@@ -1506,8 +1540,11 @@ void ex_file(exarg_T *eap)
if (rename_buffer(eap->arg) == FAIL)
return;
}
- /* print full file name if :cd used */
- fileinfo(FALSE, FALSE, eap->forceit);
+
+ if (!shortmess(SHM_FILEINFO)) {
+ // print full file name if :cd used
+ fileinfo(false, false, eap->forceit);
+ }
}
/*
@@ -1586,15 +1623,14 @@ int do_write(exarg_T *eap)
}
}
- /*
- * Writing to the current file is not allowed in readonly mode
- * and a file name is required.
- * "nofile" and "nowrite" buffers cannot be written implicitly either.
- */
- if (!other && (
- bt_dontwrite_msg(curbuf) ||
- check_fname() == FAIL || check_readonly(&eap->forceit, curbuf)))
+ // Writing to the current file is not allowed in readonly mode
+ // and a file name is required.
+ // "nofile" and "nowrite" buffers cannot be written implicitly either.
+ if (!other && (bt_dontwrite_msg(curbuf)
+ || check_fname() == FAIL
+ || check_readonly(&eap->forceit, curbuf))) {
goto theend;
+ }
if (!other) {
ffname = curbuf->b_ffname;
@@ -2090,15 +2126,13 @@ do_ecmd (
if ((command != NULL || newlnum > (linenr_T)0)
&& *get_vim_var_str(VV_SWAPCOMMAND) == NUL) {
- char_u *p;
-
- /* Set v:swapcommand for the SwapExists autocommands. */
- size_t len = (command != NULL) ? STRLEN(command) + 3 : 30;
- p = xmalloc(len);
+ // Set v:swapcommand for the SwapExists autocommands.
+ const size_t len = (command != NULL) ? STRLEN(command) + 3 : 30;
+ char *const p = xmalloc(len);
if (command != NULL) {
- vim_snprintf((char *)p, len, ":%s\r", command);
+ vim_snprintf(p, len, ":%s\r", command);
} else {
- vim_snprintf((char *)p, len, "%" PRId64 "G", (int64_t)newlnum);
+ vim_snprintf(p, len, "%" PRId64 "G", (int64_t)newlnum);
}
set_vim_var_string(VV_SWAPCOMMAND, p, -1);
did_set_swapcommand = TRUE;
@@ -2223,16 +2257,15 @@ do_ecmd (
delbuf_msg(new_name); /* frees new_name */
goto theend;
}
- if (buf == curbuf) /* already in new buffer */
- auto_buf = TRUE;
- else {
- /*
- * <VN> We could instead free the synblock
- * and re-attach to buffer, perhaps.
- */
- if (curwin->w_buffer != NULL &&
- curwin->w_s == &(curwin->w_buffer->b_s))
+ if (buf == curbuf) { // already in new buffer
+ auto_buf = true;
+ } else {
+ // <VN> We could instead free the synblock
+ // and re-attach to buffer, perhaps.
+ if (curwin->w_buffer != NULL
+ && curwin->w_s == &(curwin->w_buffer->b_s)) {
curwin->w_s = &(buf->b_s);
+ }
curwin->w_buffer = buf;
curbuf = buf;
@@ -2259,11 +2292,11 @@ do_ecmd (
curwin->w_pcmark.lnum = 1;
curwin->w_pcmark.col = 0;
- } else { /* !other_file */
- if (
- (flags & ECMD_ADDBUF) ||
- check_fname() == FAIL)
+ } else { // !other_file
+ if ((flags & ECMD_ADDBUF)
+ || check_fname() == FAIL) {
goto theend;
+ }
oldbuf = (flags & ECMD_OLDBUF);
}
@@ -2483,7 +2516,9 @@ do_ecmd (
msg_scroll = msg_scroll_save;
msg_scrolled_ign = TRUE;
- fileinfo(FALSE, TRUE, FALSE);
+ if (!shortmess(SHM_FILEINFO)) {
+ fileinfo(false, true, false);
+ }
msg_scrolled_ign = FALSE;
}
@@ -3017,7 +3052,7 @@ void do_sub(exarg_T *eap)
// The number of lines joined is the number of lines in the range
linenr_T joined_lines_count = eap->line2 - eap->line1 + 1
// plus one extra line if not at the end of file.
- + eap->line2 < curbuf->b_ml.ml_line_count ? 1 : 0;
+ + (eap->line2 < curbuf->b_ml.ml_line_count ? 1 : 0);
if (joined_lines_count > 1) {
do_join(joined_lines_count, FALSE, TRUE, FALSE, true);
sub_nsubs = joined_lines_count - 1;
@@ -3781,16 +3816,17 @@ skip:
EMSG2(_(e_patnotf2), get_search_pat());
}
- if (do_ask && hasAnyFolding(curwin))
- /* Cursor position may require updating */
+ if (do_ask && hasAnyFolding(curwin)) {
+ // Cursor position may require updating
changed_window_setting();
+ }
- vim_regfree(regmatch.regprog);
+ vim_regfree(regmatch.regprog);
- // Restore the flag values, they can be used for ":&&".
- do_all = save_do_all;
- do_ask = save_do_ask;
- }
+ // Restore the flag values, they can be used for ":&&".
+ do_all = save_do_all;
+ do_ask = save_do_ask;
+}
/*
* Give message for number of substitutions.
@@ -4378,17 +4414,20 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
|| (arg[0] == '\\' && arg[1] == '{'))
*d++ = '\\';
- for (s = arg; *s; ++s) {
- /*
- * Replace "|" with "bar" and '"' with "quote" to match the name of
- * the tags for these commands.
- * Replace "*" with ".*" and "?" with "." to match command line
- * completion.
- * Insert a backslash before '~', '$' and '.' to avoid their
- * special meaning.
- */
- if (d - IObuff > IOSIZE - 10) /* getting too long!? */
+ // If tag starts with "('", skip the "(". Fixes CTRL-] on ('option'.
+ if (*arg == '(' && arg[1] == '\'') {
+ arg++;
+ }
+ for (s = arg; *s; s++) {
+ // Replace "|" with "bar" and '"' with "quote" to match the name of
+ // the tags for these commands.
+ // Replace "*" with ".*" and "?" with "." to match command line
+ // completion.
+ // Insert a backslash before '~', '$' and '.' to avoid their
+ // special meaning.
+ if (d - IObuff > IOSIZE - 10) { // getting too long!?
break;
+ }
switch (*s) {
case '|': STRCPY(d, "bar");
d += 3;
@@ -4449,6 +4488,12 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
*d++ = *s;
+ // If tag contains "({" or "([", tag terminates at the "(".
+ // This is for help on functions, e.g.: abs({expr}).
+ if (*s == '(' && (s[1] == '{' || s[1] =='[')) {
+ break;
+ }
+
/*
* If tag starts with ', toss everything after a second '. Fixes
* CTRL-] on 'option'. (would include the trailing '.').
@@ -5011,7 +5056,9 @@ helptags_one (
/*
* Sort the tags.
*/
- sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ if (ga.ga_data != NULL) {
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
+ }
/*
* Check for duplicates.
@@ -5779,13 +5826,14 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
switch (cmd_idx)
{
case SIGNCMD_DEFINE:
- if (STRNCMP(last, "texthl", p - last) == 0 ||
- STRNCMP(last, "linehl", p - last) == 0)
+ if (STRNCMP(last, "texthl", p - last) == 0
+ || STRNCMP(last, "linehl", p - last) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
- else if (STRNCMP(last, "icon", p - last) == 0)
+ } else if (STRNCMP(last, "icon", p - last) == 0) {
xp->xp_context = EXPAND_FILES;
- else
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
break;
case SIGNCMD_PLACE:
if (STRNCMP(last, "name", p - last) == 0)
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 6c8835b5c5..04fd88cc8d 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -2575,6 +2575,18 @@ return {
func='ex_copymove',
},
{
+ command='tcd',
+ flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_cd',
+ },
+ {
+ command='tchdir',
+ flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_cd',
+ },
+ {
command='tNext',
flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR),
addr_type=ADDR_LINES,
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 47774f5a99..5fe6209a0a 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -57,23 +57,23 @@ typedef struct scriptitem_S {
char_u *sn_name;
bool file_id_valid;
FileID file_id;
- int sn_prof_on; /* TRUE when script is/was profiled */
- int sn_pr_force; /* forceit: profile functions in this script */
- proftime_T sn_pr_child; /* time set when going into first child */
- int sn_pr_nest; /* nesting for sn_pr_child */
- /* profiling the script as a whole */
- int sn_pr_count; /* nr of times sourced */
- proftime_T sn_pr_total; /* time spent in script + children */
- proftime_T sn_pr_self; /* time spent in script itself */
- proftime_T sn_pr_start; /* time at script start */
- proftime_T sn_pr_children; /* time in children after script start */
- /* profiling the script per line */
- garray_T sn_prl_ga; /* things stored for every line */
- proftime_T sn_prl_start; /* start time for current line */
- proftime_T sn_prl_children; /* time spent in children for this line */
- proftime_T sn_prl_wait; /* wait start time for current line */
- int sn_prl_idx; /* index of line being timed; -1 if none */
- int sn_prl_execed; /* line being timed was executed */
+ bool sn_prof_on; ///< true when script is/was profiled
+ int sn_pr_force; ///< forceit: profile functions in this script
+ proftime_T sn_pr_child; ///< time set when going into first child
+ int sn_pr_nest; ///< nesting for sn_pr_child
+ // profiling the script as a whole
+ int sn_pr_count; ///< nr of times sourced
+ proftime_T sn_pr_total; ///< time spent in script + children
+ proftime_T sn_pr_self; ///< time spent in script itself
+ proftime_T sn_pr_start; ///< time at script start
+ proftime_T sn_pr_children; ///< time in children after script start
+ // profiling the script per line
+ garray_T sn_prl_ga; ///< things stored for every line
+ proftime_T sn_prl_start; ///< start time for current line
+ proftime_T sn_prl_children; ///< time spent in children for this line
+ proftime_T sn_prl_wait; ///< wait start time for current line
+ linenr_T sn_prl_idx; ///< index of line being timed; -1 if none
+ int sn_prl_execed; ///< line being timed was executed
} scriptitem_T;
static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
@@ -81,9 +81,9 @@ static garray_T script_items = {0, 0, sizeof(scriptitem_T), 4, NULL};
/* Struct used in sn_prl_ga for every line of a script. */
typedef struct sn_prl_S {
- int snp_count; /* nr of times line was executed */
- proftime_T sn_prl_total; /* time spent in a line + children */
- proftime_T sn_prl_self; /* time spent in a line itself */
+ int snp_count; ///< nr of times line was executed
+ proftime_T sn_prl_total; ///< time spent in a line + children
+ proftime_T sn_prl_self; ///< time spent in a line itself
} sn_prl_T;
/*
@@ -93,18 +93,18 @@ typedef struct sn_prl_S {
* sourcing can be done recursively.
*/
struct source_cookie {
- FILE *fp; /* opened file for sourcing */
- char_u *nextline; /* if not NULL: line that was read ahead */
- int finished; /* ":finish" used */
+ FILE *fp; ///< opened file for sourcing
+ char_u *nextline; ///< if not NULL: line that was read ahead
+ int finished; ///< ":finish" used
#if defined(USE_CRNL)
- int fileformat; /* EOL_UNKNOWN, EOL_UNIX or EOL_DOS */
- int error; /* TRUE if LF found after CR-LF */
+ int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
+ int error; ///< TRUE if LF found after CR-LF
#endif
- linenr_T breakpoint; /* next line with breakpoint or zero */
- char_u *fname; /* name of sourced file */
- int dbg_tick; /* debug_tick when breakpoint was set */
- int level; /* top nesting level of sourced file */
- vimconv_T conv; /* type of conversion */
+ linenr_T breakpoint; ///< next line with breakpoint or zero
+ char_u *fname; ///< name of sourced file
+ int dbg_tick; ///< debug_tick when breakpoint was set
+ int level; ///< top nesting level of sourced file
+ vimconv_T conv; ///< type of conversion
};
# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
@@ -144,6 +144,10 @@ void do_debug(char_u *cmd)
#define CMD_FINISH 4
#define CMD_QUIT 5
#define CMD_INTERRUPT 6
+#define CMD_BACKTRACE 7
+#define CMD_FRAME 8
+#define CMD_UP 9
+#define CMD_DOWN 10
++RedrawingDisabled; /* don't redisplay the window */
@@ -185,6 +189,7 @@ void do_debug(char_u *cmd)
ignore_script = TRUE;
}
+ xfree(cmdline);
cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
if (typeahead_saved) {
@@ -194,6 +199,7 @@ void do_debug(char_u *cmd)
ex_normal_busy = save_ex_normal_busy;
cmdline_row = msg_row;
+ msg_starthere();
if (cmdline != NULL) {
/* If this is a debug command, set "last_cmd".
* If not, reset "last_cmd".
@@ -210,8 +216,15 @@ void do_debug(char_u *cmd)
case 's': last_cmd = CMD_STEP;
tail = "tep";
break;
- case 'f': last_cmd = CMD_FINISH;
- tail = "inish";
+ case 'f':
+ last_cmd = 0;
+ if (p[1] == 'r') {
+ last_cmd = CMD_FRAME;
+ tail = "rame";
+ } else {
+ last_cmd = CMD_FINISH;
+ tail = "inish";
+ }
break;
case 'q': last_cmd = CMD_QUIT;
tail = "uit";
@@ -219,6 +232,26 @@ void do_debug(char_u *cmd)
case 'i': last_cmd = CMD_INTERRUPT;
tail = "nterrupt";
break;
+ case 'b':
+ last_cmd = CMD_BACKTRACE;
+ if (p[1] == 't') {
+ tail = "t";
+ } else {
+ tail = "acktrace";
+ }
+ break;
+ case 'w':
+ last_cmd = CMD_BACKTRACE;
+ tail = "here";
+ break;
+ case 'u':
+ last_cmd = CMD_UP;
+ tail = "p";
+ break;
+ case 'd':
+ last_cmd = CMD_DOWN;
+ tail = "own";
+ break;
default: last_cmd = 0;
}
if (last_cmd != 0) {
@@ -228,8 +261,9 @@ void do_debug(char_u *cmd)
++p;
++tail;
}
- if (ASCII_ISALPHA(*p))
+ if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {
last_cmd = 0;
+ }
}
}
@@ -259,7 +293,28 @@ void do_debug(char_u *cmd)
/* Do not repeat ">interrupt" cmd, continue stepping. */
last_cmd = CMD_STEP;
break;
+ case CMD_BACKTRACE:
+ do_showbacktrace(cmd);
+ continue;
+ case CMD_FRAME:
+ if (*p == NUL) {
+ do_showbacktrace(cmd);
+ } else {
+ p = skipwhite(p);
+ do_setdebugtracelevel(p);
+ }
+ continue;
+ case CMD_UP:
+ debug_backtrace_level++;
+ do_checkbacktracelevel();
+ continue;
+ case CMD_DOWN:
+ debug_backtrace_level--;
+ do_checkbacktracelevel();
+ continue;
}
+ // Going out reset backtrace_level
+ debug_backtrace_level = 0;
break;
}
@@ -269,10 +324,8 @@ void do_debug(char_u *cmd)
(void)do_cmdline(cmdline, getexline, NULL,
DOCMD_VERBOSE|DOCMD_EXCRESET);
debug_break_level = n;
-
- xfree(cmdline);
}
- lines_left = Rows - 1;
+ lines_left = (int)(Rows - 1);
}
xfree(cmdline);
@@ -281,7 +334,7 @@ void do_debug(char_u *cmd)
redraw_all_later(NOT_VALID);
need_wait_return = FALSE;
msg_scroll = save_msg_scroll;
- lines_left = Rows - 1;
+ lines_left = (int)(Rows - 1);
State = save_State;
did_emsg = save_did_emsg;
cmd_silent = save_cmd_silent;
@@ -294,6 +347,78 @@ void do_debug(char_u *cmd)
debug_did_msg = TRUE;
}
+static int get_maxbacktrace_level(void)
+{
+ int maxbacktrace = 0;
+
+ if (sourcing_name != NULL) {
+ char *p = (char *)sourcing_name;
+ char *q;
+ while ((q = strstr(p, "..")) != NULL) {
+ p = q + 2;
+ maxbacktrace++;
+ }
+ }
+ return maxbacktrace;
+}
+
+static void do_setdebugtracelevel(char_u *arg)
+{
+ int level = atoi((char *)arg);
+ if (*arg == '+' || level < 0) {
+ debug_backtrace_level += level;
+ } else {
+ debug_backtrace_level = level;
+ }
+
+ do_checkbacktracelevel();
+}
+
+static void do_checkbacktracelevel(void)
+{
+ if (debug_backtrace_level < 0) {
+ debug_backtrace_level = 0;
+ MSG(_("frame is zero"));
+ } else {
+ int max = get_maxbacktrace_level();
+ if (debug_backtrace_level > max) {
+ debug_backtrace_level = max;
+ smsg(_("frame at highest level: %d"), max);
+ }
+ }
+}
+
+static void do_showbacktrace(char_u *cmd)
+{
+ if (sourcing_name != NULL) {
+ int i = 0;
+ int max = get_maxbacktrace_level();
+ char *cur = (char *)sourcing_name;
+ while (!got_int) {
+ char *next = strstr(cur, "..");
+ if (next != NULL) {
+ *next = NUL;
+ }
+ if (i == max - debug_backtrace_level) {
+ smsg("->%d %s", max - i, cur);
+ } else {
+ smsg(" %d %s", max - i, cur);
+ }
+ i++;
+ if (next == NULL) {
+ break;
+ }
+ *next = '.';
+ cur = next + 2;
+ }
+ }
+ if (sourcing_lnum != 0) {
+ smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
+ } else {
+ smsg(_("cmd: %s"), cmd);
+ }
+}
+
/*
* ":debug".
*/
@@ -392,12 +517,12 @@ int dbg_check_skipped(exarg_T *eap)
* This is a grow-array of structs.
*/
struct debuggy {
- int dbg_nr; /* breakpoint number */
- int dbg_type; /* DBG_FUNC or DBG_FILE */
- char_u *dbg_name; /* function or file name */
- regprog_T *dbg_prog; /* regexp program */
- linenr_T dbg_lnum; /* line number in function or file */
- int dbg_forceit; /* ! used */
+ int dbg_nr; ///< breakpoint number
+ int dbg_type; ///< DBG_FUNC or DBG_FILE
+ char_u *dbg_name; ///< function or file name
+ regprog_T *dbg_prog; ///< regexp program
+ linenr_T dbg_lnum; ///< line number in function or file
+ int dbg_forceit; ///< ! used
};
static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
@@ -432,14 +557,12 @@ dbg_parsearg (
bp = &DEBUGGY(gap, gap->ga_len);
- /* Find "func" or "file". */
- if (STRNCMP(p, "func", 4) == 0)
+ // Find "func" or "file".
+ if (STRNCMP(p, "func", 4) == 0) {
bp->dbg_type = DBG_FUNC;
- else if (STRNCMP(p, "file", 4) == 0)
+ } else if (STRNCMP(p, "file", 4) == 0) {
bp->dbg_type = DBG_FILE;
- else if (
- gap != &prof_ga &&
- STRNCMP(p, "here", 4) == 0) {
+ } else if (gap != &prof_ga && STRNCMP(p, "here", 4) == 0) {
if (curbuf->b_ffname == NULL) {
EMSG(_(e_noname));
return FAIL;
@@ -452,16 +575,15 @@ dbg_parsearg (
}
p = skipwhite(p + 4);
- /* Find optional line number. */
- if (here)
+ // Find optional line number.
+ if (here) {
bp->dbg_lnum = curwin->w_cursor.lnum;
- else if (
- gap != &prof_ga &&
- ascii_isdigit(*p)) {
+ } else if (gap != &prof_ga && ascii_isdigit(*p)) {
bp->dbg_lnum = getdigits_long(&p);
p = skipwhite(p);
- } else
+ } else {
bp->dbg_lnum = 0;
+ }
/* Find the function or file name. Don't accept a function name with (). */
if ((!here && *p == NUL)
@@ -563,13 +685,14 @@ void ex_breakdel(exarg_T *eap)
}
if (ascii_isdigit(*eap->arg)) {
- /* ":breakdel {nr}" */
- nr = atol((char *)eap->arg);
- for (int i = 0; i < gap->ga_len; ++i)
+ // ":breakdel {nr}"
+ nr = atoi((char *)eap->arg);
+ for (int i = 0; i < gap->ga_len; ++i) {
if (DEBUGGY(gap, i).dbg_nr == nr) {
todel = i;
break;
}
+ }
} else if (*eap->arg == '*') {
todel = 0;
del_all = TRUE;
@@ -602,11 +725,13 @@ void ex_breakdel(exarg_T *eap)
--gap->ga_len;
if (todel < gap->ga_len)
memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
- (gap->ga_len - todel) * sizeof(struct debuggy));
- if (eap->cmdidx == CMD_breakdel)
+ (size_t)(gap->ga_len - todel) * sizeof(struct debuggy));
+ if (eap->cmdidx == CMD_breakdel) {
++debug_tick;
- if (!del_all)
+ }
+ if (!del_all) {
break;
+ }
}
/* If all breakpoints were removed clear the array. */
@@ -697,14 +822,13 @@ debuggy_find (
/* Skip entries that are not useful or are for a line that is beyond
* an already found breakpoint. */
bp = &DEBUGGY(gap, i);
- if (((bp->dbg_type == DBG_FILE) == file && (
- gap == &prof_ga ||
- (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum))))) {
- /*
- * Save the value of got_int and reset it. We don't want a
- * previous interruption cancel matching, only hitting CTRL-C
- * while matching should abort it.
- */
+ if (((bp->dbg_type == DBG_FILE) == file
+ && (gap == &prof_ga
+ || (bp->dbg_lnum > after
+ && (lnum == 0 || bp->dbg_lnum < lnum))))) {
+ // Save the value of got_int and reset it. We don't want a
+ // previous interruption cancel matching, only hitting CTRL-C
+ // while matching should abort it.
prev_got_int = got_int;
got_int = FALSE;
if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) {
@@ -810,8 +934,8 @@ void ex_pydo3(exarg_T *eap)
/* Command line expansion for :profile. */
static enum {
- PEXP_SUBCMD, /* expand :profile sub-commands */
- PEXP_FUNC /* expand :profile func {funcname} */
+ PEXP_SUBCMD, ///< expand :profile sub-commands
+ PEXP_FUNC ///< expand :profile func {funcname}
} pexpand_what;
static char *pexpand_cmds[] = {
@@ -892,7 +1016,7 @@ static void profile_reset(void)
for (int id = 1; id <= script_items.ga_len; id++) {
scriptitem_T *si = &SCRIPT_ITEM(id);
if (si->sn_prof_on) {
- si->sn_prof_on = 0;
+ si->sn_prof_on = false;
si->sn_pr_force = 0;
si->sn_pr_child = profile_zero();
si->sn_pr_nest = 0;
@@ -949,7 +1073,7 @@ static void profile_init(scriptitem_T *si)
ga_init(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
si->sn_prl_idx = -1;
- si->sn_prof_on = TRUE;
+ si->sn_prof_on = true;
si->sn_pr_nest = 0;
}
@@ -1242,28 +1366,31 @@ static void add_bufnum(int *bufnrs, int *bufnump, int nr)
*bufnump = *bufnump + 1;
}
-/*
- * Return TRUE if any buffer was changed and cannot be abandoned.
- * That changed buffer becomes the current buffer.
- */
-int
-check_changed_any (
- int hidden /* Only check hidden buffers */
-)
+/// Check if any buffer was changed and cannot be abandoned.
+/// That changed buffer becomes the current buffer.
+/// When "unload" is true the current buffer is unloaded instead of making it
+/// hidden. This is used for ":q!".
+///
+/// @param[in] hidden specifies whether to check only hidden buffers.
+/// @param[in] unload specifies whether to unload, instead of hide, the buffer.
+///
+/// @returns true if any buffer is changed and cannot be abandoned
+int check_changed_any(bool hidden, bool unload)
{
- int ret = FALSE;
+ bool ret = false;
int save;
int i;
int bufnum = 0;
- int bufcount = 0;
+ size_t bufcount = 0;
int *bufnrs;
FOR_ALL_BUFFERS(buf) {
++bufcount;
}
- if (bufcount == 0)
- return FALSE;
+ if (bufcount == 0) {
+ return false;
+ }
bufnrs = xmalloc(sizeof(*bufnrs) * bufcount);
@@ -1347,9 +1474,10 @@ check_changed_any (
}
buf_found:
- /* Open the changed buffer in the current window. */
- if (buf != curbuf)
- set_curbuf(buf, DOBUF_GOTO);
+ // Open the changed buffer in the current window.
+ if (buf != curbuf) {
+ set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
+ }
theend:
xfree(bufnrs);
@@ -1520,7 +1648,7 @@ do_arglist (
didone = TRUE;
xfree(ARGLIST[match].ae_fname);
memmove(ARGLIST + match, ARGLIST + match + 1,
- (ARGCOUNT - match - 1) * sizeof(aentry_T));
+ (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T));
--ALIST(curwin)->al_ga.ga_len;
if (curwin->w_arg_idx > match)
--curwin->w_arg_idx;
@@ -1537,9 +1665,7 @@ do_arglist (
int i = expand_wildcards(new_ga.ga_len, (char_u **)new_ga.ga_data,
&exp_count, &exp_files, EW_DIR|EW_FILE|EW_ADDSLASH|EW_NOTFOUND);
ga_clear(&new_ga);
- if (i == FAIL)
- return FAIL;
- if (exp_count == 0) {
+ if (i == FAIL || exp_count == 0) {
EMSG(_(e_nomatch));
return FAIL;
}
@@ -1702,10 +1828,11 @@ void ex_argument(exarg_T *eap)
{
int i;
- if (eap->addr_count > 0)
- i = eap->line2 - 1;
- else
+ if (eap->addr_count > 0) {
+ i = (int)eap->line2 - 1;
+ } else {
i = curwin->w_arg_idx;
+ }
do_argfile(eap, i);
}
@@ -1844,22 +1971,25 @@ void ex_argadd(exarg_T *eap)
void ex_argdelete(exarg_T *eap)
{
if (eap->addr_count > 0) {
- /* ":1,4argdel": Delete all arguments in the range. */
- if (eap->line2 > ARGCOUNT)
+ // ":1,4argdel": Delete all arguments in the range.
+ if (eap->line2 > ARGCOUNT) {
eap->line2 = ARGCOUNT;
- int n = eap->line2 - eap->line1 + 1;
- if (*eap->arg != NUL || n <= 0)
+ }
+ linenr_T n = eap->line2 - eap->line1 + 1;
+ if (*eap->arg != NUL || n <= 0) {
EMSG(_(e_invarg));
- else {
- for (int i = eap->line1; i <= eap->line2; ++i)
+ } else {
+ for (linenr_T i = eap->line1; i <= eap->line2; ++i) {
xfree(ARGLIST[i - 1].ae_fname);
+ }
memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
- (size_t)((ARGCOUNT - eap->line2) * sizeof(aentry_T)));
- ALIST(curwin)->al_ga.ga_len -= n;
- if (curwin->w_arg_idx >= eap->line2)
- curwin->w_arg_idx -= n;
- else if (curwin->w_arg_idx > eap->line1)
- curwin->w_arg_idx = eap->line1;
+ (size_t)(ARGCOUNT - eap->line2) * sizeof(aentry_T));
+ ALIST(curwin)->al_ga.ga_len -= (int)n;
+ if (curwin->w_arg_idx >= eap->line2) {
+ curwin->w_arg_idx -= (int)n;
+ } else if (curwin->w_arg_idx > eap->line1) {
+ curwin->w_arg_idx = (int)eap->line1;
+ }
}
} else if (*eap->arg == NUL)
EMSG(_(e_argreq));
@@ -1909,7 +2039,7 @@ void ex_listdo(exarg_T *eap)
}
break;
case CMD_argdo:
- i = eap->line1 - 1;
+ i = (int)eap->line1 - 1;
break;
default:
break;
@@ -1932,8 +2062,8 @@ void ex_listdo(exarg_T *eap)
if (buf != NULL) {
goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
}
- } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
- eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
+ } else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
qf_size = qf_get_size(eap);
assert(eap->line1 >= 0);
if (qf_size == 0 || (size_t)eap->line1 > qf_size) {
@@ -1942,10 +2072,11 @@ void ex_listdo(exarg_T *eap)
ex_cc(eap);
buf = curbuf;
- i = eap->line1 - 1;
+ i = (int)eap->line1 - 1;
if (eap->addr_count <= 0) {
// Default to all quickfix/location list entries.
- eap->line2 = qf_size;
+ assert(qf_size < MAXLNUM);
+ eap->line2 = (linenr_T)qf_size;
}
}
} else {
@@ -2034,8 +2165,8 @@ void ex_listdo(exarg_T *eap)
}
}
- if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
- eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
assert(i >= 0);
if ((size_t)i >= qf_size || i >= eap->line2) {
break;
@@ -2098,7 +2229,7 @@ alist_add_list (
after = ARGCOUNT;
if (after < ARGCOUNT)
memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
- (ARGCOUNT - after) * sizeof(aentry_T));
+ (size_t)(ARGCOUNT - after) * sizeof(aentry_T));
for (int i = 0; i < count; ++i) {
ARGLIST[after + i].ae_fname = files[i];
ARGLIST[after + i].ae_fnum = buflist_add(files[i], BLN_LISTED);
@@ -2367,8 +2498,9 @@ static FILE *fopen_noinh_readbin(char *filename)
# ifdef HAVE_FD_CLOEXEC
{
int fdflags = fcntl(fd_tmp, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
- fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
+ (void)fcntl(fd_tmp, F_SETFD, fdflags | FD_CLOEXEC);
+ }
}
# endif
@@ -2571,7 +2703,7 @@ do_source (
while (script_items.ga_len < current_SID) {
++script_items.ga_len;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
- SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
+ SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false;
}
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
@@ -3162,27 +3294,30 @@ static char_u *get_mess_env(void)
*/
void set_lang_var(void)
{
- char_u *loc;
+ const char *loc;
# ifdef HAVE_GET_LOCALE_VAL
- loc = (char_u *)get_locale_val(LC_CTYPE);
+ loc = get_locale_val(LC_CTYPE);
# else
- /* setlocale() not supported: use the default value */
- loc = (char_u *)"C";
+ // setlocale() not supported: use the default value
+ loc = "C";
# endif
set_vim_var_string(VV_CTYPE, loc, -1);
/* When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
* back to LC_CTYPE if it's empty. */
# ifdef HAVE_WORKING_LIBINTL
- loc = get_mess_env();
+ loc = (char *) get_mess_env();
+# elif defined(LC_MESSAGES)
+ loc = get_locale_val(LC_MESSAGES);
# else
- loc = (char_u *)get_locale_val(LC_MESSAGES);
+ // In Windows LC_MESSAGES is not defined fallback to LC_CTYPE
+ loc = get_locale_val(LC_CTYPE);
# endif
set_vim_var_string(VV_LANG, loc, -1);
# ifdef HAVE_GET_LOCALE_VAL
- loc = (char_u *)get_locale_val(LC_TIME);
+ loc = get_locale_val(LC_TIME);
# endif
set_vim_var_string(VV_LC_TIME, loc, -1);
}
@@ -3386,8 +3521,8 @@ static void script_host_execute(char *name, exarg_T *eap)
// script
list_append_string(args, script ? script : eap->arg, -1);
// current range
- list_append_number(args, eap->line1);
- list_append_number(args, eap->line2);
+ list_append_number(args, (int)eap->line1);
+ list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute", args);
}
@@ -3403,16 +3538,16 @@ static void script_host_execute_file(char *name, exarg_T *eap)
// filename
list_append_string(args, buffer, -1);
// current range
- list_append_number(args, eap->line1);
- list_append_number(args, eap->line2);
+ list_append_number(args, (int)eap->line1);
+ list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute_file", args);
}
static void script_host_do_range(char *name, exarg_T *eap)
{
list_T *args = list_alloc();
- list_append_number(args, eap->line1);
- list_append_number(args, eap->line2);
+ list_append_number(args, (int)eap->line1);
+ list_append_number(args, (int)eap->line2);
list_append_string(args, eap->arg, -1);
(void)eval_call_provider(name, "do_range", args);
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 3a24f194c1..870284a0f7 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1654,16 +1654,15 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* If we got a line, but no command, then go to the line.
* If we find a '|' or '\n' we set ea.nextcmd.
*/
- if (*ea.cmd == NUL || *ea.cmd == '"' ||
- (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) {
- /*
- * strange vi behaviour:
- * ":3" jumps to line 3
- * ":3|..." prints line 3
- * ":|" prints current line
- */
- if (ea.skip) /* skip this if inside :if */
+ if (*ea.cmd == NUL || *ea.cmd == '"'
+ || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) {
+ // strange vi behaviour:
+ // ":3" jumps to line 3
+ // ":3|..." prints line 3
+ // ":|" prints current line
+ if (ea.skip) { // skip this if inside :if
goto doend;
+ }
if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) {
ea.cmdidx = CMD_print;
ea.argt = RANGE | COUNT | TRLBAR;
@@ -1826,9 +1825,10 @@ static char_u * do_one_cmd(char_u **cmdlinep,
correct_range(&ea);
- if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy) {
- /* Put the first line at the start of a closed fold, put the last line
- * at the end of a closed fold. */
+ if (((ea.argt & WHOLEFOLD) || ea.addr_count >= 2) && !global_busy
+ && ea.addr_type == ADDR_LINES) {
+ // Put the first line at the start of a closed fold, put the last line
+ // at the end of a closed fold.
(void)hasFolding(ea.line1, &ea.line1, NULL);
(void)hasFolding(ea.line2, NULL, &ea.line2);
}
@@ -2823,10 +2823,11 @@ set_one_cmd_context (
}
}
- /* no arguments allowed */
- if (!(ea.argt & EXTRA) && *arg != NUL &&
- vim_strchr((char_u *)"|\"", *arg) == NULL)
+ // no arguments allowed
+ if (!(ea.argt & EXTRA) && *arg != NUL
+ && vim_strchr((char_u *)"|\"", *arg) == NULL) {
return NULL;
+ }
/* Find start of last argument (argument just before cursor): */
p = buff;
@@ -2958,8 +2959,11 @@ set_one_cmd_context (
case CMD_chdir:
case CMD_lcd:
case CMD_lchdir:
- if (xp->xp_context == EXPAND_FILES)
+ case CMD_tcd:
+ case CMD_tchdir:
+ if (xp->xp_context == EXPAND_FILES) {
xp->xp_context = EXPAND_DIRECTORIES;
+ }
break;
case CMD_help:
xp->xp_context = EXPAND_HELP;
@@ -4553,7 +4557,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
char_u *rep_buf = NULL;
garray_T *gap;
- replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE);
+ replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, false,
+ CPO_TO_CPO_FLAGS);
if (rep_buf == NULL) {
/* Can't replace termcodes - try using the string as is */
rep_buf = vim_strsave(rep);
@@ -4767,14 +4772,15 @@ static void uc_list(char_u *name, size_t name_len)
IObuff[len++] = ' ';
} while (len < 11);
- /* Address Type */
- for (j = 0; addr_type_complete[j].expand != -1; ++j)
- if (addr_type_complete[j].expand != ADDR_LINES &&
- addr_type_complete[j].expand == cmd->uc_addr_type) {
+ // Address Type
+ for (j = 0; addr_type_complete[j].expand != -1; j++) {
+ if (addr_type_complete[j].expand != ADDR_LINES
+ && addr_type_complete[j].expand == cmd->uc_addr_type) {
STRCPY(IObuff + len, addr_type_complete[j].name);
len += (int)STRLEN(IObuff + len);
break;
}
+ }
do {
IObuff[len++] = ' ';
@@ -5499,7 +5505,8 @@ int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt,
int *addr_type_arg)
{
int i, a, b;
- for (i = 0; addr_type_complete[i].expand != -1; ++i) {
+
+ for (i = 0; addr_type_complete[i].expand != -1; i++) {
a = (int)STRLEN(addr_type_complete[i].name) == vallen;
b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0;
if (a && b) {
@@ -5510,8 +5517,8 @@ int parse_addr_type_arg(char_u *value, int vallen, uint32_t *argt,
if (addr_type_complete[i].expand == -1) {
char_u *err = value;
- for (i = 0; err[i] == NUL || !ascii_iswhite(err[i]); i++)
- ;
+
+ for (i = 0; err[i] != NUL && !ascii_iswhite(err[i]); i++) {}
err[i] = NUL;
EMSG2(_("E180: Invalid address type value: %s"), err);
return FAIL;
@@ -5648,12 +5655,13 @@ static void ex_quit(exarg_T *eap)
wp = curwin;
}
- apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
- /* Refuse to quit when locked or when the buffer in the last window is
- * being closed (can only happen in autocommands). */
- if (curbuf_locked() ||
- (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_closing))
+ apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, curbuf);
+ // Refuse to quit when locked or when the buffer in the last window is
+ // being closed (can only happen in autocommands).
+ if (curbuf_locked()
+ || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_closing)) {
return;
+ }
/*
@@ -5663,10 +5671,10 @@ static void ex_quit(exarg_T *eap)
exiting = TRUE;
if ((!P_HID(curbuf)
&& check_changed(curbuf, (p_awa ? CCGD_AW : 0)
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD))
- || check_more(TRUE, eap->forceit) == FAIL
- || (only_one_window() && check_changed_any(eap->forceit))) {
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ || check_more(true, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, true))) {
not_exiting();
} else {
// quit last window
@@ -5715,9 +5723,10 @@ static void ex_quit_all(exarg_T *eap)
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
return;
- exiting = TRUE;
- if (eap->forceit || !check_changed_any(FALSE))
+ exiting = true;
+ if (eap->forceit || !check_changed_any(false, false)) {
getout(0);
+ }
not_exiting();
}
@@ -6002,21 +6011,22 @@ static void ex_exit(exarg_T *eap)
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
return;
- /*
- * if more files or windows we won't exit
- */
- if (check_more(FALSE, eap->forceit) == OK && only_one_window())
- exiting = TRUE;
- if ( ((eap->cmdidx == CMD_wq
- || curbufIsChanged())
- && do_write(eap) == FAIL)
- || check_more(TRUE, eap->forceit) == FAIL
- || (only_one_window() && check_changed_any(eap->forceit))) {
+ // if more files or windows we won't exit
+ if (check_more(false, eap->forceit) == OK && only_one_window()) {
+ exiting = true;
+ }
+ if (((eap->cmdidx == CMD_wq
+ || curbufIsChanged())
+ && do_write(eap) == FAIL)
+ || check_more(true, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, false))) {
not_exiting();
} else {
- if (only_one_window()) /* quit last window, exit Vim */
+ if (only_one_window()) {
+ // quit last window, exit Vim
getout(0);
- /* Quit current window, may free the buffer. */
+ }
+ // Quit current window, may free the buffer.
win_close(curwin, !P_HID(curwin->w_buffer));
}
}
@@ -6290,10 +6300,8 @@ void ex_splitview(exarg_T *eap)
if (eap->cmdidx == CMD_tabedit
|| eap->cmdidx == CMD_tabfind
|| eap->cmdidx == CMD_tabnew) {
- if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab
- : eap->addr_count == 0 ? 0
- : (int)eap->line2 + 1) != FAIL) {
- apply_autocmds(EVENT_TABNEW, eap->arg, eap->arg, FALSE, curbuf);
+ if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab : eap->addr_count == 0
+ ? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) {
do_exedit(eap, old_curwin);
apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, FALSE, curbuf);
@@ -6816,36 +6824,55 @@ void free_cd_dir(void)
#endif
-/*
- * Deal with the side effects of changing the current directory.
- * When "local" is TRUE then this was after an ":lcd" command.
- */
-void post_chdir(int local)
+/// Deal with the side effects of changing the current directory.
+///
+/// @param scope Scope of the function call (global, tab or window).
+void post_chdir(CdScope scope)
{
+ // The local directory of the current window is always overwritten.
xfree(curwin->w_localdir);
curwin->w_localdir = NULL;
- if (local) {
- /* If still in global directory, need to remember current
- * directory as global directory. */
- if (globaldir == NULL && prev_dir != NULL)
+
+ // Overwrite the local directory of the current tab page for `cd` and `tcd`
+ if (scope >= kCdScopeTab) {
+ xfree(curtab->localdir);
+ curtab->localdir = NULL;
+ }
+
+ if (scope < kCdScopeGlobal) {
+ // If still in global directory, need to remember current directory as
+ // global directory.
+ if (globaldir == NULL && prev_dir != NULL) {
globaldir = vim_strsave(prev_dir);
- /* Remember this local directory for the window. */
- if (os_dirname(NameBuff, MAXPATHL) == OK)
- curwin->w_localdir = vim_strsave(NameBuff);
- } else {
- /* We are now in the global directory, no need to remember its
- * name. */
+ }
+ }
+
+ switch (scope) {
+ case kCdScopeGlobal:
+ // We are now in the global directory, no need to remember its name.
xfree(globaldir);
globaldir = NULL;
+ break;
+ case kCdScopeTab:
+ // Remember this local directory for the tab page.
+ if (os_dirname(NameBuff, MAXPATHL) == OK) {
+ curtab->localdir = vim_strsave(NameBuff);
+ }
+ break;
+ case kCdScopeWindow:
+ // Remember this local directory for the window.
+ if (os_dirname(NameBuff, MAXPATHL) == OK) {
+ curwin->w_localdir = vim_strsave(NameBuff);
+ }
+ break;
}
shorten_fnames(TRUE);
}
-/*
- * ":cd", ":lcd", ":chdir" and ":lchdir".
- */
+
+/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`.
void ex_cd(exarg_T *eap)
{
char_u *new_dir;
@@ -6886,10 +6913,25 @@ void ex_cd(exarg_T *eap)
new_dir = NameBuff;
}
#endif
- if (new_dir == NULL || vim_chdir(new_dir))
+ if (vim_chdir(new_dir)) {
EMSG(_(e_failed));
- else {
- post_chdir(eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir);
+ } else {
+ CdScope scope = kCdScopeGlobal; // Depends on command invoked
+
+ switch (eap->cmdidx) {
+ case CMD_tcd:
+ case CMD_tchdir:
+ scope = kCdScopeTab;
+ break;
+ case CMD_lcd:
+ case CMD_lchdir:
+ scope = kCdScopeWindow;
+ break;
+ default:
+ break;
+ }
+
+ post_chdir(scope);
/* Echo the new current directory if the command was typed. */
if (KeyTyped || p_verbose >= 5)
@@ -7033,9 +7075,9 @@ static void ex_operators(exarg_T *eap)
oa.start.lnum = eap->line1;
oa.end.lnum = eap->line2;
oa.line_count = eap->line2 - eap->line1 + 1;
- oa.motion_type = MLINE;
- virtual_op = FALSE;
- if (eap->cmdidx != CMD_yank) { /* position cursor for undo */
+ oa.motion_type = kMTLineWise;
+ virtual_op = false;
+ if (eap->cmdidx != CMD_yank) { // position cursor for undo
setpcmark();
curwin->w_cursor.lnum = eap->line1;
beginline(BL_SOL | BL_FIX);
@@ -7423,10 +7465,10 @@ static int mksession_nl = FALSE; /* use NL only in put_eol() */
static void ex_mkrc(exarg_T *eap)
{
FILE *fd;
- int failed = FALSE;
- int view_session = FALSE;
- int using_vdir = FALSE; /* using 'viewdir'? */
- char_u *viewFile = NULL;
+ int failed = false;
+ int view_session = false;
+ int using_vdir = false; // using 'viewdir'?
+ char *viewFile = NULL;
unsigned *flagp;
if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) {
@@ -7437,32 +7479,34 @@ static void ex_mkrc(exarg_T *eap)
* short file name when 'acd' is set, that is checked later. */
did_lcd = FALSE;
- char_u *fname;
- /* ":mkview" or ":mkview 9": generate file name with 'viewdir' */
+ char *fname;
+ // ":mkview" or ":mkview 9": generate file name with 'viewdir'
if (eap->cmdidx == CMD_mkview
&& (*eap->arg == NUL
|| (ascii_isdigit(*eap->arg) && eap->arg[1] == NUL))) {
- eap->forceit = TRUE;
- fname = (char_u *)get_view_file(*eap->arg);
- if (fname == NULL)
+ eap->forceit = true;
+ fname = get_view_file(*eap->arg);
+ if (fname == NULL) {
return;
+ }
viewFile = fname;
- using_vdir = TRUE;
- } else if (*eap->arg != NUL)
- fname = eap->arg;
- else if (eap->cmdidx == CMD_mkvimrc)
- fname = (char_u *)VIMRC_FILE;
- else if (eap->cmdidx == CMD_mksession)
- fname = (char_u *)SESSION_FILE;
- else
- fname = (char_u *)EXRC_FILE;
+ using_vdir = true;
+ } else if (*eap->arg != NUL) {
+ fname = (char *) eap->arg;
+ } else if (eap->cmdidx == CMD_mkvimrc) {
+ fname = VIMRC_FILE;
+ } else if (eap->cmdidx == CMD_mksession) {
+ fname = SESSION_FILE;
+ } else {
+ fname = EXRC_FILE;
+ }
/* When using 'viewdir' may have to create the directory. */
if (using_vdir && !os_isdir(p_vdir)) {
vim_mkdir_emsg(p_vdir, 0755);
}
- fd = open_exfile(fname, eap->forceit, WRITEBIN);
+ fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN);
if (fd != NULL) {
if (eap->cmdidx == CMD_mkview)
flagp = &vop_flags;
@@ -7506,8 +7550,9 @@ static void ex_mkrc(exarg_T *eap)
|| os_chdir((char *)dirnow) != 0)
*dirnow = NUL;
if (*dirnow != NUL && (ssop_flags & SSOP_SESDIR)) {
- if (vim_chdirfile(fname) == OK)
- shorten_fnames(TRUE);
+ if (vim_chdirfile((char_u *) fname) == OK) {
+ shorten_fnames(true);
+ }
} else if (*dirnow != NUL
&& (ssop_flags & SSOP_CURDIR) && globaldir != NULL) {
if (os_chdir((char *)globaldir) == 0)
@@ -7552,15 +7597,14 @@ static void ex_mkrc(exarg_T *eap)
failed |= fclose(fd);
- if (failed)
+ if (failed) {
EMSG(_(e_write));
- else if (eap->cmdidx == CMD_mksession) {
- /* successful session write - set this_session var */
- char_u *tbuf;
-
- tbuf = xmalloc(MAXPATHL);
- if (vim_FullName((char *)fname, (char *)tbuf, MAXPATHL, FALSE) == OK)
+ } else if (eap->cmdidx == CMD_mksession) {
+ // successful session write - set this_session var
+ char *const tbuf = xmalloc(MAXPATHL);
+ if (vim_FullName(fname, tbuf, MAXPATHL, false) == OK) {
set_vim_var_string(VV_THIS_SESSION, tbuf, -1);
+ }
xfree(tbuf);
}
#ifdef MKSESSION_NL
@@ -9145,16 +9189,15 @@ static char *get_view_file(int c)
*/
int put_eol(FILE *fd)
{
- if (
-#ifdef USE_CRNL
- (
-# ifdef MKSESSION_NL
- !mksession_nl &&
-# endif
- (putc('\r', fd) < 0)) ||
+#if defined(USE_CRNL) && defined(MKSESSION_NL)
+ if ((!mksession_nl && putc('\r', fd) < 0) || putc('\n', fd) < 0) {
+#elif defined(USE_CRNL)
+ if (putc('\r', fd) < 0 || putc('\n', fd) < 0) {
+#else
+ if (putc('\n', fd) < 0) {
#endif
- (putc('\n', fd) < 0))
return FAIL;
+ }
return OK;
}
@@ -9456,12 +9499,14 @@ static void ex_folddo(exarg_T *eap)
static void ex_terminal(exarg_T *eap)
{
- // We will call termopen() with ['shell'] if not given a {cmd}.
- char *name = (char *)p_sh;
+ char *name = (char *)p_sh; // Default to 'shell' if {cmd} is not given.
+ bool mustfree = false;
char *lquote = "['";
char *rquote = "']";
+
if (*eap->arg != NUL) {
name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
+ mustfree = true;
lquote = rquote = "\"";
}
@@ -9471,7 +9516,7 @@ static void ex_terminal(exarg_T *eap)
eap->forceit==TRUE ? "!" : "", lquote, name, rquote);
do_cmdline_cmd(ex_cmd);
- if (name != (char *)p_sh) {
+ if (mustfree) {
xfree(name);
}
}
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index a5a4edbbbf..dbfc64e2f1 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -19,6 +19,20 @@
#define EXMODE_NORMAL 1
#define EXMODE_VIM 2
+/// The scope of a working-directory command like `:cd`.
+///
+/// Scopes are enumerated from lowest to highest. When adding a scope make sure
+/// to update all functions using scopes as well, such as the implementation of
+/// `getcwd()`. When using scopes as limits (e.g. in loops) don't use the scopes
+/// directly, use `MIN_CD_SCOPE` and `MAX_CD_SCOPE` instead.
+typedef enum {
+ kCdScopeWindow, ///< Affects one window.
+ kCdScopeTab, ///< Affects one tab page.
+ kCdScopeGlobal, ///< Affects the entire instance of Neovim.
+} CdScope;
+#define MIN_CD_SCOPE kCdScopeWindow
+#define MAX_CD_SCOPE kCdScopeGlobal
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_docmd.h.generated.h"
#endif
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index bf67047ae8..82d4c2b2d5 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -378,7 +378,7 @@ char_u *get_exception_string(void *value, int type, char_u *cmdname, int *should
char_u *p, *val;
if (type == ET_ERROR) {
- *should_free = FALSE;
+ *should_free = true;
mesg = ((struct msglist *)value)->throw_msg;
if (cmdname != NULL && *cmdname != NUL) {
size_t cmdlen = STRLEN(cmdname);
@@ -403,14 +403,15 @@ char_u *get_exception_string(void *value, int type, char_u *cmdname, int *should
&& (p[3] == ':'
|| (ascii_isdigit(p[3])
&& p[4] == ':')))))) {
- if (*p == NUL || p == mesg)
- STRCAT(val, mesg); /* 'E123' missing or at beginning */
- else {
- /* '"filename" E123: message text' */
- if (mesg[0] != '"' || p-2 < &mesg[1] ||
- p[-2] != '"' || p[-1] != ' ')
- /* "E123:" is part of the file name. */
+ if (*p == NUL || p == mesg) {
+ STRCAT(val, mesg); // 'E123' missing or at beginning
+ } else {
+ // '"filename" E123: message text'
+ if (mesg[0] != '"' || p-2 < &mesg[1]
+ || p[-2] != '"' || p[-1] != ' ') {
+ // "E123:" is part of the file name.
continue;
+ }
STRCAT(val, p);
p[-2] = NUL;
@@ -569,17 +570,19 @@ static void catch_exception(except_T *excp)
{
excp->caught = caught_stack;
caught_stack = excp;
- set_vim_var_string(VV_EXCEPTION, excp->value, -1);
+ set_vim_var_string(VV_EXCEPTION, (char *) excp->value, -1);
if (*excp->throw_name != NUL) {
- if (excp->throw_lnum != 0)
+ if (excp->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE, _("%s, line %" PRId64),
- excp->throw_name, (int64_t)excp->throw_lnum);
- else
+ excp->throw_name, (int64_t)excp->throw_lnum);
+ } else {
vim_snprintf((char *)IObuff, IOSIZE, "%s", excp->throw_name);
- set_vim_var_string(VV_THROWPOINT, IObuff, -1);
- } else
- /* throw_name not set on an exception from a command that was typed. */
+ }
+ set_vim_var_string(VV_THROWPOINT, (char *) IObuff, -1);
+ } else {
+ // throw_name not set on an exception from a command that was typed.
set_vim_var_string(VV_THROWPOINT, NULL, -1);
+ }
if (p_verbose >= 13 || debug_break_level > 0) {
int save_msg_silent = msg_silent;
@@ -614,20 +617,22 @@ static void finish_exception(except_T *excp)
EMSG(_(e_internal));
caught_stack = caught_stack->caught;
if (caught_stack != NULL) {
- set_vim_var_string(VV_EXCEPTION, caught_stack->value, -1);
+ set_vim_var_string(VV_EXCEPTION, (char *) caught_stack->value, -1);
if (*caught_stack->throw_name != NUL) {
- if (caught_stack->throw_lnum != 0)
+ if (caught_stack->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE,
- _("%s, line %" PRId64), caught_stack->throw_name,
- (int64_t)caught_stack->throw_lnum);
- else
+ _("%s, line %" PRId64), caught_stack->throw_name,
+ (int64_t)caught_stack->throw_lnum);
+ } else {
vim_snprintf((char *)IObuff, IOSIZE, "%s",
- caught_stack->throw_name);
- set_vim_var_string(VV_THROWPOINT, IObuff, -1);
- } else
- /* throw_name not set on an exception from a command that was
- * typed. */
+ caught_stack->throw_name);
+ }
+ set_vim_var_string(VV_THROWPOINT, (char *) IObuff, -1);
+ } else {
+ // throw_name not set on an exception from a command that was
+ // typed.
set_vim_var_string(VV_THROWPOINT, NULL, -1);
+ }
} else {
set_vim_var_string(VV_EXCEPTION, NULL, -1);
set_vim_var_string(VV_THROWPOINT, NULL, -1);
@@ -1370,19 +1375,24 @@ void ex_catch(exarg_T *eap)
}
save_cpo = p_cpo;
p_cpo = (char_u *)"";
+ // Disable error messages, it will make current exception
+ // invalid
+ emsg_off++;
regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
- regmatch.rm_ic = FALSE;
- if (end != NULL)
+ emsg_off--;
+ regmatch.rm_ic = false;
+ if (end != NULL) {
*end = save_char;
+ }
p_cpo = save_cpo;
- if (regmatch.regprog == NULL)
+ if (regmatch.regprog == NULL) {
EMSG2(_(e_invarg2), pat);
- else {
- /*
- * Save the value of got_int and reset it. We don't want
- * a previous interruption cancel matching, only hitting
- * CTRL-C while matching should abort it.
- */
+ } else {
+ //
+ // Save the value of got_int and reset it. We don't want
+ // a previous interruption cancel matching, only hitting
+ // CTRL-C while matching should abort it.
+ //
prev_got_int = got_int;
got_int = FALSE;
caught = vim_regexec_nl(&regmatch, current_exception->value,
@@ -1556,22 +1566,21 @@ void ex_endtry(exarg_T *eap)
void *rettv = NULL;
struct condstack *cstack = eap->cstack;
- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
+ if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = (char_u *)N_("E602: :endtry without :try");
- else {
- /*
- * Don't do something after an error, interrupt or throw in the try
- * block, catch clause, or finally clause preceding this ":endtry" or
- * when an error or interrupt occurred after a ":continue", ":break",
- * ":return", or ":finish" in a try block or catch clause preceding this
- * ":endtry" or when the try block never got active (because of an
- * inactive surrounding conditional or after an error or interrupt or
- * throw) or when there is a surrounding conditional and it has been
- * 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 || did_throw ||
- !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
+ } else {
+ // Don't do something after an error, interrupt or throw in the try
+ // block, catch clause, or finally clause preceding this ":endtry" or
+ // when an error or interrupt occurred after a ":continue", ":break",
+ // ":return", or ":finish" in a try block or catch clause preceding this
+ // ":endtry" or when the try block never got active (because of an
+ // inactive surrounding conditional or after an error or interrupt or
+ // throw) or when there is a surrounding conditional and it has been
+ // 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 || did_throw
+ || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE));
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 39bff9b2ad..a4e5a4dcd7 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -289,7 +289,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
if (ccline.cmdbuff != NULL) {
// Put line in history buffer (":" and "=" only when it was typed).
- if (ccline.cmdlen && s->firstc != NUL
+ if (s->histype != HIST_INVALID
+ && ccline.cmdlen
+ && s->firstc != NUL
&& (s->some_key_typed || s->histype == HIST_SEARCH)) {
add_to_history(s->histype, ccline.cmdbuff, true,
s->histype == HIST_SEARCH ? s->firstc : NUL);
@@ -622,8 +624,8 @@ static int command_line_execute(VimState *state, int key)
// CTRL-\ e doesn't work when obtaining an expression, unless it
// is in a mapping.
if (s->c != Ctrl_N && s->c != Ctrl_G && (s->c != 'e'
- || (ccline.cmdfirstc == '=' &&
- KeyTyped))) {
+ || (ccline.cmdfirstc == '='
+ && KeyTyped))) {
vungetc(s->c);
s->c = Ctrl_BSL;
} else if (s->c == 'e') {
@@ -1130,7 +1132,7 @@ static int command_line_handle_key(CommandLineState *s)
if (!mouse_has(MOUSE_COMMAND)) {
return command_line_not_changed(s); // Ignore mouse
}
- cmdline_paste(0, true, true);
+ cmdline_paste(eval_has_provider("clipboard") ? '*' : 0, true, true);
redrawcmd();
return command_line_changed(s);
@@ -1268,7 +1270,7 @@ static int command_line_handle_key(CommandLineState *s)
case K_KPAGEUP:
case K_PAGEDOWN:
case K_KPAGEDOWN:
- if (hislen == 0 || s->firstc == NUL) {
+ if (s->histype == HIST_INVALID || hislen == 0 || s->firstc == NUL) {
// no history
return command_line_not_changed(s);
}
@@ -2424,20 +2426,17 @@ void restore_cmdline_alloc(char_u *p)
xfree(p);
}
-/*
- * paste a yank register into the command line.
- * used by CTRL-R command in command-line mode
- * insert_reg() can't be used here, because special characters from the
- * register contents will be interpreted as commands.
- *
- * return FAIL for failure, OK otherwise
- */
-static int
-cmdline_paste (
- int regname,
- int literally, /* Insert text literally instead of "as typed" */
- int remcr /* remove trailing CR */
-)
+/// Paste a yank register into the command line.
+/// Used by CTRL-R command in command-line mode.
+/// insert_reg() can't be used here, because special characters from the
+/// register contents will be interpreted as commands.
+///
+/// @param regname Register name.
+/// @param literally Insert text literally instead of "as typed".
+/// @param remcr When true, remove trailing CR.
+///
+/// @returns FAIL for failure, OK otherwise
+static bool cmdline_paste(int regname, bool literally, bool remcr)
{
long i;
char_u *arg;
@@ -3984,6 +3983,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
char_u *s, *e;
int flags = flagsarg;
int ret;
+ bool did_curdir = false;
/* for ":set path=" and ":set tags=" halve backslashes for escaped
* space */
@@ -3992,7 +3992,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
if (pat[i] == '\\' && pat[i + 1] == ' ')
STRMOVE(pat + i, pat + i + 1);
- flags |= EW_FILE | EW_EXEC;
+ flags |= EW_FILE | EW_EXEC | EW_SHELLCMD;
bool mustfree = false; // Track memory allocation for *path.
/* For an absolute name we don't use $PATH. */
@@ -4012,12 +4012,24 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
/*
* Go over all directories in $PATH. Expand matches in that directory and
- * collect them in "ga".
+ * collect them in "ga". When "." is not in $PATH also expaned for the
+ * current directory, to find "subdir/cmd".
*/
ga_init(&ga, (int)sizeof(char *), 10);
- for (s = path; *s != NUL; s = e) {
- if (*s == ' ')
- ++s; /* Skip space used for absolute path name. */
+ for (s = path; ; s = e) {
+ if (*s == NUL) {
+ if (did_curdir) {
+ break;
+ }
+ // Find directories in the current directory, path is empty.
+ did_curdir = true;
+ } else if (*s == '.') {
+ did_curdir = true;
+ }
+
+ if (*s == ' ') {
+ s++; // Skip space used for absolute path name.
+ }
e = vim_strchr(s, ':');
if (e == NULL)
@@ -4275,20 +4287,33 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options)
* Command line history stuff *
*********************************/
-/*
- * Translate a history character to the associated type number.
- */
-static int hist_char2type(int c)
+/// Translate a history character to the associated type number
+static HistoryType hist_char2type(const int c)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (c == ':')
- return HIST_CMD;
- if (c == '=')
- return HIST_EXPR;
- if (c == '@')
- return HIST_INPUT;
- if (c == '>')
- return HIST_DEBUG;
- return HIST_SEARCH; /* must be '?' or '/' */
+ switch (c) {
+ case ':': {
+ return HIST_CMD;
+ }
+ case '=': {
+ return HIST_EXPR;
+ }
+ case '@': {
+ return HIST_INPUT;
+ }
+ case '>': {
+ return HIST_DEBUG;
+ }
+ case '/':
+ case '?': {
+ return HIST_SEARCH;
+ }
+ default: {
+ return HIST_INVALID;
+ }
+ }
+ // Silence -Wreturn-type
+ return 0;
}
/*
@@ -4457,28 +4482,38 @@ in_history (
return false;
}
-/*
- * Convert history name (from table above) to its HIST_ equivalent.
- * When "name" is empty, return "cmd" history.
- * Returns -1 for unknown history name.
- */
-int get_histtype(char_u *name)
+/// Convert history name to its HIST_ equivalent
+///
+/// Names are taken from the table above. When `name` is empty returns currently
+/// active history or HIST_DEFAULT, depending on `return_default` argument.
+///
+/// @param[in] name Converted name.
+/// @param[in] len Name length.
+/// @param[in] return_default Determines whether HIST_DEFAULT should be
+/// returned or value based on `ccline.cmdfirstc`.
+///
+/// @return Any value from HistoryType enum, including HIST_INVALID. May not
+/// return HIST_DEFAULT unless return_default is true.
+HistoryType get_histtype(const char_u *const name, const size_t len,
+ const bool return_default)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- int i;
- int len = (int)STRLEN(name);
-
- /* No argument: use current history. */
- if (len == 0)
- return hist_char2type(ccline.cmdfirstc);
+ // No argument: use current history.
+ if (len == 0) {
+ return return_default ? HIST_DEFAULT : hist_char2type(ccline.cmdfirstc);
+ }
- for (i = 0; history_names[i] != NULL; ++i)
- if (STRNICMP(name, history_names[i], len) == 0)
+ for (HistoryType i = 0; history_names[i] != NULL; i++) {
+ if (STRNICMP(name, history_names[i], len) == 0) {
return i;
+ }
+ }
- if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL)
+ if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && len == 1) {
return hist_char2type(name[0]);
+ }
- return -1;
+ return HIST_INVALID;
}
static int last_maptick = -1; /* last seen maptick */
@@ -4499,8 +4534,10 @@ add_to_history (
histentry_T *hisptr;
int len;
- if (hislen == 0) /* no history */
+ if (hislen == 0 || histype == HIST_INVALID) { // no history
return;
+ }
+ assert(histype != HIST_DEFAULT);
if (cmdmod.keeppatterns && histype == HIST_SEARCH)
return;
@@ -4850,23 +4887,20 @@ void ex_history(exarg_T *eap)
while (ASCII_ISALPHA(*end)
|| vim_strchr((char_u *)":=@>/?", *end) != NULL)
end++;
- i = *end;
- *end = NUL;
- histype1 = get_histtype(arg);
- if (histype1 == -1) {
- if (STRNICMP(arg, "all", STRLEN(arg)) == 0) {
+ histype1 = get_histtype(arg, end - arg, false);
+ if (histype1 == HIST_INVALID) {
+ if (STRNICMP(arg, "all", end - arg) == 0) {
histype1 = 0;
histype2 = HIST_COUNT-1;
} else {
- *end = i;
EMSG(_(e_trailing));
return;
}
} else
histype2 = histype1;
- *end = i;
- } else
+ } else {
end = arg;
+ }
if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) {
EMSG(_(e_trailing));
return;
@@ -4974,7 +5008,6 @@ static int ex_window(void)
win_T *wp;
int i;
linenr_T lnum;
- int histtype;
garray_T winsizes;
char_u typestr[2];
int save_restart_edit = restart_edit;
@@ -5023,7 +5056,7 @@ static int ex_window(void)
/* Showing the prompt may have set need_wait_return, reset it. */
need_wait_return = FALSE;
- histtype = hist_char2type(cmdwin_type);
+ const int histtype = hist_char2type(cmdwin_type);
if (histtype == HIST_CMD || histtype == HIST_DEBUG) {
if (p_wc == TAB) {
add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
@@ -5038,7 +5071,7 @@ static int ex_window(void)
/* Fill the buffer with the history. */
init_history();
- if (hislen > 0) {
+ if (hislen > 0 && histtype != HIST_INVALID) {
i = hisidx[histtype];
if (i >= 0) {
lnum = 0;
diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h
index 21da8b9d42..24eebdc303 100644
--- a/src/nvim/ex_getln.h
+++ b/src/nvim/ex_getln.h
@@ -27,11 +27,13 @@
/// Present history tables
typedef enum {
- HIST_CMD, ///< Colon commands.
- HIST_SEARCH, ///< Search commands.
- HIST_EXPR, ///< Expressions (e.g. from entering = register).
- HIST_INPUT, ///< input() lines.
- HIST_DEBUG, ///< Debug commands.
+ HIST_DEFAULT = -2, ///< Default (current) history.
+ HIST_INVALID = -1, ///< Unknown history.
+ HIST_CMD = 0, ///< Colon commands.
+ HIST_SEARCH, ///< Search commands.
+ HIST_EXPR, ///< Expressions (e.g. from entering = register).
+ HIST_INPUT, ///< input() lines.
+ HIST_DEBUG, ///< Debug commands.
} HistoryType;
/// Number of history tables
diff --git a/src/nvim/farsi.c b/src/nvim/farsi.c
index 47a132c0d0..61e17128ea 100644
--- a/src/nvim/farsi.c
+++ b/src/nvim/farsi.c
@@ -100,8 +100,9 @@ static char_u toF_Xor_X_(int c)
case F_HE :
tempc = _HE;
- if (p_ri &&
- (curwin->w_cursor.col + 1 < (colnr_T)STRLEN(get_cursor_line_ptr()))) {
+ if (p_ri
+ && (curwin->w_cursor.col + 1
+ < (colnr_T)STRLEN(get_cursor_line_ptr()))) {
inc_cursor();
if (F_is_TyB_TyC_TyD(SRC_EDT, AT_CURSOR)) {
tempc = _HE_;
@@ -526,8 +527,8 @@ static void chg_l_toXor_X(void)
{
char_u tempc;
- if ((curwin->w_cursor.col != 0) &&
- (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(get_cursor_line_ptr()))) {
+ if ((curwin->w_cursor.col != 0)
+ && (curwin->w_cursor.col + 1 == (colnr_T)STRLEN(get_cursor_line_ptr()))) {
return;
}
@@ -680,17 +681,17 @@ int fkmap(int c)
}
}
- if ((c < 0x100) &&
- (isalpha(c) ||
- (c == '&') ||
- (c == '^') ||
- (c == ';') ||
- (c == '\'') ||
- (c == ',') ||
- (c == '[') ||
- (c == ']') ||
- (c == '{') ||
- (c == '}'))) {
+ if ((c < 0x100)
+ && (isalpha(c)
+ || (c == '&')
+ || (c == '^')
+ || (c == ';')
+ || (c == '\'')
+ || (c == ',')
+ || (c == '[')
+ || (c == ']')
+ || (c == '{')
+ || (c == '}'))) {
chg_r_to_Xor_X_();
}
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 2929790ebf..beefc4238e 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1400,8 +1400,14 @@ find_file_in_path_option (
&& (ff_file_to_find[2] == NUL
|| vim_ispathsep(ff_file_to_find[2])))));
if (vim_isAbsName(ff_file_to_find)
- /* "..", "../path", "." and "./path": don't use the path_option */
+ // "..", "../path", "." and "./path": don't use the path_option
|| rel_to_curdir
+#if defined(WIN32)
+ // handle "\tmp" as absolute path
+ || vim_ispathsep(ff_file_to_find[0])
+ // handle "c:name" as absolute path
+ || (ff_file_to_find[0] != NUL && ff_file_to_find[1] == ':')
+#endif
) {
/*
* Absolute path, no need to use "path_option".
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 383cd47dbe..db1469db97 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -45,7 +45,6 @@
#include "nvim/search.h"
#include "nvim/sha256.h"
#include "nvim/strings.h"
-#include "nvim/tempfile.h"
#include "nvim/ui.h"
#include "nvim/types.h"
#include "nvim/undo.h"
@@ -606,13 +605,14 @@ readfile (
* Don't do this for a "nofile" or "nowrite" buffer type. */
if (!bt_dontwrite(curbuf)) {
check_need_swap(newfile);
- if (!read_stdin && (curbuf != old_curbuf
- || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
- || (using_b_fname &&
- (old_b_fname != curbuf->b_fname)))) {
+ if (!read_stdin
+ && (curbuf != old_curbuf
+ || (using_b_ffname && (old_b_ffname != curbuf->b_ffname))
+ || (using_b_fname && (old_b_fname != curbuf->b_fname)))) {
EMSG(_(e_auchangedbuf));
- if (!read_buffer)
+ if (!read_buffer) {
close(fd);
+ }
return FAIL;
}
#ifdef UNIX
@@ -2139,9 +2139,10 @@ readfile_charconvert (
else {
close(*fdp); /* close the input file, ignore errors */
*fdp = -1;
- if (eval_charconvert(fenc, enc_utf8 ? (char_u *)"utf-8" : p_enc,
- fname, tmpname) == FAIL)
+ if (eval_charconvert((char *) fenc, enc_utf8 ? "utf-8" : (char *) p_enc,
+ (char *) fname, (char *) tmpname) == FAIL) {
errmsg = (char_u *)_("Conversion with 'charconvert' failed");
+ }
if (errmsg == NULL && (*fdp = os_open((char *)tmpname, O_RDONLY, 0)) < 0) {
errmsg = (char_u *)_("can't read output of 'charconvert'");
}
@@ -2576,7 +2577,7 @@ buf_write (
errmsg = (char_u *)_("is a directory");
goto fail;
}
- if (mch_nodetype(fname) != NODE_WRITABLE) {
+ if (os_nodetype((char *)fname) != NODE_WRITABLE) {
errnum = (char_u *)"E503: ";
errmsg = (char_u *)_("is not a file or writable device");
goto fail;
@@ -2588,11 +2589,11 @@ buf_write (
perm = -1;
}
}
-#else /* !UNIX */
+#else /* win32 */
/*
* Check for a writable device name.
*/
- c = mch_nodetype(fname);
+ c = os_nodetype((char *)fname);
if (c == NODE_OTHER) {
errnum = (char_u *)"E503: ";
errmsg = (char_u *)_("is not a file or writable device");
@@ -2688,7 +2689,6 @@ buf_write (
} else if ((bkc & BKC_AUTO)) { /* "auto" */
int i;
-# ifdef UNIX
/*
* Don't rename the file when:
* - it's a hard link
@@ -2699,9 +2699,7 @@ buf_write (
|| !os_fileinfo_link((char *)fname, &file_info)
|| !os_fileinfo_id_equal(&file_info, &file_info_old)) {
backup_copy = TRUE;
- } else
-# endif
- {
+ } else {
/*
* Check if we can create a file and set the owner/group to
* the ones from the original file.
@@ -3435,9 +3433,9 @@ restore_backup:
* with 'charconvert' to (overwrite) the output file.
*/
if (end != 0) {
- if (eval_charconvert(enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc,
- wfname, fname) == FAIL) {
- write_info.bw_conv_error = TRUE;
+ if (eval_charconvert(enc_utf8 ? "utf-8" : (char *) p_enc, (char *) fenc,
+ (char *) wfname, (char *) fname) == FAIL) {
+ write_info.bw_conv_error = true;
end = 0;
}
}
@@ -4372,8 +4370,8 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
// (we need the full path in case :cd is used).
if (fname == NULL || *fname == NUL) {
retval = xmalloc(MAXPATHL + extlen + 3); // +3 for PATHSEP, "_" (Win), NUL
- if (os_dirname((char_u *)retval, MAXPATHL) == FAIL ||
- (fnamelen = strlen(retval)) == 0) {
+ if (os_dirname((char_u *)retval, MAXPATHL) == FAIL
+ || (fnamelen = strlen(retval)) == 0) {
xfree(retval);
return NULL;
}
@@ -4740,7 +4738,6 @@ buf_check_timestamp (
{
int retval = 0;
char_u *path;
- char_u *tbuf;
char *mesg = NULL;
char *mesg2 = "";
int helpmesg = FALSE;
@@ -4810,19 +4807,17 @@ buf_check_timestamp (
else
reason = "time";
- /*
- * Only give the warning if there are no FileChangedShell
- * autocommands.
- * Avoid being called recursively by setting "busy".
- */
- busy = TRUE;
- set_vim_var_string(VV_FCS_REASON, (char_u *)reason, -1);
- set_vim_var_string(VV_FCS_CHOICE, (char_u *)"", -1);
- ++allbuf_lock;
+ // Only give the warning if there are no FileChangedShell
+ // autocommands.
+ // Avoid being called recursively by setting "busy".
+ busy = true;
+ set_vim_var_string(VV_FCS_REASON, reason, -1);
+ set_vim_var_string(VV_FCS_CHOICE, "", -1);
+ allbuf_lock++;
n = apply_autocmds(EVENT_FILECHANGEDSHELL,
- buf->b_fname, buf->b_fname, FALSE, buf);
- --allbuf_lock;
- busy = FALSE;
+ buf->b_fname, buf->b_fname, false, buf);
+ allbuf_lock--;
+ busy = false;
if (n) {
if (!buf_valid(buf))
EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
@@ -4876,35 +4871,39 @@ buf_check_timestamp (
if (mesg != NULL) {
path = home_replace_save(buf, buf->b_fname);
- if (!helpmesg)
+ if (!helpmesg) {
mesg2 = "";
- tbuf = xmalloc(STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2);
- sprintf((char *)tbuf, mesg, path);
- /* Set warningmsg here, before the unimportant and output-specific
- * mesg2 has been appended. */
+ }
+ const size_t tbuf_len = STRLEN(path) + STRLEN(mesg) + STRLEN(mesg2) + 2;
+ char *const tbuf = xmalloc(tbuf_len);
+ snprintf(tbuf, tbuf_len, mesg, path);
+ // Set warningmsg here, before the unimportant and output-specific
+ // mesg2 has been appended.
set_vim_var_string(VV_WARNINGMSG, tbuf, -1);
if (can_reload) {
if (*mesg2 != NUL) {
- STRCAT(tbuf, "\n");
- STRCAT(tbuf, mesg2);
+ strncat(tbuf, "\n", tbuf_len);
+ strncat(tbuf, mesg2, tbuf_len);
+ }
+ if (do_dialog(VIM_WARNING, (char_u *) _("Warning"), (char_u *) tbuf,
+ (char_u *) _("&OK\n&Load File"), 1, NULL, true) == 2) {
+ reload = true;
}
- if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), tbuf,
- (char_u *)_("&OK\n&Load File"), 1, NULL, TRUE) == 2)
- reload = TRUE;
} else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) {
if (*mesg2 != NUL) {
- STRCAT(tbuf, "; ");
- STRCAT(tbuf, mesg2);
+ strncat(tbuf, "; ", tbuf_len);
+ strncat(tbuf, mesg2, tbuf_len);
}
EMSG(tbuf);
retval = 2;
} else {
if (!autocmd_busy) {
msg_start();
- msg_puts_attr(tbuf, hl_attr(HLF_E) + MSG_HIST);
- if (*mesg2 != NUL)
+ msg_puts_attr((char_u *) tbuf, hl_attr(HLF_E) + MSG_HIST);
+ if (*mesg2 != NUL) {
msg_puts_attr((char_u *)mesg2,
hl_attr(HLF_W) + MSG_HIST);
+ }
msg_clr_eos();
(void)msg_end();
if (emsg_silent == 0) {
@@ -5098,22 +5097,167 @@ void write_lnum_adjust(linenr_T offset)
}
#if defined(BACKSLASH_IN_FILENAME)
-/*
- * Convert all backslashes in fname to forward slashes in-place.
- */
+/// Convert all backslashes in fname to forward slashes in-place,
+/// unless when it looks like a URL.
void forward_slash(char_u *fname)
{
char_u *p;
- for (p = fname; *p != NUL; ++p)
- /* The Big5 encoding can have '\' in the trail byte. */
- if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1)
- ++p;
- else if (*p == '\\')
+ if (path_with_url(fname)) {
+ return;
+ }
+ for (p = fname; *p != NUL; p++) {
+ // The Big5 encoding can have '\' in the trail byte.
+ if (enc_dbcs != 0 && (*mb_ptr2len)(p) > 1) {
+ p++;
+ } else if (*p == '\\') {
*p = '/';
+ }
+ }
}
#endif
+/// Name of Vim's own temp dir. Ends in a slash.
+static char_u *vim_tempdir = NULL;
+
+/// Create a directory for private use by this instance of Neovim.
+/// This is done once, and the same directory is used for all temp files.
+/// This method avoids security problems because of symlink attacks et al.
+/// It's also a bit faster, because we only need to check for an existing
+/// file when creating the directory and not for each temp file.
+static void vim_maketempdir(void)
+{
+ static const char *temp_dirs[] = TEMP_DIR_NAMES;
+ // Try the entries in `TEMP_DIR_NAMES` to create the temp directory.
+ char_u template[TEMP_FILE_PATH_MAXLEN];
+ char_u path[TEMP_FILE_PATH_MAXLEN];
+ for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); i++) {
+ // Expand environment variables, leave room for "/nvimXXXXXX/999999999"
+ expand_env((char_u *)temp_dirs[i], template, TEMP_FILE_PATH_MAXLEN - 22);
+ if (!os_isdir(template)) { // directory doesn't exist
+ continue;
+ }
+
+ add_pathsep((char *)template);
+ // Concatenate with temporary directory name pattern
+ STRCAT(template, "nvimXXXXXX");
+
+ if (os_mkdtemp((const char *)template, (char *)path) != 0) {
+ continue;
+ }
+
+ if (vim_settempdir((char *)path)) {
+ // Successfully created and set temporary directory so stop trying.
+ break;
+ } else {
+ // Couldn't set `vim_tempdir` to `path` so remove created directory.
+ os_rmdir((char *)path);
+ }
+ }
+}
+
+/// Delete "name" and everything in it, recursively.
+/// @param name The path which should be deleted.
+/// @return 0 for success, -1 if some file was not deleted.
+int delete_recursive(char_u *name)
+{
+ int result = 0;
+
+ if (os_isrealdir(name)) {
+ snprintf((char *)NameBuff, MAXPATHL, "%s/*", name); // NOLINT
+
+ char_u **files;
+ int file_count;
+ char_u *exp = vim_strsave(NameBuff);
+ if (gen_expand_wildcards(1, &exp, &file_count, &files,
+ EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
+ | EW_DODOT | EW_EMPTYOK) == OK) {
+ for (int i = 0; i < file_count; i++) {
+ if (delete_recursive(files[i]) != 0) {
+ result = -1;
+ }
+ }
+ FreeWild(file_count, files);
+ } else {
+ result = -1;
+ }
+
+ xfree(exp);
+ os_rmdir((char *)name);
+ } else {
+ result = os_remove((char *)name) == 0 ? 0 : -1;
+ }
+
+ return result;
+}
+
+/// Delete the temp directory and all files it contains.
+void vim_deltempdir(void)
+{
+ if (vim_tempdir != NULL) {
+ // remove the trailing path separator
+ path_tail(vim_tempdir)[-1] = NUL;
+ delete_recursive(vim_tempdir);
+ xfree(vim_tempdir);
+ vim_tempdir = NULL;
+ }
+}
+
+/// Get the name of temp directory. This directory would be created on the first
+/// call to this function.
+char_u *vim_gettempdir(void)
+{
+ if (vim_tempdir == NULL) {
+ vim_maketempdir();
+ }
+
+ return vim_tempdir;
+}
+
+/// Set Neovim own temporary directory name to `tempdir`. This directory should
+/// be already created. Expand this name to a full path and put it in
+/// `vim_tempdir`. This avoids that using `:cd` would confuse us.
+///
+/// @param tempdir must be no longer than MAXPATHL.
+///
+/// @return false if we run out of memory.
+static bool vim_settempdir(char *tempdir)
+{
+ char *buf = verbose_try_malloc(MAXPATHL + 2);
+ if (!buf) {
+ return false;
+ }
+ vim_FullName(tempdir, buf, MAXPATHL, false);
+ add_pathsep(buf);
+ vim_tempdir = (char_u *)xstrdup(buf);
+ xfree(buf);
+ return true;
+}
+
+/// Return a unique name that can be used for a temp file.
+///
+/// @note The temp file is NOT created.
+///
+/// @return pointer to the temp file name or NULL if Neovim can't create
+/// temporary directory for its own temporary files.
+char_u *vim_tempname(void)
+{
+ // Temp filename counter.
+ static uint32_t temp_count;
+
+ char_u *tempdir = vim_gettempdir();
+ if (!tempdir) {
+ return NULL;
+ }
+
+ // There is no need to check if the file exists, because we own the directory
+ // and nobody else creates a file in it.
+ char_u template[TEMP_FILE_PATH_MAXLEN];
+ snprintf((char *)template, TEMP_FILE_PATH_MAXLEN,
+ "%s%" PRIu32, tempdir, temp_count++);
+ return vim_strsave(template);
+}
+
/*
* Code for automatic commands.
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 6c135ef47b..ac3cf959c8 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -762,6 +762,10 @@ void clearFolding(win_T *win)
*/
void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
{
+ if (compl_busy) {
+ return;
+ }
+
fold_T *fp;
if (wp->w_buffer->terminal) {
return;
@@ -1695,14 +1699,14 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
did_emsg = FALSE;
if (*wp->w_p_fdt != NUL) {
- char_u dashes[MAX_LEVEL + 2];
+ char dashes[MAX_LEVEL + 2];
win_T *save_curwin;
int level;
char_u *p;
- /* Set "v:foldstart" and "v:foldend". */
- set_vim_var_nr(VV_FOLDSTART, lnum);
- set_vim_var_nr(VV_FOLDEND, lnume);
+ // Set "v:foldstart" and "v:foldend".
+ set_vim_var_nr(VV_FOLDSTART, (varnumber_T) lnum);
+ set_vim_var_nr(VV_FOLDEND, (varnumber_T) lnume);
/* Set "v:folddashes" to a string of "level" dashes. */
/* Set "v:foldlevel" to "level". */
@@ -1712,7 +1716,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
memset(dashes, '-', (size_t)level);
dashes[level] = NUL;
set_vim_var_string(VV_FOLDDASHES, dashes, -1);
- set_vim_var_nr(VV_FOLDLEVEL, (long)level);
+ set_vim_var_nr(VV_FOLDLEVEL, (varnumber_T) level);
/* skip evaluating foldtext on errors */
if (!got_fdt_error) {
@@ -2106,10 +2110,11 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
*/
if (getlevel == foldlevelMarker && flp->start <= flp->lvl - level
&& flp->lvl > 0) {
- foldFind(gap, startlnum - 1, &fp);
+ (void)foldFind(gap, startlnum - 1, &fp);
if (fp >= ((fold_T *)gap->ga_data) + gap->ga_len
- || fp->fd_top >= startlnum)
+ || fp->fd_top >= startlnum) {
fp = NULL;
+ }
}
/*
@@ -2163,13 +2168,15 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
}
}
if (lvl < level + i) {
- foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2);
- if (fp2 != NULL)
+ (void)foldFind(&fp->fd_nested, flp->lnum - fp->fd_top, &fp2);
+ if (fp2 != NULL) {
bot = fp2->fd_top + fp2->fd_len - 1 + fp->fd_top;
- } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level)
- finish = TRUE;
- else
+ }
+ } else if (fp->fd_top + fp->fd_len <= flp->lnum && lvl >= level) {
+ finish = true;
+ } else {
break;
+ }
}
/* At the start of the first nested fold and at the end of the current
@@ -2672,7 +2679,7 @@ static void foldlevelExpr(fline_T *flp)
win = curwin;
curwin = flp->wp;
curbuf = flp->wp->w_buffer;
- set_vim_var_nr(VV_LNUM, lnum);
+ set_vim_var_nr(VV_LNUM, (varnumber_T) lnum);
flp->start = 0;
flp->had_end = flp->end;
diff --git a/src/nvim/garray.c b/src/nvim/garray.c
index e6cbd9332b..98cec69b54 100644
--- a/src/nvim/garray.c
+++ b/src/nvim/garray.c
@@ -188,12 +188,23 @@ void ga_concat(garray_T *gap, const char_u *restrict s)
return;
}
- int len = (int)strlen((char *) s);
+ ga_concat_len(gap, (const char *restrict) s, strlen((char *) s));
+}
+
+/// Concatenate a string to a growarray which contains characters
+///
+/// @param[out] gap Growarray to modify.
+/// @param[in] s String to concatenate.
+/// @param[in] len String length.
+void ga_concat_len(garray_T *const gap, const char *restrict s,
+ const size_t len)
+ FUNC_ATTR_NONNULL_ALL
+{
if (len) {
- ga_grow(gap, len);
+ ga_grow(gap, (int) len);
char *data = gap->ga_data;
- memcpy(data + gap->ga_len, s, (size_t)len);
- gap->ga_len += len;
+ memcpy(data + gap->ga_len, s, len);
+ gap->ga_len += (int) len;
}
}
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 437495faa4..dbf0322d78 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -144,7 +144,7 @@ static int KeyNoremap = 0; /* remapping flags */
static char_u typebuf_init[TYPELEN_INIT]; /* initial typebuf.tb_buf */
static char_u noremapbuf_init[TYPELEN_INIT]; /* initial typebuf.tb_noremap */
-static int last_recorded_len = 0; /* number of last recorded chars */
+static size_t last_recorded_len = 0; // number of last recorded chars
static const uint8_t ui_toggle[] = { K_SPECIAL, KS_EXTRA, KE_PASTE, 0 };
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -211,7 +211,7 @@ char_u *get_recorded(void)
* (possibly mapped) characters that stopped the recording.
*/
len = STRLEN(p);
- if ((int)len >= last_recorded_len) {
+ if (len >= last_recorded_len) {
len -= last_recorded_len;
p[len] = NUL;
}
@@ -243,13 +243,15 @@ static void
add_buff (
buffheader_T *buf,
char_u *s,
- long slen /* length of "s" or -1 */
+ ssize_t slen // length of "s" or -1
)
{
- if (slen < 0)
- slen = (long)STRLEN(s);
- if (slen == 0) /* don't add empty strings */
+ if (slen < 0) {
+ slen = (ssize_t)STRLEN(s);
+ }
+ if (slen == 0) { // don't add empty strings
return;
+ }
if (buf->bh_first.b_next == NULL) { /* first add to list */
buf->bh_space = 0;
@@ -263,18 +265,19 @@ add_buff (
STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
buf->bh_index = 0;
- ssize_t len;
- if (buf->bh_space >= (int)slen) {
+ size_t len;
+ if (buf->bh_space >= (size_t)slen) {
len = STRLEN(buf->bh_curr->b_str);
STRLCPY(buf->bh_curr->b_str + len, s, slen + 1);
- buf->bh_space -= slen;
+ buf->bh_space -= (size_t)slen;
} else {
- if (slen < MINIMAL_SIZE)
+ if (slen < MINIMAL_SIZE) {
len = MINIMAL_SIZE;
- else
- len = slen;
+ } else {
+ len = (size_t)slen;
+ }
buffblock_T *p = xmalloc(sizeof(buffblock_T) + len);
- buf->bh_space = (int)(len - slen);
+ buf->bh_space = len - (size_t)slen;
STRLCPY(p->b_str, s, slen + 1);
p->b_next = buf->bh_curr->b_next;
@@ -317,11 +320,11 @@ static void add_char_buff(buffheader_T *buf, int c)
if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) {
/* translate special key code into three byte sequence */
temp[0] = K_SPECIAL;
- temp[1] = K_SECOND(c);
- temp[2] = K_THIRD(c);
+ temp[1] = (char_u)K_SECOND(c);
+ temp[2] = (char_u)K_THIRD(c);
temp[3] = NUL;
} else {
- temp[0] = c;
+ temp[0] = (char_u)c;
temp[1] = NUL;
}
add_buff(buf, temp, -1L);
@@ -694,10 +697,11 @@ static int read_redo(int init, int old_redo)
bp = bp->b_next;
p = bp->b_str;
}
- buf[i] = c;
- if (i == n - 1) { /* last byte of a character */
- if (n != 1)
+ buf[i] = (char_u)c;
+ if (i == n - 1) { // last byte of a character
+ if (n != 1) {
c = (*mb_ptr2char)(buf);
+ }
break;
}
c = *p;
@@ -882,8 +886,8 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
setcursor();
return FAIL;
}
- s1 = xmalloc(newlen);
- s2 = xmalloc(newlen);
+ s1 = xmalloc((size_t)newlen);
+ s2 = xmalloc((size_t)newlen);
typebuf.tb_buflen = newlen;
/* copy the old chars, before the insertion point */
@@ -937,7 +941,7 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
nrm = noremap;
for (i = 0; i < addlen; ++i)
typebuf.tb_noremap[typebuf.tb_off + i + offset] =
- (--nrm >= 0) ? val : RM_YES;
+ (char_u)((--nrm >= 0) ? val : RM_YES);
/* tb_maplen and tb_silent only remember the length of mapped and/or
* silent mappings at the start of the buffer, assuming that a mapped
@@ -965,8 +969,8 @@ void ins_char_typebuf(int c)
char_u buf[MB_MAXBYTES + 1];
if (IS_SPECIAL(c)) {
buf[0] = K_SPECIAL;
- buf[1] = K_SECOND(c);
- buf[2] = K_THIRD(c);
+ buf[1] = (char_u)K_SECOND(c);
+ buf[2] = (char_u)K_THIRD(c);
buf[3] = NUL;
} else {
buf[(*mb_char2bytes)(c, buf)] = NUL;
@@ -1083,25 +1087,25 @@ void del_typebuf(int len, int offset)
* Write typed characters to script file.
* If recording is on put the character in the recordbuffer.
*/
-static void gotchars(char_u *chars, int len)
+static void gotchars(char_u *chars, size_t len)
{
char_u *s = chars;
int c;
char_u buf[2];
- int todo = len;
- /* remember how many chars were last recorded */
- if (Recording)
+ // remember how many chars were last recorded
+ if (Recording) {
last_recorded_len += len;
+ }
buf[1] = NUL;
- while (todo--) {
- /* Handle one byte at a time; no translation to be done. */
+ while (len--) {
+ // Handle one byte at a time; no translation to be done.
c = *s++;
updatescript(c);
if (Recording) {
- buf[0] = c;
+ buf[0] = (char_u)c;
add_buff(&recordbuff, buf, 1L);
}
}
@@ -1465,10 +1469,10 @@ int vgetc(void)
* Note: This will loop until enough bytes are received!
*/
if (has_mbyte && (n = MB_BYTE2LEN_CHECK(c)) > 1) {
- ++no_mapping;
- buf[0] = c;
- for (i = 1; i < n; ++i) {
- buf[i] = vgetorpeek(TRUE);
+ no_mapping++;
+ buf[0] = (char_u)c;
+ for (i = 1; i < n; i++) {
+ buf[i] = (char_u)vgetorpeek(true);
if (buf[i] == K_SPECIAL
) {
/* Must be a K_SPECIAL - KS_SPECIAL - KE_FILLER sequence,
@@ -1562,7 +1566,7 @@ int char_avail(void)
{
int retval;
- ++no_mapping;
+ no_mapping++;
retval = vpeekc();
--no_mapping;
return retval != NUL;
@@ -1711,7 +1715,7 @@ static int vgetorpeek(int advance)
if (advance) {
/* Also record this character, it might be needed to
* get out of Insert mode. */
- *typebuf.tb_buf = c;
+ *typebuf.tb_buf = (char_u)c;
gotchars(typebuf.tb_buf, 1);
}
cmd_silent = FALSE;
@@ -1877,19 +1881,19 @@ static int vgetorpeek(int advance)
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,
- mlen - typebuf.tb_maplen);
+ // 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((char_u *)"paste",
(long)!p_paste, NULL, 0);
if (!(State & INSERT)) {
msg_col = 0;
- msg_row = Rows - 1;
- msg_clr_eos(); /* clear ruler */
+ msg_row = (int)Rows - 1;
+ msg_clr_eos(); // clear ruler
}
status_redraw_all();
redraw_statuslines();
@@ -1975,11 +1979,11 @@ static int vgetorpeek(int advance)
char_u *save_m_keys;
char_u *save_m_str;
- /* write chars to script file(s) */
- if (keylen > typebuf.tb_maplen)
- gotchars(typebuf.tb_buf + typebuf.tb_off
- + typebuf.tb_maplen,
- keylen - typebuf.tb_maplen);
+ // write chars to script file(s)
+ if (keylen > typebuf.tb_maplen) {
+ 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 */
@@ -2417,7 +2421,7 @@ inchar (
else
return -1;
} else {
- buf[0] = script_char;
+ buf[0] = (char_u)script_char;
len = 1;
}
}
@@ -2453,7 +2457,7 @@ inchar (
* Fill up to a third of the buffer, because each character may be
* tripled below.
*/
- len = os_inchar(buf, maxlen / 3, wait_time, tb_change_cnt);
+ len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);
}
if (typebuf_changed(tb_change_cnt))
@@ -2496,8 +2500,8 @@ fix_input_buffer (
&& !script
&& (i < 2 || p[1] != KS_EXTRA))) {
memmove(p + 3, p + 1, (size_t)i);
- p[2] = K_THIRD(p[0]);
- p[1] = K_SECOND(p[0]);
+ p[2] = (char_u)K_THIRD(p[0]);
+ p[1] = (char_u)K_SECOND(p[0]);
p[0] = K_SPECIAL;
p += 2;
len += 2;
@@ -2573,11 +2577,11 @@ do_map (
int new_hash;
mapblock_T **abbr_table;
mapblock_T **map_table;
- int unique = FALSE;
- int nowait = FALSE;
- int silent = FALSE;
- int special = FALSE;
- int expr = FALSE;
+ bool unique = false;
+ bool nowait = false;
+ bool silent = false;
+ bool special = false;
+ bool expr = false;
int noremap;
char_u *orig_rhs;
@@ -2609,7 +2613,7 @@ do_map (
*/
if (STRNCMP(keys, "<nowait>", 8) == 0) {
keys = skipwhite(keys + 8);
- nowait = TRUE;
+ nowait = true;
continue;
}
@@ -2618,7 +2622,7 @@ do_map (
*/
if (STRNCMP(keys, "<silent>", 8) == 0) {
keys = skipwhite(keys + 8);
- silent = TRUE;
+ silent = true;
continue;
}
@@ -2627,7 +2631,7 @@ do_map (
*/
if (STRNCMP(keys, "<special>", 9) == 0) {
keys = skipwhite(keys + 9);
- special = TRUE;
+ special = true;
continue;
}
@@ -2645,7 +2649,7 @@ do_map (
*/
if (STRNCMP(keys, "<expr>", 6) == 0) {
keys = skipwhite(keys + 6);
- expr = TRUE;
+ expr = true;
continue;
}
/*
@@ -2653,7 +2657,7 @@ do_map (
*/
if (STRNCMP(keys, "<unique>", 8) == 0) {
keys = skipwhite(keys + 8);
- unique = TRUE;
+ unique = true;
continue;
}
break;
@@ -2669,13 +2673,14 @@ do_map (
p = keys;
do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
while (*p && (maptype == 1 || !ascii_iswhite(*p))) {
- if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) &&
- p[1] != NUL)
- ++p; /* skip CTRL-V or backslash */
- ++p;
+ if ((p[0] == Ctrl_V || (do_backslash && p[0] == '\\')) && p[1] != NUL) {
+ p++; // skip CTRL-V or backslash
+ }
+ p++;
}
- if (*p != NUL)
+ if (*p != NUL) {
*p++ = NUL;
+ }
p = skipwhite(p);
rhs = p;
@@ -2688,22 +2693,24 @@ do_map (
goto theend;
}
- /*
- * If mapping has been given as ^V<C_UP> say, then replace the term codes
- * with the appropriate two bytes. If it is a shifted special key, unshift
- * it too, giving another two bytes.
- * replace_termcodes() may move the result to allocated memory, which
- * needs to be freed later (*keys_buf and *arg_buf).
- * replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
- */
- if (haskey)
- keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special);
+ // If mapping has been given as ^V<C_UP> say, then replace the term codes
+ // with the appropriate two bytes. If it is a shifted special key, unshift
+ // it too, giving another two bytes.
+ // replace_termcodes() may move the result to allocated memory, which
+ // needs to be freed later (*keys_buf and *arg_buf).
+ // replace_termcodes() also removes CTRL-Vs and sometimes backslashes.
+ if (haskey) {
+ keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, special,
+ CPO_TO_CPO_FLAGS);
+ }
orig_rhs = rhs;
if (hasarg) {
- if (STRICMP(rhs, "<nop>") == 0) /* "<Nop>" means nothing */
+ if (STRICMP(rhs, "<nop>") == 0) { // "<Nop>" means nothing
rhs = (char_u *)"";
- else
- rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special);
+ } else {
+ rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, false, true, special,
+ CPO_TO_CPO_FLAGS);
+ }
}
/*
@@ -3270,7 +3277,8 @@ int map_to_exists(char_u *str, char_u *modechars, int abbr)
char_u *buf;
int retval;
- rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE);
+ rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false,
+ CPO_TO_CPO_FLAGS);
if (vim_strchr(modechars, 'n') != NULL)
mode |= NORMAL;
@@ -3465,7 +3473,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
mp = maphash[hash];
for (; mp; mp = mp->m_next) {
if (mp->m_mode & expand_mapmodes) {
- p = translate_mapping(mp->m_keys, TRUE);
+ p = translate_mapping(mp->m_keys, true, CPO_TO_CPO_FLAGS);
if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) {
if (round == 1)
++count;
@@ -3483,7 +3491,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
break; /* for (round) */
if (round == 1) {
- *file = (char_u **)xmalloc(count * sizeof(char_u *));
+ *file = (char_u **)xmalloc((size_t)count * sizeof(char_u *));
}
} /* for (round) */
@@ -3647,8 +3655,8 @@ int check_abbr(int c, char_u *ptr, int col, int mincol)
/* special key code, split up */
if (IS_SPECIAL(c) || c == K_SPECIAL) {
tb[j++] = K_SPECIAL;
- tb[j++] = K_SECOND(c);
- tb[j++] = K_THIRD(c);
+ tb[j++] = (char_u)K_SECOND(c);
+ tb[j++] = (char_u)K_THIRD(c);
} else {
if (c < ABBR_OFF && (c < ' ' || c > '~'))
tb[j++] = Ctrl_V; /* special char needs CTRL-V */
@@ -3657,8 +3665,9 @@ int check_abbr(int c, char_u *ptr, int col, int mincol)
if (c >= ABBR_OFF)
c -= ABBR_OFF;
j += (*mb_char2bytes)(c, tb + j);
- } else
- tb[j++] = c;
+ } else {
+ tb[j++] = (char_u)c;
+ }
}
tb[j] = NUL;
/* insert the last typed char */
@@ -4190,14 +4199,15 @@ void add_map(char_u *map, int mode)
// Returns NULL when there is a problem.
static char_u * translate_mapping (
char_u *str,
- int expmap // TRUE when expanding mappings on command-line
+ int expmap, // True when expanding mappings on command-line
+ int cpo_flags // Value of various flags present in &cpo
)
{
garray_T ga;
ga_init(&ga, 1, 40);
- int cpo_bslash = (vim_strchr(p_cpo, CPO_BSLASH) != NULL);
- int cpo_special = (vim_strchr(p_cpo, CPO_SPECI) != NULL);
+ bool cpo_bslash = !(cpo_flags&FLAG_CPO_BSLASH);
+ bool cpo_special = !(cpo_flags&FLAG_CPO_SPECI);
for (; *str; ++str) {
int c = *str;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 69e65c3208..dafb75ca87 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -4,17 +4,7 @@
#include <stdbool.h>
#include <inttypes.h>
-// EXTERN is only defined in main.c. That's where global variables are
-// actually defined and initialized.
-#ifndef EXTERN
-# define EXTERN extern
-# define INIT(...)
-#else
-# ifndef INIT
-# define INIT(...) __VA_ARGS__
-# endif
-#endif
-
+#include "nvim/macros.h"
#include "nvim/ex_eval.h"
#include "nvim/iconv.h"
#include "nvim/mbyte.h"
@@ -214,6 +204,10 @@ EXTERN int compl_length INIT(= 0);
* stop looking for matches. */
EXTERN int compl_interrupted INIT(= FALSE);
+// Set when doing something for completion that may call edit() recursively,
+// which is not allowed. Also used to disable folding during completion
+EXTERN int compl_busy INIT(= false);
+
/* List of flags for method of completion. */
EXTERN int compl_cont_status INIT(= 0);
# define CONT_ADDING 1 /* "normal" or "adding" expansion */
@@ -299,10 +293,11 @@ EXTERN int msg_no_more INIT(= FALSE); /* don't use more prompt, truncate
EXTERN char_u *sourcing_name INIT( = NULL); /* name of error message source */
EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */
-EXTERN int ex_nesting_level INIT(= 0); /* nesting level */
-EXTERN int debug_break_level INIT(= -1); /* break below this level */
-EXTERN int debug_did_msg INIT(= FALSE); /* did "debug mode" message */
-EXTERN int debug_tick INIT(= 0); /* breakpoint change count */
+EXTERN int ex_nesting_level INIT(= 0); // nesting level
+EXTERN int debug_break_level INIT(= -1); // break below this level
+EXTERN int debug_did_msg INIT(= false); // did "debug mode" message
+EXTERN int debug_tick INIT(= 0); // breakpoint change count
+EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level
/* Values for "do_profiling". */
#define PROF_NONE 0 /* profiling not started */
@@ -509,6 +504,7 @@ EXTERN int cterm_normal_fg_bold INIT(= 0);
EXTERN int cterm_normal_bg_color INIT(= 0);
EXTERN RgbValue normal_fg INIT(= -1);
EXTERN RgbValue normal_bg INIT(= -1);
+EXTERN RgbValue normal_sp INIT(= -1);
EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */
EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
@@ -918,8 +914,8 @@ EXTERN int KeyTyped; // TRUE if user typed current char
EXTERN int KeyStuffed; // TRUE if current char from stuffbuf
EXTERN int maptick INIT(= 0); // tick for each non-mapped char
-EXTERN char_u chartab[256]; /* table used in charset.c; See
- init_chartab() for explanation */
+EXTERN uint8_t chartab[256]; // table used in charset.c; See
+ // init_chartab() for explanation
EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */
EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index ab8959239b..916d27a964 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -32,7 +32,6 @@
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/version.h"
-#include "nvim/tempfile.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
@@ -2191,18 +2190,19 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
mbfont_opts[OPT_MBFONT_BOLDOBLIQUE].strlen);
}
- /* Check if need to use Courier for ASCII code range, and if so pick up
- * the encoding to use */
- prt_use_courier = mbfont_opts[OPT_MBFONT_USECOURIER].present &&
- (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0])
- == 'y');
+ // Check if need to use Courier for ASCII code range, and if so pick up
+ // the encoding to use
+ prt_use_courier = (
+ mbfont_opts[OPT_MBFONT_USECOURIER].present
+ && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y'));
if (prt_use_courier) {
- /* Use national ASCII variant unless ASCII wanted */
- if (mbfont_opts[OPT_MBFONT_ASCII].present &&
- (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y'))
+ // Use national ASCII variant unless ASCII wanted
+ if (mbfont_opts[OPT_MBFONT_ASCII].present
+ && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_ASCII].string[0]) == 'y')) {
prt_ascii_encoding = "ascii";
- else
+ } else {
prt_ascii_encoding = prt_ps_mbfonts[cmap].ascii_enc;
+ }
}
prt_ps_font = &prt_ps_mb_font;
@@ -2780,11 +2780,13 @@ void mch_print_end(prt_settings_T *psettings)
}
prt_message((char_u *)_("Sending to printer..."));
- /* Not printing to a file: use 'printexpr' to print the file. */
- if (eval_printexpr(prt_ps_file_name, psettings->arguments) == FAIL)
+ // Not printing to a file: use 'printexpr' to print the file.
+ if (eval_printexpr((char *) prt_ps_file_name, (char *) psettings->arguments)
+ == FAIL) {
EMSG(_("E365: Failed to print PostScript file"));
- else
+ } else {
prt_message((char_u *)_("Print job sent."));
+ }
}
mch_print_cleanup();
@@ -3028,10 +3030,10 @@ int mch_print_text_out(char_u *p, size_t len)
prt_text_run += char_width;
prt_pos_x += char_width;
- /* The downside of fp - use relative error on right margin check */
+ // The downside of fp - use relative error on right margin check
next_pos = prt_pos_x + prt_char_width;
- need_break = (next_pos > prt_right_margin) &&
- ((next_pos - prt_right_margin) > (prt_right_margin*1e-5));
+ need_break = ((next_pos > prt_right_margin)
+ && ((next_pos - prt_right_margin) > (prt_right_margin * 1e-5)));
if (need_break)
prt_flush_buffer();
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 7169a1d963..2f9ec0b3ff 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -27,7 +27,6 @@
#include "nvim/quickfix.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
-#include "nvim/tempfile.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
@@ -1063,8 +1062,8 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m",
*qfpos == '-', cmdline) > 0) {
if (postponed_split != 0) {
- win_split(postponed_split > 0 ? postponed_split : 0,
- postponed_split_flags);
+ (void)win_split(postponed_split > 0 ? postponed_split : 0,
+ postponed_split_flags);
RESET_BINDING(curwin);
postponed_split = 0;
}
@@ -2081,12 +2080,13 @@ static int cs_show(exarg_T *eap)
if (csinfo[i].fname == NULL)
continue;
- if (csinfo[i].ppath != NULL)
- (void)smsg("%2zu %-5" PRId64 " %-34s %-32s",
- i, (long)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
- else
- (void)smsg("%2zu %-5" PRId64 " %-34s <none>",
- i, (long)csinfo[i].pid, csinfo[i].fname);
+ if (csinfo[i].ppath != NULL) {
+ (void)smsg("%2zu %-5" PRId64 " %-34s %-32s", i,
+ (int64_t)csinfo[i].pid, csinfo[i].fname, csinfo[i].ppath);
+ } else {
+ (void)smsg("%2zu %-5" PRId64 " %-34s <none>", i,
+ (int64_t)csinfo[i].pid, csinfo[i].fname);
+ }
}
}
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index d3008185dc..f197669a97 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -529,7 +529,7 @@ int get_expr_indent(void)
save_pos = curwin->w_cursor;
save_curswant = curwin->w_curswant;
save_set_curswant = curwin->w_set_curswant;
- set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
+ set_vim_var_nr(VV_LNUM, (varnumber_T) curwin->w_cursor.lnum);
if (use_sandbox) {
sandbox++;
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 17fadc4bfd..efe8e73a3c 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -2282,15 +2282,14 @@ int get_c_indent(void)
* location for b_ind_open_extra.
*/
- if (start_brace == BRACE_IN_COL0) { /* '{' is in column 0 */
+ if (start_brace == BRACE_IN_COL0) { // '{' is in column 0
amount = curbuf->b_ind_open_left_imag;
- lookfor_cpp_namespace = TRUE;
- } else if (start_brace == BRACE_AT_START &&
- lookfor_cpp_namespace) { /* '{' is at start */
-
- lookfor_cpp_namespace = TRUE;
+ lookfor_cpp_namespace = true;
+ } else if (start_brace == BRACE_AT_START
+ && lookfor_cpp_namespace) { // '{' is at start
+ lookfor_cpp_namespace = true;
} else {
- if (start_brace == BRACE_AT_END) { /* '{' is at end of line */
+ if (start_brace == BRACE_AT_END) { // '{' is at end of line
amount += curbuf->b_ind_open_imag;
l = skipwhite(get_cursor_line_ptr());
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 6c75d8bdf4..99e94fc60f 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -482,26 +482,28 @@ char_u *get_special_key_name(int c, int modifiers)
return string;
}
-/*
- * Try translating a <> name at (*srcp)[] to dst[].
- * Return the number of characters added to dst[], zero for no match.
- * If there is a match, srcp is advanced to after the <> name.
- * dst[] must be big enough to hold the result (up to six characters)!
- */
-unsigned int
-trans_special (
- char_u **srcp,
- char_u *dst,
- int keycode /* prefer key code, e.g. K_DEL instead of DEL */
-)
+/// Try translating a <> name
+///
+/// @param[in,out] srcp Source from which <> are translated. Is advanced to
+/// after the <> name if there is a match.
+/// @param[in] src_len Length of the srcp.
+/// @param[out] dst Location where translation result will be kept. Must have
+/// at least six bytes.
+/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL.
+///
+/// @return Number of characters added to dst, zero for no match.
+unsigned int trans_special(const char_u **srcp, const size_t src_len,
+ char_u *const dst, const bool keycode)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int modifiers = 0;
int key;
unsigned int dlen = 0;
- key = find_special_key(srcp, &modifiers, keycode, FALSE);
- if (key == 0)
+ key = find_special_key(srcp, src_len, &modifiers, keycode, false);
+ if (key == 0) {
return 0;
+ }
/* Put the appropriate modifier in a string */
if (modifiers != 0) {
@@ -514,69 +516,78 @@ trans_special (
dst[dlen++] = K_SPECIAL;
dst[dlen++] = (char_u)KEY2TERMCAP0(key);
dst[dlen++] = KEY2TERMCAP1(key);
- } else if (has_mbyte && !keycode)
+ } else if (has_mbyte && !keycode) {
dlen += (unsigned int)(*mb_char2bytes)(key, dst + dlen);
- else if (keycode) {
+ } else if (keycode) {
char_u *after = add_char2buf(key, dst + dlen);
assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX);
dlen = (unsigned int)(after - dst);
- }
- else
+ } else {
dst[dlen++] = (char_u)key;
+ }
return dlen;
}
-// Try translating a <> name at (*srcp)[], return the key and modifiers.
-// srcp is advanced to after the <> name.
-// returns 0 if there is no match.
-int find_special_key(
- char_u **srcp,
- int *modp,
- int keycode, // prefer key code, e.g. K_DEL instead of DEL
- int keep_x_key // don't translate xHome to Home key
-)
+/// Try translating a <> name
+///
+/// @param[in,out] srcp Translated <> name. Is advanced to after the <> name.
+/// @param[in] src_len srcp length.
+/// @param[out] modp Location where information about modifiers is saved.
+/// @param[in] keycode Prefer key code, e.g. K_DEL in place of DEL.
+/// @param[in] keep_x_key Don’t translate xHome to Home key.
+///
+/// @return Key and modifiers or 0 if there is no match.
+int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
+ const bool keycode, const bool keep_x_key)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- char_u *last_dash;
- char_u *end_of_name;
- char_u *src;
- char_u *bp;
+ const char_u *last_dash;
+ const char_u *end_of_name;
+ const char_u *src;
+ const char_u *bp;
+ const char_u *const end = *srcp + src_len - 1;
int modifiers;
int bit;
int key;
unsigned long n;
int l;
+ if (src_len == 0) {
+ return 0;
+ }
+
src = *srcp;
- if (src[0] != '<')
+ if (src[0] != '<') {
return 0;
+ }
// Find end of modifier list
last_dash = src;
- for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
+ for (bp = src + 1; bp <= end && (*bp == '-' || vim_isIDc(*bp)); bp++) {
if (*bp == '-') {
last_dash = bp;
- if (bp[1] != NUL) {
+ if (bp + 1 <= end) {
if (has_mbyte) {
- l = mb_ptr2len(bp + 1);
+ l = mb_ptr2len_len(bp + 1, (int) (end - bp) + 1);
} else {
l = 1;
}
- if (bp[l + 1] == '>') {
- bp += l; // anything accepted, like <C-?>
+ if (end - bp > l && bp[l + 1] == '>') {
+ bp += l; // anything accepted, like <C-?>
}
}
}
- if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
- bp += 3; // skip t_xx, xx may be '-' or '>'
- } else if (STRNICMP(bp, "char-", 5) == 0) {
+ if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') {
+ bp += 3; // skip t_xx, xx may be '-' or '>'
+ } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
bp += l + 5;
break;
}
}
- if (*bp == '>') { /* found matching '>' */
+ if (bp <= end && *bp == '>') { // found matching '>'
end_of_name = bp + 1;
/* Which modifiers are given? */
@@ -696,7 +707,7 @@ int find_special_key_in_table(int c)
* termcap name.
* Return the key code, or 0 if not found.
*/
-int get_special_key_code(char_u *name)
+int get_special_key_code(const char_u *name)
{
char_u *table_name;
int i, j;
@@ -730,50 +741,58 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
return 0; /* Shouldn't get here */
}
-// Replace any terminal code strings in from[] with the equivalent internal
-// vim representation. This is used for the "from" and "to" part of a
-// mapping, and the "to" part of a menu command.
-// Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains
-// '<'.
-// K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER.
-//
-// The replacement is done in result[] and finally copied into allocated
-// memory. If this all works well *bufp is set to the allocated memory and a
-// pointer to it is returned. If something fails *bufp is set to NULL and from
-// is returned.
-//
-// CTRL-V characters are removed. When "from_part" is TRUE, a trailing CTRL-V
-// is included, otherwise it is removed (for ":map xx ^V", maps xx to
-// nothing). When 'cpoptions' does not contain 'B', a backslash can be used
-// instead of a CTRL-V.
-char_u * replace_termcodes (
- char_u *from,
- char_u **bufp,
- int from_part,
- int do_lt, // also translate <lt>
- int special // always accept <key> notation
-)
+/// Replace any terminal code strings with the equivalent internal
+/// representation
+///
+/// This is used for the "from" and "to" part of a mapping, and the "to" part of
+/// a menu command. Any strings like "<C-UP>" are also replaced, unless
+/// 'cpoptions' contains '<'. K_SPECIAL by itself is replaced by K_SPECIAL
+/// KS_SPECIAL KE_FILLER.
+///
+/// @param[in] from What characters to replace.
+/// @param[in] from_len Length of the "from" argument.
+/// @param[out] bufp Location where results were saved in case of success
+/// (allocated). Will be set to NULL in case of failure.
+/// @param[in] do_lt If true, also translate <lt>.
+/// @param[in] from_part If true, trailing <C-v> is included, otherwise it is
+/// removed (to make ":map xx ^V" map xx to nothing).
+/// When cpo_flags contains #FLAG_CPO_BSLASH, a backslash
+/// can be used in place of <C-v>. All other <C-v>
+/// characters are removed.
+/// @param[in] special If true, always accept <key> notation.
+/// @param[in] cpo_flags Relevant flags derived from p_cpo, see
+/// #CPO_TO_CPO_FLAGS.
+///
+/// @return Pointer to an allocated memory in case of success, "from" in case of
+/// failure. In case of success returned pointer is also saved to
+/// "bufp".
+char_u *replace_termcodes(const char_u *from, const size_t from_len,
+ char_u **bufp, const bool from_part, const bool do_lt,
+ const bool special, int cpo_flags)
+ FUNC_ATTR_NONNULL_ALL
{
ssize_t i;
size_t slen;
char_u key;
size_t dlen = 0;
- char_u *src;
+ const char_u *src;
+ const char_u *const end = from + from_len - 1;
int do_backslash; // backslash is a special character
int do_special; // recognize <> key codes
char_u *result; // buffer for resulting string
- do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL);
- do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special;
+ do_backslash = !(cpo_flags&FLAG_CPO_BSLASH);
+ do_special = !(cpo_flags&FLAG_CPO_SPECI) || special;
// Allocate space for the translation. Worst case a single character is
// replaced by 6 bytes (shifted special key), plus a NUL at the end.
- result = xmalloc(STRLEN(from) * 6 + 1);
+ result = xmalloc(from_len * 6 + 1);
src = from;
// Check for #n at start only: function key n
- if (from_part && src[0] == '#' && ascii_isdigit(src[1])) { // function key
+ if (from_part && from_len > 1 && src[0] == '#'
+ && ascii_isdigit(src[1])) { // function key
result[dlen++] = K_SPECIAL;
result[dlen++] = 'k';
if (src[1] == '0') {
@@ -785,13 +804,14 @@ char_u * replace_termcodes (
}
// Copy each byte from *from to result[dlen]
- while (*src != NUL) {
+ while (src <= end) {
// If 'cpoptions' does not contain '<', check for special key codes,
// like "<C-S-LeftMouse>"
- if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0)) {
+ if (do_special && (do_lt || ((end - src) >= 3
+ && STRNCMP(src, "<lt>", 4) != 0))) {
// Replace <SID> by K_SNR <script-nr> _.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
- if (STRNICMP(src, "<SID>", 5) == 0) {
+ if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) {
if (current_SID <= 0) {
EMSG(_(e_usingsid));
} else {
@@ -806,7 +826,7 @@ char_u * replace_termcodes (
}
}
- slen = trans_special(&src, result + dlen, TRUE);
+ slen = trans_special(&src, (size_t) (end - src) + 1, result + dlen, true);
if (slen) {
dlen += slen;
continue;
@@ -819,10 +839,10 @@ char_u * replace_termcodes (
// Replace <Leader> by the value of "mapleader".
// Replace <LocalLeader> by the value of "maplocalleader".
// If "mapleader" or "maplocalleader" isn't set use a backslash.
- if (STRNICMP(src, "<Leader>", 8) == 0) {
+ if (end - src >= 7 && STRNICMP(src, "<Leader>", 8) == 0) {
len = 8;
p = get_var_value((char_u *)"g:mapleader");
- } else if (STRNICMP(src, "<LocalLeader>", 13) == 0) {
+ } else if (end - src >= 12 && STRNICMP(src, "<LocalLeader>", 13) == 0) {
len = 13;
p = get_var_value((char_u *)"g:maplocalleader");
} else {
@@ -851,8 +871,8 @@ char_u * replace_termcodes (
// If 'cpoptions' does not contain 'B', also accept a backslash.
key = *src;
if (key == Ctrl_V || (do_backslash && key == '\\')) {
- ++src; // skip CTRL-V or backslash
- if (*src == NUL) {
+ src++; // skip CTRL-V or backslash
+ if (src > end) {
if (from_part) {
result[dlen++] = key;
}
@@ -861,7 +881,7 @@ char_u * replace_termcodes (
}
// skip multibyte char correctly
- for (i = (*mb_ptr2len)(src); i > 0; --i) {
+ for (i = (*mb_ptr2len_len)(src, (int) (end - src) + 1); i > 0; i--) {
// If the character is K_SPECIAL, replace it with K_SPECIAL
// KS_SPECIAL KE_FILLER.
// If compiled with the GUI replace CSI with K_CSI.
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 8f9980c6b4..bb8ba84a6a 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -1,6 +1,8 @@
#ifndef NVIM_KEYMAP_H
#define NVIM_KEYMAP_H
+#include "nvim/strings.h"
+
/*
* Keycode definitions for special keys.
*
@@ -461,6 +463,14 @@ enum key_extra {
// This is a total of 6 tokens, and is currently the longest one possible.
#define MAX_KEY_CODE_LEN 6
+#define FLAG_CPO_BSLASH 0x01
+#define FLAG_CPO_SPECI 0x02
+#define CPO_TO_CPO_FLAGS (((vim_strchr(p_cpo, CPO_BSLASH) == NULL) \
+ ? 0 \
+ : FLAG_CPO_BSLASH)| \
+ (vim_strchr(p_cpo, CPO_SPECI) == NULL \
+ ? 0 \
+ : FLAG_CPO_SPECI))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "keymap.h.generated.h"
diff --git a/src/nvim/lib/kvec.h b/src/nvim/lib/kvec.h
index 53ecf232c6..b41ef0cc9f 100644
--- a/src/nvim/lib/kvec.h
+++ b/src/nvim/lib/kvec.h
@@ -60,6 +60,7 @@ int main() {
#define kv_pop(v) ((v).items[--(v).size])
#define kv_size(v) ((v).size)
#define kv_max(v) ((v).capacity)
+#define kv_last(v) kv_A(v, kv_size(v) - 1)
#define kv_resize(type, v, s) ((v).capacity = (s), (v).items = (type*)xrealloc((v).items, sizeof(type) * (v).capacity))
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 26ab5a7de7..5f69fa2f6a 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -1,6 +1,17 @@
#ifndef NVIM_MACROS_H
#define NVIM_MACROS_H
+// EXTERN is only defined in main.c. That's where global variables are
+// actually defined and initialized.
+#ifndef EXTERN
+# define EXTERN extern
+# define INIT(...)
+#else
+# ifndef INIT
+# define INIT(...) __VA_ARGS__
+# endif
+#endif
+
#ifndef MIN
# define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
diff --git a/src/nvim/main.c b/src/nvim/main.c
index d3cdfe3edf..71a972e8f6 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -238,8 +238,8 @@ int main(int argc, char **argv)
check_and_set_isatty(&params);
// Get the name with which Nvim was invoked, with and without path.
- set_vim_var_string(VV_PROGPATH, (char_u *)argv[0], -1);
- set_vim_var_string(VV_PROGNAME, path_tail((char_u *)argv[0]), -1);
+ set_vim_var_string(VV_PROGPATH, argv[0], -1);
+ set_vim_var_string(VV_PROGNAME, (char *) path_tail((char_u *) argv[0]), -1);
event_init();
/*
@@ -317,14 +317,16 @@ int main(int argc, char **argv)
}
// open terminals when opening files that start with term://
- do_cmdline_cmd("autocmd BufReadCmd term://* "
+#define PROTO "term://"
+ do_cmdline_cmd("autocmd BufReadCmd " PROTO "* nested "
":call termopen( "
// Capture the command string
"matchstr(expand(\"<amatch>\"), "
- "'\\c\\mterm://\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), "
+ "'\\c\\m" PROTO "\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), "
// capture the working directory
"{'cwd': get(matchlist(expand(\"<amatch>\"), "
- "'\\c\\mterm://\\(.\\{-}\\)//'), 1, '')})");
+ "'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, '')})");
+#undef PROTO
/* Execute --cmd arguments. */
exe_pre_commands(&params);
@@ -333,7 +335,7 @@ int main(int argc, char **argv)
source_startup_scripts(&params);
// If using the runtime (-u is not NONE), enable syntax & filetype plugins.
- if (params.use_vimrc != NULL && strcmp(params.use_vimrc, "NONE") != 0) {
+ if (params.use_vimrc == NULL || strcmp(params.use_vimrc, "NONE") != 0) {
// Does ":filetype plugin indent on".
filetype_maybe_enable();
// Sources syntax/syntax.vim, which calls `:filetype on`.
@@ -657,6 +659,9 @@ static void init_locale(void)
setlocale(LC_NUMERIC, "C");
# endif
+# ifdef LOCALE_INSTALL_DIR // gnu/linux standard: $prefix/share/locale
+ bindtextdomain(PROJECT_NAME, LOCALE_INSTALL_DIR);
+# else // old vim style: $runtime/lang
{
char_u *p;
@@ -665,11 +670,12 @@ static void init_locale(void)
p = (char_u *)vim_getenv("VIMRUNTIME");
if (p != NULL && *p != NUL) {
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
- bindtextdomain(VIMPACKAGE, (char *)NameBuff);
+ bindtextdomain(PROJECT_NAME, (char *)NameBuff);
}
xfree(p);
- textdomain(VIMPACKAGE);
}
+# endif
+ textdomain(PROJECT_NAME);
TIME_MSG("locale set");
}
#endif
@@ -747,6 +753,7 @@ static void command_line_scan(mparm_T *parmp)
putchar(b->data[i]);
}
+ msgpack_packer_free(p);
mch_exit(0);
} else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
parmp->headless = true;
@@ -1134,10 +1141,11 @@ scripterror:
/* If there is a "+123" or "-c" command, set v:swapcommand to the first
* one. */
if (parmp->n_commands > 0) {
- p = xmalloc(STRLEN(parmp->commands[0]) + 3);
- sprintf((char *)p, ":%s\r", parmp->commands[0]);
- set_vim_var_string(VV_SWAPCOMMAND, p, -1);
- xfree(p);
+ const size_t swcmd_len = STRLEN(parmp->commands[0]) + 3;
+ char *const swcmd = xmalloc(swcmd_len);
+ snprintf(swcmd, swcmd_len, ":%s\r", parmp->commands[0]);
+ set_vim_var_string(VV_SWAPCOMMAND, swcmd, -1);
+ xfree(swcmd);
}
TIME_MSG("parsing arguments");
}
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index fdd83f9dac..3495203c43 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -571,8 +571,8 @@ char_u * mb_init(void)
#ifdef HAVE_WORKING_LIBINTL
/* GNU gettext 0.10.37 supports this feature: set the codeset used for
* translated messages independently from the current locale. */
- (void)bind_textdomain_codeset(VIMPACKAGE,
- enc_utf8 ? "utf-8" : (char *)p_enc);
+ (void)bind_textdomain_codeset(PROJECT_NAME,
+ enc_utf8 ? "utf-8" : (char *)p_enc);
#endif
@@ -1304,35 +1304,38 @@ int utfc_ptr2char(const char_u *p, int *pcc)
*/
int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen)
{
- int len;
- int c;
- int cc;
+#define IS_COMPOSING(s1, s2, s3) \
+ (i == 0 ? UTF_COMPOSINGLIKE((s1), (s2)) : utf_iscomposing((s3)))
+
+ assert(maxlen > 0);
+
int i = 0;
- c = utf_ptr2char(p);
- len = utf_ptr2len_len(p, maxlen);
- /* Only accept a composing char when the first char isn't illegal. */
- if ((len > 1 || *p < 0x80)
- && len < maxlen
- && p[len] >= 0x80
- && UTF_COMPOSINGLIKE(p, p + len)) {
- cc = utf_ptr2char(p + len);
- for (;; ) {
- pcc[i++] = cc;
- if (i == MAX_MCO)
- break;
- len += utf_ptr2len_len(p + len, maxlen - len);
- if (len >= maxlen
- || p[len] < 0x80
- || !utf_iscomposing(cc = utf_ptr2char(p + len)))
+ int len = utf_ptr2len_len(p, maxlen);
+ // Is it safe to use utf_ptr2char()?
+ bool safe = len > 1 && len <= maxlen;
+ int c = safe ? utf_ptr2char(p) : *p;
+
+ // Only accept a composing char when the first char isn't illegal.
+ if ((safe || c < 0x80) && len < maxlen && p[len] >= 0x80) {
+ for (; i < MAX_MCO; i++) {
+ int len_cc = utf_ptr2len_len(p + len, maxlen - len);
+ safe = len_cc > 1 && len_cc <= maxlen - len;
+ if (!safe || (pcc[i] = utf_ptr2char(p + len)) < 0x80
+ || !IS_COMPOSING(p, p + len, pcc[i])) {
break;
+ }
+ len += len_cc;
}
}
- if (i < MAX_MCO) /* last composing char must be 0 */
+ if (i < MAX_MCO) {
+ // last composing char must be 0
pcc[i] = 0;
+ }
return c;
+#undef ISCOMPOSING
}
/*
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 8cf5642a80..6599db787f 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -79,8 +79,6 @@ static size_t total_mem_used = 0; /// total memory used for memfiles
/// - NULL, on failure.
memfile_T *mf_open(char_u *fname, int flags)
{
- off_t size;
-
memfile_T *mfp = xmalloc(sizeof(memfile_T));
if (fname == NULL) { // no file, use memory only
@@ -88,11 +86,9 @@ memfile_T *mf_open(char_u *fname, int flags)
mfp->mf_ffname = NULL;
mfp->mf_fd = -1;
} else { // try to open the file
- mf_do_open(mfp, fname, flags);
-
- if (mfp->mf_fd < 0) { // fail if file could not be opened
+ if (!mf_do_open(mfp, fname, flags)) {
xfree(mfp);
- return NULL;
+ return NULL; // fail if file could not be opened
}
}
@@ -115,6 +111,8 @@ memfile_T *mf_open(char_u *fname, int flags)
}
}
+ off_t size;
+
// When recovering, the actual block size will be retrieved from block 0
// in ml_recover(). The size used here may be wrong, therefore mf_blocknr_max
// must be rounded up.
@@ -171,13 +169,12 @@ memfile_T *mf_open(char_u *fname, int flags)
/// FAIL If file could not be opened.
int mf_open_file(memfile_T *mfp, char_u *fname)
{
- mf_do_open(mfp, fname, O_RDWR|O_CREAT|O_EXCL); // try to open the file
-
- if (mfp->mf_fd < 0)
- return FAIL;
+ if (mf_do_open(mfp, fname, O_RDWR | O_CREAT | O_EXCL)) {
+ mfp->mf_dirty = true;
+ return OK;
+ }
- mfp->mf_dirty = true;
- return OK;
+ return FAIL;
}
/// Close a memory file and optionally delete the associated file.
@@ -185,28 +182,28 @@ int mf_open_file(memfile_T *mfp, char_u *fname)
/// @param del_file Whether to delete associated file.
void mf_close(memfile_T *mfp, bool del_file)
{
- bhdr_T *hp, *nextp;
-
if (mfp == NULL) { // safety check
return;
}
if (mfp->mf_fd >= 0 && close(mfp->mf_fd) < 0) {
EMSG(_(e_swapclose));
}
- if (del_file && mfp->mf_fname != NULL)
+ if (del_file && mfp->mf_fname != NULL) {
os_remove((char *)mfp->mf_fname);
+ }
+
// free entries in used list
- for (hp = mfp->mf_used_first; hp != NULL; hp = nextp) {
+ for (bhdr_T *hp = mfp->mf_used_first, *nextp; hp != NULL; hp = nextp) {
total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
nextp = hp->bh_next;
mf_free_bhdr(hp);
}
- while (mfp->mf_free_first != NULL) // free entries in free list
+ while (mfp->mf_free_first != NULL) { // free entries in free list
xfree(mf_rem_free(mfp));
+ }
mf_hash_free(&mfp->mf_hash);
mf_hash_free_all(&mfp->mf_trans); // free hashtable and its items
- xfree(mfp->mf_fname);
- xfree(mfp->mf_ffname);
+ mf_free_fnames(mfp);
xfree(mfp);
}
@@ -216,28 +213,28 @@ void mf_close(memfile_T *mfp, bool del_file)
void mf_close_file(buf_T *buf, bool getlines)
{
memfile_T *mfp = buf->b_ml.ml_mfp;
- if (mfp == NULL || mfp->mf_fd < 0) // nothing to close
+ if (mfp == NULL || mfp->mf_fd < 0) { // nothing to close
return;
+ }
if (getlines) {
// get all blocks in memory by accessing all lines (clumsy!)
mf_dont_release = true;
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum) {
(void)ml_get_buf(buf, lnum, false);
+ }
mf_dont_release = false;
// TODO(elmart): should check if all blocks are really in core
}
- if (close(mfp->mf_fd) < 0) // close the file
+ if (close(mfp->mf_fd) < 0) { // close the file
EMSG(_(e_swapclose));
+ }
mfp->mf_fd = -1;
if (mfp->mf_fname != NULL) {
os_remove((char *)mfp->mf_fname); // delete the swap file
- xfree(mfp->mf_fname);
- xfree(mfp->mf_ffname);
- mfp->mf_fname = NULL;
- mfp->mf_ffname = NULL;
+ mf_free_fnames(mfp);
}
}
@@ -390,11 +387,11 @@ void mf_put(memfile_T *mfp, bhdr_T *hp, bool dirty, bool infile)
/// Signal block as no longer used (may put it in the free list).
void mf_free(memfile_T *mfp, bhdr_T *hp)
{
- xfree(hp->bh_data); // free data
+ xfree(hp->bh_data); // free data
mf_rem_hash(mfp, hp); // get *hp out of the hash list
mf_rem_used(mfp, hp); // get *hp out of the used list
if (hp->bh_bnum < 0) {
- xfree(hp); // don't want negative numbers in free list
+ xfree(hp); // don't want negative numbers in free list
mfp->mf_neg_count--;
} else {
mf_ins_free(mfp, hp); // put *hp in the free list
@@ -475,10 +472,11 @@ int mf_sync(memfile_T *mfp, int flags)
/// These are blocks that need to be written to a newly created swapfile.
void mf_set_dirty(memfile_T *mfp)
{
- bhdr_T *hp;
- for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
- if (hp->bh_bnum > 0)
+ for (bhdr_T *hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev) {
+ if (hp->bh_bnum > 0) {
hp->bh_flags |= BH_DIRTY;
+ }
+ }
mfp->mf_dirty = true;
}
@@ -506,10 +504,11 @@ static void mf_ins_used(memfile_T *mfp, bhdr_T *hp)
hp->bh_next = mfp->mf_used_first;
mfp->mf_used_first = hp;
hp->bh_prev = NULL;
- if (hp->bh_next == NULL) // list was empty, adjust last pointer
+ if (hp->bh_next == NULL) { // list was empty, adjust last pointer
mfp->mf_used_last = hp;
- else
+ } else {
hp->bh_next->bh_prev = hp;
+ }
mfp->mf_used_count += hp->bh_page_count;
total_mem_used += hp->bh_page_count * mfp->mf_page_size;
}
@@ -615,9 +614,10 @@ bool mf_release_all(void)
FOR_ALL_BUFFERS(buf) {
memfile_T *mfp = buf->b_ml.ml_mfp;
if (mfp != NULL) {
- // If no swap file yet, may open one.
- if (mfp->mf_fd < 0 && buf->b_may_swap)
+ // If no swap file yet, try to open one.
+ if (mfp->mf_fd < 0 && buf->b_may_swap) {
ml_open_file(buf);
+ }
// Flush as many blocks as possible, only if there is a swapfile.
if (mfp->mf_fd >= 0) {
@@ -752,7 +752,8 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
else
page_count = hp2->bh_page_count;
size = page_size * page_count;
- if (mf_write_block(mfp, hp2 == NULL ? hp : hp2, offset, size) == FAIL) {
+ void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data;
+ if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size) {
/// Avoid repeating the error message, this mostly happens when the
/// disk is full. We give the message again only after a successful
/// write or when hitting a key. We keep on trying, in case some
@@ -773,20 +774,6 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
return OK;
}
-/// Write block to memfile's file.
-///
-/// @return OK On success.
-/// FAIL On failure.
-static int mf_write_block(memfile_T *mfp, bhdr_T *hp,
- off_t offset, unsigned size)
-{
- void *data = hp->bh_data;
- int result = OK;
- if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size)
- result = FAIL;
- return result;
-}
-
/// Make block number positive and add it to the translation list.
///
/// @return OK On success.
@@ -856,13 +843,23 @@ blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr)
return new_bnum;
}
-/// Set full file name of memfile's swapfile, out of simple file name and some
-/// other considerations.
+/// Frees mf_fname and mf_ffname.
+void mf_free_fnames(memfile_T *mfp)
+{
+ xfree(mfp->mf_fname);
+ xfree(mfp->mf_ffname);
+ mfp->mf_fname = NULL;
+ mfp->mf_ffname = NULL;
+}
+
+/// Set the simple file name and the full file name of memfile's swapfile, out
+/// of simple file name and some other considerations.
///
/// Only called when creating or renaming the swapfile. Either way it's a new
/// name so we must work out the full path name.
-void mf_set_ffname(memfile_T *mfp)
+void mf_set_fnames(memfile_T *mfp, char_u *fname)
{
+ mfp->mf_fname = fname;
mfp->mf_ffname = (char_u *)FullName_save((char *)mfp->mf_fname, false);
}
@@ -878,7 +875,7 @@ void mf_fullname(memfile_T *mfp)
}
}
-/// Return TRUE if there are any translations pending for memfile.
+/// Return true if there are any translations pending for memfile.
bool mf_need_trans(memfile_T *mfp)
{
return mfp->mf_fname != NULL && mfp->mf_neg_count > 0;
@@ -889,11 +886,11 @@ bool mf_need_trans(memfile_T *mfp)
/// "fname" must be in allocated memory, and is consumed (also when error).
///
/// @param flags Flags for open().
-static void mf_do_open(memfile_T *mfp, char_u *fname, int flags)
+/// @return A bool indicating success of the `open` call.
+static bool mf_do_open(memfile_T *mfp, char_u *fname, int flags)
{
// fname cannot be NameBuff, because it must have been allocated.
- mfp->mf_fname = fname;
- mf_set_ffname(mfp);
+ mf_set_fnames(mfp, fname);
/// Extra security check: When creating a swap file it really shouldn't
/// exist yet. If there is a symbolic link, this is most likely an attack.
@@ -904,26 +901,26 @@ static void mf_do_open(memfile_T *mfp, char_u *fname, int flags)
EMSG(_("E300: Swap file already exists (symlink attack?)"));
} else {
// try to open the file
- flags |= O_NOFOLLOW;
- mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags);
+ mfp->mf_fd = mch_open_rw((char *)mfp->mf_fname, flags | O_NOFOLLOW);
}
// If the file cannot be opened, use memory only
if (mfp->mf_fd < 0) {
- xfree(mfp->mf_fname);
- xfree(mfp->mf_ffname);
- mfp->mf_fname = NULL;
- mfp->mf_ffname = NULL;
- } else {
+ mf_free_fnames(mfp);
+ return false;
+ }
+
#ifdef HAVE_FD_CLOEXEC
- int fdflags = fcntl(mfp->mf_fd, F_GETFD);
- if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0)
- fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ int fdflags = fcntl(mfp->mf_fd, F_GETFD);
+ if (fdflags >= 0 && (fdflags & FD_CLOEXEC) == 0) {
+ fcntl(mfp->mf_fd, F_SETFD, fdflags | FD_CLOEXEC);
+ }
#endif
#ifdef HAVE_SELINUX
- mch_copy_sec(fname, mfp->mf_fname);
+ mch_copy_sec(fname, mfp->mf_fname);
#endif
- }
+
+ return true;
}
//
@@ -948,20 +945,21 @@ static void mf_hash_init(mf_hashtab_T *mht)
/// The hash table must not be used again without another mf_hash_init() call.
static void mf_hash_free(mf_hashtab_T *mht)
{
- if (mht->mht_buckets != mht->mht_small_buckets)
+ if (mht->mht_buckets != mht->mht_small_buckets) {
xfree(mht->mht_buckets);
+ }
}
/// Free the array of a hash table and all the items it contains.
static void mf_hash_free_all(mf_hashtab_T *mht)
{
- mf_hashitem_T *next;
-
- for (size_t idx = 0; idx <= mht->mht_mask; idx++)
+ for (size_t idx = 0; idx <= mht->mht_mask; idx++) {
+ mf_hashitem_T *next;
for (mf_hashitem_T *mhi = mht->mht_buckets[idx]; mhi != NULL; mhi = next) {
next = mhi->mhi_next;
xfree(mhi);
}
+ }
mf_hash_free(mht);
}
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index f58b2ac38f..4e35dd481f 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -65,7 +65,6 @@
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/version.h"
-#include "nvim/tempfile.h"
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
@@ -426,10 +425,8 @@ void ml_setname(buf_T *buf)
/* try to rename the swap file */
if (vim_rename(mfp->mf_fname, fname) == 0) {
success = TRUE;
- xfree(mfp->mf_fname);
- mfp->mf_fname = fname;
- xfree(mfp->mf_ffname);
- mf_set_ffname(mfp);
+ mf_free_fnames(mfp);
+ mf_set_fnames(mfp, fname);
ml_upd_block0(buf, UB_SAME_DIR);
break;
}
@@ -789,9 +786,8 @@ void ml_recover(void)
if (fname == NULL) /* When there is no file name */
fname = (char_u *)"";
len = (int)STRLEN(fname);
- if (len >= 4 &&
- STRNICMP(fname + len - 4, ".s", 2)
- == 0
+ if (len >= 4
+ && STRNICMP(fname + len - 4, ".s", 2) == 0
&& vim_strchr((char_u *)"UVWuvw", fname[len - 2]) != NULL
&& ASCII_ISALPHA(fname[len - 1])) {
directly = TRUE;
@@ -3196,7 +3192,7 @@ attention_message (
*/
static int do_swapexists(buf_T *buf, char_u *fname)
{
- set_vim_var_string(VV_SWAPNAME, fname, -1);
+ set_vim_var_string(VV_SWAPNAME, (char *) fname, -1);
set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
/* Trigger SwapExists autocommands with <afile> set to the file being
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 91a72abfc5..3c2394d579 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -215,10 +215,12 @@ ex_menu (
if (STRICMP(map_to, "<nop>") == 0) { /* "<Nop>" means nothing */
map_to = (char_u *)"";
map_buf = NULL;
- } else if (modes & MENU_TIP_MODE)
- map_buf = NULL; /* Menu tips are plain text. */
- else
- map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
+ } else if (modes & MENU_TIP_MODE) {
+ map_buf = NULL; // Menu tips are plain text.
+ } else {
+ map_to = replace_termcodes(map_to, STRLEN(map_to), &map_buf, false, true,
+ special, CPO_TO_CPO_FLAGS);
+ }
menuarg.modes = modes;
menuarg.noremap[0] = noremap;
menuarg.silent[0] = silent;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 1dd71baaa4..47f246fc76 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -61,14 +61,8 @@ static int confirm_msg_used = FALSE; /* displaying confirm_msg */
static char_u *confirm_msg = NULL; /* ":confirm" message */
static char_u *confirm_msg_tail; /* tail of confirm_msg */
-struct msg_hist {
- struct msg_hist *next;
- char_u *msg;
- int attr;
-};
-
-static struct msg_hist *first_msg_hist = NULL;
-static struct msg_hist *last_msg_hist = NULL;
+MessageHistoryEntry *first_msg_hist = NULL;
+MessageHistoryEntry *last_msg_hist = NULL;
static int msg_hist_len = 0;
static FILE *verbose_fd = NULL;
@@ -149,10 +143,11 @@ msg_attr_keep (
{
static int entered = 0;
int retval;
- char_u *buf = NULL;
+ char_u *buf = NULL;
- if (attr == 0)
- set_vim_var_string(VV_STATUSMSG, s, -1);
+ if (attr == 0) {
+ set_vim_var_string(VV_STATUSMSG, (char *) s, -1);
+ }
/*
* It is possible that displaying a messages causes a problem (e.g.,
@@ -472,22 +467,23 @@ int emsg(char_u *s)
{
int attr;
char_u *p;
- int ignore = FALSE;
+ int ignore = false;
int severe;
- /* Skip this if not giving error messages at the moment. */
- if (emsg_not_now())
- return TRUE;
+ // Skip this if not giving error messages at the moment.
+ if (emsg_not_now()) {
+ return true;
+ }
- called_emsg = TRUE;
- ex_exitval = 1;
+ called_emsg = true;
+ if (emsg_silent == 0) {
+ ex_exitval = 1;
+ }
- /*
- * If "emsg_severe" is TRUE: When an error exception is to be thrown,
- * prefer this message over previous messages for the same command.
- */
+ // If "emsg_severe" is TRUE: When an error exception is to be thrown,
+ // prefer this message over previous messages for the same command.
severe = emsg_severe;
- emsg_severe = FALSE;
+ emsg_severe = false;
if (!emsg_off || vim_strchr(p_debug, 't') != NULL) {
/*
@@ -503,8 +499,8 @@ int emsg(char_u *s)
return TRUE;
}
- /* set "v:errmsg", also when using ":silent! cmd" */
- set_vim_var_string(VV_ERRMSG, s, -1);
+ // set "v:errmsg", also when using ":silent! cmd"
+ set_vim_var_string(VV_ERRMSG, (char *) s, -1);
/*
* When using ":silent! cmd" ignore error messages.
@@ -563,49 +559,23 @@ int emsg(char_u *s)
return msg_attr(s, attr);
}
-/*
- * Print an error message with one "%s" and one string argument.
- */
-int emsg2(char_u *s, char_u *a1)
-{
- return emsg3(s, a1, NULL);
-}
-
void emsg_invreg(int name)
{
EMSG2(_("E354: Invalid register name: '%s'"), transchar(name));
}
-/// Print an error message with one or two "%s" and one or two string arguments.
-int emsg3(char_u *s, char_u *a1, char_u *a2)
-{
- if (emsg_not_now()) {
- return TRUE; // no error messages at the moment
- }
-
- vim_snprintf((char *)IObuff, IOSIZE, (char *)s, a1, a2);
- return emsg(IObuff);
-}
-
-/// Print an error message with one "%" PRId64 and one (int64_t) argument.
-int emsgn(char_u *s, int64_t n)
+/// Print an error message with unknown number of arguments
+bool emsgf(const char *const fmt, ...)
{
if (emsg_not_now()) {
- return TRUE; // no error messages at the moment
+ return true;
}
- vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n);
- return emsg(IObuff);
-}
-
-/// Print an error message with one "%" PRIu64 and one (uint64_t) argument.
-int emsgu(char_u *s, uint64_t n)
-{
- if (emsg_not_now()) {
- return TRUE; // no error messages at the moment
- }
+ va_list ap;
+ va_start(ap, fmt);
+ vim_vsnprintf((char *) IObuff, IOSIZE, fmt, ap, NULL);
+ va_end(ap);
- vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n);
return emsg(IObuff);
}
@@ -1538,51 +1508,44 @@ void msg_puts_attr(char_u *s, int attr)
msg_puts_attr_len(s, -1, attr);
}
-/*
- * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
- * When "maxlen" is -1 there is no maximum length.
- * When "maxlen" is >= 0 the message is not put in the history.
- */
+/// Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
+/// When "maxlen" is -1 there is no maximum length.
+/// When "maxlen" is >= 0 the message is not put in the history.
static void msg_puts_attr_len(char_u *str, int maxlen, int attr)
{
- /*
- * If redirection is on, also write to the redirection file.
- */
+ // If redirection is on, also write to the redirection file.
redir_write(str, maxlen);
- /*
- * Don't print anything when using ":silent cmd".
- */
- if (msg_silent != 0)
+ // Don't print anything when using ":silent cmd".
+ if (msg_silent != 0) {
return;
+ }
- /* if MSG_HIST flag set, add message to history */
+ // if MSG_HIST flag set, add message to history
if ((attr & MSG_HIST) && maxlen < 0) {
add_msg_hist(str, -1, attr);
attr &= ~MSG_HIST;
}
- /*
- * When writing something to the screen after it has scrolled, requires a
- * wait-return prompt later. Needed when scrolling, resetting
- * need_wait_return after some prompt, and then outputting something
- * without scrolling
- */
- if (msg_scrolled != 0 && !msg_scrolled_ign)
- need_wait_return = TRUE;
- msg_didany = TRUE; /* remember that something was outputted */
+ // When writing something to the screen after it has scrolled, requires a
+ // wait-return prompt later. Needed when scrolling, resetting
+ // need_wait_return after some prompt, and then outputting something
+ // without scrolling
+ if (msg_scrolled != 0 && !msg_scrolled_ign) {
+ need_wait_return = true;
+ }
+ msg_didany = true; // remember that something was outputted
- /*
- * If there is no valid screen, use fprintf so we can see error messages.
- * If termcap is not active, we may be writing in an alternate console
- * window, cursor positioning may not work correctly (window size may be
- * different, e.g. for Win32 console) or we just don't know where the
- * cursor is.
- */
- if (msg_use_printf())
- msg_puts_printf(str, maxlen);
- else
- msg_puts_display(str, maxlen, attr, FALSE);
+ // If there is no valid screen, use fprintf so we can see error messages.
+ // If termcap is not active, we may be writing in an alternate console
+ // window, cursor positioning may not work correctly (window size may be
+ // different, e.g. for Win32 console) or we just don't know where the
+ // cursor is.
+ if (msg_use_printf()) {
+ msg_puts_printf((char *)str, maxlen);
+ } else {
+ msg_puts_display(str, maxlen, attr, false);
+ }
}
/*
@@ -1601,39 +1564,31 @@ static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse)
int wrap;
int did_last_char;
- did_wait_return = FALSE;
+ did_wait_return = false;
while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) {
- /*
- * We are at the end of the screen line when:
- * - When outputting a newline.
- * - When outputting a character in the last column.
- */
- if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || (
- cmdmsg_rl
- ? (
- msg_col <= 1
- || (*s == TAB && msg_col <= 7)
- || (has_mbyte &&
- (*mb_ptr2cells)(s) > 1 &&
- msg_col <= 2)
- )
- :
- (msg_col + t_col >= Columns - 1
- || (*s == TAB && msg_col +
- t_col >= ((Columns - 1) & ~7))
- || (has_mbyte &&
- (*mb_ptr2cells)(s) > 1
- && msg_col + t_col >=
- Columns - 2)
- )))) {
- /*
- * The screen is scrolled up when at the last row (some terminals
- * scroll automatically, some don't. To avoid problems we scroll
- * ourselves).
- */
- if (t_col > 0)
- /* output postponed text */
+ // We are at the end of the screen line when:
+ // - When outputting a newline.
+ // - When outputting a character in the last column.
+ if (!recurse && msg_row >= Rows - 1
+ && (*s == '\n' || (cmdmsg_rl
+ ? (msg_col <= 1
+ || (*s == TAB && msg_col <= 7)
+ || (has_mbyte
+ && (*mb_ptr2cells)(s) > 1
+ && msg_col <= 2))
+ : (msg_col + t_col >= Columns - 1
+ || (*s == TAB
+ && msg_col + t_col >= ((Columns - 1) & ~7))
+ || (has_mbyte
+ && (*mb_ptr2cells)(s) > 1
+ && msg_col + t_col >= Columns - 2))))) {
+ // The screen is scrolled up when at the last row (some terminals
+ // scroll automatically, some don't. To avoid problems we scroll
+ // ourselves).
+ if (t_col > 0) {
+ // output postponed text
t_puts(&t_col, t_s, s, attr);
+ }
/* When no more prompt and no more room, truncate here */
if (msg_no_more && lines_left == 0)
@@ -1740,18 +1695,15 @@ static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse)
cw = 1;
l = 1;
}
- /* When drawing from right to left or when a double-wide character
- * doesn't fit, draw a single character here. Otherwise collect
- * characters and draw them all at once later. */
- if (
- cmdmsg_rl
- ||
- (cw > 1 && msg_col + t_col >= Columns - 1)
- ) {
- if (l > 1)
+ // When drawing from right to left or when a double-wide character
+ // doesn't fit, draw a single character here. Otherwise collect
+ // characters and draw them all at once later.
+ if (cmdmsg_rl || (cw > 1 && msg_col + t_col >= Columns - 1)) {
+ if (l > 1) {
s = screen_puts_mbyte(s, l, attr) - 1;
- else
+ } else {
msg_screen_putchar(*s, attr);
+ }
} else {
/* postpone this character until later */
if (t_col == 0)
@@ -1787,25 +1739,24 @@ static void msg_scroll_up(void)
static void inc_msg_scrolled(void)
{
if (*get_vim_var_str(VV_SCROLLSTART) == NUL) {
- char_u *p = sourcing_name;
- char_u *tofree = NULL;
- int len;
-
- /* v:scrollstart is empty, set it to the script/function name and line
- * number */
- if (p == NULL)
- p = (char_u *)_("Unknown");
- else {
- len = (int)STRLEN(p) + 40;
+ char *p = (char *) sourcing_name;
+ char *tofree = NULL;
+
+ // v:scrollstart is empty, set it to the script/function name and line
+ // number
+ if (p == NULL) {
+ p = _("Unknown");
+ } else {
+ size_t len = strlen(p) + 40;
tofree = xmalloc(len);
- vim_snprintf((char *)tofree, len, _("%s line %" PRId64),
- p, (int64_t)sourcing_lnum);
+ vim_snprintf(tofree, len, _("%s line %" PRId64),
+ p, (int64_t) sourcing_lnum);
p = tofree;
}
set_vim_var_string(VV_SCROLLSTART, p, -1);
xfree(tofree);
}
- ++msg_scrolled;
+ msg_scrolled++;
}
static msgchunk_T *last_msgchunk = NULL; /* last displayed text */
@@ -1968,46 +1919,46 @@ int msg_use_printf(void)
return !embedded_mode && !ui_active();
}
-/*
- * Print a message when there is no valid screen.
- */
-static void msg_puts_printf(char_u *str, int maxlen)
+/// Print a message when there is no valid screen.
+static void msg_puts_printf(char *str, int maxlen)
{
- char_u *s = str;
- char_u buf[4];
- char_u *p;
+ char *s = str;
+ char buf[4];
+ char *p;
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) {
if (!(silent_mode && p_verbose == 0)) {
- /* NL --> CR NL translation (for Unix, not for "--version") */
- /* NL --> CR translation (for Mac) */
+ // NL --> CR NL translation (for Unix, not for "--version")
p = &buf[0];
- if (*s == '\n' && !info_message)
+ if (*s == '\n' && !info_message) {
*p++ = '\r';
+ }
*p++ = *s;
*p = '\0';
- if (info_message) /* informative message, not an error */
- mch_msg((char *)buf);
- else
- mch_errmsg((char *)buf);
+ if (info_message) {
+ mch_msg(buf);
+ } else {
+ mch_errmsg(buf);
+ }
}
- /* primitive way to compute the current column */
+ // primitive way to compute the current column
if (cmdmsg_rl) {
- if (*s == '\r' || *s == '\n')
+ if (*s == '\r' || *s == '\n') {
msg_col = Columns - 1;
- else
- --msg_col;
+ } else {
+ msg_col--;
+ }
} else {
- if (*s == '\r' || *s == '\n')
+ if (*s == '\r' || *s == '\n') {
msg_col = 0;
- else
- ++msg_col;
+ } else {
+ msg_col++;
+ }
}
- ++s;
+ s++;
}
- msg_didout = TRUE; /* assume that line is not empty */
-
+ msg_didout = true; // assume that line is not empty
}
/*
@@ -2572,7 +2523,7 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
/* Don't want a hit-enter prompt here. */
++no_wait_return;
- set_vim_var_string(VV_WARNINGMSG, message, -1);
+ set_vim_var_string(VV_WARNINGMSG, (char *) message, -1);
xfree(keep_msg);
keep_msg = NULL;
if (hl)
@@ -3086,7 +3037,7 @@ int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...)
return str_l;
}
-int vim_snprintf(char *str, size_t str_m, char *fmt, ...)
+int vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
{
va_list ap;
int str_l;
@@ -3097,11 +3048,12 @@ int vim_snprintf(char *str, size_t str_m, char *fmt, ...)
return str_l;
}
-int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
+int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,
+ typval_T *tvs)
{
size_t str_l = 0;
bool str_avail = str_l < str_m;
- char *p = fmt;
+ const char *p = fmt;
int arg_idx = 1;
if (!p) {
@@ -3135,7 +3087,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
char tmp[TMP_LEN];
// string address in case of string argument
- char *str_arg;
+ const char *str_arg;
// natural field width of arg without padding and sign
size_t str_arg_l;
@@ -3413,8 +3365,8 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// leave negative numbers for sprintf to handle, to
// avoid handling tricky cases like (short int)-32768
} else if (alternate_form) {
- if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' ||
- fmt_spec == 'b' || fmt_spec == 'B')) {
+ if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X'
+ || fmt_spec == 'b' || fmt_spec == 'B')) {
tmp[str_arg_l++] = '0';
tmp[str_arg_l++] = fmt_spec;
}
diff --git a/src/nvim/message.h b/src/nvim/message.h
index 019c7bfb73..d3a16fff93 100644
--- a/src/nvim/message.h
+++ b/src/nvim/message.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdarg.h>
#include "nvim/eval_defs.h" // for typval_T
+#include "nvim/ex_cmds_defs.h" // for exarg_T
/*
* Types of dialogs passed to do_dialog().
@@ -24,6 +25,56 @@
#define VIM_ALL 5
#define VIM_DISCARDALL 6
+/// Show plain message
+#define MSG(s) msg((char_u *)(s))
+
+/// Show message highlighted according to the attr
+#define MSG_ATTR(s, attr) msg_attr((char_u *)(s), (attr))
+
+/// Display error message
+///
+/// Sets error flag in process, can be transformed into an exception.
+#define EMSG(s) emsg((char_u *)(s))
+
+/// Like #EMSG, but for messages with one "%s" inside
+#define EMSG2(s, p) emsgf((const char *) (s), (p))
+
+/// Like #EMSG, but for messages with two "%s" inside
+#define EMSG3(s, p, q) emsgf((const char *) (s), (p), (q))
+
+/// Like #EMSG, but for messages with one "%" PRId64 inside
+#define EMSGN(s, n) emsgf((const char *) (s), (int64_t)(n))
+
+/// Like #EMSG, but for messages with one "%" PRIu64 inside
+#define EMSGU(s, n) emsgf((const char *) (s), (uint64_t)(n))
+
+/// Display message at the recorded position
+#define MSG_PUTS(s) msg_puts((char_u *)(s))
+
+/// Display message at the recorded position, highlighted
+#define MSG_PUTS_ATTR(s, a) msg_puts_attr((char_u *)(s), (a))
+
+/// Like #MSG_PUTS, but highlight like title
+#define MSG_PUTS_TITLE(s) msg_puts_title((char_u *)(s))
+
+/// Like #MSG_PUTS, but if middle part of too long messages it will be replaced
+#define MSG_PUTS_LONG(s) msg_puts_long_attr((char_u *)(s), 0)
+
+/// Like #MSG_PUTS_ATTR, but if middle part of long messages will be replaced
+#define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a))
+
+/// Message history for `:messages`
+typedef struct msg_hist {
+ struct msg_hist *next; ///< Next message.
+ char_u *msg; ///< Message text.
+ int attr; ///< Message highlighting.
+} MessageHistoryEntry;
+
+/// First message
+extern MessageHistoryEntry *first_msg_hist;
+/// Last message
+extern MessageHistoryEntry *last_msg_hist;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "message.h.generated.h"
#endif
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index db303fd54a..48791384a6 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -43,7 +43,6 @@
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
-#include "nvim/tempfile.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/window.h"
@@ -86,38 +85,32 @@ open_line (
int second_line_indent
)
{
- char_u *saved_line; /* copy of the original line */
- char_u *next_line = NULL; /* copy of the next line */
- char_u *p_extra = NULL; /* what goes to next line */
- int less_cols = 0; /* less columns for mark in new line */
- int less_cols_off = 0; /* columns to skip for mark adjust */
- pos_T old_cursor; /* old cursor position */
- int newcol = 0; /* new cursor column */
- int newindent = 0; /* auto-indent of the new line */
- int n;
- int trunc_line = FALSE; /* truncate current line afterwards */
- int retval = FALSE; /* return value, default is FAIL */
- int extra_len = 0; /* length of p_extra string */
- int lead_len; /* length of comment leader */
- char_u *lead_flags; /* position in 'comments' for comment leader */
- char_u *leader = NULL; /* copy of comment leader */
- char_u *allocated = NULL; /* allocated memory */
- char_u *p;
- int saved_char = NUL; /* init for GCC */
- pos_T *pos;
- int do_si = (!p_paste && curbuf->b_p_si
- && !curbuf->b_p_cin
- );
- int no_si = FALSE; /* reset did_si afterwards */
- int first_char = NUL; /* init for GCC */
+ char_u *next_line = NULL; // copy of the next line
+ char_u *p_extra = NULL; // what goes to next line
+ colnr_T less_cols = 0; // less columns for mark in new line
+ colnr_T less_cols_off = 0; // columns to skip for mark adjust
+ pos_T old_cursor; // old cursor position
+ colnr_T newcol = 0; // new cursor column
+ int newindent = 0; // auto-indent of the new line
+ bool trunc_line = false; // truncate current line afterwards
+ bool retval = false; // return value, default is false
+ int extra_len = 0; // length of p_extra string
+ int lead_len; // length of comment leader
+ char_u *lead_flags; // position in 'comments' for comment leader
+ char_u *leader = NULL; // copy of comment leader
+ char_u *allocated = NULL; // allocated memory
+ char_u *p;
+ char_u saved_char = NUL; // init for GCC
+ pos_T *pos;
+ bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin);
+ bool no_si = false; // reset did_si afterwards
+ int first_char = NUL; // init for GCC
int vreplace_mode;
- int did_append; /* appended a new line */
- int saved_pi = curbuf->b_p_pi; /* copy of preserveindent setting */
+ bool did_append; // appended a new line
+ int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
- /*
- * make a copy of the current line so we can mess with it
- */
- saved_line = vim_strsave(get_cursor_line_ptr());
+ // make a copy of the current line so we can mess with it
+ char_u *saved_line = vim_strsave(get_cursor_line_ptr());
if (State & VREPLACE_FLAG) {
/*
@@ -204,22 +197,19 @@ open_line (
char_u *ptr;
char_u last_char;
- old_cursor = curwin->w_cursor;
+ pos_T old_cursor = curwin->w_cursor;
ptr = saved_line;
if (flags & OPENLINE_DO_COM)
lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
else
lead_len = 0;
if (dir == FORWARD) {
- /*
- * Skip preprocessor directives, unless they are
- * recognised as comments.
- */
- if (
- lead_len == 0 &&
- ptr[0] == '#') {
- while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
+ // Skip preprocessor directives, unless they are
+ // recognised as comments.
+ if (lead_len == 0 && ptr[0] == '#') {
+ while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) {
ptr = ml_get(--curwin->w_cursor.lnum);
+ }
newindent = get_indent();
}
if (flags & OPENLINE_DO_COM)
@@ -303,28 +293,26 @@ open_line (
&& cin_is_cinword(ptr))
did_si = TRUE;
}
- } else { /* dir == BACKWARD */
- /*
- * Skip preprocessor directives, unless they are
- * recognised as comments.
- */
- if (
- lead_len == 0 &&
- ptr[0] == '#') {
- int was_backslashed = FALSE;
-
- while ((ptr[0] == '#' || was_backslashed) &&
- curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
- was_backslashed = TRUE;
- else
- was_backslashed = FALSE;
+ } else { // dir == BACKWARD
+ // Skip preprocessor directives, unless they are
+ // recognised as comments.
+ if (lead_len == 0 && ptr[0] == '#') {
+ bool was_backslashed = false;
+
+ while ((ptr[0] == '#' || was_backslashed)
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
+ if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') {
+ was_backslashed = true;
+ } else {
+ was_backslashed = false;
+ }
ptr = ml_get(++curwin->w_cursor.lnum);
}
- if (was_backslashed)
- newindent = 0; /* Got to end of file */
- else
+ if (was_backslashed) {
+ newindent = 0; // Got to end of file
+ } else {
newindent = get_indent();
+ }
}
p = skipwhite(ptr);
if (*p == '}') /* if line starts with '}': do indent */
@@ -401,7 +389,7 @@ open_line (
end_comment_pending = -1; /* means we want to set it */
++p;
}
- n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+ size_t n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
if (end_comment_pending == -1) /* we can set it now */
end_comment_pending = lead_end[n - 1];
@@ -498,10 +486,11 @@ open_line (
}
}
if (lead_len > 0) {
- /* allocate buffer (may concatenate p_extra later) */
- leader = xmalloc(lead_len + lead_repl_len + extra_space + extra_len
- + (second_line_indent > 0 ? second_line_indent : 0) + 1);
- allocated = leader; /* remember to free it later */
+ // allocate buffer (may concatenate p_extra later)
+ leader = xmalloc((size_t)(lead_len + lead_repl_len + extra_space
+ + extra_len + (second_line_indent > 0
+ ? second_line_indent : 0) + 1));
+ allocated = leader; // remember to free it later
STRLCPY(leader, saved_line, lead_len + 1);
@@ -598,9 +587,8 @@ open_line (
if (!ascii_iswhite(*p)) {
/* Don't put a space before a TAB. */
if (p + 1 < leader + lead_len && p[1] == TAB) {
- --lead_len;
- memmove(p, p + 1,
- (leader + lead_len) - p);
+ lead_len--;
+ memmove(p, p + 1, (size_t)(leader + lead_len - p));
} else {
int l = (*mb_ptr2len)(p);
@@ -611,8 +599,7 @@ open_line (
--l;
*p++ = ' ';
}
- memmove(p + 1, p + l,
- (leader + lead_len) - p);
+ memmove(p + 1, p + l, (size_t)(leader + lead_len - p));
lead_len -= l - 1;
}
*p = ' ';
@@ -675,16 +662,12 @@ open_line (
did_si = can_si = FALSE;
} else if (comment_end != NULL) {
- /*
- * We have finished a comment, so we don't use the leader.
- * If this was a C-comment and 'ai' or 'si' is set do a normal
- * indent to align with the line containing the start of the
- * comment.
- */
- if (comment_end[0] == '*' && comment_end[1] == '/' &&
- (curbuf->b_p_ai
- || do_si
- )) {
+ // We have finished a comment, so we don't use the leader.
+ // If this was a C-comment and 'ai' or 'si' is set do a normal
+ // indent to align with the line containing the start of the
+ // comment.
+ if (comment_end[0] == '*' && comment_end[1] == '/'
+ && (curbuf->b_p_ai || do_si)) {
old_cursor = curwin->w_cursor;
curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
if ((pos = findmatch(NULL, NUL)) != NULL) {
@@ -813,9 +796,11 @@ open_line (
* In REPLACE mode, for each character in the new indent, there must
* be a NUL on the replace stack, for when it is deleted with BS
*/
- if (REPLACE_NORMAL(State))
- for (n = 0; n < (int)curwin->w_cursor.col; ++n)
+ if (REPLACE_NORMAL(State)) {
+ for (colnr_T n = 0; n < curwin->w_cursor.col; n++) {
replace_push(NUL);
+ }
+ }
newcol += curwin->w_cursor.col;
if (no_si)
did_si = FALSE;
@@ -1281,11 +1266,13 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
* Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
*/
width = wp->w_width - win_col_off(wp);
- if (width <= 0)
- return 32000;
- if (col <= (unsigned int)width)
+ if (width <= 0) {
+ return 32000; // bigger than the number of lines of the screen
+ }
+ if (col <= (unsigned int)width) {
return 1;
- col -= width;
+ }
+ col -= (unsigned int)width;
width += win_col_off2(wp);
assert(col <= INT_MAX && (int)col < INT_MAX - (width -1));
return ((int)col + (width - 1)) / width + 1;
@@ -1297,15 +1284,9 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
*/
int plines_win_col(win_T *wp, linenr_T lnum, long column)
{
- long col;
- char_u *s;
- int lines = 0;
- int width;
- char_u *line;
-
- /* Check for filler lines above this buffer line. When folded the result
- * is one line anyway. */
- lines = diff_check_fill(wp, lnum);
+ // Check for filler lines above this buffer line. When folded the result
+ // is one line anyway.
+ int lines = diff_check_fill(wp, lnum);
if (!wp->w_p_wrap)
return lines + 1;
@@ -1313,30 +1294,29 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
if (wp->w_width == 0)
return lines + 1;
- line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
+ char_u *s = line;
- col = 0;
+ colnr_T col = 0;
while (*s != NUL && --column >= 0) {
- col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
+ col += win_lbr_chartabsize(wp, line, s, col, NULL);
mb_ptr_adv(s);
}
- /*
- * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
- * INSERT mode, then col must be adjusted so that it represents the last
- * screen position of the TAB. This only fixes an error when the TAB wraps
- * from one screen line to the next (when 'columns' is not a multiple of
- * 'ts') -- webb.
- */
- if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
- col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
+ // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
+ // INSERT mode, then col must be adjusted so that it represents the last
+ // screen position of the TAB. This only fixes an error when the TAB wraps
+ // from one screen line to the next (when 'columns' is not a multiple of
+ // 'ts') -- webb.
+ if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1)) {
+ col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1;
+ }
- /*
- * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
- */
- width = wp->w_width - win_col_off(wp);
- if (width <= 0)
+ // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
+ int width = wp->w_width - win_col_off(wp);
+ if (width <= 0) {
return 9999;
+ }
lines += 1;
if (col > width)
@@ -1349,11 +1329,9 @@ int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
int count = 0;
while (first <= last) {
- int x;
-
- /* Check if there are any really folded lines, but also included lines
- * that are maybe folded. */
- x = foldedCount(wp, first, NULL);
+ // Check if there are any really folded lines, but also included lines
+ // that are maybe folded.
+ linenr_T x = foldedCount(wp, first, NULL);
if (x > 0) {
++count; /* count 1 for "+-- folded" line */
first += x;
@@ -1374,117 +1352,99 @@ int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
*/
void ins_bytes(char_u *p)
{
- ins_bytes_len(p, (int)STRLEN(p));
+ ins_bytes_len(p, STRLEN(p));
}
-/*
- * Insert string "p" with length "len" at the cursor position.
- * Handles Replace mode and multi-byte characters.
- */
-void ins_bytes_len(char_u *p, int len)
+/// Insert string "p" with length "len" at the cursor position.
+/// Handles Replace mode and multi-byte characters.
+void ins_bytes_len(char_u *p, size_t len)
{
- int i;
- int n;
-
- if (has_mbyte)
- for (i = 0; i < len; i += n) {
- if (enc_utf8)
- /* avoid reading past p[len] */
- n = utfc_ptr2len_len(p + i, len - i);
- else
- n = (*mb_ptr2len)(p + i);
+ if (has_mbyte) {
+ size_t n;
+ for (size_t i = 0; i < len; i += n) {
+ if (enc_utf8) {
+ // avoid reading past p[len]
+ n = (size_t)utfc_ptr2len_len(p + i, (int)(len - i));
+ } else {
+ n = (size_t)(*mb_ptr2len)(p + i);
+ }
ins_char_bytes(p + i, n);
}
- else
- for (i = 0; i < len; ++i)
+ } else {
+ for (size_t i = 0; i < len; i++) {
ins_char(p[i]);
+ }
+ }
}
-/*
- * Insert or replace a single character at the cursor position.
- * When in REPLACE or VREPLACE mode, replace any existing character.
- * Caller must have prepared for undo.
- * For multi-byte characters we get the whole character, the caller must
- * convert bytes to a character.
- */
+/// Insert or replace a single character at the cursor position.
+/// When in REPLACE or VREPLACE mode, replace any existing character.
+/// Caller must have prepared for undo.
+/// For multi-byte characters we get the whole character, the caller must
+/// convert bytes to a character.
void ins_char(int c)
{
char_u buf[MB_MAXBYTES + 1];
- int n;
-
- n = (*mb_char2bytes)(c, buf);
+ size_t n = (size_t)(*mb_char2bytes)(c, buf);
- /* When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
- * Happens for CTRL-Vu9900. */
- if (buf[0] == 0)
+ // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
+ // Happens for CTRL-Vu9900.
+ if (buf[0] == 0) {
buf[0] = '\n';
-
+ }
ins_char_bytes(buf, n);
}
-void ins_char_bytes(char_u *buf, int charlen)
+void ins_char_bytes(char_u *buf, size_t charlen)
{
- int c = buf[0];
- int newlen; /* nr of bytes inserted */
- int oldlen; /* nr of bytes deleted (0 when not replacing) */
- char_u *p;
- char_u *newp;
- char_u *oldp;
- int linelen; /* length of old line including NUL */
- colnr_T col;
- linenr_T lnum = curwin->w_cursor.lnum;
- int i;
-
- /* Break tabs if needed. */
- if (virtual_active() && curwin->w_cursor.coladd > 0)
+ // Break tabs if needed.
+ if (virtual_active() && curwin->w_cursor.coladd > 0) {
coladvance_force(getviscol());
+ }
- col = curwin->w_cursor.col;
- oldp = ml_get(lnum);
- linelen = (int)STRLEN(oldp) + 1;
+ int c = buf[0];
+ size_t col = (size_t)curwin->w_cursor.col;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ char_u *oldp = ml_get(lnum);
+ size_t linelen = STRLEN(oldp) + 1; // length of old line including NUL
- /* The lengths default to the values for when not replacing. */
- oldlen = 0;
- newlen = charlen;
+ // The lengths default to the values for when not replacing.
+ size_t oldlen = 0; // nr of bytes inserted
+ size_t newlen = charlen; // nr of bytes deleted (0 when not replacing)
if (State & REPLACE_FLAG) {
if (State & VREPLACE_FLAG) {
- colnr_T new_vcol = 0; /* init for GCC */
+ // Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
+ // Returns the old value of list, so when finished,
+ // curwin->w_p_list should be set back to this.
+ int old_list = curwin->w_p_list;
+ if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) {
+ curwin->w_p_list = false;
+ }
+ // In virtual replace mode each character may replace one or more
+ // characters (zero if it's a TAB). Count the number of bytes to
+ // be deleted to make room for the new character, counting screen
+ // cells. May result in adding spaces to fill a gap.
colnr_T vcol;
- int old_list;
-
- /*
- * Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
- * Returns the old value of list, so when finished,
- * curwin->w_p_list should be set back to this.
- */
- old_list = curwin->w_p_list;
- if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
- curwin->w_p_list = FALSE;
-
- /*
- * In virtual replace mode each character may replace one or more
- * characters (zero if it's a TAB). Count the number of bytes to
- * be deleted to make room for the new character, counting screen
- * cells. May result in adding spaces to fill a gap.
- */
getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL);
- new_vcol = vcol + chartabsize(buf, vcol);
+ colnr_T new_vcol = vcol + chartabsize(buf, vcol);
while (oldp[col + oldlen] != NUL && vcol < new_vcol) {
vcol += chartabsize(oldp + col + oldlen, vcol);
- /* Don't need to remove a TAB that takes us to the right
- * position. */
- if (vcol > new_vcol && oldp[col + oldlen] == TAB)
+ // Don't need to remove a TAB that takes us to the right
+ // position.
+ if (vcol > new_vcol && oldp[col + oldlen] == TAB) {
break;
- oldlen += (*mb_ptr2len)(oldp + col + oldlen);
- /* Deleted a bit too much, insert spaces. */
- if (vcol > new_vcol)
- newlen += vcol - new_vcol;
+ }
+ oldlen += (size_t)(*mb_ptr2len)(oldp + col + oldlen);
+ // Deleted a bit too much, insert spaces.
+ if (vcol > new_vcol) {
+ newlen += (size_t)(vcol - new_vcol);
+ }
}
curwin->w_p_list = old_list;
} else if (oldp[col] != NUL) {
- /* normal replace */
- oldlen = (*mb_ptr2len)(oldp + col);
+ // normal replace
+ oldlen = (size_t)(*mb_ptr2len)(oldp + col);
}
@@ -1493,38 +1453,39 @@ void ins_char_bytes(char_u *buf, int charlen)
* done the other way around, so that the first byte is popped off
* first (it tells the byte length of the character). */
replace_push(NUL);
- for (i = 0; i < oldlen; ++i) {
- if (has_mbyte)
- i += replace_push_mb(oldp + col + i) - 1;
- else
+ for (size_t i = 0; i < oldlen; i++) {
+ if (has_mbyte) {
+ i += (size_t)replace_push_mb(oldp + col + i) - 1;
+ } else {
replace_push(oldp[col + i]);
+ }
}
}
- newp = (char_u *) xmalloc((size_t)(linelen + newlen - oldlen));
+ char_u *newp = (char_u *) xmalloc((size_t)(linelen + newlen - oldlen));
- /* Copy bytes before the cursor. */
- if (col > 0)
+ // Copy bytes before the cursor.
+ if (col > 0) {
memmove(newp, oldp, (size_t)col);
+ }
- /* Copy bytes after the changed character(s). */
- p = newp + col;
- memmove(p + newlen, oldp + col + oldlen,
- (size_t)(linelen - col - oldlen));
+ // Copy bytes after the changed character(s).
+ char_u *p = newp + col;
+ memmove(p + newlen, oldp + col + oldlen, (size_t)(linelen - col - oldlen));
- /* Insert or overwrite the new character. */
+ // Insert or overwrite the new character.
memmove(p, buf, charlen);
- i = charlen;
- /* Fill with spaces when necessary. */
- while (i < newlen)
- p[i++] = ' ';
+ // Fill with spaces when necessary.
+ for (size_t i = charlen; i < newlen; i++) {
+ p[i] = ' ';
+ }
/* Replace the line in the buffer. */
ml_replace(lnum, newp, FALSE);
- /* mark the buffer as changed and prepare for displaying */
- changed_bytes(lnum, col);
+ // mark the buffer as changed and prepare for displaying
+ changed_bytes(lnum, (colnr_T)col);
/*
* If we're in Insert or Replace mode and 'showmatch' is set, then briefly
@@ -1541,8 +1502,8 @@ void ins_char_bytes(char_u *buf, int charlen)
}
if (!p_ri || (State & REPLACE_FLAG)) {
- /* Normal insert: move cursor right */
- curwin->w_cursor.col += charlen;
+ // Normal insert: move cursor right
+ curwin->w_cursor.col += (int)charlen;
}
/*
* TODO: should try to update w_row here, to avoid recomputing it later.
@@ -1595,7 +1556,7 @@ int del_char(int fixpos)
return FAIL;
return del_chars(1L, fixpos);
}
- return del_bytes(1L, fixpos, TRUE);
+ return del_bytes(1, fixpos, true);
}
/*
@@ -1603,7 +1564,7 @@ int del_char(int fixpos)
*/
int del_chars(long count, int fixpos)
{
- long bytes = 0;
+ int bytes = 0;
long i;
char_u *p;
int l;
@@ -1617,30 +1578,22 @@ int del_chars(long count, int fixpos)
return del_bytes(bytes, fixpos, TRUE);
}
-/*
- * Delete "count" bytes under the cursor.
- * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
- * Caller must have prepared for undo.
- *
- * return FAIL for failure, OK otherwise
- */
-int
-del_bytes (
- long count,
- int fixpos_arg,
- int use_delcombine /* 'delcombine' option applies */
-)
+/// Delete "count" bytes under the cursor.
+/// If "fixpos" is true, don't leave the cursor on the NUL after the line.
+/// Caller must have prepared for undo.
+///
+/// @param count number of bytes to be deleted
+/// @param fixpos_arg leave the cursor on the NUL after the line
+/// @param use_delcombine 'delcombine' option applies
+///
+/// @return FAIL for failure, OK otherwise
+int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
{
- char_u *oldp, *newp;
- colnr_T oldlen;
linenr_T lnum = curwin->w_cursor.lnum;
colnr_T col = curwin->w_cursor.col;
- int was_alloced;
- long movelen;
- int fixpos = fixpos_arg;
-
- oldp = ml_get(lnum);
- oldlen = (int)STRLEN(oldp);
+ bool fixpos = fixpos_arg;
+ char_u *oldp = ml_get(lnum);
+ colnr_T oldlen = (colnr_T)STRLEN(oldp);
/*
* Can't do anything when the cursor is on the NUL after the line.
@@ -1664,14 +1617,12 @@ del_bytes (
count = utf_ptr2len(oldp + n);
n += count;
} while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
- fixpos = 0;
+ fixpos = false;
}
}
- /*
- * When count is too big, reduce it.
- */
- movelen = (long)oldlen - (long)col - count + 1; /* includes trailing NUL */
+ // When count is too big, reduce it.
+ int movelen = oldlen - col - count + 1; // includes trailing NUL
if (movelen <= 1) {
/*
* If we just took off the last character of a non-blank line, and
@@ -1691,15 +1642,14 @@ del_bytes (
movelen = 1;
}
- /*
- * If the old line has been allocated the deletion can be done in the
- * existing line. Otherwise a new line has to be allocated.
- */
- was_alloced = ml_line_alloced(); /* check if oldp was allocated */
- if (was_alloced)
- newp = oldp; /* use same allocated memory */
- else { /* need to allocate a new line */
- newp = xmalloc(oldlen + 1 - count);
+ // If the old line has been allocated the deletion can be done in the
+ // existing line. Otherwise a new line has to be allocated.
+ bool was_alloced = ml_line_alloced(); // check if oldp was allocated
+ char_u *newp;
+ if (was_alloced) {
+ newp = oldp; // use same allocated memory
+ } else { // need to allocate a new line
+ newp = xmalloc((size_t)(oldlen + 1 - count));
memmove(newp, oldp, (size_t)col);
}
memmove(newp + col, oldp + col + count, (size_t)movelen);
@@ -1725,12 +1675,12 @@ truncate_line (
linenr_T lnum = curwin->w_cursor.lnum;
colnr_T col = curwin->w_cursor.col;
- if (col == 0)
+ if (col == 0) {
newp = vim_strsave((char_u *)"");
- else
- newp = vim_strnsave(ml_get(lnum), col);
-
- ml_replace(lnum, newp, FALSE);
+ } else {
+ newp = vim_strnsave(ml_get(lnum), (size_t)col);
+ }
+ ml_replace(lnum, newp, false);
/* mark the buffer as changed and prepare for displaying */
changed_bytes(lnum, curwin->w_cursor.col);
@@ -1827,6 +1777,9 @@ void changed(void)
if (curbuf->b_may_swap
&& !bt_dontwrite(curbuf)
) {
+ int save_need_wait_return = need_wait_return;
+
+ need_wait_return = false;
ml_open_file(curbuf);
/* The ml_open_file() can cause an ATTENTION message.
@@ -1838,6 +1791,8 @@ void changed(void)
os_delay(2000L, true);
wait_return(TRUE);
msg_scroll = save_msg_scroll;
+ } else {
+ need_wait_return = save_need_wait_return;
}
}
changed_int();
@@ -2250,7 +2205,7 @@ change_warning (
msg_col = col;
msg_source(hl_attr(HLF_W));
MSG_PUTS_ATTR(_(w_readonly), hl_attr(HLF_W) | MSG_HIST);
- set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1);
+ set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
msg_clr_eos();
(void)msg_end();
if (msg_silent == 0 && !silent_mode) {
@@ -2360,13 +2315,13 @@ int get_keystroke(void)
* 5 chars plus NUL). And fix_input_buffer() can triple the number of
* bytes. */
maxlen = (buflen - 6 - len) / 3;
- if (buf == NULL)
- buf = xmalloc(buflen);
- else if (maxlen < 10) {
- /* Need some more space. This might happen when receiving a long
- * escape sequence. */
+ 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, buflen);
+ buf = xrealloc(buf, (size_t)buflen);
maxlen = (buflen - 6 - len) / 3;
}
@@ -2729,38 +2684,33 @@ void fast_breakcheck(void)
}
}
-/*
- * 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.
- * Returns an allocated string, or NULL for error.
- */
-char_u *
-get_cmd_output (
- char_u *cmd,
- char_u *infile, /* optional input file name */
- int flags, // can be kShellOptSilent
- size_t *ret_len
-)
+/// 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 *tempname;
- char_u *command;
- char_u *buffer = NULL;
- int len;
- int i = 0;
- FILE *fd;
+ char_u *buffer = NULL;
if (check_restricted() || check_secure())
return NULL;
- /* get a name for the temp file */
- if ((tempname = vim_tempname()) == 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 */
- command = make_filter_cmd(cmd, infile, tempname);
+ // Add the redirection stuff
+ char_u *command = make_filter_cmd(cmd, infile, tempname);
/*
* Call the shell to execute the command (errors are ignored).
@@ -2772,10 +2722,8 @@ get_cmd_output (
xfree(command);
- /*
- * read the names from the file into memory
- */
- fd = mch_fopen((char *)tempname, READBIN);
+ // read the names from the file into memory
+ FILE *fd = mch_fopen((char *)tempname, READBIN);
if (fd == NULL) {
EMSG2(_(e_notopen), tempname);
@@ -2783,11 +2731,11 @@ get_cmd_output (
}
fseek(fd, 0L, SEEK_END);
- len = ftell(fd); /* get size of temp file */
+ size_t len = (size_t)ftell(fd); // get size of temp file
fseek(fd, 0L, SEEK_SET);
buffer = xmalloc(len + 1);
- i = (int)fread((char *)buffer, (size_t)1, (size_t)len, fd);
+ size_t i = fread((char *)buffer, 1, len, fd);
fclose(fd);
os_remove((char *)tempname);
if (i != len) {
diff --git a/src/nvim/misc1.h b/src/nvim/misc1.h
index 11891d6f7e..f0f66854d8 100644
--- a/src/nvim/misc1.h
+++ b/src/nvim/misc1.h
@@ -2,6 +2,7 @@
#define NVIM_MISC1_H
#include "nvim/vim.h"
+#include "nvim/os/shell.h"
/* flags for open_line() */
#define OPENLINE_DELSPACES 1 /* delete spaces after cursor */
diff --git a/src/nvim/misc2.c b/src/nvim/misc2.c
index 3c0a1414a6..4b64de1be0 100644
--- a/src/nvim/misc2.c
+++ b/src/nvim/misc2.c
@@ -327,9 +327,10 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
}
}
- set_vim_var_nr(VV_SHELL_ERROR, (long)retval);
- if (do_profiling == PROF_YES)
+ set_vim_var_nr(VV_SHELL_ERROR, (varnumber_T) retval);
+ if (do_profiling == PROF_YES) {
prof_child_exit(&wait_time);
+ }
return retval;
}
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 3ae1a6a890..2f499e477c 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -14,6 +14,8 @@
#include "nvim/misc1.h"
#include "nvim/cursor.h"
#include "nvim/buffer_defs.h"
+#include "nvim/memline.h"
+#include "nvim/charset.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mouse.c.generated.h"
@@ -503,3 +505,95 @@ void set_mouse_topline(win_T *wp)
orig_topfill = wp->w_topfill;
}
+///
+/// Return length of line "lnum" for horizontal scrolling.
+///
+static colnr_T scroll_line_len(linenr_T lnum)
+{
+ colnr_T col = 0;
+ char_u *line = ml_get(lnum);
+ if (*line != NUL) {
+ for (;;) {
+ int numchar = chartabsize(line, col);
+ mb_ptr_adv(line);
+ if (*line == NUL) { // don't count the last character
+ break;
+ }
+ col += numchar;
+ }
+ }
+ return col;
+}
+
+///
+/// Find longest visible line number.
+///
+static linenr_T find_longest_lnum(void)
+{
+ linenr_T ret = 0;
+
+ // Calculate maximum for horizontal scrollbar. Check for reasonable
+ // line numbers, topline and botline can be invalid when displaying is
+ // postponed.
+ if (curwin->w_topline <= curwin->w_cursor.lnum
+ && curwin->w_botline > curwin->w_cursor.lnum
+ && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1) {
+ long max = 0;
+
+ // Use maximum of all visible lines. Remember the lnum of the
+ // longest line, closest to the cursor line. Used when scrolling
+ // below.
+ for (linenr_T lnum = curwin->w_topline; lnum < curwin->w_botline; lnum++) {
+ colnr_T len = scroll_line_len(lnum);
+ if (len > (colnr_T)max) {
+ max = len;
+ ret = lnum;
+ } else if (len == (colnr_T)max
+ && abs((int)(lnum - curwin->w_cursor.lnum))
+ < abs((int)(ret - curwin->w_cursor.lnum))) {
+ ret = lnum;
+ }
+ }
+ } else {
+ // Use cursor line only.
+ ret = curwin->w_cursor.lnum;
+ }
+
+ return ret;
+}
+
+///
+/// Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise.
+///
+bool mouse_scroll_horiz(int dir)
+{
+ if (curwin->w_p_wrap) {
+ return false;
+ }
+
+ int step = 6;
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
+ step = curwin->w_width;
+ }
+
+ int leftcol = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : +step);
+ if (leftcol < 0) {
+ leftcol = 0;
+ }
+
+ if (curwin->w_leftcol == leftcol) {
+ return false;
+ }
+
+ curwin->w_leftcol = (colnr_T)leftcol;
+
+ // When the line of the cursor is too short, move the cursor to the
+ // longest visible line.
+ if (!virtual_active()
+ && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum)) {
+ curwin->w_cursor.lnum = find_longest_lnum();
+ curwin->w_cursor.col = 0;
+ }
+
+ return leftcol_changed();
+}
diff --git a/src/nvim/mouse.h b/src/nvim/mouse.h
index c824bcc8f0..0149f7c7c0 100644
--- a/src/nvim/mouse.h
+++ b/src/nvim/mouse.h
@@ -34,6 +34,12 @@
#define MOUSE_X1 0x300 // Mouse-button X1 (6th)
#define MOUSE_X2 0x400 // Mouse-button X2
+// Direction for nv_mousescroll() and ins_mousescroll()
+#define MSCR_DOWN 0 // DOWN must be FALSE
+#define MSCR_UP 1
+#define MSCR_LEFT -1
+#define MSCR_RIGHT -2
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mouse.h.generated.h"
diff --git a/src/nvim/move.c b/src/nvim/move.c
index ba79c0411a..b129c5cb7a 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1010,12 +1010,9 @@ scrollup (
int byfold /* true: count a closed fold as one line */
)
{
- if (
- (byfold && hasAnyFolding(curwin))
- ||
- curwin->w_p_diff
- ) {
- /* count each sequence of folded lines as one logical line */
+ if ((byfold && hasAnyFolding(curwin))
+ || curwin->w_p_diff) {
+ // count each sequence of folded lines as one logical line
linenr_T lnum = curwin->w_topline;
while (line_count--) {
if (curwin->w_topfill > 0)
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 5ef81721d4..0049ae6b95 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -419,8 +419,8 @@ void msgpack_rpc_validate(uint64_t *response_id,
return;
}
- if ((type == kMessageTypeRequest && req->via.array.size != 4) ||
- (type == kMessageTypeNotification && req->via.array.size != 3)) {
+ if ((type == kMessageTypeRequest && req->via.array.size != 4)
+ || (type == kMessageTypeNotification && req->via.array.size != 3)) {
api_set_error(err, Validation, _("Request array size should be 4 (request) "
"or 3 (notification)"));
return;
diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c
index f0d92b52a0..6ffcffe2e1 100644
--- a/src/nvim/msgpack_rpc/remote_ui.c
+++ b/src/nvim/msgpack_rpc/remote_ui.c
@@ -96,6 +96,7 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id,
ui->visual_bell = remote_ui_visual_bell;
ui->update_fg = remote_ui_update_fg;
ui->update_bg = remote_ui_update_bg;
+ ui->update_sp = remote_ui_update_sp;
ui->flush = remote_ui_flush;
ui->suspend = remote_ui_suspend;
ui->set_title = remote_ui_set_title;
@@ -285,6 +286,10 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
PUT(hl, "background", INTEGER_OBJ(attrs.background));
}
+ if (attrs.special != -1) {
+ PUT(hl, "special", INTEGER_OBJ(attrs.special));
+ }
+
ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args);
}
@@ -323,6 +328,13 @@ static void remote_ui_update_bg(UI *ui, int bg)
push_call(ui, "update_bg", args);
}
+static void remote_ui_update_sp(UI *ui, int sp)
+{
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, INTEGER_OBJ(sp));
+ push_call(ui, "update_sp", args);
+}
+
static void remote_ui_flush(UI *ui)
{
UIData *data = ui->data;
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 474e25ffeb..6cc56ba3dd 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -14,7 +14,7 @@
#include "nvim/vim.h"
#include "nvim/memory.h"
#include "nvim/log.h"
-#include "nvim/tempfile.h"
+#include "nvim/fileio.h"
#include "nvim/path.h"
#include "nvim/strings.h"
@@ -59,7 +59,7 @@ static void set_vservername(garray_T *srvs)
char *default_server = (srvs->ga_len > 0)
? ((SocketWatcher **)srvs->ga_data)[0]->addr
: NULL;
- set_vim_var_string(VV_SEND_SERVER, (char_u *)default_server, -1);
+ set_vim_var_string(VV_SEND_SERVER, default_server, -1);
}
/// Teardown the server module
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e064d34e09..382c4943ff 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -569,36 +569,33 @@ static bool normal_need_aditional_char(NormalState *s)
static bool normal_need_redraw_mode_message(NormalState *s)
{
return (
- (
// 'showmode' is set and messages can be printed
- p_smd && msg_silent == 0
- // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual
- // mode
- && (restart_edit != 0 || (VIsual_active
- && s->old_pos.lnum == curwin->w_cursor.lnum
- && s->old_pos.col == curwin->w_cursor.col))
- // command-line must be cleared or redrawn
- && (clear_cmdline || redraw_cmdline)
- // some message was printed or scrolled
- && (msg_didout || (msg_didany && msg_scroll))
- // it is fine to remove the current message
- && !msg_nowait
- // the command was the result of direct user input and not a mapping
- && KeyTyped
- )
- ||
- // must restart insert mode, not in visual mode and error message is
- // being shown
- (restart_edit != 0 && !VIsual_active && (msg_scroll && emsg_on_display))
- )
- // no register was used
- && s->oa.regname == 0
- && !(s->ca.retval & CA_COMMAND_BUSY)
- && stuff_empty()
- && typebuf_typed()
- && emsg_silent == 0
- && !did_wait_return
- && s->oa.op_type == OP_NOP;
+ ((p_smd && msg_silent == 0
+ // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual
+ // mode
+ && (restart_edit != 0 || (VIsual_active
+ && s->old_pos.lnum == curwin->w_cursor.lnum
+ && s->old_pos.col == curwin->w_cursor.col))
+ // command-line must be cleared or redrawn
+ && (clear_cmdline || redraw_cmdline)
+ // some message was printed or scrolled
+ && (msg_didout || (msg_didany && msg_scroll))
+ // it is fine to remove the current message
+ && !msg_nowait
+ // the command was the result of direct user input and not a mapping
+ && KeyTyped)
+ // must restart insert mode, not in visual mode and error message is
+ // being shown
+ || (restart_edit != 0 && !VIsual_active && msg_scroll
+ && emsg_on_display))
+ // no register was used
+ && s->oa.regname == 0
+ && !(s->ca.retval & CA_COMMAND_BUSY)
+ && stuff_empty()
+ && typebuf_typed()
+ && emsg_silent == 0
+ && !did_wait_return
+ && s->oa.op_type == OP_NOP);
}
static void normal_redraw_mode_message(NormalState *s)
@@ -1436,19 +1433,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
curwin->w_p_lbr = false;
oap->is_VIsual = VIsual_active;
- if (oap->motion_force == 'V')
- oap->motion_type = MLINE;
- 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 == MLINE)
+ 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;
- /* If the motion already was characterwise, toggle "inclusive" */
- else if (oap->motion_type == MCHAR)
+ } else if (oap->motion_type == kMTCharWise) {
+ // If the motion already was characterwise, toggle "inclusive"
oap->inclusive = !oap->inclusive;
- oap->motion_type = MCHAR;
+ }
+ oap->motion_type = kMTCharWise;
} else if (oap->motion_force == Ctrl_V) {
- /* Change line- or characterwise motion into Visual block mode. */
+ // Change line- or characterwise motion into Visual block mode.
VIsual_active = true;
VIsual = oap->start;
VIsual_mode = Ctrl_V;
@@ -1586,13 +1584,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* automatically. */
curwin->w_valid &= ~VALID_VIRTCOL;
} else {
- /* Include folded lines completely. */
- if (!VIsual_active && oap->motion_type == MLINE) {
+ // Include folded lines completely.
+ if (!VIsual_active && oap->motion_type == kMTLineWise) {
if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum,
- NULL))
+ NULL)) {
curwin->w_cursor.col = 0;
- if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum))
+ }
+ 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;
@@ -1663,17 +1663,16 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
}
- /*
- * 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 == MLINE)
+ // 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 = MLINE;
+ oap->motion_type = kMTLineWise;
} else if (VIsual_mode == 'v') {
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
if (*ml_get_pos(&(oap->end)) == NUL
&& (include_line_break || !virtual_op)
) {
@@ -1731,7 +1730,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* 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 != MLINE
+ oap->empty = (oap->motion_type != kMTLineWise
&& (!oap->inclusive
|| (oap->op_type == OP_YANK
&& gchar_pos(&oap->end) == NUL))
@@ -1756,23 +1755,23 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
/*
* If the end of an operator is in column one while oap->motion_type
- * is MCHAR and oap->inclusive is false, we put op_end after the last
+ * 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 == MCHAR
+ 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 = MLINE;
- else {
+ 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;
@@ -1811,8 +1810,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
CancelRedo();
} else {
(void)op_delete(oap);
- if (oap->motion_type == MLINE && has_format_option(FO_AUTO))
- u_save_cursor(); /* cursor line wasn't saved yet */
+ if (oap->motion_type == kMTLineWise && has_format_option(FO_AUTO)) {
+ u_save_cursor(); // cursor line wasn't saved yet
+ }
auto_format(false, true);
}
break;
@@ -2011,7 +2011,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
/*
* if 'sol' not set, go back to old column for some commands
*/
- if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
+ 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;
@@ -2086,13 +2086,14 @@ static void op_function(oparg_T *oap)
/* 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 != MLINE && !oap->inclusive)
- /* Exclude the end position. */
+ if (oap->motion_type != kMTLineWise && !oap->inclusive) {
+ // Exclude the end position.
decl(&curbuf->b_op_end);
+ }
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
argv[0] = (char_u *)"block";
- } else if (oap->motion_type == MLINE) {
+ } else if (oap->motion_type == kMTLineWise) {
argv[0] = (char_u *)"line";
} else {
argv[0] = (char_u *)"char";
@@ -2344,9 +2345,12 @@ do_mouse (
if (mouse_row == 0 && firstwin->w_winrow > 0) {
if (is_drag) {
if (in_tab_line) {
- tabpage_move(tab_page_click_defs[mouse_col].type == kStlClickTabClose
- ? 9999
- : tab_page_click_defs[mouse_col].tabnr - 1);
+ if (tab_page_click_defs[mouse_col].type == kStlClickTabClose) {
+ tabpage_move(9999);
+ } else {
+ int tabnr = tab_page_click_defs[mouse_col].tabnr;
+ tabpage_move(tabnr < tabpage_index(curtab) ? tabnr - 1 : tabnr);
+ }
}
return false;
}
@@ -2527,7 +2531,7 @@ do_mouse (
*/
if (!is_drag && oap != NULL && oap->op_type != OP_NOP) {
got_click = false;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
}
/* When releasing the button let jump_to_mouse() know. */
@@ -2595,11 +2599,10 @@ do_mouse (
end_visual.col = leftcol;
else
end_visual.col = rightcol;
- if (curwin->w_cursor.lnum <
- (start_visual.lnum + end_visual.lnum) / 2)
- end_visual.lnum = end_visual.lnum;
- else
+ if (curwin->w_cursor.lnum >=
+ (start_visual.lnum + end_visual.lnum) / 2) {
end_visual.lnum = start_visual.lnum;
+ }
/* move VIsual to the right column */
start_visual = curwin->w_cursor; /* save the cursor pos */
@@ -2767,21 +2770,23 @@ do_mouse (
end_visual = curwin->w_cursor;
while (gc = gchar_pos(&end_visual), ascii_iswhite(gc))
inc(&end_visual);
- if (oap != NULL)
- oap->motion_type = MCHAR;
+ if (oap != NULL) {
+ oap->motion_type = kMTCharWise;
+ }
if (oap != NULL
&& VIsual_mode == 'v'
&& !vim_iswordc(gchar_pos(&end_visual))
&& equalpos(curwin->w_cursor, VIsual)
&& (pos = findmatch(oap, NUL)) != NULL) {
curwin->w_cursor = *pos;
- if (oap->motion_type == MLINE)
+ if (oap->motion_type == kMTLineWise) {
VIsual_mode = 'V';
- else if (*p_sel == 'e') {
- if (lt(curwin->w_cursor, VIsual))
- ++VIsual.col;
- else
- ++curwin->w_cursor.col;
+ } else if (*p_sel == 'e') {
+ if (lt(curwin->w_cursor, VIsual)) {
+ VIsual.col++;
+ } else {
+ curwin->w_cursor.col++;
+ }
}
}
}
@@ -3241,9 +3246,9 @@ void clear_showcmd(void)
top = curwin->w_cursor.lnum;
bot = VIsual.lnum;
}
- /* Include closed folds as a whole. */
- hasFolding(top, &top, NULL);
- hasFolding(bot, NULL, &bot);
+ // Include closed folds as a whole.
+ (void)hasFolding(top, &top, NULL);
+ (void)hasFolding(bot, NULL, &bot);
lines = bot - top + 1;
if (VIsual_mode == Ctrl_V) {
@@ -3779,7 +3784,7 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
int width1; /* text width for first screen line */
int width2; /* test width for wrapped screen line */
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
oap->inclusive = (curwin->w_curswant == MAXCOL);
col_off1 = curwin_col_off();
@@ -3924,6 +3929,8 @@ static void nv_mousescroll(cmdarg_T *cap)
cap->count0 = 3;
nv_scroll_line(cap);
}
+ } else {
+ mouse_scroll_horiz(cap->arg);
}
curwin->w_redr_status = true;
@@ -4050,16 +4057,15 @@ static void nv_zet(cmdarg_T *cap)
}
dozet:
- if (
- /* "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
- * and "zC" only in Visual mode. "zj" and "zk" are motion
- * commands. */
- cap->nchar != 'f' && cap->nchar != 'F'
- && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar))
- && cap->nchar != 'j' && cap->nchar != 'k'
- &&
- checkclearop(cap->oap))
+ // "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
+ // and "zC" only in Visual mode. "zj" and "zk" are motion
+ // commands. */
+ if (cap->nchar != 'f' && cap->nchar != 'F'
+ && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar))
+ && cap->nchar != 'j' && cap->nchar != 'k'
+ && checkclearop(cap->oap)) {
return;
+ }
/*
* For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb":
@@ -4096,6 +4102,7 @@ dozet:
case 't': scroll_cursor_top(0, true);
redraw_later(VALID);
+ set_fraction(curwin);
break;
/* "z." and "zz": put cursor in middle of screen */
@@ -4104,6 +4111,7 @@ dozet:
case 'z': scroll_cursor_halfway(true);
redraw_later(VALID);
+ set_fraction(curwin);
break;
/* "z^", "z-" and "zb": put cursor at bottom of screen */
@@ -4124,6 +4132,7 @@ dozet:
case 'b': scroll_cursor_bot(0, true);
redraw_later(VALID);
+ set_fraction(curwin);
break;
/* "zH" - scroll screen right half-page */
@@ -4457,8 +4466,8 @@ static void nv_colon(cmdarg_T *cap)
nv_operator(cap);
else {
if (cap->oap->op_type != OP_NOP) {
- /* Using ":" as a movement is characterwise exclusive. */
- cap->oap->motion_type = MCHAR;
+ // Using ":" as a movement is characterwise exclusive.
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
} else if (cap->count0) {
/* translate "count:" into ":.,.+(count - 1)" */
@@ -4857,7 +4866,7 @@ static void nv_scroll(cmdarg_T *cap)
linenr_T lnum;
int half;
- cap->oap->motion_type = MLINE;
+ cap->oap->motion_type = kMTLineWise;
setpcmark();
if (cap->cmdchar == 'L') {
@@ -4937,7 +4946,7 @@ static void nv_right(cmdarg_T *cap)
return;
}
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
PAST_LINE = (VIsual_active && *p_sel != 'o');
@@ -5024,7 +5033,7 @@ static void nv_left(cmdarg_T *cap)
return;
}
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
for (n = cap->count1; n > 0; --n) {
if (oneleft() == false) {
@@ -5086,11 +5095,12 @@ static void nv_up(cmdarg_T *cap)
cap->arg = BACKWARD;
nv_page(cap);
} else {
- cap->oap->motion_type = MLINE;
- if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false)
+ cap->oap->motion_type = kMTLineWise;
+ if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == false) {
clearopbeep(cap->oap);
- else if (cap->arg)
+ } else if (cap->arg) {
beginline(BL_WHITE | BL_FIX);
+ }
}
}
@@ -5104,23 +5114,24 @@ static void nv_down(cmdarg_T *cap)
/* <S-Down> is page down */
cap->arg = FORWARD;
nv_page(cap);
- } else
- /* In a quickfix window a <CR> jumps to the error under the cursor. */
- if (bt_quickfix(curbuf) && cap->cmdchar == CAR)
- if (curwin->w_llist_ref == NULL)
- do_cmdline_cmd(".cc"); /* quickfix window */
- else
- do_cmdline_cmd(".ll"); /* location list window */
- else {
- /* In the cmdline window a <CR> executes the command. */
- if (cmdwin_type != 0 && cap->cmdchar == CAR)
+ } else if (bt_quickfix(curbuf) && cap->cmdchar == CAR) {
+ // In a quickfix window a <CR> jumps to the error under the cursor.
+ if (curwin->w_llist_ref == NULL) {
+ do_cmdline_cmd(".cc"); // quickfix window
+ } else {
+ do_cmdline_cmd(".ll"); // location list window
+ }
+ } else {
+ // In the cmdline window a <CR> executes the command.
+ if (cmdwin_type != 0 && cap->cmdchar == CAR) {
cmdwin_result = CAR;
- else {
- cap->oap->motion_type = MLINE;
- if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false)
+ } else {
+ cap->oap->motion_type = kMTLineWise;
+ if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == false) {
clearopbeep(cap->oap);
- else if (cap->arg)
+ } else if (cap->arg) {
beginline(BL_WHITE | BL_FIX);
+ }
}
}
}
@@ -5146,9 +5157,10 @@ static void nv_gotofile(cmdarg_T *cap)
ptr = grab_file_name(cap->count1, &lnum);
if (ptr != NULL) {
- /* do autowrite if necessary */
- if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf))
- autowrite(curbuf, false);
+ // do autowrite if necessary
+ if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !P_HID(curbuf)) {
+ (void)autowrite(curbuf, false);
+ }
setpcmark();
(void)do_ecmd(0, ptr, NULL, NULL, ECMD_LAST,
P_HID(curbuf) ? ECMD_HIDE : 0, curwin);
@@ -5180,7 +5192,7 @@ static void nv_end(cmdarg_T *cap)
*/
static void nv_dollar(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = true;
/* In virtual mode when off the edge of a line and an operator
* is pending (whew!) keep the cursor where it is.
@@ -5255,18 +5267,19 @@ static int normal_search(
{
int i;
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
cap->oap->use_reg_one = true;
curwin->w_set_curswant = true;
i = do_search(cap->oap, dir, pat, cap->count1,
- opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL);
- if (i == 0)
+ opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, NULL);
+ if (i == 0) {
clearop(cap->oap);
- else {
- if (i == 2)
- cap->oap->motion_type = MLINE;
+ } else {
+ if (i == 2) {
+ cap->oap->motion_type = kMTLineWise;
+ }
curwin->w_cursor.coladd = 0;
if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
foldOpenCursor();
@@ -5293,10 +5306,10 @@ static void nv_csearch(cmdarg_T *cap)
else
t_cmd = false;
- cap->oap->motion_type = MCHAR;
- if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false)
+ cap->oap->motion_type = kMTCharWise;
+ if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) {
clearopbeep(cap->oap);
- else {
+ } else {
curwin->w_set_curswant = true;
/* Include a Tab for "tx" and for "dfx". */
if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD
@@ -5328,7 +5341,7 @@ static void nv_brackets(cmdarg_T *cap)
int findc;
int c;
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
old_pos = curwin->w_cursor;
curwin->w_cursor.coladd = 0; /* TODO: don't do this for an error. */
@@ -5618,11 +5631,11 @@ static void nv_percent(cmdarg_T *cap)
linenr_T lnum = curwin->w_cursor.lnum;
cap->oap->inclusive = true;
- if (cap->count0) { /* {cnt}% : goto {cnt} percentage in file */
- if (cap->count0 > 100)
+ if (cap->count0) { // {cnt}% : goto {cnt} percentage in file
+ if (cap->count0 > 100) {
clearopbeep(cap->oap);
- else {
- cap->oap->motion_type = MLINE;
+ } else {
+ cap->oap->motion_type = kMTLineWise;
setpcmark();
/* Round up, so CTRL-G will give same value. Watch out for a
* large line count, the line number must not go negative! */
@@ -5636,8 +5649,8 @@ static void nv_percent(cmdarg_T *cap)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
beginline(BL_SOL | BL_FIX);
}
- } else { /* "%" : go to matching paren */
- cap->oap->motion_type = MCHAR;
+ } else { // "%" : go to matching paren
+ cap->oap->motion_type = kMTCharWise;
cap->oap->use_reg_one = true;
if ((pos = findmatch(cap->oap, NUL)) == NULL)
clearopbeep(cap->oap);
@@ -5662,7 +5675,7 @@ static void nv_percent(cmdarg_T *cap)
*/
static void nv_brace(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->use_reg_one = true;
/* The motion used to be inclusive for "(", but that is not what Vi does. */
cap->oap->inclusive = false;
@@ -5696,7 +5709,7 @@ static void nv_mark(cmdarg_T *cap)
*/
static void nv_findpar(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
cap->oap->use_reg_one = true;
curwin->w_set_curswant = true;
@@ -5800,14 +5813,11 @@ static void nv_replace(cmdarg_T *cap)
return;
}
- /*
- * Replacing with a TAB is done by edit() when it is complicated because
- * 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB.
- * Other characters are done below to avoid problems with things like
- * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
- */
- if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' &&
- (curbuf->b_p_et || p_sta)) {
+ // Replacing with a TAB is done by edit() when it is complicated because
+ // 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB.
+ // Other characters are done below to avoid problems with things like
+ // CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
+ if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || p_sta)) {
stuffnumReadbuff(cap->count1);
stuffcharReadbuff('R');
stuffcharReadbuff('\t');
@@ -6074,10 +6084,11 @@ static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos)
else
check_cursor();
}
- cap->oap->motion_type = flag ? MLINE : MCHAR;
- if (cap->cmdchar == '`')
+ cap->oap->motion_type = flag ? kMTLineWise : kMTCharWise;
+ if (cap->cmdchar == '`') {
cap->oap->use_reg_one = true;
- cap->oap->inclusive = false; /* ignored if not MCHAR */
+ }
+ cap->oap->inclusive = false; // ignored if not kMTCharWise
curwin->w_set_curswant = true;
}
@@ -6554,7 +6565,7 @@ static void nv_g_cmd(cmdarg_T *cap)
if (!curwin->w_p_wrap
|| hasFolding(curwin->w_cursor.lnum, NULL, NULL)
) {
- oap->motion_type = MLINE;
+ oap->motion_type = kMTLineWise;
i = cursor_down(cap->count1, oap->op_type == OP_NOP);
} else
i = nv_screengo(oap, FORWARD, cap->count1);
@@ -6569,7 +6580,7 @@ static void nv_g_cmd(cmdarg_T *cap)
if (!curwin->w_p_wrap
|| hasFolding(curwin->w_cursor.lnum, NULL, NULL)
) {
- oap->motion_type = MLINE;
+ oap->motion_type = kMTLineWise;
i = cursor_up(cap->count1, oap->op_type == OP_NOP);
} else
i = nv_screengo(oap, BACKWARD, cap->count1);
@@ -6596,7 +6607,7 @@ static void nv_g_cmd(cmdarg_T *cap)
case 'm':
case K_HOME:
case K_KHOME:
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
oap->inclusive = false;
if (curwin->w_p_wrap
&& curwin->w_width != 0
@@ -6629,7 +6640,7 @@ static void nv_g_cmd(cmdarg_T *cap)
case '_':
/* "g_": to the last non-blank character in the line or <count> lines
* downward. */
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = true;
curwin->w_curswant = MAXCOL;
if (cursor_down(cap->count1 - 1,
@@ -6657,7 +6668,7 @@ static void nv_g_cmd(cmdarg_T *cap)
{
int col_off = curwin_col_off();
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
oap->inclusive = true;
if (curwin->w_p_wrap
&& curwin->w_width != 0
@@ -6719,23 +6730,19 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case 'e':
case 'E':
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
curwin->w_set_curswant = true;
oap->inclusive = true;
if (bckend_word(cap->count1, cap->nchar == 'E', false) == false)
clearopbeep(oap);
break;
- /*
- * "g CTRL-G": display info about cursor position
- */
+ // "g CTRL-G": display info about cursor position
case Ctrl_G:
- cursor_pos_info();
+ cursor_pos_info(NULL);
break;
- /*
- * "gi": start Insert at the last position.
- */
+ // "gi": start Insert at the last position.
case 'i':
if (curbuf->b_last_insert.mark.lnum != 0) {
curwin->w_cursor = curbuf->b_last_insert.mark;
@@ -7051,18 +7058,17 @@ static void nv_operator(cmdarg_T *cap)
*/
static void set_op_var(int optype)
{
- char_u opchars[3];
-
- if (optype == OP_NOP)
+ if (optype == OP_NOP) {
set_vim_var_string(VV_OP, NULL, 0);
- else {
+ } else {
+ char opchars[3];
int opchar0 = get_op_char(optype);
assert(opchar0 >= 0 && opchar0 <= UCHAR_MAX);
- opchars[0] = (char_u)opchar0;
+ opchars[0] = (char) opchar0;
int opchar1 = get_extra_op_char(optype);
assert(opchar1 >= 0 && opchar1 <= UCHAR_MAX);
- opchars[1] = (char_u)opchar1;
+ opchars[1] = (char) opchar1;
opchars[2] = NUL;
set_vim_var_string(VV_OP, opchars, -1);
@@ -7080,17 +7086,19 @@ static void set_op_var(int optype)
*/
static void nv_lineop(cmdarg_T *cap)
{
- cap->oap->motion_type = MLINE;
- if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == false)
+ cap->oap->motion_type = kMTLineWise;
+ if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == false) {
clearopbeep(cap->oap);
- else if ( (cap->oap->op_type == OP_DELETE /* only with linewise motions */
+ } else if ((cap->oap->op_type == OP_DELETE
+ // only with linewise motions
&& cap->oap->motion_force != 'v'
&& cap->oap->motion_force != Ctrl_V)
|| cap->oap->op_type == OP_LSHIFT
- || cap->oap->op_type == OP_RSHIFT)
+ || cap->oap->op_type == OP_RSHIFT) {
beginline(BL_SOL | BL_FIX);
- else if (cap->oap->op_type != OP_YANK) /* 'Y' does not move cursor */
+ } else if (cap->oap->op_type != OP_YANK) { // 'Y' does not move cursor
beginline(BL_WHITE | BL_FIX);
+ }
}
/*
@@ -7114,7 +7122,7 @@ static void nv_home(cmdarg_T *cap)
*/
static void nv_pipe(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
beginline(0);
if (cap->count0 > 0) {
@@ -7133,7 +7141,7 @@ static void nv_pipe(cmdarg_T *cap)
*/
static void nv_bck_word(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
curwin->w_set_curswant = true;
if (bck_word(cap->count1, cap->arg, false) == false)
@@ -7182,7 +7190,7 @@ static void nv_wordcmd(cmdarg_T *cap)
}
}
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
curwin->w_set_curswant = true;
if (word_end)
n = end_word(cap->count1, cap->arg, flag, false);
@@ -7233,7 +7241,7 @@ static void adjust_cursor(oparg_T *oap)
*/
static void nv_beginline(cmdarg_T *cap)
{
- cap->oap->motion_type = MCHAR;
+ cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
beginline(cap->arg);
if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
@@ -7312,7 +7320,7 @@ static void nv_goto(cmdarg_T *cap)
lnum = curbuf->b_ml.ml_line_count;
else
lnum = 1L;
- cap->oap->motion_type = MLINE;
+ cap->oap->motion_type = kMTLineWise;
setpcmark();
/* When a count is given, use it instead of the default lnum */
@@ -7640,19 +7648,25 @@ static void nv_halfpage(cmdarg_T *cap)
*/
static void nv_join(cmdarg_T *cap)
{
- if (VIsual_active) /* join the visual lines */
+ if (VIsual_active) { // join the visual lines
nv_operator(cap);
- else if (!checkclearop(cap->oap)) {
- if (cap->count0 <= 1)
- cap->count0 = 2; /* default for join is two lines! */
+ } else if (!checkclearop(cap->oap)) {
+ if (cap->count0 <= 1) {
+ cap->count0 = 2; // default for join is two lines!
+ }
if (curwin->w_cursor.lnum + cap->count0 - 1 >
- curbuf->b_ml.ml_line_count)
- clearopbeep(cap->oap); /* beyond last line */
- else {
- prep_redo(cap->oap->regname, cap->count0,
- NUL, cap->cmdchar, NUL, NUL, cap->nchar);
- do_join(cap->count0, cap->nchar == NUL, true, true, true);
+ curbuf->b_ml.ml_line_count) {
+ // can't join when on the last line
+ if (cap->count0 <= 2) {
+ clearopbeep(cap->oap);
+ return;
+ }
+ cap->count0 = curbuf->b_ml.ml_line_count - curwin->w_cursor.lnum + 1;
}
+
+ prep_redo(cap->oap->regname, cap->count0,
+ NUL, cap->cmdchar, NUL, NUL, cap->nchar);
+ do_join(cap->count0, cap->nchar == NUL, true, true, true);
}
}
@@ -7798,7 +7812,7 @@ static void get_op_vcol(
return;
}
- oap->motion_type = MBLOCK;
+ oap->motion_type = kMTBlockWise;
// prevent from moving onto a trail byte
if (has_mbyte) {
diff --git a/src/nvim/normal.h b/src/nvim/normal.h
index 95619c7ef6..51170105ed 100644
--- a/src/nvim/normal.h
+++ b/src/nvim/normal.h
@@ -10,18 +10,29 @@
#define FIND_STRING 2 /* find any string (WORD) */
#define FIND_EVAL 4 /* include "->", "[]" and "." */
+/// Motion types, used for operators and for yank/delete registers.
+///
+/// The three valid numerical values must not be changed, as they
+/// are used in external communication and serialization.
+typedef enum {
+ kMTCharWise = 0, ///< character-wise movement/register
+ kMTLineWise = 1, ///< line-wise movement/register
+ kMTBlockWise = 2, ///< block-wise movement/register
+ kMTUnknown = -1 ///< Unknown or invalid motion type
+} MotionType;
+
/*
* Arguments for operators.
*/
typedef struct oparg_S {
int op_type; // current pending operator type
int regname; // register to use for the operator
- int motion_type; // type of the current cursor motion
+ MotionType motion_type; // type of the current cursor motion
int motion_force; // force motion type: 'v', 'V' or CTRL-V
bool use_reg_one; // true if delete uses reg 1 even when not
// linewise
bool inclusive; // true if char motion is inclusive (only
- // valid when motion_type is MCHAR)
+ // valid when motion_type is kMTCharWise)
bool end_adjusted; // backuped b_op_end one char (only used by
// do_format())
pos_T start; // start of the operator
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b1adc85e1d..eda963ff77 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -19,6 +19,7 @@
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
+#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/indent.h"
@@ -190,7 +191,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
(linenr_T)(oap->end.lnum + 1)) == FAIL)
return;
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
block_col = curwin->w_cursor.col;
}
@@ -198,7 +199,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
first_char = *get_cursor_line_ptr();
if (first_char == NUL) { // empty line
curwin->w_cursor.col = 0;
- } else if (oap->motion_type == MBLOCK) {
+ } else if (oap->motion_type == kMTBlockWise) {
shift_block(oap, amount);
} else if (first_char != '#' || !preprocs_left()) {
// Move the line right if it doesn't start with '#', 'smartindent'
@@ -212,7 +213,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
/* The cursor line is not in a closed fold */
foldOpenCursor();
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
curwin->w_cursor.lnum = oap->start.lnum;
curwin->w_cursor.col = block_col;
} else if (curs_top) { /* put cursor on first line, for ">>" */
@@ -810,17 +811,17 @@ yankreg_T *copy_register(int name)
return copy;
}
-/*
- * return TRUE if the current yank register has type MLINE
- */
-int yank_register_mline(int regname)
+/// check if the current yank register has kMTLineWise register type
+bool yank_register_mline(int regname)
{
- if (regname != 0 && !valid_yank_reg(regname, false))
- return FALSE;
- if (regname == '_') /* black hole is always empty */
- return FALSE;
+ if (regname != 0 && !valid_yank_reg(regname, false)) {
+ return false;
+ }
+ if (regname == '_') { // black hole is always empty
+ return false;
+ }
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
- return reg->y_type == MLINE;
+ return reg->y_type == kMTLineWise;
}
/*
@@ -835,12 +836,13 @@ int do_record(int c)
yankreg_T *old_y_previous;
int retval;
- if (Recording == FALSE) { /* start recording */
- /* registers 0-9, a-z and " are allowed */
- if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
+ if (Recording == false) {
+ // start recording
+ // registers 0-9, a-z and " are allowed
+ if (c < 0 || (!ASCII_ISALNUM(c) && c != '"')) {
retval = FAIL;
- else {
- Recording = TRUE;
+ } else {
+ Recording = c;
showmode();
regname = c;
retval = OK;
@@ -917,7 +919,7 @@ static int stuff_yank(int regname, char_u *p)
reg->y_array = (char_u **)xmalloc(sizeof(char_u *));
reg->y_array[0] = p;
reg->y_size = 1;
- reg->y_type = MCHAR; /* used to be MLINE, why? */
+ reg->y_type = kMTCharWise;
}
reg->timestamp = os_time();
return OK;
@@ -1009,8 +1011,8 @@ do_execreg (
for (i = reg->y_size - 1; i >= 0; i--) {
char_u *escaped;
- /* insert NL between lines and after last line if type is MLINE */
- if (reg->y_type == MLINE || i < reg->y_size - 1
+ // insert NL between lines and after last line if type is kMTLineWise
+ if (reg->y_type == kMTLineWise || i < reg->y_size - 1
|| addcr) {
if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
return FAIL;
@@ -1135,12 +1137,11 @@ insert_reg (
else {
for (i = 0; i < reg->y_size; i++) {
stuffescaped(reg->y_array[i], literally);
- /*
- * Insert a newline between lines and after last line if
- * y_type is MLINE.
- */
- if (reg->y_type == MLINE || i < reg->y_size - 1)
+ // Insert a newline between lines and after last line if
+ // y_type is kMTLineWise.
+ if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
stuffcharReadbuff('\n');
+ }
}
}
}
@@ -1259,21 +1260,18 @@ get_spec_reg (
return FALSE;
}
-/*
- * Paste a yank register into the command line.
- * Only for non-special registers.
- * Used by CTRL-R command in command-line mode
- * insert_reg() can't be used here, because special characters from the
- * register contents will be interpreted as commands.
- *
- * return FAIL for failure, OK otherwise
- */
-int
-cmdline_paste_reg (
- int regname,
- int literally, /* Insert text literally instead of "as typed" */
- int remcr /* don't add trailing CR */
-)
+/// Paste a yank register into the command line.
+/// Only for non-special registers.
+/// Used by CTRL-R command in command-line mode
+/// insert_reg() can't be used here, because special characters from the
+/// register contents will be interpreted as commands.
+///
+/// @param regname Register name.
+/// @param literally Insert text literally instead of "as typed".
+/// @param remcr When true, don't add CR characters.
+///
+/// @returns FAIL for failure, OK otherwise
+bool cmdline_paste_reg(int regname, bool literally, bool remcr)
{
long i;
@@ -1284,13 +1282,9 @@ cmdline_paste_reg (
for (i = 0; i < reg->y_size; i++) {
cmdline_paste_str(reg->y_array[i], literally);
- /* Insert ^M between lines and after last line if type is MLINE.
- * Don't do this when "remcr" is TRUE and the next line is empty. */
- if (reg->y_type == MLINE
- || (i < reg->y_size - 1
- && !(remcr
- && i == reg->y_size - 2
- && *reg->y_array[i + 1] == NUL))) {
+ // Insert ^M between lines and after last line if type is kMTLineWise.
+ // Don't do this when "remcr" is true.
+ if ((reg->y_type == kMTLineWise || i < reg->y_size - 1) && !remcr) {
cmdline_paste_str((char_u *)"\r", literally);
}
@@ -1334,10 +1328,10 @@ int op_delete(oparg_T *oap)
/*
* Imitate the strange Vi behaviour: If the delete spans more than one
- * line and motion_type == MCHAR and the result is a blank line, make the
+ * line and motion_type == kMTCharWise and the result is a blank line, make the
* delete linewise. Don't do this for the change command or Visual mode.
*/
- if (oap->motion_type == MCHAR
+ if (oap->motion_type == kMTCharWise
&& !oap->is_VIsual
&& oap->line_count > 1
&& oap->motion_force == NUL
@@ -1346,15 +1340,16 @@ int op_delete(oparg_T *oap)
if (*ptr != NUL)
ptr += oap->inclusive;
ptr = skipwhite(ptr);
- if (*ptr == NUL && inindent(0))
- oap->motion_type = MLINE;
+ if (*ptr == NUL && inindent(0)) {
+ oap->motion_type = kMTLineWise;
+ }
}
/*
* Check for trying to delete (e.g. "D") in an empty line.
* Note: For the change operator it is ok.
*/
- if (oap->motion_type != MLINE
+ if (oap->motion_type != kMTLineWise
&& oap->line_count == 1
&& oap->op_type == OP_DELETE
&& *ml_get(oap->start.lnum) == NUL) {
@@ -1390,7 +1385,7 @@ int op_delete(oparg_T *oap)
* Put deleted text into register 1 and shift number registers if the
* delete contains a line break, or when a regname has been specified.
*/
- if (oap->regname != 0 || oap->motion_type == MLINE
+ if (oap->regname != 0 || oap->motion_type == kMTLineWise
|| oap->line_count > 1 || oap->use_reg_one) {
free_register(&y_regs[9]); /* free register "9 */
for (n = 9; n > 1; n--)
@@ -1403,14 +1398,15 @@ int op_delete(oparg_T *oap)
/* Yank into small delete register when no named register specified
* and the delete is within one line. */
- if (oap->regname == 0 && oap->motion_type != MLINE
+ if (oap->regname == 0 && oap->motion_type != kMTLineWise
&& oap->line_count == 1) {
reg = get_yank_register('-', YREG_YANK);
op_yank_reg(oap, false, reg, false);
}
- if(oap->regname == 0) {
+ if (oap->regname == 0) {
set_clipboard(0, reg);
+ yank_do_autocmd(oap, reg);
}
}
@@ -1418,7 +1414,7 @@ int op_delete(oparg_T *oap)
/*
* block mode delete
*/
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
if (u_save((linenr_T)(oap->start.lnum - 1),
(linenr_T)(oap->end.lnum + 1)) == FAIL) {
return FAIL;
@@ -1456,9 +1452,9 @@ int op_delete(oparg_T *oap)
check_cursor_col();
changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
- oap->end.lnum + 1, 0L);
- oap->line_count = 0; /* no lines deleted */
- } else if (oap->motion_type == MLINE) {
+ oap->end.lnum + 1, 0L);
+ oap->line_count = 0; // no lines deleted
+ } else if (oap->motion_type == kMTLineWise) {
if (oap->op_type == OP_CHANGE) {
/* Delete the lines except the first one. Temporarily move the
* cursor to the next line. Save the current line number, if the
@@ -1586,7 +1582,7 @@ int op_delete(oparg_T *oap)
msgmore(curbuf->b_ml.ml_line_count - old_lcount);
setmarks:
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
curbuf->b_op_end.lnum = oap->end.lnum;
curbuf->b_op_end.col = oap->start.col;
} else
@@ -1647,7 +1643,7 @@ int op_replace(oparg_T *oap, int c)
/*
* block mode replace
*/
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
bd.is_MAX = (curwin->w_curswant == MAXCOL);
for (; curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) {
curwin->w_cursor.col = 0; /* make sure cursor position is valid */
@@ -1736,10 +1732,8 @@ int op_replace(oparg_T *oap, int c)
}
}
} else {
- /*
- * MCHAR and MLINE motion replace.
- */
- if (oap->motion_type == MLINE) {
+ // Characterwise or linewise motion replace.
+ if (oap->motion_type == kMTLineWise) {
oap->start.col = 0;
curwin->w_cursor.col = 0;
oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
@@ -1829,8 +1823,8 @@ void op_tilde(oparg_T *oap)
return;
pos = oap->start;
- if (oap->motion_type == MBLOCK) { // Visual block mode
- for (; pos.lnum <= oap->end.lnum; ++pos.lnum) {
+ if (oap->motion_type == kMTBlockWise) { // Visual block mode
+ for (; pos.lnum <= oap->end.lnum; pos.lnum++) {
int one_change;
block_prep(oap, &bd, pos.lnum, FALSE);
@@ -1841,8 +1835,8 @@ void op_tilde(oparg_T *oap)
}
if (did_change)
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
- } else { /* not block mode */
- if (oap->motion_type == MLINE) {
+ } else { // not block mode
+ if (oap->motion_type == kMTLineWise) {
oap->start.col = 0;
pos.col = 0;
oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
@@ -1992,7 +1986,7 @@ void op_insert(oparg_T *oap, long count1)
curwin->w_cursor.lnum = oap->start.lnum;
update_screen(INVERTED);
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
// When 'virtualedit' is used, need to insert the extra spaces before
// doing block_prep(). When only "block" is used, virtual edit is
// already disabled, but still need it when calling
@@ -2018,7 +2012,7 @@ void op_insert(oparg_T *oap, long count1)
}
if (oap->op_type == OP_APPEND) {
- if (oap->motion_type == MBLOCK
+ if (oap->motion_type == kMTBlockWise
&& curwin->w_cursor.coladd == 0
) {
/* Move the cursor to the character right of the block. */
@@ -2052,8 +2046,8 @@ void op_insert(oparg_T *oap, long count1)
// When a tab was inserted, and the characters in front of the tab
// have been converted to a tab as well, the column of the cursor
// might have actually been reduced, so need to adjust here. */
- if (t1.lnum == curbuf->b_op_start_orig.lnum &&
- lt(curbuf->b_op_start_orig, t1)) {
+ if (t1.lnum == curbuf->b_op_start_orig.lnum
+ && lt(curbuf->b_op_start_orig, t1)) {
oap->start = curbuf->b_op_start_orig;
}
@@ -2063,7 +2057,7 @@ void op_insert(oparg_T *oap, long count1)
if (curwin->w_cursor.lnum != oap->start.lnum || got_int)
return;
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
struct block_def bd2;
/* The user may have moved the cursor before inserting something, try
@@ -2150,7 +2144,7 @@ int op_change(oparg_T *oap)
struct block_def bd;
l = oap->start.col;
- if (oap->motion_type == MLINE) {
+ if (oap->motion_type == kMTLineWise) {
l = 0;
if (!p_paste && curbuf->b_p_si
&& !curbuf->b_p_cin
@@ -2172,7 +2166,7 @@ int op_change(oparg_T *oap)
// check for still on same line (<CR> in inserted text meaningless)
// skip blank lines too
- if (oap->motion_type == MBLOCK) {
+ if (oap->motion_type == kMTBlockWise) {
// Add spaces before getting the current line length.
if (virtual_op && (curwin->w_cursor.coladd > 0
|| gchar_cursor() == NUL)) {
@@ -2184,8 +2178,9 @@ int op_change(oparg_T *oap)
bd.textcol = curwin->w_cursor.col;
}
- if (oap->motion_type == MLINE)
+ if (oap->motion_type == kMTLineWise) {
fix_indent();
+ }
retval = edit(NUL, FALSE, (linenr_T)1);
@@ -2194,7 +2189,7 @@ int op_change(oparg_T *oap)
* block.
* Don't repeat the insert when Insert mode ended with CTRL-C.
*/
- if (oap->motion_type == MBLOCK
+ if (oap->motion_type == kMTBlockWise
&& oap->start.lnum != oap->end.lnum && !got_int) {
// Auto-indenting may have changed the indent. If the cursor was past
// the indent, exclude that indent change from the inserted text.
@@ -2309,6 +2304,8 @@ bool op_yank(oparg_T *oap, bool message)
yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
op_yank_reg(oap, message, reg, is_append_register(oap->regname));
set_clipboard(oap->regname, reg);
+ yank_do_autocmd(oap, reg);
+
return true;
}
@@ -2320,7 +2317,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
char_u **new_ptr;
linenr_T lnum; /* current line number */
long j;
- int yanktype = oap->motion_type;
+ MotionType yank_type = oap->motion_type;
long yanklines = oap->line_count;
linenr_T yankendlnum = oap->end.lnum;
char_u *p;
@@ -2338,19 +2335,19 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
* If the cursor was in column 1 before and after the movement, and the
* operator is not inclusive, the yank is always linewise.
*/
- if (oap->motion_type == MCHAR
+ if (oap->motion_type == kMTCharWise
&& oap->start.col == 0
&& !oap->inclusive
&& (!oap->is_VIsual || *p_sel == 'o')
&& oap->end.col == 0
&& yanklines > 1) {
- yanktype = MLINE;
- --yankendlnum;
- --yanklines;
+ yank_type = kMTLineWise;
+ yankendlnum--;
+ yanklines--;
}
reg->y_size = yanklines;
- reg->y_type = yanktype; /* set the yank register type */
+ reg->y_type = yank_type; // set the yank register type
reg->y_width = 0;
reg->y_array = xcalloc(yanklines, sizeof(char_u *));
reg->additional_data = NULL;
@@ -2359,7 +2356,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
y_idx = 0;
lnum = oap->start.lnum;
- if (yanktype == MBLOCK) {
+ if (yank_type == kMTBlockWise) {
// Visual block mode
reg->y_width = oap->end_vcol - oap->start_vcol;
@@ -2369,16 +2366,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
for (; lnum <= yankendlnum; lnum++, y_idx++) {
switch (reg->y_type) {
- case MBLOCK:
- block_prep(oap, &bd, lnum, FALSE);
+ case kMTBlockWise:
+ block_prep(oap, &bd, lnum, false);
yank_copy_line(reg, &bd, y_idx);
break;
- case MLINE:
+ case kMTLineWise:
reg->y_array[y_idx] = vim_strsave(ml_get(lnum));
break;
- case MCHAR:
+ case kMTCharWise:
{
colnr_T startcol = 0, endcol = MAXCOL;
int is_oneChar = FALSE;
@@ -2439,7 +2436,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
yank_copy_line(reg, &bd, y_idx);
break;
}
- /* NOTREACHED */
+ // NOTREACHED
+ case kMTUnknown:
+ assert(false);
}
}
@@ -2450,12 +2449,15 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
xfree(curr->y_array);
curr->y_array = new_ptr;
- if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */
- curr->y_type = MLINE;
+ if (yank_type == kMTLineWise) {
+ // kMTLineWise overrides kMTCharWise and kMTBlockWise
+ curr->y_type = kMTLineWise;
+ }
- /* Concatenate the last line of the old block with the first line of
- * the new block, unless being Vi compatible. */
- if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) {
+ // Concatenate the last line of the old block with the first line of
+ // the new block, unless being Vi compatible.
+ if (curr->y_type == kMTCharWise
+ && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) {
pnew = xmalloc(STRLEN(curr->y_array[curr->y_size - 1])
+ STRLEN(reg->y_array[0]) + 1);
STRCPY(pnew, curr->y_array[--j]);
@@ -2475,7 +2477,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
redraw_later(SOME_VALID); // cursor moved to start
}
if (message) { // Display message about yank?
- if (yanktype == MCHAR && yanklines == 1) {
+ if (yank_type == kMTCharWise && yanklines == 1) {
yanklines = 0;
}
// Some versions of Vi use ">=" here, some don't...
@@ -2483,12 +2485,12 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
// redisplay now, so message is not deleted
update_topline_redraw();
if (yanklines == 1) {
- if (yanktype == MBLOCK) {
+ if (yank_type == kMTBlockWise) {
MSG(_("block of 1 line yanked"));
} else {
MSG(_("1 line yanked"));
}
- } else if (yanktype == MBLOCK) {
+ } else if (yank_type == kMTBlockWise) {
smsg(_("block of %" PRId64 " lines yanked"),
(int64_t)yanklines);
} else {
@@ -2502,7 +2504,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
*/
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
- if (yanktype == MLINE) {
+ if (yank_type == kMTLineWise) {
curbuf->b_op_start.col = 0;
curbuf->b_op_end.col = MAXCOL;
}
@@ -2524,6 +2526,58 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, long y_idx)
*pnew = NUL;
}
+/// Execute autocommands for TextYankPost.
+///
+/// @param oap Operator arguments.
+/// @param reg The yank register used.
+static void yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
+ FUNC_ATTR_NONNULL_ALL
+{
+ static bool recursive = false;
+
+ if (recursive || !has_event(EVENT_TEXTYANKPOST)) {
+ // No autocommand was defined
+ // or we yanked from this autocommand.
+ return;
+ }
+
+ recursive = true;
+
+ // set v:event to a dictionary with information about the yank
+ dict_T *dict = get_vim_var_dict(VV_EVENT);
+
+ // the yanked text
+ list_T *list = list_alloc();
+ for (linenr_T i = 0; i < reg->y_size; i++) {
+ list_append_string(list, reg->y_array[i], -1);
+ }
+ list->lv_lock = VAR_FIXED;
+ dict_add_list(dict, "regcontents", list);
+
+ // the register type
+ char buf[NUMBUFLEN+2];
+ format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf));
+ dict_add_nr_str(dict, "regtype", 0, (char_u *)buf);
+
+ // name of requested register or the empty string for an unnamed operation.
+ buf[0] = (char)oap->regname;
+ buf[1] = NUL;
+ dict_add_nr_str(dict, "regname", 0, (char_u *)buf);
+
+ // kind of operation (yank/delete/change)
+ buf[0] = get_op_char(oap->op_type);
+ buf[1] = NUL;
+ dict_add_nr_str(dict, "operator", 0, (char_u *)buf);
+
+ dict_set_keys_readonly(dict);
+ textlock++;
+ apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
+ textlock--;
+ dict_clear(dict);
+
+ recursive = false;
+}
+
/*
* Put contents of register "regname" into the text.
@@ -2540,8 +2594,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
int totlen = 0; /* init for gcc */
linenr_T lnum;
colnr_T col;
- long i; /* index in y_array[] */
- int y_type;
+ long i; // index in y_array[]
+ MotionType y_type;
long y_size;
int oldlen;
long y_width = 0;
@@ -2602,7 +2656,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
if (insert_string != NULL) {
- y_type = MCHAR;
+ y_type = kMTCharWise;
if (regname == '=') {
/* For the = register we need to split the string at NL
* characters.
@@ -2621,7 +2675,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
++ptr;
/* A trailing '\n' makes the register linewise. */
if (*ptr == NUL) {
- y_type = MLINE;
+ y_type = kMTLineWise;
break;
}
}
@@ -2662,7 +2716,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
return;
}
- if (y_type == MLINE) {
+ if (y_type == kMTLineWise) {
if (flags & PUT_LINE_SPLIT) {
// "p" or "P" in Visual mode: split the lines to put the text in
// between.
@@ -2696,8 +2750,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */
}
- if (flags & PUT_LINE) /* :put command or "p" in Visual line mode. */
- y_type = MLINE;
+ if (flags & PUT_LINE) { // :put command or "p" in Visual line mode.
+ y_type = kMTLineWise;
+ }
if (y_size == 0 || y_array == NULL) {
EMSG2(_("E353: Nothing in register %s"),
@@ -2705,13 +2760,13 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
goto end;
}
- if (y_type == MBLOCK) {
+ if (y_type == kMTBlockWise) {
lnum = curwin->w_cursor.lnum + y_size + 1;
if (lnum > curbuf->b_ml.ml_line_count)
lnum = curbuf->b_ml.ml_line_count + 1;
if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
goto end;
- } else if (y_type == MLINE) {
+ } else if (y_type == kMTLineWise) {
lnum = curwin->w_cursor.lnum;
/* Correct line number for closed fold. Don't move the cursor yet,
* u_save() uses it. */
@@ -2735,7 +2790,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
yanklen = (int)STRLEN(y_array[0]);
- if (ve_flags == VE_ALL && y_type == MCHAR) {
+ if (ve_flags == VE_ALL && y_type == kMTCharWise) {
if (gchar_cursor() == TAB) {
/* Don't need to insert spaces when "p" on the last position of a
* tab or "P" on the first position. */
@@ -2755,7 +2810,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/*
* Block mode
*/
- if (y_type == MBLOCK) {
+ if (y_type == kMTBlockWise) {
char c = gchar_cursor();
colnr_T endcol2 = 0;
@@ -2903,12 +2958,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
} else
curwin->w_cursor.lnum = lnum;
} else {
- /*
- * Character or Line mode
- */
- if (y_type == MCHAR) {
- /* if type is MCHAR, FORWARD is the same as BACKWARD on the next
- * char */
+ // Character or Line mode
+ if (y_type == kMTCharWise) {
+ // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next
+ // char
if (dir == FORWARD && gchar_cursor() != NUL) {
if (has_mbyte) {
int bytelen = (*mb_ptr2len)(get_cursor_pos_ptr());
@@ -2939,7 +2992,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/*
* simple case: insert into current line
*/
- if (y_type == MCHAR && y_size == 1) {
+ if (y_type == kMTCharWise && y_size == 1) {
do {
totlen = count * yanklen;
if (totlen > 0) {
@@ -2974,18 +3027,14 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
++curwin->w_cursor.col;
changed_bytes(lnum, col);
} else {
- /*
- * Insert at least one line. When y_type is MCHAR, break the first
- * line in two.
- */
- for (cnt = 1; cnt <= count; ++cnt) {
+ // Insert at least one line. When y_type is kMTCharWise, break the first
+ // line in two.
+ for (cnt = 1; cnt <= count; cnt++) {
i = 0;
- if (y_type == MCHAR) {
- /*
- * Split the current line in two at the insert position.
- * First insert y_array[size - 1] in front of second line.
- * Then append y_array[0] to first line.
- */
+ if (y_type == kMTCharWise) {
+ // Split the current line in two at the insert position.
+ // First insert y_array[size - 1] in front of second line.
+ // Then append y_array[0] to first line.
lnum = new_cursor.lnum;
ptr = ml_get(lnum) + col;
totlen = (int)STRLEN(y_array[y_size - 1]);
@@ -3009,10 +3058,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
for (; i < y_size; i++) {
- if ((y_type != MCHAR || i < y_size - 1)
- && ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
- == FAIL)
+ if ((y_type != kMTCharWise || i < y_size - 1)
+ && ml_append(lnum, y_array[i], (colnr_T)0, false)
+ == FAIL) {
goto error;
+ }
lnum++;
++nr_lines;
if (flags & PUT_FIXINDENT) {
@@ -3041,22 +3091,23 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
error:
- /* Adjust marks. */
- if (y_type == MLINE) {
+ // Adjust marks.
+ if (y_type == kMTLineWise) {
curbuf->b_op_start.col = 0;
if (dir == FORWARD)
curbuf->b_op_start.lnum++;
}
- mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
- (linenr_T)MAXLNUM, nr_lines, 0L);
+ mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise),
+ (linenr_T)MAXLNUM, nr_lines, 0L);
- /* note changed text for displaying and folding */
- if (y_type == MCHAR)
+ // note changed text for displaying and folding
+ if (y_type == kMTCharWise) {
changed_lines(curwin->w_cursor.lnum, col,
- curwin->w_cursor.lnum + 1, nr_lines);
- else
+ curwin->w_cursor.lnum + 1, nr_lines);
+ } else {
changed_lines(curbuf->b_op_start.lnum, 0,
- curbuf->b_op_start.lnum, nr_lines);
+ curbuf->b_op_start.lnum, nr_lines);
+ }
/* put '] mark at last inserted character */
curbuf->b_op_end.lnum = lnum;
@@ -3072,19 +3123,20 @@ error:
curwin->w_cursor.lnum = lnum;
beginline(BL_WHITE | BL_FIX);
} else if (flags & PUT_CURSEND) {
- /* put cursor after inserted text */
- if (y_type == MLINE) {
- if (lnum >= curbuf->b_ml.ml_line_count)
+ // put cursor after inserted text
+ if (y_type == kMTLineWise) {
+ if (lnum >= curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
curwin->w_cursor.lnum = lnum + 1;
+ }
curwin->w_cursor.col = 0;
} else {
curwin->w_cursor.lnum = lnum;
curwin->w_cursor.col = col;
}
- } else if (y_type == MLINE) {
- /* put cursor on first non-blank in first inserted line */
+ } else if (y_type == kMTLineWise) {
+ // put cursor on first non-blank in first inserted line
curwin->w_cursor.col = 0;
if (dir == FORWARD)
++curwin->w_cursor.lnum;
@@ -3137,11 +3189,9 @@ void adjust_cursor_eol(void)
*/
int preprocs_left(void)
{
- return
- (curbuf->b_p_si && !curbuf->b_p_cin) ||
- (curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
- && curbuf->b_ind_hash_comment == 0)
- ;
+ return ((curbuf->b_p_si && !curbuf->b_p_cin)
+ || (curbuf->b_p_cin && in_cinkeys('#', ' ', true)
+ && curbuf->b_ind_hash_comment == 0));
}
/* Return the character name of the register with the given number */
@@ -3223,9 +3273,10 @@ void ex_display(exarg_T *eap)
p += clen - 1;
}
}
- if (n > 1 && yb->y_type == MLINE)
+ if (n > 1 && yb->y_type == kMTLineWise) {
MSG_PUTS_ATTR("^J", attr);
- ui_flush(); /* show one line at a time */
+ }
+ ui_flush(); // show one line at a time
}
os_breakcheck();
}
@@ -3939,7 +3990,7 @@ format_lines (
if (line_count < 0 && u_save_cursor() == FAIL)
break;
if (next_leader_len > 0) {
- (void)del_bytes((long)next_leader_len, FALSE, FALSE);
+ (void)del_bytes(next_leader_len, false, false);
mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
(long)-next_leader_len);
} else if (second_indent > 0) { /* the "leader" for FO_Q_SECOND */
@@ -4215,18 +4266,18 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
}
pos = oap->start;
- for (; pos.lnum <= oap->end.lnum; ++pos.lnum) {
- if (oap->motion_type == MBLOCK) {
+ for (; pos.lnum <= oap->end.lnum; pos.lnum++) {
+ if (oap->motion_type == kMTBlockWise) {
// Visual block mode
block_prep(oap, &bd, pos.lnum, false);
pos.col = bd.textcol;
length = bd.textlen;
- } else if (oap->motion_type == MLINE) {
+ } else if (oap->motion_type == kMTLineWise) {
curwin->w_cursor.col = 0;
pos.col = 0;
length = (colnr_T)STRLEN(ml_get(pos.lnum));
} else {
- // oap->motion_type == MCHAR
+ // oap->motion_type == kMTCharWise
if (!oap->inclusive) {
dec(&(oap->end));
}
@@ -4346,8 +4397,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
if (dobin
&& dohex
&& !((col > 0
- && (ptr[col] == 'X' ||
- ptr[col] == 'x')
+ && (ptr[col] == 'X' || ptr[col] == 'x')
&& ptr[col - 1] == '0'
&& ascii_isxdigit(ptr[col + 1])))) {
// In case of binary/hexadecimal pattern overlap match, rescan
@@ -4361,17 +4411,15 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
if ((dohex
&& col > 0
- && (ptr[col] == 'X'
- || ptr[col] == 'x')
- && ptr[col - 1] == '0'
- && ascii_isxdigit(ptr[col + 1])) ||
- (dobin
- && col > 0
- && (ptr[col] == 'B'
- || ptr[col] == 'b')
+ && (ptr[col] == 'X' || ptr[col] == 'x')
&& ptr[col - 1] == '0'
- && ascii_isbdigit(ptr[col + 1]))) {
- // Found hexadecimal or binary number, move to its start.
+ && ascii_isxdigit(ptr[col + 1]))
+ || (dobin
+ && col > 0
+ && (ptr[col] == 'B' || ptr[col] == 'b')
+ && ptr[col - 1] == '0'
+ && ascii_isbdigit(ptr[col + 1]))) {
+ // Found hexadecimal or binary number, move to its start.
col--;
} else {
// Search forward and then backward to find the start of number.
@@ -4392,8 +4440,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
}
if (visual) {
- while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) &&
- !(doalp && ASCII_ISALPHA(ptr[col]))) {
+ while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col]))) {
col++;
length--;
}
@@ -4555,8 +4603,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
*ptr++ = '0';
length--;
}
- if (pre == 'b' || pre == 'B' ||
- pre == 'x' || pre == 'X') {
+ if (pre == 'b' || pre == 'B' || pre == 'x' || pre == 'X') {
*ptr++ = pre;
length--;
}
@@ -4629,38 +4676,71 @@ theend:
/*
* Return the type of a register.
* Used for getregtype()
- * Returns MAUTO for error.
+ * Returns kMTUnknown for error.
*/
-char_u get_reg_type(int regname, long *reglen)
+MotionType get_reg_type(int regname, colnr_T *reg_width)
{
switch (regname) {
- case '%': /* file name */
- case '#': /* alternate file name */
- case '=': /* expression */
- case ':': /* last command line */
- case '/': /* last search-pattern */
- case '.': /* last inserted text */
- case Ctrl_F: /* Filename under cursor */
- case Ctrl_P: /* Path under cursor, expand via "path" */
- case Ctrl_W: /* word under cursor */
- case Ctrl_A: /* WORD (mnemonic All) under cursor */
- case '_': /* black hole: always empty */
- return MCHAR;
+ case '%': // file name
+ case '#': // alternate file name
+ case '=': // expression
+ case ':': // last command line
+ case '/': // last search-pattern
+ case '.': // last inserted text
+ case Ctrl_F: // Filename under cursor
+ case Ctrl_P: // Path under cursor, expand via "path"
+ case Ctrl_W: // word under cursor
+ case Ctrl_A: // WORD (mnemonic All) under cursor
+ case '_': // black hole: always empty
+ return kMTCharWise;
}
- if (regname != NUL && !valid_yank_reg(regname, false))
- return MAUTO;
+ if (regname != NUL && !valid_yank_reg(regname, false)) {
+ return kMTUnknown;
+ }
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (reg->y_array != NULL) {
- if (reglen != NULL && reg->y_type == MBLOCK)
- *reglen = reg->y_width;
+ if (reg_width != NULL && reg->y_type == kMTBlockWise) {
+ *reg_width = reg->y_width;
+ }
return reg->y_type;
}
- return MAUTO;
+ return kMTUnknown;
}
+/// Format the register type as a string.
+///
+/// @param reg_type The register type.
+/// @param reg_width The width, only used if "reg_type" is kMTBlockWise.
+/// @param[out] buf Buffer to store formatted string. The allocated size should
+/// be at least NUMBUFLEN+2 to always fit the value.
+/// @param buf_len The allocated size of the buffer.
+void format_reg_type(MotionType reg_type, colnr_T reg_width,
+ char *buf, size_t buf_len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(buf_len > 1);
+ switch (reg_type) {
+ case kMTLineWise:
+ buf[0] = 'V';
+ buf[1] = NUL;
+ break;
+ case kMTCharWise:
+ buf[0] = 'v';
+ buf[1] = NUL;
+ break;
+ case kMTBlockWise:
+ snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1);
+ break;
+ case kMTUnknown:
+ buf[0] = NUL;
+ break;
+ }
+}
+
+
/// When `flags` has `kGRegList` return a list with text `s`.
/// Otherwise just return `s`.
///
@@ -4739,10 +4819,11 @@ void *get_reg_contents(int regname, int flags)
len += STRLEN(reg->y_array[i]);
/*
* Insert a newline between lines and after last line if
- * y_type is MLINE.
+ * y_type is kMTLineWise.
*/
- if (reg->y_type == MLINE || i < reg->y_size - 1)
- ++len;
+ if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
+ len++;
+ }
}
retval = xmalloc(len + 1);
@@ -4757,10 +4838,11 @@ void *get_reg_contents(int regname, int flags)
/*
* Insert a NL between lines and after the last line if y_type is
- * MLINE.
+ * kMTLineWise.
*/
- if (reg->y_type == MLINE || i < reg->y_size - 1)
+ if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
retval[len++] = '\n';
+ }
}
retval[len] = NUL;
@@ -4801,11 +4883,12 @@ static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous
void write_reg_contents(int name, const char_u *str, ssize_t len,
int must_append)
{
- write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L);
+ write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0L);
}
void write_reg_contents_lst(int name, char_u **strings, int maxlen,
- bool must_append, int yank_type, long block_len)
+ bool must_append, MotionType yank_type,
+ long block_len)
{
if (name == '/' || name == '=') {
char_u *s = strings[0];
@@ -4851,13 +4934,13 @@ void write_reg_contents_lst(int name, char_u **strings, int maxlen,
/// contents of the register. Note that regardless of
/// `must_append`, this function will append when `name`
/// is an uppercase letter.
-/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO
+/// @param yank_type The motion type (kMTUnknown to auto detect)
/// @param block_len width of visual block
void write_reg_contents_ex(int name,
const char_u *str,
ssize_t len,
bool must_append,
- int yank_type,
+ MotionType yank_type,
long block_len)
{
if (len < 0) {
@@ -4931,24 +5014,24 @@ void write_reg_contents_ex(int name,
/// When the register is not empty, the string is appended.
///
/// @param y_ptr pointer to yank register
-/// @param yank_type MCHAR, MLINE, MBLOCK or MAUTO
+/// @param yank_type The motion type (kMTUnknown to auto detect)
/// @param str string or list of strings to put in register
/// @param len length of the string (Ignored when str_list=true.)
/// @param blocklen width of visual block, or -1 for "I don't know."
/// @param str_list True if str is `char_u **`.
-static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str,
- size_t len, colnr_T blocklen, bool str_list)
+static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
+ const char_u *str, size_t len, colnr_T blocklen,
+ bool str_list)
FUNC_ATTR_NONNULL_ALL
{
if (y_ptr->y_array == NULL) { // NULL means empty register
y_ptr->y_size = 0;
}
- int type = yank_type; // MCHAR, MLINE or MBLOCK
- if (yank_type == MAUTO) {
- type = ((str_list ||
- (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
- ? MLINE : MCHAR);
+ if (yank_type == kMTUnknown) {
+ yank_type = ((str_list
+ || (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
+ ? kMTLineWise : kMTCharWise);
}
size_t newlines = 0;
@@ -4962,11 +5045,11 @@ static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str,
}
} else {
newlines = memcnt(str, '\n', len);
- if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
+ if (yank_type == kMTCharWise || len == 0 || str[len - 1] != '\n') {
extraline = 1;
++newlines; // count extra newline at the end
}
- if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
+ if (y_ptr->y_size > 0 && y_ptr->y_type == kMTCharWise) {
append = true;
--newlines; // uncount newline when appending first line
}
@@ -5019,11 +5102,11 @@ static void str_to_reg(yankreg_T *y_ptr, int yank_type, const char_u *str,
memchrsub(pp[lnum], NUL, '\n', s_len);
}
}
- y_ptr->y_type = type;
+ y_ptr->y_type = yank_type;
y_ptr->y_size = lnum;
set_yreg_additional_data(y_ptr, NULL);
y_ptr->timestamp = os_time();
- if (type == MBLOCK) {
+ if (yank_type == kMTBlockWise) {
y_ptr->y_width = (blocklen == -1 ? (colnr_T) maxlen - 1 : blocklen);
} else {
y_ptr->y_width = 0;
@@ -5082,18 +5165,18 @@ static long line_count_info(char_u *line, long *wc, long *cc, long limit, int eo
return i;
}
-/*
- * Give some info about the position of the cursor (for "g CTRL-G").
- * In Visual mode, give some info about the selected region. (In this case,
- * the *_count_cursor variables store running totals for the selection.)
- */
-void cursor_pos_info(void)
+/// Give some info about the position of the cursor (for "g CTRL-G").
+/// In Visual mode, give some info about the selected region. (In this case,
+/// the *_count_cursor variables store running totals for the selection.)
+/// When "dict" is not NULL store the info there instead of showing it.
+void cursor_pos_info(dict_T *dict)
{
char_u *p;
char_u buf1[50];
char_u buf2[40];
linenr_T lnum;
long byte_count = 0;
+ long bom_count = 0;
long byte_count_cursor = 0;
long char_count = 0;
long char_count_cursor = 0;
@@ -5108,11 +5191,12 @@ void cursor_pos_info(void)
const int l_VIsual_active = VIsual_active;
const int l_VIsual_mode = VIsual_mode;
- /*
- * Compute the length of the file in characters.
- */
+ // Compute the length of the file in characters.
if (curbuf->b_ml.ml_flags & ML_EMPTY) {
- MSG(_(no_lines_msg));
+ if (dict == NULL) {
+ MSG(_(no_lines_msg));
+ return;
+ }
} else {
if (get_fileformat(curbuf) == EOL_DOS)
eol_size = 2;
@@ -5136,7 +5220,7 @@ void cursor_pos_info(void)
/* Make 'sbr' empty for a moment to get the correct size. */
p_sbr = empty_option;
oparg.is_VIsual = true;
- oparg.motion_type = MBLOCK;
+ oparg.motion_type = kMTBlockWise;
oparg.op_type = OP_NOP;
getvcols(curwin, &min_pos, &max_pos,
&oparg.start_vcol, &oparg.end_vcol);
@@ -5217,78 +5301,105 @@ void cursor_pos_info(void)
&char_count, (long)MAXCOL, eol_size);
}
- /* Correction for when last line doesn't have an EOL. */
- if (!curbuf->b_p_eol && (curbuf->b_p_bin || !curbuf->b_p_fixeol))
+ // Correction for when last line doesn't have an EOL.
+ if (!curbuf->b_p_eol && (curbuf->b_p_bin || !curbuf->b_p_fixeol)) {
byte_count -= eol_size;
+ }
+
+ if (dict == NULL) {
+ if (l_VIsual_active) {
+ if (l_VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) {
+ getvcols(curwin, &min_pos, &max_pos, &min_pos.col, &max_pos.col);
+ vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "),
+ (int64_t)(oparg.end_vcol - oparg.start_vcol + 1));
+ } else {
+ buf1[0] = NUL;
+ }
+
+ if (char_count_cursor == byte_count_cursor
+ && char_count == byte_count) {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Selected %s%" PRId64 " of %" PRId64 " Lines;"
+ " %" PRId64 " of %" PRId64 " Words;"
+ " %" PRId64 " of %" PRId64 " Bytes"),
+ buf1, (int64_t)line_count_selected,
+ (int64_t)curbuf->b_ml.ml_line_count,
+ (int64_t)word_count_cursor, (int64_t)word_count,
+ (int64_t)byte_count_cursor, (int64_t)byte_count);
+ } else {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Selected %s%" PRId64 " of %" PRId64 " Lines;"
+ " %" PRId64 " of %" PRId64 " Words;"
+ " %" PRId64 " of %" PRId64 " Chars;"
+ " %" PRId64 " of %" PRId64 " Bytes"),
+ buf1, (int64_t)line_count_selected,
+ (int64_t)curbuf->b_ml.ml_line_count,
+ (int64_t)word_count_cursor, (int64_t)word_count,
+ (int64_t)char_count_cursor, (int64_t)char_count,
+ (int64_t)byte_count_cursor, (int64_t)byte_count);
+ }
+ } else {
+ p = get_cursor_line_ptr();
+ validate_virtcol();
+ col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1,
+ (int)curwin->w_virtcol + 1);
+ col_print(buf2, sizeof(buf2), (int)STRLEN(p), linetabsize(p));
+
+ if (char_count_cursor == byte_count_cursor
+ && char_count == byte_count) {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Col %s of %s; Line %" PRId64 " of %" PRId64 ";"
+ " Word %" PRId64 " of %" PRId64 ";"
+ " Byte %" PRId64 " of %" PRId64 ""),
+ (char *)buf1, (char *)buf2,
+ (int64_t)curwin->w_cursor.lnum,
+ (int64_t)curbuf->b_ml.ml_line_count,
+ (int64_t)word_count_cursor, (int64_t)word_count,
+ (int64_t)byte_count_cursor, (int64_t)byte_count);
+ } else {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Col %s of %s; Line %" PRId64 " of %" PRId64 ";"
+ " Word %" PRId64 " of %" PRId64 ";"
+ " Char %" PRId64 " of %" PRId64 ";"
+ " Byte %" PRId64 " of %" PRId64 ""),
+ (char *)buf1, (char *)buf2,
+ (int64_t)curwin->w_cursor.lnum,
+ (int64_t)curbuf->b_ml.ml_line_count,
+ (int64_t)word_count_cursor, (int64_t)word_count,
+ (int64_t)char_count_cursor, (int64_t)char_count,
+ (int64_t)byte_count_cursor, (int64_t)byte_count);
+ }
+ }
+ }
+
+ // Don't shorten this message, the user asked for it.
+ bom_count = bomb_size();
+ if (bom_count > 0) {
+ vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
+ _("(+%" PRId64 " for BOM)"), (int64_t)byte_count);
+ }
+ if (dict == NULL) {
+ p = p_shm;
+ p_shm = (char_u *)"";
+ msg(IObuff);
+ p_shm = p;
+ }
+ }
+
+ if (dict != NULL) {
+ dict_add_nr_str(dict, "words", word_count, NULL);
+ dict_add_nr_str(dict, "chars", char_count, NULL);
+ dict_add_nr_str(dict, "bytes", byte_count + bom_count, NULL);
if (l_VIsual_active) {
- if (l_VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) {
- getvcols(curwin, &min_pos, &max_pos, &min_pos.col,
- &max_pos.col);
- vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "),
- (int64_t)(oparg.end_vcol - oparg.start_vcol + 1));
- } else
- buf1[0] = NUL;
-
- if (char_count_cursor == byte_count_cursor
- && char_count == byte_count)
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Selected %s%" PRId64 " of %" PRId64 " Lines; %" PRId64
- " of %" PRId64 " Words; %" PRId64 " of %" PRId64 " Bytes"),
- buf1, (int64_t)line_count_selected,
- (int64_t)curbuf->b_ml.ml_line_count,
- (int64_t)word_count_cursor, (int64_t)word_count,
- (int64_t)byte_count_cursor, (int64_t)byte_count);
- else
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Selected %s%" PRId64 " of %" PRId64 " Lines; %" PRId64
- " of %" PRId64 " Words; %" PRId64 " of %" PRId64
- " Chars; %" PRId64 " of %" PRId64 " Bytes"),
- buf1, (int64_t)line_count_selected,
- (int64_t)curbuf->b_ml.ml_line_count,
- (int64_t)word_count_cursor, (int64_t)word_count,
- (int64_t)char_count_cursor, (int64_t)char_count,
- (int64_t)byte_count_cursor, (int64_t)byte_count);
+ dict_add_nr_str(dict, "visual_bytes", byte_count_cursor, NULL);
+ dict_add_nr_str(dict, "visual_chars", char_count_cursor, NULL);
+ dict_add_nr_str(dict, "visual_words", word_count_cursor, NULL);
} else {
- p = get_cursor_line_ptr();
- validate_virtcol();
- col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1,
- (int)curwin->w_virtcol + 1);
- col_print(buf2, sizeof(buf2), (int)STRLEN(p), linetabsize(p));
-
- if (char_count_cursor == byte_count_cursor
- && char_count == byte_count)
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Col %s of %s; Line %" PRId64 " of %" PRId64 "; Word %" PRId64
- " of %" PRId64 "; Byte %" PRId64 " of %" PRId64 ""),
- (char *)buf1, (char *)buf2,
- (int64_t)curwin->w_cursor.lnum,
- (int64_t)curbuf->b_ml.ml_line_count,
- (int64_t)word_count_cursor, (int64_t)word_count,
- (int64_t)byte_count_cursor, (int64_t)byte_count);
- else
- vim_snprintf((char *)IObuff, IOSIZE,
- _(
- "Col %s of %s; Line %" PRId64 " of %" PRId64 "; Word %" PRId64
- " of %" PRId64 "; Char %" PRId64 " of %" PRId64
- "; Byte %" PRId64 " of %" PRId64 ""),
- (char *)buf1, (char *)buf2,
- (int64_t)curwin->w_cursor.lnum,
- (int64_t)curbuf->b_ml.ml_line_count,
- (int64_t)word_count_cursor, (int64_t)word_count,
- (int64_t)char_count_cursor, (int64_t)char_count,
- (int64_t)byte_count_cursor, (int64_t)byte_count);
- }
-
- byte_count = bomb_size();
- if (byte_count > 0)
- sprintf((char *)IObuff + STRLEN(IObuff), _("(+%" PRId64 " for BOM)"),
- (int64_t)byte_count);
- /* Don't shorten this message, the user asked for it. */
- p = p_shm;
- p_shm = (char_u *)"";
- msg(IObuff);
- p_shm = p;
+ dict_add_nr_str(dict, "cursor_bytes", byte_count_cursor, NULL);
+ dict_add_nr_str(dict, "cursor_chars", char_count_cursor, NULL);
+ dict_add_nr_str(dict, "cursor_words", word_count_cursor, NULL);
+ }
}
}
@@ -5391,16 +5502,16 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
}
switch (regtype[0]) {
case 0:
- reg->y_type = MAUTO;
+ reg->y_type = kMTUnknown;
break;
case 'v': case 'c':
- reg->y_type = MCHAR;
+ reg->y_type = kMTCharWise;
break;
case 'V': case 'l':
- reg->y_type = MLINE;
+ reg->y_type = kMTLineWise;
break;
case 'b': case Ctrl_V:
- reg->y_type = MBLOCK;
+ reg->y_type = kMTBlockWise;
break;
default:
goto err;
@@ -5408,7 +5519,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
} else {
lines = res;
// provider did not specify regtype, calculate it below
- reg->y_type = MAUTO;
+ reg->y_type = kMTUnknown;
}
reg->y_array = xcalloc(lines->lv_len, sizeof(uint8_t *));
@@ -5429,20 +5540,20 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
// a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline
- if (reg->y_type != MCHAR) {
+ if (reg->y_type != kMTCharWise) {
xfree(reg->y_array[reg->y_size-1]);
reg->y_size--;
- if (reg->y_type == MAUTO) {
- reg->y_type = MLINE;
+ if (reg->y_type == kMTUnknown) {
+ reg->y_type = kMTLineWise;
}
}
} else {
- if (reg->y_type == MAUTO) {
- reg->y_type = MCHAR;
+ if (reg->y_type == kMTUnknown) {
+ reg->y_type = kMTCharWise;
}
}
- if (reg->y_type == MBLOCK) {
+ if (reg->y_type == kMTBlockWise) {
int maxlen = 0;
for (int i = 0; i < reg->y_size; i++) {
int rowlen = STRLEN(reg->y_array[i]);
@@ -5491,17 +5602,19 @@ static void set_clipboard(int name, yankreg_T *reg)
char_u regtype;
switch (reg->y_type) {
- case MLINE:
+ case kMTLineWise:
regtype = 'V';
list_append_string(lines, (char_u*)"", 0);
break;
- case MCHAR:
+ case kMTCharWise:
regtype = 'v';
break;
- case MBLOCK:
+ case kMTBlockWise:
regtype = 'b';
list_append_string(lines, (char_u*)"", 0);
break;
+ case kMTUnknown:
+ assert(false);
}
list_append_string(args, &regtype, 1);
@@ -5542,7 +5655,7 @@ static inline bool reg_empty(const yankreg_T *const reg)
return (reg->y_array == NULL
|| reg->y_size == 0
|| (reg->y_size == 1
- && reg->y_type == MCHAR
+ && reg->y_type == kMTCharWise
&& *(reg->y_array[0]) == NUL));
}
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index f33e87572f..8c8a586957 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -78,10 +78,10 @@ enum GRegFlags {
/// Definition of one register
typedef struct yankreg {
- char_u **y_array; ///< Pointer to an array of line pointers.
- linenr_T y_size; ///< Number of lines in y_array.
- char_u y_type; ///< Register type: MLINE, MCHAR or MBLOCK.
- colnr_T y_width; ///< Register width (only valid for y_type == MBLOCK).
+ char_u **y_array; ///< Pointer to an array of line pointers.
+ linenr_T y_size; ///< Number of lines in y_array.
+ MotionType y_type; ///< Register type
+ colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise).
Timestamp timestamp; ///< Time when register was last modified.
dict_T *additional_data; ///< Additional data from ShaDa file.
} yankreg_T;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index af7b272467..2f22c245dd 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -32,6 +32,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/edit.h"
#include "nvim/option.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
@@ -1177,28 +1178,27 @@ do_set (
errmsg = e_invarg;
goto skip;
}
- arg[len] = NUL; /* put NUL after name */
- if (arg[1] == 't' && arg[2] == '_') /* could be term code */
- opt_idx = findoption(arg + 1);
- arg[len++] = '>'; /* restore '>' */
- if (opt_idx == -1)
+ if (arg[1] == 't' && arg[2] == '_') { // could be term code
+ opt_idx = findoption_len(arg + 1, (size_t) (len - 1));
+ }
+ len++;
+ if (opt_idx == -1) {
key = find_key_option(arg + 1);
+ }
} else {
len = 0;
- /*
- * The two characters after "t_" may not be alphanumeric.
- */
- if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+ // The two characters after "t_" may not be alphanumeric.
+ if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) {
len = 4;
- else
- while (ASCII_ISALNUM(arg[len]) || arg[len] == '_')
- ++len;
- nextchar = arg[len];
- arg[len] = NUL; /* put NUL after name */
- opt_idx = findoption(arg);
- arg[len] = nextchar; /* restore nextchar */
- if (opt_idx == -1)
+ } else {
+ while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') {
+ len++;
+ }
+ }
+ opt_idx = findoption_len(arg, (size_t) len);
+ if (opt_idx == -1) {
key = find_key_option(arg);
+ }
}
/* remember character after option name */
@@ -1448,7 +1448,7 @@ do_set (
char_u *oldval = NULL; // previous value if *varp
char_u *newval;
char_u *origval = NULL;
- char_u *saved_origval = NULL;
+ char *saved_origval = NULL;
unsigned newlen;
int comma;
int bs;
@@ -1725,7 +1725,7 @@ do_set (
if (!starting && origval != NULL) {
// origval may be freed by
// did_set_string_option(), make a copy.
- saved_origval = vim_strsave(origval);
+ saved_origval = xstrdup((char *) origval);
}
/* Handle side effects, and set the global value for
@@ -1740,11 +1740,10 @@ do_set (
}
if (saved_origval != NULL) {
- char_u buf_type[7];
- vim_snprintf((char *)buf_type, ARRAY_SIZE(buf_type), "%s",
+ char buf_type[7];
+ vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_NEW,
- *(char_u **)varp, -1);
+ set_vim_var_string(VV_OPTION_NEW, *(char **) varp, -1);
set_vim_var_string(VV_OPTION_OLD, saved_origval, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET,
@@ -2058,6 +2057,7 @@ static void didset_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)spell_check_msm();
(void)spell_check_sps();
@@ -2145,6 +2145,7 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_ep);
check_string_option(&buf->b_p_path);
check_string_option(&buf->b_p_tags);
+ check_string_option(&buf->b_p_tc);
check_string_option(&buf->b_p_dict);
check_string_option(&buf->b_p_tsr);
check_string_option(&buf->b_p_lw);
@@ -2324,7 +2325,7 @@ set_string_option (
char_u *s;
char_u **varp;
char_u *oldval;
- char_u *saved_oldval = NULL;
+ char *saved_oldval = NULL;
char_u *r = NULL;
if (options[opt_idx].var == NULL) /* don't set hidden option */
@@ -2340,7 +2341,7 @@ set_string_option (
*varp = s;
if (!starting) {
- saved_oldval = vim_strsave(oldval);
+ saved_oldval = xstrdup((char *) oldval);
}
if ((r = did_set_string_option(opt_idx, varp, (int)true, oldval, NULL,
@@ -2349,10 +2350,10 @@ set_string_option (
// call autocommand after handling side effects
if (saved_oldval != NULL) {
- char_u buf_type[7];
- vim_snprintf((char *)buf_type, ARRAY_SIZE(buf_type), "%s",
+ char buf_type[7];
+ vim_snprintf(buf_type, ARRAY_SIZE(buf_type), "%s",
(opt_flags & OPT_LOCAL) ? "local" : "global");
- set_vim_var_string(VV_OPTION_NEW, *varp, -1);
+ set_vim_var_string(VV_OPTION_NEW, (char *) (*varp), -1);
set_vim_var_string(VV_OPTION_OLD, saved_oldval, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET,
@@ -2958,13 +2959,17 @@ did_set_string_option (
}
/* 'completeopt' */
else if (varp == &p_cot) {
- if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK)
+ if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
errmsg = e_invarg;
+ } else {
+ completeopt_was_set();
+ }
}
/* 'pastetoggle': translate key codes like in a mapping */
else if (varp == &p_pt) {
if (*p_pt) {
- (void)replace_termcodes(p_pt, &p, TRUE, TRUE, FALSE);
+ (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, false,
+ CPO_TO_CPO_FLAGS);
if (p != NULL) {
if (new_value_alloced)
free_string_option(p_pt);
@@ -2984,6 +2989,24 @@ did_set_string_option (
if (opt_strings_flags(p_bo, p_bo_values, &bo_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (gvarp == &p_tc) { // 'tagcase'
+ unsigned int *flags;
+
+ if (opt_flags & OPT_LOCAL) {
+ p = curbuf->b_p_tc;
+ flags = &curbuf->b_tc_flags;
+ } else {
+ p = p_tc;
+ flags = &tc_flags;
+ }
+
+ if ((opt_flags & OPT_LOCAL) && *p == NUL) {
+ // make the local value empty: use the global value
+ *flags = 0;
+ } else if (*p == NUL
+ || opt_strings_flags(p, p_tc_values, flags, false) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_cmp) { // 'casemap'
if (opt_strings_flags(p_cmp, p_cmp_values, &cmp_flags, true) != OK)
errmsg = e_invarg;
@@ -3800,7 +3823,7 @@ set_bool_option (
msg_source(hl_attr(HLF_W));
MSG_ATTR(_(w_arabic), hl_attr(HLF_W));
- set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_arabic), -1);
+ set_vim_var_string(VV_WARNINGMSG, _(w_arabic), -1);
}
/* set 'delcombine' */
@@ -3847,14 +3870,14 @@ set_bool_option (
options[opt_idx].flags |= P_WAS_SET;
if (!starting) {
- char_u buf_old[2];
- char_u buf_new[2];
- char_u buf_type[7];
- vim_snprintf((char *)buf_old, ARRAY_SIZE(buf_old), "%d",
+ char buf_old[2];
+ char buf_new[2];
+ char buf_type[7];
+ vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%d",
old_value ? true: false);
- vim_snprintf((char *)buf_new, ARRAY_SIZE(buf_new), "%d",
+ vim_snprintf(buf_new, ARRAY_SIZE(buf_new), "%d",
value ? true: false);
- vim_snprintf((char *)buf_type, ARRAY_SIZE(buf_type), "%s",
+ 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);
@@ -4237,12 +4260,12 @@ set_num_option (
options[opt_idx].flags |= P_WAS_SET;
if (!starting && errmsg == NULL) {
- char_u buf_old[NUMBUFLEN];
- char_u buf_new[NUMBUFLEN];
- char_u buf_type[7];
- vim_snprintf((char *)buf_old, ARRAY_SIZE(buf_old), "%ld", old_value);
- vim_snprintf((char *)buf_new, ARRAY_SIZE(buf_new), "%ld", value);
- vim_snprintf((char *)buf_type, ARRAY_SIZE(buf_type), "%s",
+ char buf_old[NUMBUFLEN];
+ char buf_new[NUMBUFLEN];
+ char buf_type[7];
+ vim_snprintf(buf_old, ARRAY_SIZE(buf_old), "%ld", old_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);
@@ -4284,14 +4307,16 @@ static void check_redraw(uint32_t flags)
redraw_all_later(NOT_VALID);
}
-/*
- * Find index for option 'arg'.
- * Return -1 if not found.
- */
-static int findoption(char_u *arg)
+/// Find index for named option
+///
+/// @param[in] arg Option to find index for.
+/// @param[in] len Length of the option.
+///
+/// @return Index of the option or -1 if option was not found.
+int findoption_len(const char_u *const arg, const size_t len)
{
- char *s, *p;
- static short quick_tab[27] = {0, 0}; /* quick access table */
+ char *s, *p;
+ static int quick_tab[27] = { 0, 0 }; // quick access table
int is_term_opt;
/*
@@ -4315,25 +4340,31 @@ static int findoption(char_u *arg)
/*
* Check for name starting with an illegal character.
*/
- if (arg[0] < 'a' || arg[0] > 'z')
+ if (len == 0 || arg[0] < 'a' || arg[0] > 'z') {
return -1;
+ }
int opt_idx;
- is_term_opt = (arg[0] == 't' && arg[1] == '_');
- if (is_term_opt)
+ is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_');
+ if (is_term_opt) {
opt_idx = quick_tab[26];
- else
+ } else {
opt_idx = quick_tab[CharOrdLow(arg[0])];
+ }
+ // Match full name
for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) {
- if (STRCMP(arg, s) == 0) /* match full name */
+ if (STRNCMP(arg, s, len) == 0 && s[len] == NUL) {
break;
+ }
}
if (s == NULL && !is_term_opt) {
opt_idx = quick_tab[CharOrdLow(arg[0])];
+ // Match short name
for (; options[opt_idx].fullname != NULL; opt_idx++) {
s = options[opt_idx].shortname;
- if (s != NULL && STRCMP(arg, s) == 0) /* match short name */
+ if (s != NULL && STRNCMP(arg, s, len) == 0 && s[len] == NUL) {
break;
+ }
s = NULL;
}
}
@@ -4401,6 +4432,15 @@ bool set_tty_option(char *name, char *value)
}
/*
+ * Find index for option 'arg'.
+ * Return -1 if not found.
+ */
+static int findoption(char_u *arg)
+{
+ return findoption_len(arg, STRLEN(arg));
+}
+
+/*
* Get the value for an option.
*
* Returns:
@@ -4656,27 +4696,32 @@ char_u *get_highlight_default(void)
/*
* Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
*/
-static int find_key_option(char_u *arg)
+int find_key_option_len(const char_u *arg, size_t len)
{
int key;
int modifiers;
- /*
- * Don't use get_special_key_code() for t_xx, we don't want it to call
- * add_termcap_entry().
- */
- if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3])
+ // Don't use get_special_key_code() for t_xx, we don't want it to call
+ // add_termcap_entry().
+ if (len >= 4 && arg[0] == 't' && arg[1] == '_') {
key = TERMCAP2KEY(arg[2], arg[3]);
- else {
- --arg; /* put arg at the '<' */
+ } else {
+ arg--; // put arg at the '<'
modifiers = 0;
- key = find_special_key(&arg, &modifiers, TRUE, TRUE);
- if (modifiers) /* can't handle modifiers here */
+ key = find_special_key(&arg, len + 1, &modifiers, true, true);
+ if (modifiers) { // can't handle modifiers here
key = 0;
+ }
}
return key;
}
+static int find_key_option(const char_u *arg)
+{
+ return find_key_option_len(arg, STRLEN(arg));
+}
+
+
/*
* if 'all' == 0: show changed options
* if 'all' == 1: show all normal options
@@ -4737,9 +4782,10 @@ showoptions (
option_value2string(p, opt_flags);
len = (int)STRLEN(p->fullname) + vim_strsize(NameBuff) + 1;
}
- if ((len <= INC - GAP && run == 1) ||
- (len > INC - GAP && run == 2))
+ if ((len <= INC - GAP && run == 1)
+ || (len > INC - GAP && run == 2)) {
items[item_count++] = p;
+ }
}
}
@@ -4928,18 +4974,15 @@ int makeset(FILE *fd, int opt_flags, int local_only)
} else { /* P_STRING */
int do_endif = FALSE;
- /* Don't set 'syntax' and 'filetype' again if the value is
- * already right, avoids reloading the syntax file. */
- if (
- p->indir == PV_SYN
- ||
- p->indir == PV_FT
- ) {
+ // Don't set 'syntax' and 'filetype' again if the value is
+ // already right, avoids reloading the syntax file.
+ if (p->indir == PV_SYN || p->indir == PV_FT) {
if (fprintf(fd, "if &%s != '%s'", p->fullname,
- *(char_u **)(varp)) < 0
- || put_eol(fd) < 0)
+ *(char_u **)(varp)) < 0
+ || put_eol(fd) < 0) {
return FAIL;
- do_endif = TRUE;
+ }
+ do_endif = true;
}
if (put_setstring(fd, cmd, p->fullname, (char_u **)varp,
(p->flags & P_EXPAND) != 0) == FAIL)
@@ -5112,6 +5155,10 @@ void unset_global_local_option(char *name, void *from)
case PV_TAGS:
clear_string_option(&buf->b_p_tags);
break;
+ case PV_TC:
+ clear_string_option(&buf->b_p_tc);
+ buf->b_tc_flags = 0;
+ break;
case PV_DEF:
clear_string_option(&buf->b_p_def);
break;
@@ -5165,6 +5212,7 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
case PV_PATH: return (char_u *)&(curbuf->b_p_path);
case PV_AR: return (char_u *)&(curbuf->b_p_ar);
case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
+ case PV_TC: return (char_u *)&(curbuf->b_p_tc);
case PV_DEF: return (char_u *)&(curbuf->b_p_def);
case PV_INC: return (char_u *)&(curbuf->b_p_inc);
case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
@@ -5202,6 +5250,8 @@ static char_u *get_varp(vimoption_T *p)
? (char_u *)&(curbuf->b_p_ar) : p->var;
case PV_TAGS: return *curbuf->b_p_tags != NUL
? (char_u *)&(curbuf->b_p_tags) : p->var;
+ case PV_TC: return *curbuf->b_p_tc != NUL
+ ? (char_u *)&(curbuf->b_p_tc) : p->var;
case PV_BKC: return *curbuf->b_p_bkc != NUL
? (char_u *)&(curbuf->b_p_bkc) : p->var;
case PV_DEF: return *curbuf->b_p_def != NUL
@@ -5581,6 +5631,8 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_kp = empty_option;
buf->b_p_path = empty_option;
buf->b_p_tags = empty_option;
+ buf->b_p_tc = empty_option;
+ buf->b_tc_flags = 0;
buf->b_p_def = empty_option;
buf->b_p_inc = empty_option;
buf->b_p_inex = vim_strsave(p_inex);
@@ -6167,16 +6219,14 @@ int has_format_option(int x)
return vim_strchr(curbuf->b_p_fo, x) != NULL;
}
-/*
- * Return TRUE if "x" is present in 'shortmess' option, or
- * 'shortmess' contains 'a' and "x" is present in SHM_A.
- */
-int shortmess(int x)
+/// @returns true if "x" is present in 'shortmess' option, or
+/// 'shortmess' contains 'a' and "x" is present in SHM_ALL_ABBREVIATIONS.
+bool shortmess(int x)
{
- return p_shm != NULL &&
- ( vim_strchr(p_shm, x) != NULL
- || (vim_strchr(p_shm, 'a') != NULL
- && vim_strchr((char_u *)SHM_A, x) != NULL));
+ return (p_shm != NULL
+ && (vim_strchr(p_shm, x) != NULL
+ || (vim_strchr(p_shm, 'a') != NULL
+ && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL)));
}
/*
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 10706a0753..904e97f8ca 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include "nvim/types.h"
+#include "nvim/macros.h" // For EXTERN
// option_defs.h: definition of global variables for settable options
@@ -151,26 +152,42 @@
#define COCU_ALL "nvic" /* flags for 'concealcursor' */
-/* characters for p_shm option: */
-#define SHM_RO 'r' /* readonly */
-#define SHM_MOD 'm' /* modified */
-#define SHM_FILE 'f' /* (file 1 of 2) */
-#define SHM_LAST 'i' /* last line incomplete */
-#define SHM_TEXT 'x' /* tx instead of textmode */
-#define SHM_LINES 'l' /* "L" instead of "lines" */
-#define SHM_NEW 'n' /* "[New]" instead of "[New file]" */
-#define SHM_WRI 'w' /* "[w]" instead of "written" */
-#define SHM_A "rmfixlnw" /* represented by 'a' flag */
-#define SHM_WRITE 'W' /* don't use "written" at all */
-#define SHM_TRUNC 't' /* trunctate file messages */
-#define SHM_TRUNCALL 'T' /* trunctate all messages */
-#define SHM_OVER 'o' /* overwrite file messages */
-#define SHM_OVERALL 'O' /* overwrite more messages */
-#define SHM_SEARCH 's' /* no search hit bottom messages */
-#define SHM_ATTENTION 'A' /* no ATTENTION messages */
-#define SHM_INTRO 'I' /* intro messages */
-#define SHM_COMPLETIONMENU 'c' // completion menu messages
-#define SHM_ALL "rmfixlnwaWtToOsAIc" /* all possible flags for 'shm' */
+/// characters for p_shm option:
+enum {
+ SHM_RO = 'r', ///< Readonly.
+ SHM_MOD = 'm', ///< Modified.
+ SHM_FILE = 'f', ///< (file 1 of 2)
+ SHM_LAST = 'i', ///< Last line incomplete.
+ SHM_TEXT = 'x', ///< Tx instead of textmode.
+ SHM_LINES = 'l', ///< "L" instead of "lines".
+ SHM_NEW = 'n', ///< "[New]" instead of "[New file]".
+ SHM_WRI = 'w', ///< "[w]" instead of "written".
+ SHM_ABBREVIATIONS = 'a', ///< Use abbreviations from #SHM_ALL_ABBREVIATIONS.
+ SHM_WRITE = 'W', ///< Don't use "written" at all.
+ SHM_TRUNC = 't', ///< Trunctate file messages.
+ SHM_TRUNCALL = 'T', ///< Trunctate all messages.
+ SHM_OVER = 'o', ///< Overwrite file messages.
+ SHM_OVERALL = 'O', ///< Overwrite more messages.
+ SHM_SEARCH = 's', ///< No search hit bottom messages.
+ SHM_ATTENTION = 'A', ///< No ATTENTION messages.
+ SHM_INTRO = 'I', ///< Intro messages.
+ SHM_COMPLETIONMENU = 'c', ///< Completion menu messages.
+ SHM_RECORDING = 'q', ///< Short recording message.
+ SHM_FILEINFO = 'F', ///< No file info messages.
+};
+/// Represented by 'a' flag.
+#define SHM_ALL_ABBREVIATIONS ((char_u[]) { \
+ SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, \
+ 0, \
+})
+/// All possible flags for 'shm'.
+#define SHM_ALL ((char_u[]) { \
+ SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, \
+ SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, \
+ SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU, \
+ SHM_RECORDING, SHM_FILEINFO, \
+ 0, \
+})
/* characters for p_go: */
#define GO_ASEL 'a' /* autoselect */
@@ -580,6 +597,14 @@ static char *(p_swb_values[]) =
#define SWB_NEWTAB 0x008
#define SWB_VSPLIT 0x010
EXTERN int p_tbs; ///< 'tagbsearch'
+EXTERN char_u *p_tc; ///< 'tagcase'
+EXTERN unsigned tc_flags; ///< flags from 'tagcase'
+#ifdef IN_OPTION_C
+static char *(p_tc_values[]) = { "followic", "ignore", "match", NULL };
+#endif
+#define TC_FOLLOWIC 0x01
+#define TC_IGNORE 0x02
+#define TC_MATCH 0x04
EXTERN long p_tl; ///< 'taglength'
EXTERN int p_tr; ///< 'tagrelative'
EXTERN char_u *p_tags; ///< 'tags'
@@ -594,6 +619,7 @@ EXTERN long p_titlelen; ///< 'titlelen'
EXTERN char_u *p_titleold; ///< 'titleold'
EXTERN char_u *p_titlestring; ///< 'titlestring'
EXTERN char_u *p_tsr; ///< 'thesaurus'
+EXTERN bool p_tgc; ///< 'termguicolors'
EXTERN int p_ttimeout; ///< 'ttimeout'
EXTERN long p_ttm; ///< 'ttimeoutlen'
EXTERN char_u *p_udir; ///< 'undodir'
@@ -720,6 +746,7 @@ enum {
, BV_SW
, BV_SWF
, BV_TAGS
+ , BV_TC
, BV_TS
, BV_TW
, BV_TX
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index df77c374ec..218e34f595 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -2332,6 +2332,13 @@ return {
defaults={if_true={vi=true}}
},
{
+ full_name='tagcase', abbreviation='tc',
+ type='string', scope={'global', 'buffer'},
+ vim=true,
+ varname='p_tc',
+ defaults={if_true={vi="followic", vim="followic"}}
+ },
+ {
full_name='taglength', abbreviation='tl',
type='number', scope={'global'},
vi_def=true,
@@ -2376,6 +2383,14 @@ return {
defaults={if_true={vi=""}}
},
{
+ full_name='termguicolors', abbreviation='tgc',
+ type='bool', scope={'global'},
+ vi_def=false,
+ redraw={'everything'},
+ varname='p_tgc',
+ defaults={if_true={vi=false}}
+ },
+ {
full_name='terse',
type='bool', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 41ce8ddbc2..edc430410c 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -147,7 +147,7 @@ static char_u *homedir = NULL;
void init_homedir(void)
{
- /* In case we are called a second time (when 'encoding' changes). */
+ // In case we are called a second time (when 'encoding' changes).
xfree(homedir);
homedir = NULL;
@@ -176,16 +176,16 @@ void init_homedir(void)
if (var != NULL) {
#ifdef UNIX
- /*
- * Change to the directory and get the actual path. This resolves
- * links. Don't do it when we can't return.
- */
+ // Change to the directory and get the actual path. This resolves
+ // links. Don't do it when we can't return.
if (os_dirname(NameBuff, MAXPATHL) == OK
&& os_chdir((char *)NameBuff) == 0) {
- if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK)
+ if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK) {
var = IObuff;
- if (os_chdir((char *)NameBuff) != 0)
+ }
+ if (os_chdir((char *)NameBuff) != 0) {
EMSG(_(e_prev_dir));
+ }
}
#endif
homedir = vim_strsave(var);
@@ -239,29 +239,29 @@ void expand_env(char_u *src, char_u *dst, int dstlen)
/// "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
/// Skips over "\ ", "\~" and "\$" (not for Win32 though).
/// If anything fails no expansion is done and dst equals src.
-/// startstr recognize the start of a new name, for '~' expansion.
+/// prefix recognize the start of a new name, for '~' expansion.
/// @param srcp Input string e.g. "$HOME/vim.hlp"
/// @param dst Where to put the result
/// @param dstlen Maximum length of the result
/// @param esc Should we escape spaces in expanded variables?
/// @param one Should we expand more than one '~'?
-/// @param startstr Common prefix for paths, can be NULL
-void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
- char_u *startstr)
+/// @param prefix Common prefix for paths, can be NULL
+void expand_env_esc(char_u *restrict srcp,
+ char_u *restrict dst,
+ int dstlen,
+ bool esc,
+ bool one,
+ char_u *prefix)
{
- char_u *src;
char_u *tail;
- int c;
char_u *var;
bool copy_char;
bool mustfree; // var was allocated, need to free it later
bool at_start = true; // at start of a name
- int startstr_len = 0;
- if (startstr != NULL)
- startstr_len = (int)STRLEN(startstr);
+ int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix);
- src = skipwhite(srcp);
+ char_u *src = skipwhite(srcp);
dstlen--; // leave one char space for "\,"
while (*src && dstlen > 0) {
// Skip over `=expr`.
@@ -281,6 +281,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
dstlen -= (int)len;
continue;
}
+
copy_char = true;
if ((*src == '$') || (*src == '~' && at_start)) {
mustfree = false;
@@ -290,14 +291,15 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
if (*src != '~') { // environment var
tail = src + 1;
var = dst;
- c = dstlen - 1;
+ int c = dstlen - 1;
#ifdef UNIX
// Unix has ${var-name} type environment vars
if (*tail == '{' && !vim_isIDc('{')) {
- tail++; /* ignore '{' */
- while (c-- > 0 && *tail && *tail != '}')
+ tail++; // ignore '{'
+ while (c-- > 0 && *tail != NUL && *tail != '}') {
*var++ = *tail++;
+ }
} else // NOLINT
#endif
{
@@ -321,7 +323,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
#if defined(UNIX)
}
#endif
- } else if ( src[1] == NUL /* home directory */
+ } else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
var = homedir;
@@ -331,12 +333,13 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
// Copy ~user to dst[], so we can put a NUL after it.
tail = src;
var = dst;
- c = dstlen - 1;
- while ( c-- > 0
- && *tail
- && vim_isfilec(*tail)
- && !vim_ispathsep(*tail))
+ int c = dstlen - 1;
+ while (c-- > 0
+ && *tail
+ && vim_isfilec(*tail)
+ && !vim_ispathsep(*tail)) {
*var++ = *tail++;
+ }
*var = NUL;
// Use os_get_user_directory() to get the user directory.
// If this function fails, the shell is used to
@@ -344,8 +347,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
// does not support ~user (old versions of /bin/sh).
var = (char_u *)os_get_user_directory((char *)dst + 1);
mustfree = true;
- if (var == NULL)
- {
+ if (var == NULL) {
expand_T xpc;
ExpandInit(&xpc);
@@ -381,8 +383,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
- if (mustfree)
+ if (mustfree) {
xfree(var);
+ }
var = p;
mustfree = true;
}
@@ -391,7 +394,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
&& (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) {
STRCPY(dst, var);
dstlen -= (int)STRLEN(var);
- c = (int)STRLEN(var);
+ int c = (int)STRLEN(var);
// if var[] ends in a path separator and tail[] starts
// with it, skip a character
if (*var != NUL && after_pathsep((char *)dst, (char *)dst + c)
@@ -404,8 +407,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
src = tail;
copy_char = false;
}
- if (mustfree)
+ if (mustfree) {
xfree(var);
+ }
}
if (copy_char) { // copy at least one char
@@ -422,9 +426,10 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
*dst++ = *src++;
--dstlen;
- if (startstr != NULL && src - startstr_len >= srcp
- && STRNCMP(src - startstr_len, startstr, startstr_len) == 0)
+ if (prefix != NULL && src - prefix_len >= srcp
+ && STRNCMP(src - prefix_len, prefix, prefix_len) == 0) {
at_start = true;
+ }
}
}
*dst = NUL;
@@ -451,17 +456,37 @@ static char *vim_version_dir(const char *vimdir)
return NULL;
}
-/// If the string between "p" and "pend" ends in "name/", return "pend" minus
-/// the length of "name/". Otherwise return "pend".
-static char *remove_tail(char *p, char *pend, char *name)
+/// If `dirname + "/"` precedes `pend` in the path, return the pointer to
+/// `dirname + "/" + pend`. Otherwise return `pend`.
+///
+/// Examples (path = /usr/local/share/nvim/runtime/doc/help.txt):
+///
+/// pend = help.txt
+/// dirname = doc
+/// -> doc/help.txt
+///
+/// pend = doc/help.txt
+/// dirname = runtime
+/// -> runtime/doc/help.txt
+///
+/// pend = runtime/doc/help.txt
+/// dirname = vim74
+/// -> runtime/doc/help.txt
+///
+/// @param path Path to a file
+/// @param pend A suffix of the path
+/// @param dirname The immediate path fragment before the pend
+/// @return The new pend including dirname or just pend
+static char *remove_tail(char *path, char *pend, char *dirname)
{
- size_t len = STRLEN(name) + 1;
- char *newend = pend - len;
+ size_t len = STRLEN(dirname);
+ char *new_tail = pend - len - 1;
- if (newend >= p
- && fnamencmp((char_u *)newend, (char_u *)name, len - 1) == 0
- && (newend == p || after_pathsep(p, newend)))
- return newend;
+ if (new_tail >= path
+ && fnamencmp((char_u *)new_tail, (char_u *)dirname, len) == 0
+ && (new_tail == path || after_pathsep(path, new_tail))) {
+ return new_tail;
+ }
return pend;
}
@@ -745,9 +770,10 @@ void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one)
/// @param src Input file name
char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
{
- size_t len = 3; /* space for "~/" and trailing NUL */
- if (src != NULL) /* just in case */
+ size_t len = 3; // space for "~/" and trailing NUL
+ if (src != NULL) { // just in case
len += STRLEN(src);
+ }
char_u *dst = xmalloc(len);
home_replace(buf, src, dst, (int)len, true);
return dst;
@@ -759,15 +785,15 @@ char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
void vim_setenv(const char *name, const char *val)
{
os_setenv(name, val, 1);
- /*
- * When setting $VIMRUNTIME adjust the directory to find message
- * translations to $VIMRUNTIME/lang.
- */
+#ifndef LOCALE_INSTALL_DIR
+ // When setting $VIMRUNTIME adjust the directory to find message
+ // translations to $VIMRUNTIME/lang.
if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) {
char *buf = (char *)concat_str((char_u *)val, (char_u *)"/lang");
- bindtextdomain(VIMPACKAGE, buf);
+ bindtextdomain(PROJECT_NAME, buf);
xfree(buf);
}
+#endif
}
@@ -783,8 +809,7 @@ char_u *get_env_name(expand_T *xp, int idx)
STRLCPY(name, envname, ENVNAMELEN);
xfree(envname);
return name;
- } else {
- return NULL;
}
+ return NULL;
}
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 2e671653ed..49a74cf0d1 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -2,6 +2,7 @@
#include <stdbool.h>
#include <assert.h>
+#include <fcntl.h>
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
@@ -59,6 +60,23 @@ int os_dirname(char_u *buf, size_t len)
return OK;
}
+/// Check if the given path is a directory and not a symlink to a directory.
+/// @return `true` if `name` is a directory and NOT a symlink to a directory.
+/// `false` if `name` is not a directory or if an error occurred.
+bool os_isrealdir(const char_u *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uv_fs_t request;
+ if (uv_fs_lstat(&fs_loop, &request, (char *)name, NULL) != kLibuvSuccess) {
+ return false;
+ }
+ if (S_ISLNK(request.statbuf.st_mode)) {
+ return false;
+ } else {
+ return S_ISDIR(request.statbuf.st_mode);
+ }
+}
+
/// Check if the given path is a directory or not.
///
/// @return `true` if `fname` is a directory.
@@ -77,10 +95,76 @@ bool os_isdir(const char_u *name)
return true;
}
+/// Check what `name` is:
+/// @return NODE_NORMAL: file or directory (or doesn't exist)
+/// NODE_WRITABLE: writable device, socket, fifo, etc.
+/// NODE_OTHER: non-writable things
+int os_nodetype(const char *name)
+{
+#ifdef WIN32
+ // Edge case from Vim os_win32.c:
+ // We can't open a file with a name "\\.\con" or "\\.\prn", trying to read
+ // from it later will cause Vim to hang. Thus return NODE_WRITABLE here.
+ if (STRNCMP(name, "\\\\.\\", 4) == 0) {
+ return NODE_WRITABLE;
+ }
+#endif
+
+ uv_stat_t statbuf;
+ if (os_stat(name, &statbuf) == 0) {
+ return NODE_NORMAL;
+ }
+
+#ifndef WIN32
+ // libuv does not handle BLK and DIR in uv_handle_type.
+ // Related: https://github.com/joyent/libuv/pull/1421
+ if (S_ISREG(statbuf.st_mode) || S_ISDIR(statbuf.st_mode)) {
+ return NODE_NORMAL;
+ }
+ if (S_ISBLK(statbuf.st_mode)) { // block device isn't writable
+ return NODE_OTHER;
+ }
+#endif
+
+ // Vim os_win32.c:mch_nodetype does this (since patch 7.4.015):
+ // if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) {
+ // wn = enc_to_utf16(name, NULL);
+ // hFile = CreatFile(wn, ...)
+ // to get a HANDLE. But libuv just calls win32's _get_osfhandle() on the fd we
+ // give it. uv_fs_open calls fs__capture_path which does a similar dance and
+ // saves us the hassle.
+
+ int nodetype = NODE_WRITABLE;
+ int fd = os_open(name, O_RDONLY, 0);
+ switch(uv_guess_handle(fd)) {
+ case UV_TTY: // FILE_TYPE_CHAR
+ nodetype = NODE_WRITABLE;
+ break;
+ case UV_FILE: // FILE_TYPE_DISK
+ nodetype = NODE_NORMAL;
+ break;
+ case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c
+ case UV_UDP: // unix only
+ case UV_TCP: // unix only
+ case UV_UNKNOWN_HANDLE:
+ default:
+#ifdef WIN32
+ nodetype = NODE_NORMAL;
+#else
+ nodetype = NODE_WRITABLE; // Everything else is writable?
+#endif
+ break;
+ }
+
+ close(fd);
+ return nodetype;
+}
+
/// Checks if the given path represents an executable file.
///
-/// @param[in] name The name of the executable.
+/// @param[in] name Name of the executable.
/// @param[out] abspath Path of the executable, if found and not `NULL`.
+/// @param[in] use_path If 'false', only check if "name" is executable
///
/// @return `true` if `name` is executable and
/// - can be found in $PATH,
@@ -88,14 +172,18 @@ bool os_isdir(const char_u *name)
/// - is absolute.
///
/// @return `false` otherwise.
-bool os_can_exe(const char_u *name, char_u **abspath)
+bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
FUNC_ATTR_NONNULL_ARG(1)
{
- // If it's an absolute or relative path don't need to use $PATH.
- if (path_is_absolute_path(name) ||
- (name[0] == '.' && (name[1] == '/' ||
- (name[1] == '.' && name[2] == '/')))) {
- if (is_executable(name)) {
+ // when use_path is false or if it's an absolute or relative path don't
+ // need to use $PATH.
+ if (!use_path || path_is_absolute_path(name)
+ || (name[0] == '.'
+ && (name[1] == '/'
+ || (name[1] == '.' && name[2] == '/')))) {
+ // There must be a path separator, files in the current directory
+ // can't be executed
+ if (gettail_dir(name) != name && is_executable(name)) {
if (abspath != NULL) {
*abspath = save_absolute_path(name);
}
@@ -166,7 +254,7 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
// Glue together the given directory from $PATH with name and save into
// buf.
STRLCPY(buf, path, e - path + 1);
- append_path((char *) buf, (const char *) name, (int)buf_len);
+ append_path((char *) buf, (const char *) name, buf_len);
if (is_executable(buf)) {
// Check if the caller asked for a copy of the path.
diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h
index 52b2841514..0bd9c37750 100644
--- a/src/nvim/os/fs_defs.h
+++ b/src/nvim/os/fs_defs.h
@@ -26,4 +26,10 @@ typedef struct {
/// negative libuv error codes are returned by a number of os functions.
#define os_strerror uv_strerror
+// Values returned by os_nodetype()
+#define NODE_NORMAL 0 // file or directory, check with os_isdir()
+#define NODE_WRITABLE 1 // something we can write to (character
+ // device, fifo, socket, ..)
+#define NODE_OTHER 2 // non-writable thing (e.g., block device)
+
#endif // NVIM_OS_FS_DEFS_H
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index f317fd6b5a..7687b14f02 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -175,8 +175,9 @@ size_t input_enqueue(String keys)
char *ptr = keys.data, *end = ptr + keys.size;
while (rbuffer_space(input_buffer) >= 6 && ptr < end) {
- uint8_t buf[6] = {0};
- unsigned int new_size = trans_special((uint8_t **)&ptr, buf, true);
+ uint8_t buf[6] = { 0 };
+ unsigned int new_size = trans_special((const uint8_t **)&ptr, keys.size,
+ buf, true);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
@@ -402,9 +403,9 @@ static int push_event_key(uint8_t *buf, int maxlen)
// Check if there's pending input
static bool input_ready(void)
{
- return typebuf_was_filled || // API call filled typeahead
- rbuffer_size(input_buffer) || // Input buffer filled
- pending_events(); // Events must be processed
+ return (typebuf_was_filled // API call filled typeahead
+ || rbuffer_size(input_buffer) // Input buffer filled
+ || pending_events()); // Events must be processed
}
// Exit because of an input read error.
diff --git a/src/nvim/os/mem.c b/src/nvim/os/mem.c
index 5e483c0c3d..871ece7a0e 100644
--- a/src/nvim/os/mem.c
+++ b/src/nvim/os/mem.c
@@ -8,5 +8,5 @@
uint64_t os_get_total_mem_kib(void)
{
// Convert bytes to KiB.
- return uv_get_total_memory() >> 10;
+ return uv_get_total_memory() / 1024;
}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index c9631a434c..81ceb919c4 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -22,9 +22,9 @@ static const char *xdg_env_vars[] = {
static const char *const xdg_defaults[] = {
#ifdef WIN32
// Windows
- [kXDGConfigHome] = "$LOCALAPPDATA\\nvim\\config",
- [kXDGDataHome] = "$LOCALAPPDATA\\nvim\\data",
- [kXDGCacheHome] = "$LOCALAPPDATA\\nvim\\cache",
+ [kXDGConfigHome] = "$LOCALAPPDATA",
+ [kXDGDataHome] = "$LOCALAPPDATA",
+ [kXDGCacheHome] = "$TEMP",
[kXDGRuntimeDir] = NULL,
[kXDGConfigDirs] = NULL,
[kXDGDataDirs] = NULL,
@@ -66,12 +66,21 @@ char *stdpaths_get_xdg_var(const XDGVarType idx)
/// @param[in] idx XDG directory to use.
///
/// @return [allocated] `{xdg_directory}/nvim`
+///
+/// In WIN32 get_xdg_home(kXDGDataHome) returns `{xdg_directory}/nvim-data` to
+/// avoid storing configuration and data files in the same path.
static char *get_xdg_home(const XDGVarType idx)
FUNC_ATTR_WARN_UNUSED_RESULT
{
char *dir = stdpaths_get_xdg_var(idx);
if (dir) {
+#if defined(WIN32)
+ dir = concat_fnames_realloc(dir,
+ (idx == kXDGDataHome ? "nvim-data" : "nvim"),
+ true);
+#else
dir = concat_fnames_realloc(dir, "nvim", true);
+#endif
}
return dir;
}
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index 242d355f77..6a29f86e79 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -1,6 +1,9 @@
#ifndef NVIM_OS_WIN_DEFS_H
#define NVIM_OS_WIN_DEFS_H
+// winsock2.h must be first to avoid incompatibilities
+// with winsock.h (included by windows.h)
+#include <winsock2.h>
#include <windows.h>
#include <sys/stat.h>
#include <io.h>
@@ -43,6 +46,8 @@
# endif
#endif
+#define BACKSLASH_IN_FILENAME
+
#ifdef _MSC_VER
typedef SSIZE_T ssize_t;
#endif
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index cb9a58cc77..2ed0c2c856 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -34,7 +34,6 @@
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/tempfile.h"
#include "nvim/ui.h"
#include "nvim/types.h"
#include "nvim/os/os.h"
@@ -137,26 +136,6 @@ void mch_free_acl(vim_acl_T aclent)
}
#endif
-/*
- * Check what "name" is:
- * NODE_NORMAL: file or directory (or doesn't exist)
- * NODE_WRITABLE: writable device, socket, fifo, etc.
- * NODE_OTHER: non-writable things
- */
-int mch_nodetype(char_u *name)
-{
- struct stat st;
-
- if (stat((char *)name, &st))
- return NODE_NORMAL;
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
- return NODE_NORMAL;
- if (S_ISBLK(st.st_mode)) /* block device isn't writable */
- return NODE_OTHER;
- /* Everything else is writable? */
- return NODE_WRITABLE;
-}
-
void mch_exit(int r)
{
exiting = true;
@@ -597,9 +576,11 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
continue;
- /* Skip files that are not executable if we check for that. */
- if (!dir && (flags & EW_EXEC) && !os_can_exe((*file)[i], NULL))
+ // Skip files that are not executable if we check for that.
+ if (!dir && (flags & EW_EXEC)
+ && !os_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD))) {
continue;
+ }
p = xmalloc(STRLEN((*file)[i]) + 1 + dir);
STRCPY(p, (*file)[i]);
diff --git a/src/nvim/os_unix.h b/src/nvim/os_unix.h
index 5a3eb84ba4..d627b16ec0 100644
--- a/src/nvim/os_unix.h
+++ b/src/nvim/os_unix.h
@@ -4,12 +4,6 @@
#include "nvim/types.h" // for vim_acl_T
#include "nvim/os/shell.h"
-/* Values returned by mch_nodetype() */
-#define NODE_NORMAL 0 /* file or directory, check with os_isdir()*/
-#define NODE_WRITABLE 1 /* something we can write to (character
- device, fifo, socket, ..) */
-#define NODE_OTHER 2 /* non-writable thing (e.g., block device) */
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os_unix.h.generated.h"
#endif
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 5cd93ab811..41fd69f238 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -268,16 +268,13 @@ char_u *shorten_dir(char_u *str)
*/
bool dir_of_file_exists(char_u *fname)
{
- char_u *p;
- int c;
- bool retval;
-
- p = path_tail_with_sep(fname);
- if (p == fname)
+ char_u *p = path_tail_with_sep(fname);
+ if (p == fname) {
return true;
- c = *p;
+ }
+ char_u c = *p;
*p = NUL;
- retval = os_isdir(fname);
+ bool retval = os_isdir(fname);
*p = c;
return retval;
}
@@ -539,15 +536,10 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
size_t wildoff, int flags, bool didstar)
FUNC_ATTR_NONNULL_ALL
{
- char_u *buf;
- char_u *p, *s, *e;
int start_len = gap->ga_len;
- char_u *pat;
- int starts_with_dot;
- int matches;
- int len;
+ size_t len;
bool starstar = false;
- static int stardepth = 0; /* depth for "**" expansion */
+ static int stardepth = 0; // depth for "**" expansion
/* Expanding "**" may take a long time, check for CTRL-C. */
if (stardepth > 0) {
@@ -558,16 +550,14 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
// Make room for file name. When doing encoding conversion the actual
// length may be quite a bit longer, thus use the maximum possible length.
- buf = xmalloc(MAXPATHL);
-
- /*
- * Find the first part in the path name that contains a wildcard.
- * When EW_ICASE is set every letter is considered to be a wildcard.
- * Copy it into "buf", including the preceding characters.
- */
- p = buf;
- s = buf;
- e = NULL;
+ char_u *buf = xmalloc(MAXPATHL);
+
+ // Find the first part in the path name that contains a wildcard.
+ // When EW_ICASE is set every letter is considered to be a wildcard.
+ // Copy it into "buf", including the preceding characters.
+ char_u *p = buf;
+ char_u *s = buf;
+ char_u *e = NULL;
const char_u *path_end = path;
while (*path_end != NUL) {
/* May ignore a wildcard that has a backslash before it; it will
@@ -588,7 +578,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
e = p;
}
if (has_mbyte) {
- len = (*mb_ptr2len)(path_end);
+ len = (size_t)(*mb_ptr2len)(path_end);
STRNCPY(p, path_end, len);
p += len;
path_end += len;
@@ -613,9 +603,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
if (p[0] == '*' && p[1] == '*')
starstar = true;
- /* convert the file pattern to a regexp pattern */
- starts_with_dot = (*s == '.');
- pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
+ // convert the file pattern to a regexp pattern
+ int starts_with_dot = *s == '.';
+ char_u *pat = file_pat_to_reg_pat(s, e, NULL, false);
if (pat == NULL) {
xfree(buf);
return 0;
@@ -646,9 +636,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
if (!didstar && stardepth < 100 && starstar && e - s == 2
&& *path_end == '/') {
STRCPY(s, path_end + 1);
- ++stardepth;
- (void)do_path_expand(gap, buf, (int)(s - buf), flags, true);
- --stardepth;
+ stardepth++;
+ (void)do_path_expand(gap, buf, (size_t)(s - buf), flags, true);
+ stardepth--;
}
*s = NUL;
@@ -657,9 +647,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
if (os_file_is_readable(dirpath) && os_scandir(&dir, dirpath)) {
// Find all matching entries.
char_u *name;
- scandir_next_with_dots(NULL /* initialize */);
- while((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) {
- if ((name[0] != '.' || starts_with_dot)
+ scandir_next_with_dots(NULL); // initialize
+ while ((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) {
+ if ((name[0] != '.'
+ || starts_with_dot
+ || ((flags & EW_DODOT)
+ && name[1] != NUL && (name[1] != '.' || name[2] != NUL)))
&& ((regmatch.regprog != NULL && vim_regexec(&regmatch, name, 0))
|| ((flags & EW_NOTWILD)
&& fnamencmp(path + (s - buf), name, e - s) == 0))) {
@@ -703,10 +696,11 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
xfree(buf);
vim_regfree(regmatch.regprog);
- matches = gap->ga_len - start_len;
- if (matches > 0)
+ size_t matches = (size_t)(gap->ga_len - start_len);
+ if (matches > 0) {
qsort(((char_u **)gap->ga_data) + start_len, matches,
- sizeof(char_u *), pstrcmp);
+ sizeof(char_u *), pstrcmp);
+ }
return matches;
}
@@ -736,27 +730,24 @@ static int find_previous_pathsep(char_u *path, char_u **psep)
*/
static bool is_unique(char_u *maybe_unique, garray_T *gap, int i)
{
- int candidate_len;
- int other_path_len;
- char_u **other_paths = (char_u **)gap->ga_data;
- char_u *rival;
+ char_u **other_paths = (char_u **)gap->ga_data;
for (int j = 0; j < gap->ga_len; j++) {
- if (j == i)
- continue; /* don't compare it with itself */
-
- candidate_len = (int)STRLEN(maybe_unique);
- other_path_len = (int)STRLEN(other_paths[j]);
- if (other_path_len < candidate_len)
- continue; /* it's different when it's shorter */
-
- rival = other_paths[j] + other_path_len - candidate_len;
+ if (j == i) {
+ continue; // don't compare it with itself
+ }
+ size_t candidate_len = STRLEN(maybe_unique);
+ size_t other_path_len = STRLEN(other_paths[j]);
+ if (other_path_len < candidate_len) {
+ continue; // it's different when it's shorter
+ }
+ char_u *rival = other_paths[j] + other_path_len - candidate_len;
if (fnamecmp(maybe_unique, rival) == 0
- && (rival == other_paths[j] || vim_ispathsep(*(rival - 1))))
- return false; /* match */
+ && (rival == other_paths[j] || vim_ispathsep(*(rival - 1)))) {
+ return false; // match
+ }
}
-
- return true; /* no match found */
+ return true; // no match found
}
/*
@@ -770,12 +761,8 @@ static bool is_unique(char_u *maybe_unique, garray_T *gap, int i)
*/
static void expand_path_option(char_u *curdir, garray_T *gap)
{
- char_u *path_option = *curbuf->b_p_path == NUL
- ? p_path : curbuf->b_p_path;
- char_u *buf;
- int len;
-
- buf = xmalloc(MAXPATHL);
+ char_u *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
+ char_u *buf = xmalloc(MAXPATHL);
while (*path_option != NUL) {
copy_option_part(&path_option, buf, MAXPATHL, " ,");
@@ -787,26 +774,27 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
if (curbuf->b_ffname == NULL)
continue;
char_u *p = path_tail(curbuf->b_ffname);
- len = (int)(p - curbuf->b_ffname);
- if (len + (int)STRLEN(buf) >= MAXPATHL)
+ size_t len = (size_t)(p - curbuf->b_ffname);
+ if (len + STRLEN(buf) >= MAXPATHL) {
continue;
- if (buf[1] == NUL)
+ }
+ if (buf[1] == NUL) {
buf[len] = NUL;
- else
+ } else {
STRMOVE(buf + len, buf + 2);
+ }
memmove(buf, curbuf->b_ffname, len);
simplify_filename(buf);
- } else if (buf[0] == NUL)
- /* relative to current directory */
- STRCPY(buf, curdir);
- else if (path_with_url((char *)buf))
- /* URL can't be used here */
- continue;
- else if (!path_is_absolute_path(buf)) {
- /* Expand relative path to their full path equivalent */
- len = (int)STRLEN(curdir);
- if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
+ } else if (buf[0] == NUL) {
+ STRCPY(buf, curdir); // relative to current directory
+ } else if (path_with_url((char *)buf)) {
+ continue; // URL can't be used here
+ } else if (!path_is_absolute_path(buf)) {
+ // Expand relative path to their full path equivalent
+ size_t len = STRLEN(curdir);
+ if (len + STRLEN(buf) + 3 > MAXPATHL) {
continue;
+ }
STRMOVE(buf + len + 1, buf);
STRCPY(buf, curdir);
buf[len] = PATHSEP;
@@ -860,31 +848,25 @@ static char_u *get_path_cutoff(char_u *fname, garray_T *gap)
*/
static void uniquefy_paths(garray_T *gap, char_u *pattern)
{
- int len;
- char_u **fnames = (char_u **)gap->ga_data;
+ char_u **fnames = (char_u **)gap->ga_data;
bool sort_again = false;
- char_u *pat;
- char_u *file_pattern;
- char_u *curdir;
regmatch_T regmatch;
garray_T path_ga;
- char_u **in_curdir = NULL;
- char_u *short_name;
+ char_u **in_curdir = NULL;
+ char_u *short_name;
ga_remove_duplicate_strings(gap);
ga_init(&path_ga, (int)sizeof(char_u *), 1);
- /*
- * We need to prepend a '*' at the beginning of file_pattern so that the
- * regex matches anywhere in the path. FIXME: is this valid for all
- * possible patterns?
- */
- len = (int)STRLEN(pattern);
- file_pattern = xmalloc(len + 2);
+ // We need to prepend a '*' at the beginning of file_pattern so that the
+ // regex matches anywhere in the path. FIXME: is this valid for all
+ // possible patterns?
+ size_t len = STRLEN(pattern);
+ char_u *file_pattern = xmalloc(len + 2);
file_pattern[0] = '*';
file_pattern[1] = NUL;
STRCAT(file_pattern, pattern);
- pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
+ char_u *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true);
xfree(file_pattern);
if (pat == NULL)
return;
@@ -895,11 +877,11 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
if (regmatch.regprog == NULL)
return;
- curdir = xmalloc(MAXPATHL);
+ char_u *curdir = xmalloc(MAXPATHL);
os_dirname(curdir, MAXPATHL);
expand_path_option(curdir, &path_ga);
- in_curdir = xcalloc(gap->ga_len, sizeof(char_u *));
+ in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char_u *));
for (int i = 0; i < gap->ga_len && !got_int; i++) {
char_u *path = fnames[i];
@@ -908,7 +890,7 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
char_u *pathsep_p;
char_u *path_cutoff;
- len = (int)STRLEN(path);
+ len = STRLEN(path);
is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
&& curdir[dir_end - path] == NUL;
if (is_in_curdir)
@@ -999,12 +981,12 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
* "/path/file", "/path/dir/", "/path//dir", "/file"
* ^ ^ ^ ^
*/
-static char_u *gettail_dir(char_u *fname)
+char_u *gettail_dir(const char_u *fname)
{
- char_u *dir_end = fname;
- char_u *next_dir_end = fname;
+ const char_u *dir_end = fname;
+ const char_u *next_dir_end = fname;
bool look_for_sep = true;
- char_u *p;
+ const char_u *p;
for (p = fname; *p != NUL; ) {
if (vim_ispathsep(*p)) {
@@ -1019,7 +1001,7 @@ static char_u *gettail_dir(char_u *fname)
}
mb_ptr_adv(p);
}
- return dir_end;
+ return (char_u *)dir_end;
}
@@ -1113,9 +1095,8 @@ static bool has_special_wildchar(char_u *p)
int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
char_u ***file, int flags)
{
- int i;
garray_T ga;
- char_u *p;
+ char_u *p;
static bool recursive = false;
int add_pat;
bool did_expand_in_path = false;
@@ -1140,11 +1121,11 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
* avoids starting the shell for each argument separately.
* For `=expr` do use the internal function.
*/
- for (i = 0; i < num_pat; i++) {
+ for (int i = 0; i < num_pat; i++) {
if (has_special_wildchar(pat[i])
- && !(vim_backtick(pat[i]) && pat[i][1] == '=')
- )
+ && !(vim_backtick(pat[i]) && pat[i][1] == '=')) {
return mch_expand_wildcards(num_pat, pat, num_file, file, flags);
+ }
}
#endif
@@ -1155,7 +1136,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
*/
ga_init(&ga, (int)sizeof(char_u *), 30);
- for (i = 0; i < num_pat; ++i) {
+ for (int i = 0; i < num_pat; ++i) {
add_pat = -1;
p = pat[i];
@@ -1212,7 +1193,9 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
recursive = true;
did_expand_in_path = true;
} else {
- add_pat = path_expand(&ga, p, flags);
+ size_t tmp_add_pat = path_expand(&ga, p, flags);
+ assert(tmp_add_pat <= INT_MAX);
+ add_pat = (int)tmp_add_pat;
}
}
}
@@ -1240,7 +1223,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
recursive = false;
- return (ga.ga_data != NULL) ? OK : FAIL;
+ return ((flags & EW_EMPTYOK) || ga.ga_data != NULL) ? OK : FAIL;
}
@@ -1261,14 +1244,12 @@ static int expand_backtick(
int flags /* EW_* flags */
)
{
- char_u *p;
- char_u *cmd;
- char_u *buffer;
+ char_u *p;
+ char_u *buffer;
int cnt = 0;
- int i;
- /* Create the command: lop off the backticks. */
- cmd = vim_strnsave(pat + 1, (int)STRLEN(pat) - 2);
+ // Create the command: lop off the backticks.
+ char_u *cmd = vim_strnsave(pat + 1, STRLEN(pat) - 2);
if (*cmd == '=') /* `={expr}`: Expand expression */
buffer = eval_to_string(cmd + 1, &p, TRUE);
@@ -1288,7 +1269,7 @@ static int expand_backtick(
++p;
/* add an entry if it is not empty */
if (p > cmd) {
- i = *p;
+ char_u i = *p;
*p = NUL;
addfile(gap, cmd, flags);
*p = i;
@@ -1303,6 +1284,29 @@ static int expand_backtick(
return cnt;
}
+#ifdef BACKSLASH_IN_FILENAME
+/// Replace all slashes by backslashes.
+/// This used to be the other way around, but MS-DOS sometimes has problems
+/// with slashes (e.g. in a command name). We can't have mixed slashes and
+/// backslashes, because comparing file names will not work correctly. The
+/// commands that use a file name should try to avoid the need to type a
+/// backslash twice.
+/// When 'shellslash' set do it the other way around.
+/// When the path looks like a URL leave it unmodified.
+void slash_adjust(char_u *p)
+{
+ if (path_with_url(p)) {
+ return;
+ }
+ while (*p) {
+ if (*p == psepcN) {
+ *p = psepc;
+ }
+ mb_ptr_adv(p);
+ }
+}
+#endif
+
// Add a file to a file list. Accepted flags:
// EW_DIR add directories
// EW_FILE add files
@@ -1320,9 +1324,10 @@ void addfile(
FileInfo file_info;
// if the file/dir/link doesn't exist, may not add it
- if (!(flags & EW_NOTFOUND) &&
- ((flags & EW_ALLLINKS) ?
- !os_fileinfo_link((char *)f, &file_info) : !os_file_exists(f))) {
+ if (!(flags & EW_NOTFOUND)
+ && ((flags & EW_ALLLINKS)
+ ? !os_fileinfo_link((char *)f, &file_info)
+ : !os_file_exists(f))) {
return;
}
@@ -1336,9 +1341,12 @@ void addfile(
if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE)))
return;
- /* If the file isn't executable, may not add it. Do accept directories. */
- if (!isdir && (flags & EW_EXEC) && !os_can_exe(f, NULL))
+ // If the file isn't executable, may not add it. Do accept directories.
+ // When invoked from expand_shellcmd() do not use $PATH.
+ if (!isdir && (flags & EW_EXEC)
+ && !os_can_exe(f, NULL, !(flags & EW_SHELLCMD))) {
return;
+ }
char_u *p = xmalloc(STRLEN(f) + 1 + isdir);
@@ -1402,9 +1410,9 @@ void simplify_filename(char_u *filename)
--p; /* strip preceding path separator */
STRMOVE(p, tail);
}
- } else if (p[0] == '.' && p[1] == '.' &&
- (vim_ispathsep(p[2]) || p[2] == NUL)) {
- /* Skip to after ".." or "../" or "..///". */
+ } else if (p[0] == '.' && p[1] == '.'
+ && (vim_ispathsep(p[2]) || p[2] == NUL)) {
+ // Skip to after ".." or "../" or "..///".
tail = p + 2;
while (vim_ispathsep(*tail))
mb_ptr_adv(tail);
@@ -1517,13 +1525,12 @@ void simplify_filename(char_u *filename)
} while (*p != NUL);
}
-static char_u *eval_includeexpr(char_u *ptr, size_t len)
+static char *eval_includeexpr(const char *const ptr, const size_t len)
{
- assert(len <= INT_MAX);
- set_vim_var_string(VV_FNAME, ptr, (int)len);
- char_u *res = eval_to_string_safe(curbuf->b_p_inex, NULL,
- was_set_insecurely((char_u *)"includeexpr",
- OPT_LOCAL));
+ set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t) len);
+ char *res = (char *) eval_to_string_safe(
+ curbuf->b_p_inex, NULL, was_set_insecurely((char_u *)"includeexpr",
+ OPT_LOCAL));
set_vim_var_string(VV_FNAME, NULL, 0);
return res;
}
@@ -1541,12 +1548,11 @@ find_file_name_in_path (
char_u *rel_fname /* file we are searching relative to */
)
{
- char_u *file_name;
- int c;
- char_u *tofree = NULL;
+ char_u *file_name;
+ char_u *tofree = NULL;
if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = eval_includeexpr(ptr, len);
+ tofree = (char_u *) eval_includeexpr((char *) ptr, len);
if (tofree != NULL) {
ptr = tofree;
len = STRLEN(ptr);
@@ -1554,8 +1560,8 @@ find_file_name_in_path (
}
if (options & FNAME_EXP) {
- file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS,
- TRUE, rel_fname);
+ file_name = find_file_in_path(ptr, len, options & ~FNAME_MESS, true,
+ rel_fname);
/*
* If the file could not be found in a normal way, try applying
@@ -1563,7 +1569,7 @@ find_file_name_in_path (
*/
if (file_name == NULL
&& !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = eval_includeexpr(ptr, len);
+ tofree = (char_u *) eval_includeexpr((char *) ptr, len);
if (tofree != NULL) {
ptr = tofree;
len = STRLEN(ptr);
@@ -1572,7 +1578,7 @@ find_file_name_in_path (
}
}
if (file_name == NULL && (options & FNAME_MESS)) {
- c = ptr[len];
+ char_u c = ptr[len];
ptr[len] = NUL;
EMSG2(_("E447: Can't find file \"%s\" in path"), ptr);
ptr[len] = c;
@@ -1631,7 +1637,7 @@ bool vim_isAbsName(char_u *name)
/// @param force is a flag to force expanding even if the path is absolute
///
/// @return FAIL for failure, OK otherwise
-int vim_FullName(const char *fname, char *buf, int len, bool force)
+int vim_FullName(const char *fname, char *buf, size_t len, bool force)
FUNC_ATTR_NONNULL_ARG(2)
{
int retval = OK;
@@ -1947,7 +1953,7 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file,
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set to
/// NULL or points to "".
-int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file,
+int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files,
int flags)
{
int retval;
@@ -1955,7 +1961,7 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file,
char_u *p;
int non_suf_match; /* number without matching suffix */
- retval = gen_expand_wildcards(num_pat, pat, num_file, file, flags);
+ retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
/* When keeping all matches, return here */
if ((flags & EW_KEEPALL) || retval == FAIL)
@@ -1967,18 +1973,20 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file,
if (*p_wig) {
char_u *ffname;
- /* check all files in (*file)[] */
- for (i = 0; i < *num_file; ++i) {
- ffname = (char_u *)FullName_save((char *)(*file)[i], FALSE);
- if (ffname == NULL) /* out of memory */
+ // check all filess in (*files)[]
+ for (i = 0; i < *num_files; i++) {
+ ffname = (char_u *)FullName_save((char *)(*files)[i], false);
+ if (ffname == NULL) { // out of memory
break;
- if (match_file_list(p_wig, (*file)[i], ffname)) {
- /* remove this matching file from the list */
- xfree((*file)[i]);
- for (j = i; j + 1 < *num_file; ++j)
- (*file)[j] = (*file)[j + 1];
- --*num_file;
- --i;
+ }
+ if (match_file_list(p_wig, (*files)[i], ffname)) {
+ // remove this matching files from the list
+ xfree((*files)[i]);
+ for (j = i; j + 1 < *num_files; j++) {
+ (*files)[j] = (*files)[j + 1];
+ }
+ (*num_files)--;
+ i--;
}
xfree(ffname);
}
@@ -1987,26 +1995,28 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file,
/*
* Move the names where 'suffixes' match to the end.
*/
- if (*num_file > 1) {
+ if (*num_files > 1) {
non_suf_match = 0;
- for (i = 0; i < *num_file; ++i) {
- if (!match_suffix((*file)[i])) {
- /*
- * Move the name without matching suffix to the front
- * of the list.
- */
- p = (*file)[i];
- for (j = i; j > non_suf_match; --j)
- (*file)[j] = (*file)[j - 1];
- (*file)[non_suf_match++] = p;
+ for (i = 0; i < *num_files; i++) {
+ if (!match_suffix((*files)[i])) {
+ //
+ // Move the name without matching suffix to the front
+ // of the list.
+ //
+ p = (*files)[i];
+ for (j = i; j > non_suf_match; j--) {
+ (*files)[j] = (*files)[j - 1];
+ }
+ (*files)[non_suf_match++] = p;
}
}
}
// Free empty array of matches
- if (*num_file == 0) {
- xfree(*file);
- *file = NULL;
+ if (*num_files == 0) {
+ xfree(*files);
+ *files = NULL;
+ return FAIL;
}
return retval;
@@ -2017,14 +2027,12 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file,
*/
int match_suffix(char_u *fname)
{
- int fnamelen, setsuflen;
- char_u *setsuf;
-#define MAXSUFLEN 30 /* maximum length of a file suffix */
+#define MAXSUFLEN 30 // maximum length of a file suffix
char_u suf_buf[MAXSUFLEN];
- fnamelen = (int)STRLEN(fname);
- setsuflen = 0;
- for (setsuf = p_su; *setsuf; ) {
+ size_t fnamelen = STRLEN(fname);
+ size_t setsuflen = 0;
+ for (char_u *setsuf = p_su; *setsuf; ) {
setsuflen = copy_option_part(&setsuf, suf_buf, MAXSUFLEN, ".,");
if (setsuflen == 0) {
char_u *tail = path_tail(fname);
@@ -2036,9 +2044,9 @@ int match_suffix(char_u *fname)
}
} else {
if (fnamelen >= setsuflen
- && fnamencmp(suf_buf, fname + fnamelen - setsuflen,
- (size_t)setsuflen) == 0)
+ && fnamencmp(suf_buf, fname + fnamelen - setsuflen, setsuflen) == 0) {
break;
+ }
setsuflen = 0;
}
}
@@ -2049,7 +2057,7 @@ int match_suffix(char_u *fname)
///
/// @param directory Directory name, relative to current directory.
/// @return `FAIL` for failure, `OK` for success.
-int path_full_dir_name(char *directory, char *buffer, int len)
+int path_full_dir_name(char *directory, char *buffer, size_t len)
{
int SUCCESS = 0;
int retval = OK;
@@ -2091,10 +2099,10 @@ int path_full_dir_name(char *directory, char *buffer, int len)
// Append to_append to path with a slash in between.
// Append to_append to path with a slash in between.
-int append_path(char *path, const char *to_append, int max_len)
+int append_path(char *path, const char *to_append, size_t max_len)
{
- int current_length = STRLEN(path);
- int to_append_length = STRLEN(to_append);
+ size_t current_length = strlen(path);
+ size_t to_append_length = strlen(to_append);
// Do not append empty strings.
if (to_append_length == 0) {
@@ -2129,12 +2137,14 @@ int append_path(char *path, const char *to_append, int max_len)
/// Expand a given file to its absolute path.
///
-/// @param fname The filename which should be expanded.
-/// @param buf Buffer to store the absolute path of `fname`.
-/// @param len Length of `buf`.
-/// @param force Also expand when `fname` is already absolute.
-/// @return `FAIL` for failure, `OK` for success.
-static int path_get_absolute_path(const char_u *fname, char_u *buf, int len, int force)
+/// @param fname filename which should be expanded.
+/// @param buf buffer to store the absolute path of "fname".
+/// @param len length of "buf".
+/// @param force also expand when "fname" is already absolute.
+///
+/// @return FAIL for failure, OK for success.
+static int path_get_absolute_path(const char_u *fname, char_u *buf,
+ size_t len, int force)
{
char_u *p;
*buf = NUL;
diff --git a/src/nvim/path.h b/src/nvim/path.h
index eac367d0ac..4e466d1b71 100644
--- a/src/nvim/path.h
+++ b/src/nvim/path.h
@@ -21,6 +21,10 @@
/* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND
* is used when executing commands and EW_SILENT for interactive expanding. */
#define EW_ALLLINKS 0x1000 // also links not pointing to existing file
+#define EW_SHELLCMD 0x2000 // called from expand_shellcmd(), don't check
+ // if executable is in $PATH
+#define EW_DODOT 0x4000 // also files starting with a dot
+#define EW_EMPTYOK 0x8000 // no matches is not an error
/// Return value for the comparison of two files. Also @see path_full_compare.
typedef enum file_comparison {
diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt
index d1e08db65e..184c4894b9 100644
--- a/src/nvim/po/CMakeLists.txt
+++ b/src/nvim/po/CMakeLists.txt
@@ -72,8 +72,8 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG)
install_helper(
FILES ${moFile}
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/nvim/runtime/lang/${name}/LC_MESSAGES
- RENAME nvim.mo)
+ DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${name}/LC_MESSAGES
+ RENAME ${PROJECT_NAME}.mo)
list(APPEND LANGUAGE_MO_FILES ${moFile})
endmacro()
diff --git a/src/nvim/po/eo.po b/src/nvim/po/eo.po
index 8215b31e65..5b0cb2260b 100644
--- a/src/nvim/po/eo.po
+++ b/src/nvim/po/eo.po
@@ -23,8 +23,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim(Esperanto)\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-05-27 04:55+0200\n"
+"POT-Creation-Date: 2015-07-30 17:54+0200\n"
+"PO-Revision-Date: 2015-07-30 18:00+0200\n"
"Last-Translator: Dominique PELLÉ <dominique.pelle@gmail.com>\n"
"Language-Team: \n"
"Language: eo\n"
@@ -115,11 +115,6 @@ msgstr "E84: Neniu modifita bufro trovita"
msgid "E85: There is no listed buffer"
msgstr "E85: Estas neniu listigita bufro"
-#: ../buffer.c:913
-#, c-format
-msgid "E86: Buffer %<PRId64> does not exist"
-msgstr "E86: La bufro %<PRId64> ne ekzistas"
-
#: ../buffer.c:915
msgid "E87: Cannot go beyond last buffer"
msgstr "E87: Ne eblas iri preter la lastan bufron"
@@ -692,6 +687,10 @@ msgstr "E696: Mankas komo en Listo: %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: Mankas fino de Listo ']': %s"
+#: ../eval.c:5750
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Ne sufiĉa memory por valorigi referencojn, senrubigado ĉesigita!"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -1616,14 +1615,13 @@ msgstr "E173: %<PRId64> pliaj redaktendaj dosieroj"
msgid "E174: Command already exists: add ! to replace it"
msgstr "E174: La komando jam ekzistas: aldonu ! por anstataÅ­igi Äin"
-# DP: malfacilas traduki tion, kaj samtempe honori spacetojn
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" Nomo Arg Interv Kompleto Difino"
+" Nomo Argumentoj Adreso Kompleto Difino"
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
@@ -1649,6 +1647,10 @@ msgstr "E178: Nevalida defaÅ­lta valoro de kvantoro"
msgid "E179: argument required for -complete"
msgstr "E179: argumento bezonata por -complete"
+#: ../ex_docmd.c:4933
+msgid "E179: argument required for -addr"
+msgstr "E179: argumento bezonata por -addr"
+
#: ../ex_docmd.c:4635
#, c-format
msgid "E181: Invalid attribute: %s"
@@ -1671,6 +1673,11 @@ msgstr "E841: Rezervita nomo, neuzebla por komando difinita de uzanto"
msgid "E184: No such user-defined command: %s"
msgstr "E184: Neniu komando-difinita-de-uzanto kiel: %s"
+#: ../ex_docmd.c:5516
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Nevalida valoro de tipo de adreso: %s"
+
#: ../ex_docmd.c:5219
#, c-format
msgid "E180: Invalid complete value: %s"
@@ -2951,6 +2958,11 @@ msgstr "E363: Åablono uzas pli da memoro ol 'maxmempattern'"
msgid "E749: empty buffer"
msgstr "E749: malplena bufro"
+#: ../globals.h:1226
+#, c-format
+msgid "E86: Buffer %<PRId64> does not exist"
+msgstr "E86: La bufro %<PRId64> ne ekzistas"
+
#: ../globals.h:1108
msgid "E682: Invalid search pattern or delimiter"
msgstr "E682: Nevalida serĉa Åablono aÅ­ disigilo"
@@ -4599,6 +4611,11 @@ msgstr "E522: Netrovita en termcap"
msgid "E539: Illegal character <%s>"
msgstr "E539: Nevalida signo <%s>"
+#: ../option.c:2253
+#, c-format
+msgid "For option %s"
+msgstr "Por opcio %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: Ne eblas agordi 'term' al malplena ĉeno"
@@ -6552,15 +6569,15 @@ msgstr "E446: Neniu dosiernomo sub la kursoro"
#~ msgid "Reading from stdin..."
#~ msgstr "Legado el stdin..."
-#~ msgid "[blowfish]"
-#~ msgstr "[blowfish]"
-
#~ msgid "[crypted]"
#~ msgstr "[ĉifrita]"
#~ msgid "E821: File is encrypted with unknown method"
#~ msgstr "E821: Dosiero estas ĉifrata per nekonata metodo"
+#~ msgid "Warning: Using a weak encryption method; see :help 'cm'"
+#~ msgstr "Averto: uzo de malfortika ĉifrada metodo; vidu :help 'cm'"
+
#~ msgid "NetBeans disallows writes of unmodified buffers"
#~ msgstr "NetBeans malpermesas skribojn de neÅanÄitaj bufroj"
@@ -6676,8 +6693,8 @@ msgstr "E446: Neniu dosiernomo sub la kursoro"
#~ msgid "Vim: Received \"die\" request from session manager\n"
#~ msgstr "Vim: Ricevis peton \"die\" (morti) el la seanca administrilo\n"
-#~ msgid "Close"
-#~ msgstr "Fermi"
+#~ msgid "Close tab"
+#~ msgstr "Fermi langeton"
#~ msgid "New tab"
#~ msgstr "Nova langeto"
@@ -6733,9 +6750,6 @@ msgstr "E446: Neniu dosiernomo sub la kursoro"
#~ msgid "E672: Unable to open window inside MDI application"
#~ msgstr "E672: Ne eblas malfermi fenestron interne de aplikaĵo MDI"
-#~ msgid "Close tab"
-#~ msgstr "Fermi langeton"
-
#~ msgid "Open tab..."
#~ msgstr "Malfermi langeton..."
diff --git a/src/nvim/po/es.po b/src/nvim/po/es.po
index 1a5ef991dc..8a9c86e88d 100644
--- a/src/nvim/po/es.po
+++ b/src/nvim/po/es.po
@@ -4276,7 +4276,8 @@ msgstr ""
"&Abrir para lectura únicamente\n"
"&Editar de todas formas\n"
"&Recuperar\n"
-"&Borrar&Salir\n"
+"&Borrar\n"
+"&Salir\n"
"&Abortar"
#.
diff --git a/src/nvim/po/fr.po b/src/nvim/po/fr.po
index 9b2d44ce7d..41efd5c5e3 100644
--- a/src/nvim/po/fr.po
+++ b/src/nvim/po/fr.po
@@ -6,7 +6,7 @@
# FIRST AUTHOR DindinX <David.Odin@bigfoot.com> 2000.
# SECOND AUTHOR Adrien Beau <version.francaise@free.fr> 2002, 2003.
# THIRD AUTHOR David Blanchet <david.blanchet@free.fr> 2006, 2008.
-# FOURTH AUTHOR Dominique Pellé <dominique.pelle@gmail.com> 2008, 2013.
+# FOURTH AUTHOR Dominique Pellé <dominique.pelle@gmail.com> 2008, 2015.
#
# Latest translation available at:
# http://dominique.pelle.free.fr/vim-fr.php
@@ -15,8 +15,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim(Français)\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-05-27 10:22+0200\n"
+"POT-Creation-Date: 2015-07-30 17:54+0200\n"
+"PO-Revision-Date: 2015-07-30 18:00+0200\n"
"Last-Translator: Dominique Pellé <dominique.pelle@gmail.com>\n"
"Language-Team: \n"
"Language: fr\n"
@@ -113,11 +113,6 @@ msgstr "E84: Aucun tampon n'est modifié"
msgid "E85: There is no listed buffer"
msgstr "E85: Aucun tampon n'est listé"
-#: ../buffer.c:913
-#, c-format
-msgid "E86: Buffer %<PRId64> does not exist"
-msgstr "E86: Le tampon %<PRId64> n'existe pas"
-
# AB - Je ne suis pas sûr que l'on puisse obtenir ce message.
#: ../buffer.c:915
msgid "E87: Cannot go beyond last buffer"
@@ -756,6 +751,11 @@ msgstr "E696: Il manque une virgule dans la Liste %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: Il manque ']' à la fin de la Liste %s"
+#: ../eval.c:5750
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr ""
+"Pas assez de mémoire pour les références, arrêt du ramassage de miètes !"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -832,15 +832,15 @@ msgstr "E785: complete() n'est utilisable que dans le mode Insertion"
msgid "&Ok"
msgstr "&Ok"
-#: ../eval.c:8676
-#, c-format
-msgid "E737: Key already exists: %s"
-msgstr "E737: un mappage existe déjà pour %s"
-
#: ../eval.c:8692
msgid "extend() argument"
msgstr "argument de extend()"
+#: ../eval.c:9345
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: un mappage existe déjà pour %s"
+
#: ../eval.c:8915
msgid "map() argument"
msgstr "argument de map()"
@@ -1798,10 +1798,10 @@ msgstr "E174: La commande existe déjà : ajoutez ! pour la redéfinir"
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" Nom Args Plage Complet. Définition"
+" Nom Args Adresse Complet. Définition"
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
@@ -1827,6 +1827,10 @@ msgstr "E178: La valeur par défaut du quantificateur est invalide"
msgid "E179: argument required for -complete"
msgstr "E179: argument requis avec -complete"
+#: ../ex_docmd.c:4933
+msgid "E179: argument required for -addr"
+msgstr "E179: argument requis avec -addr"
+
#: ../ex_docmd.c:4635
#, c-format
msgid "E181: Invalid attribute: %s"
@@ -1850,6 +1854,11 @@ msgstr ""
msgid "E184: No such user-defined command: %s"
msgstr "E184: Aucune commande %s définie par l'utilisateur"
+#: ../ex_docmd.c:5516
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Valeur de type d'adresse invalide : %s"
+
#: ../ex_docmd.c:5219
#, c-format
msgid "E180: Invalid complete value: %s"
@@ -3155,6 +3164,11 @@ msgstr "E363: le motif utilise plus de mémoire que 'maxmempattern'"
msgid "E749: empty buffer"
msgstr "E749: tampon vide"
+#: ../buffer.c:1587
+#, c-format
+msgid "E86: Buffer %<PRId64> does not exist"
+msgstr "E86: Le tampon %<PRId64> n'existe pas"
+
#: ../globals.h:1108
msgid "E682: Invalid search pattern or delimiter"
msgstr "E682: Délimiteur ou motif de recherche invalide"
@@ -4308,7 +4322,7 @@ msgid ""
" to recover the changes (see \":help recovery\").\n"
msgstr ""
"\"\n"
-" pour récupérer le fichier (voir \":help recovery\").\n"
+" pour récupérer le fichier (consultez \":help recovery\").\n"
#: ../memline.c:3250
msgid " If you did this already, delete the swap file \""
@@ -4805,6 +4819,11 @@ msgstr "E522: Introuvable dans termcap"
msgid "E539: Illegal character <%s>"
msgstr "E539: Caractère <%s> invalide"
+#: ../option.c:2253
+#, c-format
+msgid "For option %s"
+msgstr "Pour l'option %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: 'term' ne doit pas être une chaîne vide"
@@ -6779,9 +6798,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "Reading from stdin..."
#~ msgstr "Lecture de stdin..."
-#~ msgid "[blowfish]"
-#~ msgstr "[blowfish]"
-
#~ msgid "[crypted]"
#~ msgstr "[chiffré]"
@@ -6909,8 +6925,8 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgstr ""
#~ "Vim : Une requête \"die\" a été reçue par le gestionnaire de session\n"
-#~ msgid "Close"
-#~ msgstr "Fermer"
+#~ msgid "Close tab"
+#~ msgstr "Fermer l'onglet"
#~ msgid "New tab"
#~ msgstr "Nouvel onglet"
@@ -6968,13 +6984,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "E672: Unable to open window inside MDI application"
#~ msgstr "E672: Impossible d'ouvrir une fenêtre dans une application MDI"
-# DB - Les quelques messages qui suivent se retrouvent aussi ici :
-# gui_gtk_x11.c:3170 et suivants.
-# Les libellés changent un peu (majuscule par exemple).
-# La VF tâche de les unifier.
-#~ msgid "Close tab"
-#~ msgstr "Fermer l'onglet"
-
#~ msgid "Open tab..."
#~ msgstr "Ouvrir dans un onglet..."
@@ -7148,9 +7157,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "E836: This Vim cannot execute :python after using :py3"
#~ msgstr "E836: Vim ne peut pas exécuter :python après avoir utilisé :py3"
-#~ msgid "only string keys are allowed"
-#~ msgstr "seule une chaine est autorisée comme clé"
-
#~ msgid ""
#~ "E263: Sorry, this command is disabled, the Python library could not be "
#~ "loaded."
@@ -7684,12 +7690,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "E338: Sorry, no file browser in console mode"
#~ msgstr "E338: Désolé, pas de sélecteur de fichiers en mode console"
-#~ msgid "Vim: preserving files...\n"
-#~ msgstr "Vim : préservation des fichiers...\n"
-
-#~ msgid "Vim: Finished.\n"
-#~ msgstr "Vim : Fini.\n"
-
#~ msgid "ERROR: "
#~ msgstr "ERREUR : "
@@ -7718,6 +7718,10 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "E547: Illegal mouseshape"
#~ msgstr "E547: Forme de curseur invalide"
+#~ msgid "Warning: Using a weak encryption method; see :help 'cm'"
+#~ msgstr ""
+#~ "Alerte : utilisation d'une méthode de chiffrage faible ; consultez :help 'cm'"
+
#~ msgid "Enter encryption key: "
#~ msgstr "Tapez la clé de chiffrement : "
@@ -7861,15 +7865,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "E245: Illegal char '%c' in font name \"%s\""
#~ msgstr "E245: Caractère '%c' invalide dans le nom de fonte \"%s\""
-#~ msgid "Vim: Double signal, exiting\n"
-#~ msgstr "Vim : Double signal, sortie\n"
-
-#~ msgid "Vim: Caught deadly signal %s\n"
-#~ msgstr "Vim : Signal mortel %s intercepté\n"
-
-#~ msgid "Vim: Caught deadly signal\n"
-#~ msgstr "Vim : Signal mortel intercepté\n"
-
#~ msgid "Opening the X display took %<PRId64> msec"
#~ msgstr "L'ouverture du display X a pris %<PRId64> ms"
@@ -7970,7 +7965,7 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgstr ""
#~ "VIMRUN.EXE est introuvable votre $PATH.\n"
#~ "Les commandes externes ne feront pas de pause une fois terminées.\n"
-#~ "Voir :help win32-vimrun pour plus d'informations."
+#~ "Consultez :help win32-vimrun pour plus d'informations."
#~ msgid "Vim Warning"
#~ msgstr "Alerte Vim"
@@ -7982,11 +7977,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgstr ""
#~ "E868: Erreur lors de la construction du NFA avec classe d'équivalence"
-#~ msgid "E999: (NFA regexp internal error) Should not process NOT node !"
-#~ msgstr ""
-#~ "E999: (erreur interne du regexp NFA) Un noeud 'NOT' ne devrait pas être "
-#~ "traité !"
-
#~ msgid "E878: (NFA) Could not allocate memory for branch traversal!"
#~ msgstr ""
#~ "E878: (NFA) Impossible d'allouer la mémoire pour parcourir les branches!"
@@ -8306,30 +8296,18 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "can't delete OutputObject attributes"
#~ msgstr "impossible d'effacer les attributs d'OutputObject"
-#~ msgid "softspace must be an integer"
-#~ msgstr "softspace doit être un nombre entier"
-
#~ msgid "invalid attribute"
#~ msgstr "attribut invalide"
-#~ msgid "writelines() requires list of strings"
-#~ msgstr "writelines() requiert une liste de chaînes"
-
#~ msgid "E264: Python: Error initialising I/O objects"
#~ msgstr "E264: Python : Erreur d'initialisation des objets d'E/S"
#~ msgid "empty keys are not allowed"
#~ msgstr "les clés vides ne sont pas autorisées"
-#~ msgid "Cannot delete DictionaryObject attributes"
-#~ msgstr "Impossible d'effacer les attributs de DictionaryObject"
-
#~ msgid "Cannot modify fixed dictionary"
#~ msgstr "Impossible de modifier un dictionnaire fixe"
-#~ msgid "Cannot set this attribute"
-#~ msgstr "Impossible d'initialiser cet attribut"
-
#~ msgid "dict is locked"
#~ msgstr "dictionnaire est verrouillé"
@@ -8348,15 +8326,9 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "Failed to add item to list"
#~ msgstr "Ajout à la liste a échoué"
-#~ msgid "can only assign lists to slice"
-#~ msgstr "seules des tranches peuvent être assignées aux listes"
-
#~ msgid "internal error: failed to add item to list"
#~ msgstr "erreur interne : ajout d'élément à la liste a échoué"
-#~ msgid "can only concatenate with lists"
-#~ msgstr "on ne peut que concaténer avec des listes"
-
#~ msgid "cannot delete vim.dictionary attributes"
#~ msgstr "impossible d'effacer les attributs de vim.dictionary"
@@ -8366,9 +8338,6 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "cannot set this attribute"
#~ msgstr "impossible d'initialiser cet attribut"
-#~ msgid "'self' argument must be a dictionary"
-#~ msgstr "l'argument 'self' doit être un dictionnaire"
-
#~ msgid "failed to run function"
#~ msgstr "exécution de la fonction a échoué"
@@ -8378,24 +8347,9 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "unable to unset option without global value"
#~ msgstr "impossible de désactiver une option sans une valeur globale"
-#~ msgid "object must be integer"
-#~ msgstr "objet doit être un nombre entier"
-
-#~ msgid "object must be string"
-#~ msgstr "objet doit être de type string"
-
#~ msgid "attempt to refer to deleted tab page"
#~ msgstr "tentative de référencer un onglet effacé"
-#~ msgid "<tabpage object (deleted) at %p>"
-#~ msgstr "<objet onglet (effacé) à %p>"
-
-#~ msgid "<tabpage object (unknown) at %p>"
-#~ msgstr "<objet onglet (inconnu) à %p>"
-
-#~ msgid "<tabpage %d>"
-#~ msgstr "<onglet %d>"
-
#~ msgid "no such tab page"
#~ msgstr "cet onglet n'existe pas"
@@ -8408,27 +8362,12 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "cursor position outside buffer"
#~ msgstr "curseur positionné en dehors du tampon"
-#~ msgid "<window object (deleted) at %p>"
-#~ msgstr "<objet fenêtre (effacé) à %p>"
-
-#~ msgid "<window object (unknown) at %p>"
-#~ msgstr "<objet fenêtre (inconnu) à %p>"
-
-#~ msgid "<window %d>"
-#~ msgstr "<fenêtre %d>"
-
#~ msgid "no such window"
#~ msgstr "Cette fenêtre n'existe pas"
#~ msgid "attempt to refer to deleted buffer"
#~ msgstr "tentative de référencer un tampon effacé"
-#~ msgid "<buffer object (deleted) at %p>"
-#~ msgstr "<objet tampon (effacé) à %p>"
-
-#~ msgid "key must be integer"
-#~ msgstr "la clé doit être un nombre entier"
-
#~ msgid "expected vim.buffer object"
#~ msgstr "objet vim.buffer attendu"
@@ -8467,18 +8406,3 @@ msgstr "E446: Aucun nom de fichier sous le curseur"
#~ msgid "internal error: invalid value type"
#~ msgstr "erreur interne : type de valeur invalide"
-
-#~ msgid "E860: Eval did not return a valid python 3 object"
-#~ msgstr "E860: Eval n'a pas retourné un object python 3 valid"
-
-#~ msgid "E861: Failed to convert returned python 3 object to vim value"
-#~ msgstr "E861: Conversion d'objet python 3 à une valeur de vim a échoué"
-
-#~ msgid "E863: return value must be an instance of str"
-#~ msgstr "E863: valeur de retour doit être une instance de Str"
-
-#~ msgid "Only boolean objects are allowed"
-#~ msgstr "Seuls les objets booléens sont autorisés"
-
-#~ msgid "no such key in dictionary"
-#~ msgstr "cette clé est inexistante dans le dictionnaire"
diff --git a/src/nvim/po/it.po b/src/nvim/po/it.po
index 729697eee3..171e155689 100644
--- a/src/nvim/po/it.po
+++ b/src/nvim/po/it.po
@@ -11,10 +11,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: vim 7.4b\n"
+"Project-Id-Version: vim 7.4\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-05-26 14:21+0200\n"
-"PO-Revision-Date: 2013-08-03 17:14+0200\n"
+"POT-Creation-Date: 2015-08-11 20:58+0200\n"
+"PO-Revision-Date: 2015-08-11 22:02+0200\n"
"Last-Translator: Vlad Sandrini <vlad.gently@gmail.com>\n"
"Language-Team: Italian Antonio Colombo <azc100@gmail."
"com> Vlad Sandrini <vlad.gently@gmail."
@@ -104,11 +104,6 @@ msgstr "E84: Nessun buffer risulta modificato"
msgid "E85: There is no listed buffer"
msgstr "E85: Non c'è alcun buffer elencato"
-#: ../buffer.c:913
-#, c-format
-msgid "E86: Buffer %<PRId64> does not exist"
-msgstr "E86: Non esiste il buffer %<PRId64>"
-
#: ../buffer.c:915
msgid "E87: Cannot go beyond last buffer"
msgstr "E87: Non posso oltrepassare l'ultimo buffer"
@@ -128,7 +123,7 @@ msgstr ""
#. wrap around (may cause duplicates)
#: ../buffer.c:1423
msgid "W14: Warning: List of file names overflow"
-msgstr "W14: Attenzione: Superato limite della lista dei nomi di file"
+msgstr "W14: Avviso: Superato limite della lista dei nomi di file"
#: ../buffer.c:1555 ../quickfix.c:3361
#, c-format
@@ -148,7 +143,7 @@ msgstr "E94: Nessun buffer corrispondente a %s"
#: ../buffer.c:2161
#, c-format
msgid "line %<PRId64>"
-msgstr "linea %<PRId64>"
+msgstr "riga %<PRId64>"
#: ../buffer.c:2233
msgid "E95: Buffer with this name already exists"
@@ -181,17 +176,17 @@ msgstr "[in sola lettura]"
#: ../buffer.c:2524
#, c-format
msgid "1 line --%d%%--"
-msgstr "1 linea --%d%%--"
+msgstr "1 riga --%d%%--"
#: ../buffer.c:2526
#, c-format
msgid "%<PRId64> lines --%d%%--"
-msgstr "%<PRId64> linee --%d%%--"
+msgstr "%<PRId64> righe --%d%%--"
#: ../buffer.c:2530
#, c-format
msgid "line %<PRId64> of %<PRId64> --%d%%-- col "
-msgstr "linea %<PRId64> di %<PRId64> --%d%%-- col "
+msgstr "riga %<PRId64> di %<PRId64> --%d%%-- col "
#: ../buffer.c:2632 ../buffer.c:4292 ../memline.c:1554
msgid "[No Name]"
@@ -250,7 +245,7 @@ msgstr "Segni per %s:"
#: ../buffer.c:4543
#, c-format
msgid " line=%<PRId64> id=%d name=%s"
-msgstr " linea=%<PRId64> id=%d, nome=%s"
+msgstr " riga=%<PRId64> id=%d, nome=%s"
#: ../cursor_shape.c:68
msgid "E545: Missing colon"
@@ -346,11 +341,11 @@ msgstr " modalità ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"
#: ../edit.c:85
msgid " Whole line completion (^L^N^P)"
-msgstr " Completamento Linea Intera (^L^N^P)"
+msgstr " Completamento riga intera (^L^N^P)"
#: ../edit.c:86
msgid " File name completion (^F^N^P)"
-msgstr " Completamento nomi File (^F^N^P)"
+msgstr " Completamento nomi file (^F^N^P)"
#: ../edit.c:87
msgid " Tag completion (^]^N^P)"
@@ -374,7 +369,7 @@ msgstr " Completamento Thesaurus (^T^N^P)"
#: ../edit.c:93
msgid " Command-line completion (^V^N^P)"
-msgstr " Completamento linea comandi (^V^N^P)"
+msgstr " Completamento riga comandi (^V^N^P)"
#: ../edit.c:94
msgid " User defined completion (^U^N^P)"
@@ -452,7 +447,7 @@ msgstr "Ritorno all'originale"
#: ../edit.c:4621
msgid "Word from other line"
-msgstr "Parola da un'altra linea"
+msgstr "Parola da un'altra riga"
#: ../edit.c:4624
msgid "The only match"
@@ -680,6 +675,11 @@ msgstr "E696: Manca virgola nella Lista: %s"
msgid "E697: Missing end of List ']': %s"
msgstr "E697: Manca ']' a fine Lista: %s"
+#: ../eval.c:5750
+#, c-format
+msgid "Not enough memory to set references, garbage collection aborted!"
+msgstr "Memoria insufficiente per impostarlo, recupero memoria fallito!"
+
#: ../eval.c:6475
#, c-format
msgid "E720: Missing colon in Dictionary: %s"
@@ -754,15 +754,15 @@ msgstr "E785: complete() può essere usata solo in modalità inserimento"
msgid "&Ok"
msgstr "&OK"
-#: ../eval.c:8676
-#, c-format
-msgid "E737: Key already exists: %s"
-msgstr "E737: Chiave già esistente: %s"
-
#: ../eval.c:8692
msgid "extend() argument"
msgstr "argomento di extend()"
+#: ../eval.c:9345
+#, c-format
+msgid "E737: Key already exists: %s"
+msgstr "E737: Chiave già esistente: %s"
+
#: ../eval.c:8915
msgid "map() argument"
msgstr "argomento di map()"
@@ -774,7 +774,7 @@ msgstr "argomento di filter()"
#: ../eval.c:9229
#, c-format
msgid "+-%s%3ld lines: "
-msgstr "+-%s%3ld linee: "
+msgstr "+-%s%3ld righe: "
#: ../eval.c:9291
#, c-format
@@ -1043,21 +1043,21 @@ msgstr "> %d, Esa %08x, Ottale %o"
#: ../ex_cmds.c:684
msgid "E134: Move lines into themselves"
-msgstr "E134: Movimento di linee verso se stesse"
+msgstr "E134: Movimento di righe verso se stesse"
#: ../ex_cmds.c:747
msgid "1 line moved"
-msgstr "1 linea mossa"
+msgstr "1 riga mossa"
#: ../ex_cmds.c:749
#, c-format
msgid "%<PRId64> lines moved"
-msgstr "%<PRId64> linee mosse"
+msgstr "%<PRId64> righe mosse"
#: ../ex_cmds.c:1175
#, c-format
msgid "%<PRId64> lines filtered"
-msgstr "%<PRId64> linee filtrate"
+msgstr "%<PRId64> righe filtrate"
#: ../ex_cmds.c:1194
msgid "E135: *Filter* Autocommands must not change current buffer"
@@ -1070,7 +1070,7 @@ msgstr "[Non salvato dopo l'ultima modifica]\n"
#: ../ex_cmds.c:1424
#, c-format
msgid "%sviminfo: %s in line: "
-msgstr "%sviminfo: %s nella linea: "
+msgstr "%sviminfo: %s nella riga: "
#: ../ex_cmds.c:1431
msgid "E136: viminfo: Too many errors, skipping rest of file"
@@ -1239,12 +1239,12 @@ msgstr "%<PRId64> sostituzioni"
#: ../ex_cmds.c:4392
msgid " on 1 line"
-msgstr " in 1 linea"
+msgstr " in 1 riga"
#: ../ex_cmds.c:4395
#, c-format
msgid " on %<PRId64> lines"
-msgstr " in %<PRId64> linee"
+msgstr " in %<PRId64> righe"
#: ../ex_cmds.c:4438
msgid "E147: Cannot do :global recursive"
@@ -1257,7 +1257,7 @@ msgstr "E148: Manca espressione regolare nel comando 'global'"
#: ../ex_cmds.c:4508
#, c-format
msgid "Pattern found in every line: %s"
-msgstr "Espressione trovata su ogni linea: %s"
+msgstr "Espressione trovata su ogni riga: %s"
#: ../ex_cmds.c:4510
#, c-format
@@ -1355,6 +1355,11 @@ msgstr "E158: Nome buffer non valido: %s"
msgid "E157: Invalid sign ID: %<PRId64>"
msgstr "E157: ID 'sign' non valido: %<PRId64>"
+#: ../ex_cmds.c:5517
+#, c-format
+msgid "E885: Not possible to change sign %s"
+msgstr "E885: Impossibile cambiare segno %s"
+
#: ../ex_cmds.c:6066
msgid " (not supported)"
msgstr " (non supportata)"
@@ -1370,7 +1375,7 @@ msgstr "Entro modalità Debug. Batti \"cont\" per continuare."
#: ../ex_cmds2.c:143 ../ex_docmd.c:759
#, c-format
msgid "line %<PRId64>: %s"
-msgstr "linea %<PRId64>: %s"
+msgstr "riga %<PRId64>: %s"
#: ../ex_cmds2.c:145
#, c-format
@@ -1380,7 +1385,7 @@ msgstr "com: %s"
#: ../ex_cmds2.c:322
#, c-format
msgid "Breakpoint in \"%s%s\" line %<PRId64>"
-msgstr "Pausa in \"%s%s\" linea %<PRId64>"
+msgstr "Pausa in \"%s%s\" riga %<PRId64>"
#: ../ex_cmds2.c:581
#, c-format
@@ -1394,7 +1399,7 @@ msgstr "Nessun 'breakpoint' definito"
#: ../ex_cmds2.c:617
#, c-format
msgid "%3d %s %s line %<PRId64>"
-msgstr "%3d %s %s linea %<PRId64>"
+msgstr "%3d %s %s riga %<PRId64>"
#: ../ex_cmds2.c:942
msgid "E750: First use \":profile start {fname}\""
@@ -1417,7 +1422,7 @@ msgstr "E162: Buffer \"%s\" non salvato dopo modifica"
#: ../ex_cmds2.c:1480
msgid "Warning: Entered other buffer unexpectedly (check autocommands)"
msgstr ""
-"Attenzione: Entrato in altro buffer inaspettatamente (controllare "
+"Avviso: Entrato in altro buffer inaspettatamente (controllare "
"autocomandi)"
#: ../ex_cmds2.c:1826
@@ -1465,7 +1470,7 @@ msgstr "non riesco ad eseguire \"%s\""
#: ../ex_cmds2.c:2520
#, c-format
msgid "line %<PRId64>: could not source \"%s\""
-msgstr "linea %<PRId64>: non riesco ad eseguire \"%s\""
+msgstr "riga %<PRId64>: non riesco ad eseguire \"%s\""
#: ../ex_cmds2.c:2535
#, c-format
@@ -1475,7 +1480,7 @@ msgstr "eseguo \"%s\""
#: ../ex_cmds2.c:2537
#, c-format
msgid "line %<PRId64>: sourcing \"%s\""
-msgstr "linea %<PRId64>: eseguo \"%s\""
+msgstr "riga %<PRId64>: eseguo \"%s\""
#: ../ex_cmds2.c:2693
#, c-format
@@ -1504,7 +1509,7 @@ msgstr "gestore di errore"
#: ../ex_cmds2.c:3020
msgid "W15: Warning: Wrong line separator, ^M may be missing"
-msgstr "W15: Attenzione: Separatore di linea errato, forse manca ^M"
+msgstr "W15: Avviso: Separatore di riga errato, forse manca ^M"
#: ../ex_cmds2.c:3139
msgid "E167: :scriptencoding used outside of a sourced file"
@@ -1606,10 +1611,10 @@ msgstr "E174: Il comando esiste già: aggiungi ! per sostituirlo"
#: ../ex_docmd.c:4432
msgid ""
"\n"
-" Name Args Range Complete Definition"
+" Name Args Address Complete Definition"
msgstr ""
"\n"
-" Nome Arg. Inter Completo Definizione"
+" Nome Arg. Indir. Completo Definizione"
#: ../ex_docmd.c:4516
msgid "No user-defined commands found"
@@ -1635,6 +1640,10 @@ msgstr "E178: Valore predefinito del contatore non valido"
msgid "E179: argument required for -complete"
msgstr "E179: argomento necessario per -complete"
+#: ../ex_docmd.c:4923
+msgid "E179: argument required for -addr"
+msgstr "E179: argomento necessario per -addr"
+
#: ../ex_docmd.c:4635
#, c-format
msgid "E181: Invalid attribute: %s"
@@ -1658,6 +1667,11 @@ msgstr "E841: Nome riservato, non usabile in un comando definito dall'utente"
msgid "E184: No such user-defined command: %s"
msgstr "E184: Comando definito dall'utente %s inesistente"
+#: ../ex_docmd.c:5516
+#, c-format
+msgid "E180: Invalid address type value: %s"
+msgstr "E180: Tipo di indirizzo non valido: %s"
+
#: ../ex_docmd.c:5219
#, c-format
msgid "E180: Invalid complete value: %s"
@@ -1666,7 +1680,7 @@ msgstr "E180: Valore %s non valido per 'complete'"
#: ../ex_docmd.c:5225
msgid "E468: Completion argument only allowed for custom completion"
msgstr ""
-"E468: Argomento di completamento permesso solo per completamento "
+"E468: Argomento di completamento consentito solo per completamento "
"personalizzato"
#: ../ex_docmd.c:5231
@@ -1815,7 +1829,7 @@ msgstr "Eccezione scartata: %s"
#: ../ex_eval.c:588 ../ex_eval.c:634
#, c-format
msgid "%s, line %<PRId64>"
-msgstr "%s, linea %<PRId64>"
+msgstr "%s, riga %<PRId64>"
#. always scroll up, don't overwrite
#: ../ex_eval.c:608
@@ -1961,7 +1975,7 @@ msgstr ""
#: ../ex_getln.c:5047
msgid "Command Line"
-msgstr "Linea di Comando"
+msgstr "Riga di Comando"
#: ../ex_getln.c:5048
msgid "Search String"
@@ -1973,7 +1987,7 @@ msgstr "Espressione"
#: ../ex_getln.c:5050
msgid "Input Line"
-msgstr "Linea di Input"
+msgstr "Riga di Input"
#: ../ex_getln.c:5117
msgid "E198: cmd_pchar beyond the command length"
@@ -2091,7 +2105,7 @@ msgstr "[manca CR]"
#: ../fileio.c:1819
msgid "[long lines split]"
-msgstr "[linee lunghe divise]"
+msgstr "[righe lunghe divise]"
#: ../fileio.c:1823 ../fileio.c:3512
msgid "[NOT converted]"
@@ -2104,12 +2118,12 @@ msgstr "[convertito]"
#: ../fileio.c:1831
#, c-format
msgid "[CONVERSION ERROR in line %<PRId64>]"
-msgstr "[ERRORE DI CONVERSIONE alla linea %<PRId64>]"
+msgstr "[ERRORE DI CONVERSIONE alla riga %<PRId64>]"
#: ../fileio.c:1835
#, c-format
msgid "[ILLEGAL BYTE in line %<PRId64>]"
-msgstr "[BYTE NON VALIDO alla linea %<PRId64>]"
+msgstr "[BYTE NON VALIDO alla riga %<PRId64>]"
#: ../fileio.c:1838
msgid "[READ ERRORS]"
@@ -2137,7 +2151,7 @@ msgstr "E203: Buffer in scrittura cancellato o scaricato dagli autocomandi"
#: ../fileio.c:2486
msgid "E204: Autocommand changed number of lines in unexpected way"
-msgstr "E204: L'autocomando ha modificato numero linee in maniera imprevista"
+msgstr "E204: L'autocomando ha modificato numero righe in maniera imprevista"
#: ../fileio.c:2548 ../fileio.c:2565
msgid "is not a file or writable device"
@@ -2213,7 +2227,7 @@ msgid ""
"E513: write error, conversion failed in line %<PRId64> (make 'fenc' empty to "
"override)"
msgstr ""
-"E513: errore in scrittura, conversione fallita alla linea %<PRId64> (rendere "
+"E513: errore in scrittura, conversione fallita alla riga %<PRId64> (rendere "
"'fenc' nullo per eseguire comunque)"
#: ../fileio.c:3448
@@ -2227,7 +2241,7 @@ msgstr " ERRORE DI CONVERSIONE"
#: ../fileio.c:3509
#, c-format
msgid " in line %<PRId64>;"
-msgstr " alla linea %<PRId64>;"
+msgstr " alla riga %<PRId64>;"
#: ../fileio.c:3519
msgid "[Device]"
@@ -2271,7 +2285,7 @@ msgid ""
"WARNING: Original file may be lost or damaged\n"
msgstr ""
"\n"
-"ATTENZIONE: Il file originale può essere perso o danneggiato\n"
+"AVVISO: Il file originale può essere perso o danneggiato\n"
#: ../fileio.c:3675
msgid "don't quit the editor until the file is successfully written!"
@@ -2303,12 +2317,12 @@ msgstr "[in formato UNIX]"
#: ../fileio.c:3831
msgid "1 line, "
-msgstr "1 linea, "
+msgstr "1 riga, "
#: ../fileio.c:3833
#, c-format
msgid "%<PRId64> lines, "
-msgstr "%<PRId64> linee,"
+msgstr "%<PRId64> righe,"
#: ../fileio.c:3836
msgid "1 character"
@@ -2325,14 +2339,14 @@ msgstr "[noeol]"
#: ../fileio.c:3849
msgid "[Incomplete last line]"
-msgstr "[Manca carattere di fine linea]"
+msgstr "[Manca carattere di fine riga]"
#. don't overwrite messages here
#. must give this prompt
#. don't use emsg() here, don't want to flush the buffers
#: ../fileio.c:3865
msgid "WARNING: The file has been changed since reading it!!!"
-msgstr "ATTENZIONE: File modificato dopo essere stato letto dall'Editor!!!"
+msgstr "AVVISO: File modificato dopo essere stato letto dall'Editor!!!"
#: ../fileio.c:3867
msgid "Do you really want to write to it"
@@ -2368,7 +2382,7 @@ msgid ""
"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as "
"well"
msgstr ""
-"W12: Attenzione: File \"%s\" modificato su disco ed anche nel buffer di Vim"
+"W12: Avviso: File \"%s\" modificato su disco ed anche nel buffer di Vim"
#: ../fileio.c:4907
msgid "See \":help W12\" for more info."
@@ -2377,7 +2391,7 @@ msgstr "Vedere \":help W12\" per ulteriori informazioni."
#: ../fileio.c:4910
#, c-format
msgid "W11: Warning: File \"%s\" has changed since editing started"
-msgstr "W11: Attenzione: File \"%s\" modificato dopo l'apertura"
+msgstr "W11: Avviso: File \"%s\" modificato dopo l'apertura"
#: ../fileio.c:4911
msgid "See \":help W11\" for more info."
@@ -2386,7 +2400,7 @@ msgstr "Vedere \":help W11\" per ulteriori informazioni."
#: ../fileio.c:4914
#, c-format
msgid "W16: Warning: Mode of file \"%s\" has changed since editing started"
-msgstr "W16: Attenzione: Modo File \"%s\" modificato dopo l'apertura"
+msgstr "W16: Avviso: Modo File \"%s\" modificato dopo l'apertura"
#: ../fileio.c:4915
msgid "See \":help W16\" for more info."
@@ -2395,11 +2409,11 @@ msgstr "Vedere \":help W16\" per ulteriori informazioni."
#: ../fileio.c:4927
#, c-format
msgid "W13: Warning: File \"%s\" has been created after editing started"
-msgstr "W13: Attenzione: Il file \"%s\" risulta creato dopo l'apertura"
+msgstr "W13: Avviso: Il file \"%s\" risulta creato dopo l'apertura"
#: ../fileio.c:4947
msgid "Warning"
-msgstr "Attenzione"
+msgstr "Avviso"
#: ../fileio.c:4948
msgid ""
@@ -2513,7 +2527,7 @@ msgstr "E351: Non posso cancellare piegatura con il 'foldmethod' in uso"
#: ../fold.c:1784
#, c-format
msgid "+--%3ld lines folded "
-msgstr "+--%3ld linee piegate"
+msgstr "+--%3ld righe piegate"
#. buffer has already been read
#: ../getchar.c:273
@@ -2679,7 +2693,7 @@ msgstr "E364: Chiamata a libreria fallita per \"%s()\""
#: ../globals.h:1026
msgid "E19: Mark has invalid line number"
-msgstr "E19: 'Mark' con numero linea non valido"
+msgstr "E19: 'Mark' con numero riga non valido"
#: ../globals.h:1027
msgid "E20: Mark not set"
@@ -2720,7 +2734,7 @@ msgstr "E29: Ancora nessun testo inserito"
#: ../globals.h:1038
msgid "E30: No previous command line"
-msgstr "E30: Nessuna linea comandi precedente"
+msgstr "E30: Nessuna riga comandi precedente"
#: ../globals.h:1039
msgid "E31: No such mapping"
@@ -2947,6 +2961,11 @@ msgstr "E363: l'espressione usa troppa memoria rispetto a 'maxmempattern'"
msgid "E749: empty buffer"
msgstr "E749: buffer vuoto"
+#: ../globals.h:1226
+#, c-format
+msgid "E86: Buffer %<PRId64> does not exist"
+msgstr "E86: Non esiste il buffer %<PRId64>"
+
#: ../globals.h:1108
msgid "E682: Invalid search pattern or delimiter"
msgstr "E682: Espressione o delimitatore di ricerca non validi"
@@ -3260,11 +3279,11 @@ msgid ""
" # line"
msgstr ""
"\n"
-" # linea"
+" # riga"
#: ../if_cscope.c:1713
msgid "filename / context / line\n"
-msgstr "nomefile / contest / linea\n"
+msgstr "nomefile / contest / riga\n"
#: ../if_cscope.c:1809
#, c-format
@@ -3326,16 +3345,16 @@ msgstr "Non posso aprire come script output: \""
#: ../main.c:1622
msgid "Vim: Warning: Output is not to a terminal\n"
-msgstr "Vim: Attenzione: Output non diretto a un terminale\n"
+msgstr "Vim: Avviso: Output non diretto a un terminale\n"
#: ../main.c:1624
msgid "Vim: Warning: Input is not from a terminal\n"
-msgstr "Vim: Attenzione: Input non proveniente da un terminale\n"
+msgstr "Vim: Avviso: Input non proveniente da un terminale\n"
#. just in case..
#: ../main.c:1891
msgid "pre-vimrc command line"
-msgstr "linea comandi prima di vimrc"
+msgstr "riga comandi prima di vimrc"
#: ../main.c:1964
#, c-format
@@ -3528,7 +3547,7 @@ msgstr "+\t\t\tPosizionati alla fine del file"
#: ../main.c:2231
msgid "+<lnum>\t\tStart at line <lnum>"
-msgstr "+<lnum>\t\tPosizionati alla linea <lnum>"
+msgstr "+<lnum>\t\tPosizionati alla riga <lnum>"
#: ../main.c:2232
msgid "--cmd <command>\tExecute <command> before loading any vimrc file"
@@ -3589,7 +3608,7 @@ msgid ""
"mark line col file/text"
msgstr ""
"\n"
-"mark linea col.file/testo"
+"mark riga col.file/testo"
#. Highlight title
#: ../mark.c:789
@@ -3598,7 +3617,7 @@ msgid ""
" jump line col file/text"
msgstr ""
"\n"
-" salt.linea col.file/testo"
+" salt.riga col.file/testo"
#. Highlight title
#: ../mark.c:831
@@ -3607,7 +3626,7 @@ msgid ""
"change line col text"
msgstr ""
"\n"
-"modif linea col testo"
+"modif riga col testo"
#: ../mark.c:1238
msgid ""
@@ -3767,7 +3786,7 @@ msgstr "File originale \"%s\""
#: ../memline.c:995
msgid "E308: Warning: Original file may have been changed"
msgstr ""
-"E308: Attenzione: il file originale può essere stato modificato nel frattempo"
+"E308: Avviso: il file originale può essere stato modificato nel frattempo"
#: ../memline.c:1061
#, c-format
@@ -3776,7 +3795,7 @@ msgstr "E309: Impossibile leggere blocco 1 da %s"
#: ../memline.c:1065
msgid "???MANY LINES MISSING"
-msgstr "???MOLTE LINEE MANCANTI"
+msgstr "???MOLTE RIGHE MANCANTI"
#: ../memline.c:1076
msgid "???LINE COUNT WRONG"
@@ -3788,7 +3807,7 @@ msgstr "???BLOCCO VUOTO"
#: ../memline.c:1103
msgid "???LINES MISSING"
-msgstr "???LINEE MANCANTI"
+msgstr "???RIGHE MANCANTI"
#: ../memline.c:1128
#, c-format
@@ -3801,12 +3820,12 @@ msgstr "???BLOCCO MANCANTE"
#: ../memline.c:1147
msgid "??? from here until ???END lines may be messed up"
-msgstr "??? da qui fino a ???END le linee possono essere fuori ordine"
+msgstr "??? da qui fino a ???END le righe possono essere fuori ordine"
#: ../memline.c:1164
msgid "??? from here until ???END lines may have been inserted/deleted"
msgstr ""
-"??? da qui fino a ???END linee possono essere state inserite/cancellate"
+"??? da qui fino a ???END righe possono essere state inserite/cancellate"
#: ../memline.c:1181
msgid "???END"
@@ -3819,7 +3838,7 @@ msgstr "E311: Recupero Interrotto"
#: ../memline.c:1243
msgid ""
"E312: Errors detected while recovering; look for lines starting with ???"
-msgstr "E312: Errori durante recupero; controlla linee che iniziano con ???"
+msgstr "E312: Errori durante recupero; controlla righe che iniziano con ???"
#: ../memline.c:1245
msgid "See \":help E312\" for more information."
@@ -3980,12 +3999,12 @@ msgstr "E314: Preservazione fallita"
#: ../memline.c:1819
#, c-format
msgid "E315: ml_get: invalid lnum: %<PRId64>"
-msgstr "E315: ml_get: numero linea non valido: %<PRId64>"
+msgstr "E315: ml_get: numero riga non valido: %<PRId64>"
#: ../memline.c:1851
#, c-format
msgid "E316: ml_get: cannot find line %<PRId64>"
-msgstr "E316: ml_get: non riesco a trovare la linea %<PRId64>"
+msgstr "E316: ml_get: non riesco a trovare la riga %<PRId64>"
#: ../memline.c:2236
msgid "E317: pointer block id wrong 3"
@@ -4010,7 +4029,7 @@ msgstr "cancellato blocco 1?"
#: ../memline.c:2707
#, c-format
msgid "E320: Cannot find line %<PRId64>"
-msgstr "E320: Non riesco a trovare la linea %<PRId64>"
+msgstr "E320: Non riesco a trovare la riga %<PRId64>"
#: ../memline.c:2916
msgid "E317: pointer block id wrong"
@@ -4023,12 +4042,12 @@ msgstr "pe_line_count a zero"
#: ../memline.c:2955
#, c-format
msgid "E322: line number out of range: %<PRId64> past the end"
-msgstr "E322: numero linea non ammissibile: %<PRId64> dopo la fine"
+msgstr "E322: numero riga non ammissibile: %<PRId64> dopo la fine"
#: ../memline.c:2959
#, c-format
msgid "E323: line count wrong in block %<PRId64>"
-msgstr "E323: contatore linee errato nel blocco %<PRId64>"
+msgstr "E323: contatore righe errato nel blocco %<PRId64>"
#: ../memline.c:2999
msgid "Stack size increases"
@@ -4242,7 +4261,7 @@ msgstr "Errore/i eseguendo %s:"
#: ../message.c:445
#, c-format
msgid "line %4ld:"
-msgstr "linea %4ld:"
+msgstr "riga %4ld:"
#: ../message.c:617
#, c-format
@@ -4264,7 +4283,7 @@ msgstr "Premi INVIO o un comando per proseguire"
#: ../message.c:1843
#, c-format
msgid "%s line %<PRId64>"
-msgstr "%s linea %<PRId64>"
+msgstr "%s riga %<PRId64>"
#: ../message.c:2392
msgid "-- More --"
@@ -4272,7 +4291,7 @@ msgstr "-- Ancora --"
#: ../message.c:2398
msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "
-msgstr " SPAZIO/d/j: schermo/pagina/linea giù, b/u/k: su, q: abbandona "
+msgstr " SPAZIO/d/j: schermo/pagina/riga giù, b/u/k: su, q: abbandona "
#: ../message.c:3021 ../message.c:3031
msgid "Question"
@@ -4324,7 +4343,7 @@ msgstr "E767: Troppi argomenti per printf()"
#: ../misc1.c:2256
msgid "W10: Warning: Changing a readonly file"
-msgstr "W10: Attenzione: Modifica a un file in sola-lettura"
+msgstr "W10: Avviso: Modifica a un file in sola-lettura"
#: ../misc1.c:2537
msgid "Type number and <Enter> or click with mouse (empty cancels): "
@@ -4337,21 +4356,21 @@ msgstr "Inserire numero e <Invio> (vuoto per annullare): "
#: ../misc1.c:2585
msgid "1 more line"
-msgstr "1 linea in più"
+msgstr "1 riga in più"
#: ../misc1.c:2588
msgid "1 line less"
-msgstr "1 linea in meno"
+msgstr "1 riga in meno"
#: ../misc1.c:2593
#, c-format
msgid "%<PRId64> more lines"
-msgstr "%<PRId64> linee in più"
+msgstr "%<PRId64> righe in più"
#: ../misc1.c:2596
#, c-format
msgid "%<PRId64> fewer lines"
-msgstr "%<PRId64> linee in meno"
+msgstr "%<PRId64> righe in meno"
#: ../misc1.c:2599
msgid " (Interrupted)"
@@ -4376,7 +4395,7 @@ msgstr "E774: opzione 'operatorfunc' non impostata"
#: ../normal.c:2637
msgid "Warning: terminal cannot highlight"
-msgstr "Attenzione: il terminale non è in grado di evidenziare"
+msgstr "Avviso: il terminale non è in grado di evidenziare"
#: ../normal.c:2807
msgid "E348: No string under cursor"
@@ -4405,36 +4424,36 @@ msgstr "Batti :quit<Invio> per uscire da Vim"
#: ../ops.c:248
#, c-format
msgid "1 line %sed 1 time"
-msgstr "1 linea %sa 1 volta"
+msgstr "1 riga %sa 1 volta"
#: ../ops.c:250
#, c-format
msgid "1 line %sed %d times"
-msgstr "1 linea %sa %d volte"
+msgstr "1 riga %sa %d volte"
#: ../ops.c:253
#, c-format
msgid "%<PRId64> lines %sed 1 time"
-msgstr "%<PRId64> linee %se 1 volta"
+msgstr "%<PRId64> righe %se 1 volta"
#: ../ops.c:256
#, c-format
msgid "%<PRId64> lines %sed %d times"
-msgstr "%<PRId64> linee %se %d volte"
+msgstr "%<PRId64> righe %se %d volte"
#: ../ops.c:592
#, c-format
msgid "%<PRId64> lines to indent... "
-msgstr "%<PRId64> linee da rientrare... "
+msgstr "%<PRId64> righe da rientrare... "
#: ../ops.c:634
msgid "1 line indented "
-msgstr "1 linea rientrata "
+msgstr "1 riga rientrata "
#: ../ops.c:636
#, c-format
msgid "%<PRId64> lines indented "
-msgstr "%<PRId64> linee rientrate "
+msgstr "%<PRId64> righe rientrate "
#: ../ops.c:938
msgid "E748: No previously used register"
@@ -4447,30 +4466,30 @@ msgstr "non riesco a salvare in un registro; cancello comunque"
#: ../ops.c:1929
msgid "1 line changed"
-msgstr "1 linea cambiata"
+msgstr "1 riga cambiata"
#: ../ops.c:1931
#, c-format
msgid "%<PRId64> lines changed"
-msgstr "%<PRId64> linee cambiate"
+msgstr "%<PRId64> righe cambiate"
#: ../ops.c:2521
msgid "block of 1 line yanked"
-msgstr "blocco di 1 linea messo in registro"
+msgstr "blocco di 1 riga messo in registro"
#: ../ops.c:2523
msgid "1 line yanked"
-msgstr "1 linea messa in registro"
+msgstr "1 riga messa in registro"
#: ../ops.c:2525
#, c-format
msgid "block of %<PRId64> lines yanked"
-msgstr "blocco di %<PRId64> linee messo in registro"
+msgstr "blocco di %<PRId64> righe messo in registro"
#: ../ops.c:2528
#, c-format
msgid "%<PRId64> lines yanked"
-msgstr "%<PRId64> linee messe in registro"
+msgstr "%<PRId64> righe messe in registro"
#: ../ops.c:2710
#, c-format
@@ -4503,6 +4522,13 @@ msgstr ""
msgid "E574: Unknown register type %d"
msgstr "E574: Tipo di registro sconosciuto: %d"
+#: ../ops.c:4897
+msgid ""
+"E883: search pattern and expression register may not contain two or more "
+"lines"
+msgstr "E883: espressione di ricerca e registro dell'espressione non possono "
+"contenere due o più righe"
+
#: ../ops.c:5089
#, c-format
msgid "%<PRId64> Cols; "
@@ -4514,7 +4540,7 @@ msgid ""
"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
"%<PRId64> of %<PRId64> Bytes"
msgstr ""
-"Selezionate %s%<PRId64> di %<PRId64> Linee; %<PRId64> di %<PRId64> Parole; "
+"Selezionate %s%<PRId64> di %<PRId64> Righe; %<PRId64> di %<PRId64> Parole; "
"%<PRId64> di %<PRId64> Caratt."
#: ../ops.c:5105
@@ -4523,7 +4549,7 @@ msgid ""
"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; "
"%<PRId64> of %<PRId64> Chars; %<PRId64> of %<PRId64> Bytes"
msgstr ""
-"Selezionate %s%<PRId64> di %<PRId64> Linee; %<PRId64> di %<PRId64> Parole; "
+"Selezionate %s%<PRId64> di %<PRId64> Righe; %<PRId64> di %<PRId64> Parole; "
"%<PRId64> di %<PRId64> Caratt.; %<PRId64> di %<PRId64> Byte"
#: ../ops.c:5123
@@ -4532,7 +4558,7 @@ msgid ""
"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Byte "
"%<PRId64> of %<PRId64>"
msgstr ""
-"Col. %s di %s; Linea %<PRId64> di %<PRId64>; Parola %<PRId64> di %<PRId64>; "
+"Col. %s di %s; Riga %<PRId64> di %<PRId64>; Parola %<PRId64> di %<PRId64>; "
"Caratt. %<PRId64> di %<PRId64>"
#: ../ops.c:5133
@@ -4541,7 +4567,7 @@ msgid ""
"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Char "
"%<PRId64> of %<PRId64>; Byte %<PRId64> of %<PRId64>"
msgstr ""
-"Col. %s di %s; Linea %<PRId64> di %<PRId64>; Parola %<PRId64> di %<PRId64>; "
+"Col. %s di %s; Riga %<PRId64> di %<PRId64>; Parola %<PRId64> di %<PRId64>; "
"Caratt. %<PRId64> di %<PRId64>; Byte %<PRId64> di %<PRId64>"
#: ../ops.c:5146
@@ -4587,6 +4613,11 @@ msgstr "E522: Non trovato in 'termcap'"
msgid "E539: Illegal character <%s>"
msgstr "E539: Carattere non ammesso <%s>"
+#: ../option.c:2253
+#, c-format
+msgid "For option %s"
+msgstr "Per opzione %s"
+
#: ../option.c:3862
msgid "E529: Cannot set 'term' to empty string"
msgstr "E529: Non posso assegnare a 'term' il valore 'stringa nulla'"
@@ -4665,7 +4696,7 @@ msgstr "W17: Arabo richiede UTF-8, esegui ':set encoding=utf-8'"
#: ../option.c:5623
#, c-format
msgid "E593: Need at least %d lines"
-msgstr "E593: Servono almeno %d linee"
+msgstr "E593: Servono almeno %d righe"
#: ../option.c:5631
#, c-format
@@ -4822,7 +4853,7 @@ msgstr "(%d di %d)%s%s: "
#: ../quickfix.c:1676
msgid " (line deleted)"
-msgstr " (linea cancellata)"
+msgstr " (riga cancellata)"
#: ../quickfix.c:1863
msgid "E380: At bottom of quickfix stack"
@@ -4973,6 +5004,10 @@ msgstr "E554: Errore sintattico in %s{...}"
msgid "External submatches:\n"
msgstr "Sotto-corrispondenze esterne:\n"
+#: ../regexp.c:2470
+msgid "E888: (NFA regexp) cannot repeat %s"
+msgstr "E888: (NFA regexp) non riesco a ripetere %s"
+
#: ../regexp.c:7022
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
@@ -4981,6 +5016,10 @@ msgstr ""
"E864: \\%#= può essere seguito solo da 0, 1 o 2. Sarà usato il motore "
"automatico "
+#: ../regexp.c:7039
+msgid "Switching to backtracking RE engine for pattern: "
+msgstr "Passo alla ricerca di RE col vecchio metodo: "
+
#: ../regexp_nfa.c:239
msgid "E865: (NFA) Regexp end encountered prematurely"
msgstr "E865: (NFA) Fine prematura dell'espressione regolare"
@@ -5113,7 +5152,7 @@ msgstr " VISUALE"
#: ../screen.c:7470
msgid " VISUAL LINE"
-msgstr " VISUALE LINEA"
+msgstr " VISUALE RIGA"
#: ../screen.c:7471
msgid " VISUAL BLOCK"
@@ -5125,7 +5164,7 @@ msgstr " SELEZIONA"
#: ../screen.c:7473
msgid " SELECT LINE"
-msgstr " SELEZIONA LINEA"
+msgstr " SELEZIONA RIGA"
#: ../screen.c:7474
msgid " SELECT BLOCK"
@@ -5191,7 +5230,7 @@ msgstr "Cerco nel file incluso: %s"
#: ../search.c:4405
msgid "E387: Match is on current line"
-msgstr "E387: Corrispondenza nella linea corrente"
+msgstr "E387: Corrispondenza nella riga corrente"
#: ../search.c:4517
msgid "All included files were found"
@@ -5235,12 +5274,12 @@ msgstr "E758: File ortografico troncato"
#: ../spell.c:953
#, c-format
msgid "Trailing text in %s line %d: %s"
-msgstr "Testo in eccesso in %s linea %d: %s"
+msgstr "Testo in eccesso in %s riga %d: %s"
#: ../spell.c:954
#, c-format
msgid "Affix name too long in %s line %d: %s"
-msgstr "Nome affisso troppo lungo in %s linea %d: %s"
+msgstr "Nome affisso troppo lungo in %s riga %d: %s"
#: ../spell.c:955
msgid "E761: Format error in affix file FOL, LOW or UPP"
@@ -5261,7 +5300,7 @@ msgstr "E756: Controllo ortografico non abilitato"
#: ../spell.c:2249
#, c-format
msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""
-msgstr "Attenzione: Non trovo lista parole \"%s.%s.spl\" o \"%s.ascii.spl\""
+msgstr "Avviso: Non trovo lista parole \"%s.%s.spl\" o \"%s.ascii.spl\""
#: ../spell.c:2473
#, c-format
@@ -5287,7 +5326,7 @@ msgstr "E770: Sezione non supportata nel file ortografico"
#: ../spell.c:3762
#, c-format
msgid "Warning: region %s not supported"
-msgstr "Attenzione: regione %s non supportata"
+msgstr "Avviso: regione %s non supportata"
#: ../spell.c:4550
#, c-format
@@ -5297,7 +5336,7 @@ msgstr "Lettura file affissi %s ..."
#: ../spell.c:4589 ../spell.c:5635 ../spell.c:6140
#, c-format
msgid "Conversion failure for word in %s line %d: %s"
-msgstr "Conversione fallita per una parola in %s linea %d: %s"
+msgstr "Conversione fallita per una parola in %s riga %d: %s"
#: ../spell.c:4630 ../spell.c:6170
#, c-format
@@ -5307,12 +5346,12 @@ msgstr "Conversione in %s non supportata: da %s a %s"
#: ../spell.c:4642
#, c-format
msgid "Invalid value for FLAG in %s line %d: %s"
-msgstr "Valore di FLAG non valido in %s linea %d: %s"
+msgstr "Valore di FLAG non valido in %s riga %d: %s"
#: ../spell.c:4655
#, c-format
msgid "FLAG after using flags in %s line %d: %s"
-msgstr "FLAG dopo l'uso di flags in %s linea %d: %s"
+msgstr "FLAG dopo l'uso di flags in %s riga %d: %s"
#: ../spell.c:4723
#, c-format
@@ -5321,7 +5360,7 @@ msgid ""
"%d"
msgstr ""
"Definire COMPOUNDFORBIDFLAG dopo l'elemento PFX potrebbe dare risultati "
-"errati in %s linea %d"
+"errati in %s riga %d"
#: ../spell.c:4731
#, c-format
@@ -5330,43 +5369,43 @@ msgid ""
"%d"
msgstr ""
"Definire COMPOUNDPERMITFLAG dopo l'elemento PFX potrebbe dare risultati "
-"errati in %s linea %d"
+"errati in %s riga %d"
#: ../spell.c:4747
#, c-format
msgid "Wrong COMPOUNDRULES value in %s line %d: %s"
-msgstr "Valore errato per COMPOUNDRULES in %s linea %d: %s"
+msgstr "Valore errato per COMPOUNDRULES in %s riga %d: %s"
#: ../spell.c:4771
#, c-format
msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s"
-msgstr "Valore errato per COMPOUNDWORDMAX in %s linea %d: %s"
+msgstr "Valore errato per COMPOUNDWORDMAX in %s riga %d: %s"
#: ../spell.c:4777
#, c-format
msgid "Wrong COMPOUNDMIN value in %s line %d: %s"
-msgstr "Valore errato per COMPOUNDMIN in %s linea %d: %s"
+msgstr "Valore errato per COMPOUNDMIN in %s riga %d: %s"
#: ../spell.c:4783
#, c-format
msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s"
-msgstr "Valore errato per COMPOUNDSYLMAX in %s linea %d: %s"
+msgstr "Valore errato per COMPOUNDSYLMAX in %s riga %d: %s"
#: ../spell.c:4795
#, c-format
msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"
-msgstr "Valore errato per CHECKCOMPOUNDPATTERN in %s linea %d: %s"
+msgstr "Valore errato per CHECKCOMPOUNDPATTERN in %s riga %d: %s"
#: ../spell.c:4847
#, c-format
msgid "Different combining flag in continued affix block in %s line %d: %s"
msgstr ""
-"Flag combinazione diverso in blocco affissi continuo in %s linea %d: %s"
+"Flag combinazione diverso in blocco affissi continuo in %s riga %d: %s"
#: ../spell.c:4850
#, c-format
msgid "Duplicate affix in %s line %d: %s"
-msgstr "Affisso duplicato in %s linea %d: %s"
+msgstr "Affisso duplicato in %s riga %d: %s"
#: ../spell.c:4871
#, c-format
@@ -5375,42 +5414,42 @@ msgid ""
"line %d: %s"
msgstr ""
"Affisso usato anche per BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST "
-"in %s linea %d: %s"
+"in %s riga %d: %s"
#: ../spell.c:4893
#, c-format
msgid "Expected Y or N in %s line %d: %s"
-msgstr "Y o N deve essere presente in %s linea %d: %s"
+msgstr "Y o N deve essere presente in %s riga %d: %s"
#: ../spell.c:4968
#, c-format
msgid "Broken condition in %s line %d: %s"
-msgstr "Condizione non rispettata in %s linea %d: %s"
+msgstr "Condizione non rispettata in %s riga %d: %s"
#: ../spell.c:5091
#, c-format
msgid "Expected REP(SAL) count in %s line %d"
-msgstr "Contatore REP(SAL) necessario in %s linea %d"
+msgstr "Contatore REP(SAL) necessario in %s riga %d"
#: ../spell.c:5120
#, c-format
msgid "Expected MAP count in %s line %d"
-msgstr "Contatore MAP necessario in %s linea %d"
+msgstr "Contatore MAP necessario in %s riga %d"
#: ../spell.c:5132
#, c-format
msgid "Duplicate character in MAP in %s line %d"
-msgstr "Carattere duplicato in MAP in %s linea %d"
+msgstr "Carattere duplicato in MAP in %s riga %d"
#: ../spell.c:5176
#, c-format
msgid "Unrecognized or duplicate item in %s line %d: %s"
-msgstr "Elemento non riconosciuto o duplicato in %s linea %d: %s"
+msgstr "Elemento non riconosciuto o duplicato in %s riga %d: %s"
#: ../spell.c:5197
#, c-format
msgid "Missing FOL/LOW/UPP line in %s"
-msgstr "Linea FOL/LOW/UPP mancante in %s"
+msgstr "Riga FOL/LOW/UPP mancante in %s"
#: ../spell.c:5220
msgid "COMPOUNDSYLMAX used without SYLLABLE"
@@ -5431,22 +5470,22 @@ msgstr "Troppi suffissi e/o flag composti"
#: ../spell.c:5250
#, c-format
msgid "Missing SOFO%s line in %s"
-msgstr "Linea SOFO%s mancante in %s"
+msgstr "Riga SOFO%s mancante in %s"
#: ../spell.c:5253
#, c-format
msgid "Both SAL and SOFO lines in %s"
-msgstr "Linee sia SAL che SOFO in %s"
+msgstr "Riga sia SAL che SOFO in %s"
#: ../spell.c:5331
#, c-format
msgid "Flag is not a number in %s line %d: %s"
-msgstr "Il flag non è un numero in %s linea %d: %s"
+msgstr "Il flag non è un numero in %s riga %d: %s"
#: ../spell.c:5334
#, c-format
msgid "Illegal flag in %s line %d: %s"
-msgstr "Flag non ammesso in %s linea %d: %s"
+msgstr "Flag non ammesso in %s riga %d: %s"
#: ../spell.c:5493 ../spell.c:5501
#, c-format
@@ -5466,17 +5505,17 @@ msgstr "E760: Nessun contatore parole in %s"
#: ../spell.c:5669
#, c-format
msgid "line %6d, word %6d - %s"
-msgstr "linea %6d, parola %6d - %s"
+msgstr "riga %6d, parola %6d - %s"
#: ../spell.c:5691
#, c-format
msgid "Duplicate word in %s line %d: %s"
-msgstr "Parola duplicata in %s linea %d: %s"
+msgstr "Parola duplicata in %s riga %d: %s"
#: ../spell.c:5694
#, c-format
msgid "First duplicate word in %s line %d: %s"
-msgstr "Prima parola duplicata in %s linea %d: %s"
+msgstr "Prima parola duplicata in %s riga %d: %s"
#: ../spell.c:5746
#, c-format
@@ -5496,37 +5535,37 @@ msgstr "Lettura file parole %s ..."
#: ../spell.c:6155
#, c-format
msgid "Duplicate /encoding= line ignored in %s line %d: %s"
-msgstr "Linea /encoding= duplicata ignorata in %s linea %d: %s"
+msgstr "Riga /encoding= duplicata ignorata in %s riga %d: %s"
#: ../spell.c:6159
#, c-format
msgid "/encoding= line after word ignored in %s line %d: %s"
-msgstr "Linea /encoding= dopo parola ignorata in %s linea %d: %s"
+msgstr "Riga /encoding= dopo parola ignorata in %s riga %d: %s"
#: ../spell.c:6180
#, c-format
msgid "Duplicate /regions= line ignored in %s line %d: %s"
-msgstr "Linea /regions= duplicata ignorata in %s linea %d: %s"
+msgstr "Riga /regions= duplicata ignorata in %s riga %d: %s"
#: ../spell.c:6185
#, c-format
msgid "Too many regions in %s line %d: %s"
-msgstr "Troppe regioni in %s linea %d: %s"
+msgstr "Troppe regioni in %s riga %d: %s"
#: ../spell.c:6198
#, c-format
msgid "/ line ignored in %s line %d: %s"
-msgstr "Linea / ignorata in %s linea %d: %s"
+msgstr "Riga / ignorata in %s riga %d: %s"
#: ../spell.c:6224
#, c-format
msgid "Invalid region nr in %s line %d: %s"
-msgstr "N. regione non valido in %s linea %d: %s"
+msgstr "N. regione non valido in %s riga %d: %s"
#: ../spell.c:6230
#, c-format
msgid "Unrecognized flags in %s line %d: %s"
-msgstr "Flag non riconosciuti in %s linea %d: %s"
+msgstr "Flag non riconosciuti in %s riga %d: %s"
#: ../spell.c:6257
#, c-format
@@ -5583,7 +5622,7 @@ msgstr "E755: Regione non valida in %s"
#: ../spell.c:7907
msgid "Warning: both compounding and NOBREAK specified"
-msgstr "Attenzione: specificati sia composizione sia NOBREAK"
+msgstr "Avviso: specificati sia composizione sia NOBREAK"
#: ../spell.c:7920
#, c-format
@@ -5700,7 +5739,7 @@ msgstr "la sincronizzazione inizia "
#: ../syntax.c:3443 ../syntax.c:3506
msgid " lines before top line"
-msgstr " linee prima della linea iniziale"
+msgstr " righe prima della riga iniziale"
#: ../syntax.c:3448
msgid ""
@@ -5745,7 +5784,7 @@ msgstr "; corrisp. "
#: ../syntax.c:3515
msgid " line breaks"
-msgstr " interruzioni di linea"
+msgstr " interruzioni di riga"
#: ../syntax.c:4076
msgid "E395: contains argument not accepted here"
@@ -5809,7 +5848,7 @@ msgstr "E402: Spazzatura dopo espressione: %s"
#: ../syntax.c:5120
msgid "E403: syntax sync: line continuations pattern specified twice"
msgstr ""
-"E403: syntax sync: espressione di continuazione linea specificata due volte"
+"E403: syntax sync: espressione di continuazione riga specificata due volte"
#: ../syntax.c:5169
#, c-format
@@ -5998,7 +6037,7 @@ msgid ""
" # TO tag FROM line in file/text"
msgstr ""
"\n"
-" # A tag DA__ linea in file/testo"
+" # A tag DA__ riga in file/testo"
#: ../tag.c:1303
#, c-format
@@ -6007,7 +6046,7 @@ msgstr "Ricerca nel tag file %s"
#: ../tag.c:1545
msgid "Ignoring long line in tags file"
-msgstr "Linea lunga ignorata nel tag file"
+msgstr "Riga lunga ignorata nel tag file"
#: ../tag.c:1915
#, c-format
@@ -6177,23 +6216,23 @@ msgstr "E830: Undo numero %<PRId64> non trovato"
#: ../undo.c:1979
msgid "E438: u_undo: line numbers wrong"
-msgstr "E438: u_undo: numeri linee errati"
+msgstr "E438: u_undo: numeri righe errati"
#: ../undo.c:2183
msgid "more line"
-msgstr "linea in più"
+msgstr "riga in più"
#: ../undo.c:2185
msgid "more lines"
-msgstr "linee in più"
+msgstr "righe in più"
#: ../undo.c:2187
msgid "line less"
-msgstr "linea in meno"
+msgstr "riga in meno"
#: ../undo.c:2189
msgid "fewer lines"
-msgstr "linee in meno"
+msgstr "righe in meno"
#: ../undo.c:2193
msgid "change"
@@ -6239,7 +6278,7 @@ msgstr "E439: lista 'undo' non valida"
#: ../undo.c:2495
msgid "E440: undo line missing"
-msgstr "E440: linea di 'undo' mancante"
+msgstr "E440: riga di 'undo' mancante"
#: ../version.c:600
msgid ""
@@ -6439,6 +6478,10 @@ msgstr "E445: Altre finestre contengono modifiche"
msgid "E446: No file name under cursor"
msgstr "E446: Nessun nome file sotto il cursore"
+#: ../window.c:5484
+msgid "List or number required"
+msgstr "È necessaria una lista o un numero"
+
#~ msgid "E831: bf_key_init() called with empty password"
#~ msgstr "E831: chiamata a bf_key_init() con password nulla"
@@ -6524,15 +6567,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "Reading from stdin..."
#~ msgstr "Leggo da 'stdin'..."
-#~ msgid "[blowfish]"
-#~ msgstr "[blowfish]"
-
-#~ msgid "[crypted]"
-#~ msgstr "[cifrato]"
-
-#~ msgid "E821: File is encrypted with unknown method"
-#~ msgstr "E821: File cifrato con metodo sconosciuto"
-
#~ msgid "NetBeans disallows writes of unmodified buffers"
#~ msgstr "NetBeans non permette la scrittura di un buffer non modificato"
@@ -6648,8 +6682,8 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "Vim: Received \"die\" request from session manager\n"
#~ msgstr "Vim: Ricevuta richiesta \"die\" dal session manager\n"
-#~ msgid "Close"
-#~ msgstr "Chiusura"
+#~ msgid "Close tab"
+#~ msgstr "Chiudi linguetta"
#~ msgid "New tab"
#~ msgstr "Nuova linguetta"
@@ -6705,9 +6739,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "E672: Unable to open window inside MDI application"
#~ msgstr "E672: Non posso aprire la finestra in un'applicazione MDI"
-#~ msgid "Close tab"
-#~ msgstr "Chiudi linguetta"
-
#~ msgid "Open tab..."
#~ msgstr "Apri linguetta..."
@@ -6830,13 +6861,13 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "non sono riuscito ad aprire il buffer"
#~ msgid "cannot delete line"
-#~ msgstr "non posso cancellare la linea"
+#~ msgstr "non posso cancellare la riga"
#~ msgid "cannot replace line"
-#~ msgstr "non posso sostituire la linea"
+#~ msgstr "non posso sostituire la riga"
#~ msgid "cannot insert line"
-#~ msgstr "non posso inserire la linea"
+#~ msgstr "non posso inserire la riga"
#~ msgid "string cannot contain newlines"
#~ msgstr "la stringa non può contenere caratteri 'A CAPO'"
@@ -6857,7 +6888,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "finestra non valida"
#~ msgid "linenr out of range"
-#~ msgstr "numero linea non nell'intervallo"
+#~ msgstr "numero riga non nell'intervallo"
#~ msgid "not allowed in the Vim sandbox"
#~ msgstr "non ammesso in ambiente protetto"
@@ -6865,9 +6896,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "E836: This Vim cannot execute :python after using :py3"
#~ msgstr "E836: Python: Impossibile usare :py e :py3 nella stessa sessione"
-#~ msgid "E837: This Vim cannot execute :py3 after using :python"
-#~ msgstr "E837: Impossibile usare ora :py3 dopo aver usato :python"
-
#~ msgid ""
#~ "E263: Sorry, this command is disabled, the Python library could not be "
#~ "loaded."
@@ -6875,14 +6903,18 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ "E263: Spiacente, comando non disponibile, non riesco a caricare libreria "
#~ "programmi Python."
+#~ msgid ""
+#~ "E887: Sorry, this command is disabled, the Python's site module could not be "
+#~ "loaded."
+#~ msgstr ""
+#~ "E887: Spiacente, comando non disponibile, non riesco a caricare il modulo "
+#~ "Python locale."
+
#~ msgid "E659: Cannot invoke Python recursively"
#~ msgstr "E659: Python non può essere chiamato ricorsivamente"
-#~ msgid "line number out of range"
-#~ msgstr "numero linea non nell'intervallo"
-
-#~ msgid "invalid mark name"
-#~ msgstr "nome di mark non valido"
+#~ msgid "E837: This Vim cannot execute :py3 after using :python"
+#~ msgstr "E837: Impossibile usare ora :py3 dopo aver usato :python"
#~ msgid "E265: $_ must be an instance of String"
#~ msgstr "E265: $_ deve essere un'istanza di String"
@@ -7010,7 +7042,10 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "non ancora implementato"
#~ msgid "cannot set line(s)"
-#~ msgstr "non posso impostare linea(e)"
+#~ msgstr "non posso impostare riga(he)"
+
+#~ msgid "invalid mark name"
+#~ msgstr "nome di mark non valido"
#~ msgid "mark not set"
#~ msgstr "mark non impostato"
@@ -7019,7 +7054,10 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "riga %d colonna %d"
#~ msgid "cannot insert/append line"
-#~ msgstr "non riesco a inserire/aggiungere linea"
+#~ msgstr "non riesco a inserire/aggiungere riga"
+
+#~ msgid "line number out of range"
+#~ msgstr "numero linea non nell'intervallo"
#~ msgid "unknown flag: "
#~ msgstr "opzione inesistente: "
@@ -7067,7 +7105,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "E572: codice di uscita %d"
#~ msgid "cannot get line"
-#~ msgstr "non riesco a ottenere la linea"
+#~ msgstr "non riesco a ottenere la riga"
#~ msgid "Unable to register a command server name"
#~ msgstr "Non riesco a registrare un nome di server comando"
@@ -7293,7 +7331,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "E286: Apertura 'input method' fallita"
#~ msgid "E287: Warning: Could not set destroy callback to IM"
-#~ msgstr "E287: Attenzione: Non posso assegnare IM a 'destroy callback'"
+#~ msgstr "E287: Avviso: Non posso assegnare IM a 'destroy callback'"
#~ msgid "E288: input method doesn't support any style"
#~ msgstr "E288: 'input method' non sopporta alcuno stile"
@@ -7365,12 +7403,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "E338: Sorry, no file browser in console mode"
#~ msgstr "E338: Spiacente, niente esplorazione file in modalità console"
-#~ msgid "Vim: preserving files...\n"
-#~ msgstr "Vim: preservo file...\n"
-
-#~ msgid "Vim: Finished.\n"
-#~ msgstr "Vim: Finito.\n"
-
#~ msgid "ERROR: "
#~ msgstr "ERRORE: "
@@ -7391,7 +7423,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ "\n"
#~ msgid "E340: Line is becoming too long"
-#~ msgstr "E340: La linea sta diventando troppo lunga"
+#~ msgstr "E340: La riga sta diventando troppo lunga"
#~ msgid "E341: Internal error: lalloc(%<PRId64>, )"
#~ msgstr "E341: Errore interno: lalloc(%<PRId64>, )"
@@ -7399,15 +7431,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "E547: Illegal mouseshape"
#~ msgstr "E547: Forma del mouse non valida"
-#~ msgid "Enter encryption key: "
-#~ msgstr "Immetti chiave di cifratura: "
-
-#~ msgid "Enter same key again: "
-#~ msgstr "Ribatti per conferma la stessa chiave: "
-
-#~ msgid "Keys don't match!"
-#~ msgstr "Le chiavi non corrispondono!"
-
#~ msgid "Cannot connect to Netbeans #2"
#~ msgstr "Non posso connettermi a Netbeans #2"
@@ -7437,7 +7460,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "E775: Funzionalità [eval] non disponibile"
#~ msgid "freeing %<PRId64> lines"
-#~ msgstr "libero %<PRId64> linee"
+#~ msgstr "libero %<PRId64> righe"
#~ msgid "E530: Cannot change term in GUI"
#~ msgstr "E530: Non posso modificare 'term' mentre sono nella GUI"
@@ -7538,15 +7561,6 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "E245: Illegal char '%c' in font name \"%s\""
#~ msgstr "E245: Carattere non ammesso '%c' nel font di nome \"%s\""
-#~ msgid "Vim: Double signal, exiting\n"
-#~ msgstr "Vim: Segnale doppio, esco\n"
-
-#~ msgid "Vim: Caught deadly signal %s\n"
-#~ msgstr "Vim: Intercettato segnale fatale %s\n"
-
-#~ msgid "Vim: Caught deadly signal\n"
-#~ msgstr "Vim: Intercettato segnale fatale\n"
-
#~ msgid "Opening the X display took %<PRId64> msec"
#~ msgstr "Attivazione visualizzazione X ha richiesto %<PRId64> msec"
@@ -7610,7 +7624,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr "XSMP SmcOpenConnection fallita: %s"
#~ msgid "At line"
-#~ msgstr "Alla linea"
+#~ msgstr "Alla riga"
#~ msgid "Could not load vim32.dll!"
#~ msgstr "Non riesco a caricare vim32.dll!"
@@ -7875,7 +7889,7 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgstr " modo Vim predefinito "
#~ msgid "WARNING: Windows 95/98/ME detected"
-#~ msgstr "ATTENZIONE: Trovato Windows 95/98/ME"
+#~ msgstr "AVVISO: Trovato Windows 95/98/ME"
#~ msgid "type :help windows95<Enter> for info on this"
#~ msgstr "batti :help windows95<Enter> per info al riguardo"
@@ -7962,6 +7976,22 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "Need encryption key for \"%s\""
#~ msgstr "Serve una chiave di cifratura per \"%s\""
+#~ msgid "empty keys are not allowed"
+#~ msgstr "chiavi nulle non consentite"
+
+#~ msgid "dictionary is locked"
+#~ msgstr "il dizionario è bloccato"
+
+#~ msgid "list is locked"
+#~ msgstr "la lista è bloccata"
+
+#~ msgid "failed to add key '%s' to dictionary"
+#~ msgstr "non non riusciato ad aggiungere la chiave '%s' al dizionario"
+
+#~ #, c-format
+#~ msgid "index must be int or slice, not %s"
+#~ msgstr "l'indice deve'essere un intero o un intervallo, non %s"
+
#~ msgid "expected str() or unicode() instance, but got %s"
#~ msgstr "attesa istanza di str() o unicode(), trovato invece %s"
@@ -7985,8 +8015,8 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "value is too small to fit into C int type"
#~ msgstr "valore troppo piccolo per il tipo int del C"
-#~ msgid "number must be greater then zero"
-#~ msgstr "il numero dev'essere maggiore di zero"
+#~ msgid "number must be greater than zero"
+#~ msgstr "il numero deve essere maggiore di zero"
#~ msgid "number must be greater or equal to zero"
#~ msgstr "il numero dev'essere maggiore o uguale a zero"
@@ -8005,7 +8035,8 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "expected 3-tuple as imp.find_module() result, but got %s"
#~ msgstr ""
-#~ "atteso terzetto come risultato di imp.find_module(), trovato invece %s"
+#~ "atteso terzetto come risultato di imp.find_module(), trovato invece tuple di "
+#~ "dimens. %d"
#~ msgid ""
#~ "expected 3-tuple as imp.find_module() result, but got tuple of size %d"
@@ -8042,15 +8073,30 @@ msgstr "E446: Nessun nome file sotto il cursore"
#~ msgid "internal error: failed to get vim list item %d"
#~ msgstr "errore interno: non ho potuto ottenere l'elemento di vim list %d"
-#~ msgid "failed to add item to list"
-#~ msgstr "non ho potuto aggiungere un elemento alla lista"
+#~ msgid "slice step cannot be zero"
+#~ msgstr "il passo scorrendo un intervallo non può essere zero"
+
+#~ #, c-format
+#~ msgid "attempt to assign sequence of size greater than %d to extended slice"
+#~ msgstr "tentativo di assegnare una sequenza maggiore di %d a un intervallo "
+#~ "esteso"
#~ msgid "internal error: no vim list item %d"
#~ msgstr "errore interno: non c'è un elemento di vim list %d"
+#~ msgid "internal error: not enough list items"
+#~ msgstr "errore interno: non ci sono abbastanza elementi per la lista"
+
#~ msgid "internal error: failed to add item to list"
#~ msgstr "errore interno: non ho potuto aggiungere un elemento alla lista"
+#~ msgid "attempt to assign sequence of size %d to extended slice of size %d"
+#~ msgstr "tentativo di assegnare sequenza di dimensione %d a un intervallo "
+#~ " esteso di dimensione %d"
+
+#~ msgid "failed to add item to list"
+#~ msgstr "non ho potuto aggiungere un elemento alla lista"
+
#~ msgid "cannot delete vim.List attributes"
#~ msgstr "non riesco a cancellare gli attributi vim.List"
diff --git a/src/nvim/pos.h b/src/nvim/pos.h
index 7071df51e8..864f3fe866 100644
--- a/src/nvim/pos.h
+++ b/src/nvim/pos.h
@@ -2,7 +2,11 @@
#define NVIM_POS_H
typedef long linenr_T; // line number type
-typedef int colnr_T; // column number type
+
+/// Column number type
+typedef int colnr_T;
+/// Format used to print values which have colnr_T type
+#define PRIdCOLNR "d"
#define MAXLNUM 0x7fffffff // maximum (invalid) line number
#define MAXCOL 0x7fffffff // maximum column number, 31 bits
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index f3abf864fb..17cb8a86aa 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -39,7 +39,6 @@
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
-#include "nvim/tempfile.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
@@ -200,9 +199,8 @@ qf_init_ext (
char_u *pattern;
char_u *fmtstr = NULL;
int col = 0;
- char_u use_viscol = FALSE;
- int type = 0;
- int valid;
+ bool use_viscol = false;
+ char_u type = 0;
linenr_T buflnum = lnumfirst;
long lnum = 0L;
int enr = 0;
@@ -220,16 +218,16 @@ qf_init_ext (
int i;
int round;
int idx = 0;
- int multiline = FALSE;
- int multiignore = FALSE;
- int multiscan = FALSE;
- int retval = -1; /* default: return error flag */
- char_u *directory = NULL;
- char_u *currfile = NULL;
- char_u *tail = NULL;
- char_u *p_str = NULL;
- listitem_T *p_li = NULL;
- struct dir_stack_T *file_stack = NULL;
+ bool multiline = false;
+ bool multiignore = false;
+ bool multiscan = false;
+ int retval = -1; // default: return error flag
+ char_u *directory = NULL;
+ char_u *currfile = NULL;
+ char_u *tail = NULL;
+ char_u *p_str = NULL;
+ listitem_T *p_li = NULL;
+ struct dir_stack_T *file_stack = NULL;
regmatch_T regmatch;
static struct fmtpattern {
char_u convchar;
@@ -278,15 +276,16 @@ qf_init_ext (
/*
* Get some space to modify the format string into.
*/
- i = 3 * FMT_PATTERNS + 4 * (int)STRLEN(efm);
- for (round = FMT_PATTERNS; round > 0; )
- i += (int)STRLEN(fmt_pat[--round].pattern);
+ size_t fmtstr_size = 3 * FMT_PATTERNS + 4 * STRLEN(efm);
+ for (round = FMT_PATTERNS; round > 0; ) {
+ fmtstr_size += STRLEN(fmt_pat[--round].pattern);
+ }
#ifdef COLON_IN_FILENAME
- i += 12; /* "%f" can become twelve chars longer */
+ fmtstr_size += 12; // "%f" can become twelve chars longer
#else
- i += 2; /* "%f" can become two chars longer */
+ fmtstr_size += 2; // "%f" can become two chars longer
#endif
- fmtstr = xmalloc(i);
+ fmtstr = xmalloc(fmtstr_size);
while (efm[0] != NUL) {
/*
@@ -530,11 +529,9 @@ qf_init_ext (
fmt_start = NULL;
}
- /*
- * Try to match each part of 'errorformat' until we find a complete
- * match or no match.
- */
- valid = TRUE;
+ // Try to match each part of 'errorformat' until we find a complete
+ // match or no match.
+ bool valid = true;
restofline:
for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) {
idx = fmt_ptr->prefix;
@@ -546,7 +543,7 @@ restofline:
errmsg[0] = NUL;
lnum = 0;
col = 0;
- use_viscol = FALSE;
+ use_viscol = false;
enr = -1;
type = 0;
tail = NULL;
@@ -555,25 +552,23 @@ restofline:
int r = vim_regexec(&regmatch, IObuff, (colnr_T)0);
fmt_ptr->prog = regmatch.regprog;
if (r) {
- if ((idx == 'C' || idx == 'Z') && !multiline)
+ if ((idx == 'C' || idx == 'Z') && !multiline) {
continue;
- if (vim_strchr((char_u *)"EWI", idx) != NULL)
- type = idx;
- else
+ }
+ if (vim_strchr((char_u *)"EWI", idx) != NULL) {
+ type = (char_u)idx;
+ } else {
type = 0;
- /*
- * Extract error message data from matched line.
- * We check for an actual submatch, because "\[" and "\]" in
- * the 'errorformat' may cause the wrong submatch to be used.
- */
- if ((i = (int)fmt_ptr->addr[0]) > 0) { /* %f */
- int c;
-
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
+ }
+ // Extract error message data from matched line.
+ // We check for an actual submatch, because "\[" and "\]" in
+ // the 'errorformat' may cause the wrong submatch to be used.
+ if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) {
continue;
-
- /* Expand ~/file and $HOME/file to full path. */
- c = *regmatch.endp[i];
+ }
+ // Expand ~/file and $HOME/file to full path.
+ char_u c = *regmatch.endp[i];
*regmatch.endp[i] = NUL;
expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE);
*regmatch.endp[i] = c;
@@ -629,14 +624,14 @@ restofline:
col -= col % 8;
}
}
- ++col;
- use_viscol = TRUE;
+ col++;
+ use_viscol = true;
}
if ((i = (int)fmt_ptr->addr[8]) > 0) { /* %v */
if (regmatch.startp[i] == NULL)
continue;
col = (int)atol((char *)regmatch.startp[i]);
- use_viscol = TRUE;
+ use_viscol = true;
}
if ((i = (int)fmt_ptr->addr[9]) > 0) { /* %s */
if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL)
@@ -653,7 +648,7 @@ restofline:
break;
}
}
- multiscan = FALSE;
+ multiscan = false;
if (fmt_ptr == NULL || idx == 'D' || idx == 'X') {
if (fmt_ptr != NULL) {
@@ -667,20 +662,21 @@ restofline:
} else if (idx == 'X') /* leave directory */
directory = qf_pop_dir(&dir_stack);
}
- namebuf[0] = NUL; /* no match found, remove file name */
- lnum = 0; /* don't jump to this line */
- valid = FALSE;
- STRCPY(errmsg, IObuff); /* copy whole line to error message */
- if (fmt_ptr == NULL)
- multiline = multiignore = FALSE;
+ namebuf[0] = NUL; // no match found, remove file name
+ lnum = 0; // don't jump to this line
+ valid = false;
+ STRCPY(errmsg, IObuff); // copy whole line to error message
+ if (fmt_ptr == NULL) {
+ multiline = multiignore = false;
+ }
} else if (fmt_ptr != NULL) {
/* honor %> item */
if (fmt_ptr->conthere)
fmt_start = fmt_ptr;
if (vim_strchr((char_u *)"AEWI", idx) != NULL) {
- multiline = TRUE; /* start of a multi-line message */
- multiignore = FALSE; /* reset continuation */
+ multiline = true; // start of a multi-line message
+ multiignore = false; // reset continuation
} else if (vim_strchr((char_u *)"CZ", idx)
!= NULL) { /* continuation of multi-line msg */
if (qfprev == NULL)
@@ -702,15 +698,17 @@ restofline:
qfprev->qf_viscol = use_viscol;
if (!qfprev->qf_fnum)
qfprev->qf_fnum = qf_get_fnum(directory,
- *namebuf || directory ? namebuf
- : currfile && valid ? currfile : 0);
- if (idx == 'Z')
- multiline = multiignore = FALSE;
+ *namebuf
+ || directory ? namebuf : currfile
+ && valid ? currfile : 0);
+ if (idx == 'Z') {
+ multiline = multiignore = false;
+ }
line_breakcheck();
continue;
} else if (vim_strchr((char_u *)"OPQ", idx) != NULL) {
- /* global file names */
- valid = FALSE;
+ // global file names
+ valid = false;
if (*namebuf == NUL || os_file_exists(namebuf)) {
if (*namebuf && idx == 'P')
currfile = qf_push_dir(namebuf, &file_stack);
@@ -719,14 +717,15 @@ restofline:
*namebuf = NUL;
if (tail && *tail) {
STRMOVE(IObuff, skipwhite(tail));
- multiscan = TRUE;
+ multiscan = true;
goto restofline;
}
}
}
- if (fmt_ptr->flags == '-') { /* generally exclude this line */
- if (multiline)
- multiignore = TRUE; /* also exclude continuation lines */
+ if (fmt_ptr->flags == '-') { // generally exclude this line
+ if (multiline) {
+ multiignore = true; // also exclude continuation lines
+ }
continue;
}
}
@@ -867,26 +866,27 @@ void qf_free_all(win_T *wp)
qf_free(qi, i);
}
-/*
- * Add an entry to the end of the list of errors.
- * Returns OK or FAIL.
- */
-static int
-qf_add_entry (
- qf_info_T *qi, /* quickfix list */
- qfline_T **prevp, /* nonnull pointer (to previously added entry or NULL) */
- char_u *dir, /* optional directory name */
- char_u *fname, /* file name or NULL */
- int bufnum, /* buffer number or zero */
- char_u *mesg, /* message */
- long lnum, /* line number */
- int col, /* column */
- int vis_col, /* using visual column */
- char_u *pattern, /* search pattern */
- int nr, /* error number */
- int type, /* type character */
- int valid /* valid entry */
-)
+/// Add an entry to the end of the list of errors.
+///
+/// @param qi quickfix list
+/// @param prevp nonnull pointer (to previously added entry or NULL)
+/// @param dir optional directory name
+/// @param fname file name or NULL
+/// @param bufnum buffer number or zero
+/// @param mesg message
+/// @param lnum line number
+/// @param col column
+/// @param vis_col using visual column
+/// @param pattern search pattern
+/// @param nr error number
+/// @param type type character
+/// @param valid valid entry
+///
+/// @returns OK or FAIL.
+static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir,
+ char_u *fname, int bufnum, char_u *mesg, long lnum,
+ int col, char_u vis_col, char_u *pattern, int nr,
+ char_u type, char_u valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
@@ -1657,12 +1657,13 @@ win_found:
* flag is present in 'shortmess'; But when not jumping, print the
* whole message. */
i = msg_scroll;
- if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
- msg_scroll = TRUE;
- else if (!msg_scrolled && shortmess(SHM_OVERALL))
- msg_scroll = FALSE;
- msg_attr_keep(IObuff, 0, TRUE);
- msg_scroll = i;
+ if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) {
+ msg_scroll = true;
+ } else if (!msg_scrolled && shortmess(SHM_OVERALL)) {
+ msg_scroll = false;
+ }
+ msg_attr_keep(IObuff, 0, true);
+ msg_scroll = (int)i;
}
} else {
if (opened_window)
@@ -1827,10 +1828,12 @@ void qf_age(exarg_T *eap)
}
}
- if (eap->addr_count != 0)
- count = eap->line2;
- else
+ if (eap->addr_count != 0) {
+ assert(eap->line2 <= INT_MAX);
+ count = (int)eap->line2;
+ } else {
count = 1;
+ }
while (count--) {
if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder) {
if (qi->qf_curlist == 0) {
@@ -1882,6 +1885,8 @@ static void qf_free(qf_info_T *qi, int idx)
--qi->qf_lists[idx].qf_count;
}
xfree(qi->qf_lists[idx].qf_title);
+ qi->qf_lists[idx].qf_start = NULL;
+ qi->qf_lists[idx].qf_ptr = NULL;
qi->qf_lists[idx].qf_title = NULL;
qi->qf_lists[idx].qf_index = 0;
}
@@ -1948,7 +1953,7 @@ static char_u *qf_types(int c, int nr)
p = (char_u *)"";
else {
cc[0] = ' ';
- cc[1] = c;
+ cc[1] = (char_u)c;
cc[2] = NUL;
p = cc;
}
@@ -2036,12 +2041,13 @@ void ex_copen(exarg_T *eap)
}
}
- if (eap->addr_count != 0)
- height = eap->line2;
- else
+ if (eap->addr_count != 0) {
+ assert(eap->line2 <= INT_MAX);
+ height = (int)eap->line2;
+ } else {
height = QF_WINHEIGHT;
-
- reset_VIsual_and_resel(); /* stop Visual mode */
+ }
+ reset_VIsual_and_resel(); // stop Visual mode
/*
* Find existing quickfix window, or open a new one.
@@ -2299,13 +2305,15 @@ static void qf_fill_buffer(qf_info_T *qi)
if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
- if (qfp->qf_type == 1) /* :helpgrep */
- STRCPY(IObuff, path_tail(errbuf->b_fname));
- else
- STRCPY(IObuff, errbuf->b_fname);
+ if (qfp->qf_type == 1) { // :helpgrep
+ STRLCPY(IObuff, path_tail(errbuf->b_fname), sizeof(IObuff));
+ } else {
+ STRLCPY(IObuff, errbuf->b_fname, sizeof(IObuff));
+ }
len = (int)STRLEN(IObuff);
- } else
+ } else {
len = 0;
+ }
IObuff[len++] = '|';
if (qfp->qf_lnum > 0) {
@@ -2431,8 +2439,6 @@ int grep_internal(cmdidx_T cmdidx)
void ex_make(exarg_T *eap)
{
char_u *fname;
- char_u *cmd;
- unsigned len;
win_T *wp = NULL;
qf_info_T *qi = &ql_info;
int res;
@@ -2470,29 +2476,28 @@ void ex_make(exarg_T *eap)
return;
os_remove((char *)fname); // in case it's not unique
- /*
- * If 'shellpipe' empty: don't redirect to 'errorfile'.
- */
- len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1;
- if (*p_sp != NUL)
- len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
- cmd = xmalloc(len);
- sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg,
- (char *)p_shq);
- if (*p_sp != NUL)
- append_redir(cmd, len, p_sp, fname);
- /*
- * Output a newline if there's something else than the :make command that
- * was typed (in which case the cursor is in column 0).
- */
- if (msg_col == 0)
- msg_didout = FALSE;
+ // If 'shellpipe' empty: don't redirect to 'errorfile'.
+ const size_t len = (STRLEN(p_shq) * 2 + STRLEN(eap->arg) + 1
+ + (*p_sp == NUL
+ ? 0
+ : STRLEN(p_sp) + STRLEN(fname) + 3));
+ char *const cmd = xmalloc(len);
+ snprintf(cmd, len, "%s%s%s", (char *)p_shq, (char *)eap->arg,
+ (char *)p_shq);
+ if (*p_sp != NUL) {
+ append_redir(cmd, len, (char *) p_sp, (char *) fname);
+ }
+ // Output a newline if there's something else than the :make command that
+ // was typed (in which case the cursor is in column 0).
+ if (msg_col == 0) {
+ msg_didout = false;
+ }
msg_start();
MSG_PUTS(":!");
- msg_outtrans(cmd); /* show what we are doing */
+ msg_outtrans((char_u *) cmd); // show what we are doing
- /* let the shell know if we are redirecting output or not */
- do_shell(cmd, *p_sp != NUL ? kShellOptDoOut : 0);
+ // let the shell know if we are redirecting output or not
+ do_shell((char_u *) cmd, *p_sp != NUL ? kShellOptDoOut : 0);
res = qf_init(wp, fname, (eap->cmdidx != CMD_make
@@ -2546,11 +2551,11 @@ static char_u *get_mef_name(void)
/* Keep trying until the name doesn't exist yet. */
for (;; ) {
- if (start == -1)
- start = os_get_pid();
- else
+ if (start == -1) {
+ start = (int)os_get_pid();
+ } else {
off += 19;
-
+ }
name = xmalloc(STRLEN(p_mef) + 30);
STRCPY(name, p_mef);
sprintf((char *)name + (p - p_mef), "%d%d", start, off);
@@ -2752,8 +2757,8 @@ void ex_cc(exarg_T *eap)
// For cdo and ldo commands, jump to the nth valid error.
// For cfdo and lfdo commands, jump to the nth valid file entry.
- if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
- eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
+ if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+ || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
size_t n;
if (eap->addr_count > 0) {
assert(eap->line1 >= 0);
@@ -2796,9 +2801,9 @@ void ex_cnext(exarg_T *eap)
}
int errornr;
- if (eap->addr_count > 0 &&
- (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo &&
- eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) {
+ if (eap->addr_count > 0
+ && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo
+ && eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo)) {
errornr = (int)eap->line2;
} else {
errornr = 1;
@@ -2897,7 +2902,7 @@ void ex_vimgrep(exarg_T *eap)
int found_match;
buf_T *first_match_buf = NULL;
time_t seconds = 0;
- int save_mls;
+ long save_mls;
char_u *save_ei = NULL;
aco_save_T aco;
int flags = 0;
@@ -2967,16 +2972,18 @@ void ex_vimgrep(exarg_T *eap)
goto theend;
}
- if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd &&
- eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd)
- || qi->qf_curlist == qi->qf_listcount)
- /* make place for a new list */
+ if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
+ && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd)
+ || qi->qf_curlist == qi->qf_listcount) {
+ // make place for a new list
qf_new_list(qi, *eap->cmdlinep);
- else if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
- /* Adding to existing list, find last entry. */
+ } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
+ // Adding to existing list, find last entry.
for (prevp = qi->qf_lists[qi->qf_curlist].qf_start;
- prevp->qf_next != prevp; prevp = prevp->qf_next)
- ;
+ prevp->qf_next != prevp;
+ prevp = prevp->qf_next) {
+ }
+ }
/* parse the list of arguments */
if (get_arglist_exp(p, &fcount, &fnames, true) == FAIL)
@@ -3454,18 +3461,12 @@ int get_errorlist(win_T *wp, list_T *list)
*/
int set_errorlist(win_T *wp, list_T *list, int action, char_u *title)
{
- listitem_T *li;
- dict_T *d;
- char_u *filename, *pattern, *text, *type;
- int bufnum;
- long lnum;
- int col, nr;
- int vcol;
- qfline_T *prevp = NULL;
- int valid, status;
+ listitem_T *li;
+ dict_T *d;
+ qfline_T *prevp = NULL;
int retval = OK;
- qf_info_T *qi = &ql_info;
- int did_bufnr_emsg = FALSE;
+ qf_info_T *qi = &ql_info;
+ bool did_bufnr_emsg = false;
if (wp != NULL) {
qi = ll_get_or_alloc_list(wp);
@@ -3492,21 +3493,22 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title)
if (d == NULL)
continue;
- filename = get_dict_string(d, (char_u *)"filename", TRUE);
- bufnum = get_dict_number(d, (char_u *)"bufnr");
- lnum = get_dict_number(d, (char_u *)"lnum");
- col = get_dict_number(d, (char_u *)"col");
- vcol = get_dict_number(d, (char_u *)"vcol");
- nr = get_dict_number(d, (char_u *)"nr");
- type = get_dict_string(d, (char_u *)"type", TRUE);
- pattern = get_dict_string(d, (char_u *)"pattern", TRUE);
- text = get_dict_string(d, (char_u *)"text", TRUE);
- if (text == NULL)
+ char_u *filename = get_dict_string(d, (char_u *)"filename", true);
+ int bufnum = (int)get_dict_number(d, (char_u *)"bufnr");
+ long lnum = get_dict_number(d, (char_u *)"lnum");
+ int col = (int)get_dict_number(d, (char_u *)"col");
+ char_u vcol = (char_u)get_dict_number(d, (char_u *)"vcol");
+ int nr = (int)get_dict_number(d, (char_u *)"nr");
+ char_u *type = get_dict_string(d, (char_u *)"type", true);
+ char_u *pattern = get_dict_string(d, (char_u *)"pattern", true);
+ char_u *text = get_dict_string(d, (char_u *)"text", true);
+ if (text == NULL) {
text = vim_strsave((char_u *)"");
-
- valid = TRUE;
- if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL))
- valid = FALSE;
+ }
+ bool valid = true;
+ if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) {
+ valid = false;
+ }
/* Mark entries with non-existing buffer number as not valid. Give the
* error message only once. */
@@ -3515,22 +3517,23 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title)
did_bufnr_emsg = TRUE;
EMSGN(_("E92: Buffer %" PRId64 " not found"), bufnum);
}
- valid = FALSE;
+ valid = false;
bufnum = 0;
}
- status = qf_add_entry(qi, &prevp,
- NULL, /* dir */
- filename,
- bufnum,
- text,
- lnum,
- col,
- vcol, /* vis_col */
- pattern, /* search pattern */
- nr,
- type == NULL ? NUL : *type,
- valid);
+ int status = qf_add_entry(qi,
+ &prevp,
+ NULL, // dir
+ filename,
+ bufnum,
+ text,
+ lnum,
+ col,
+ vcol, // vis_col
+ pattern, // search pattern
+ nr,
+ (char_u)(type == NULL ? NUL : *type),
+ valid);
xfree(filename);
xfree(pattern);
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 608aa38466..886a48e7c5 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -3445,13 +3445,14 @@ static long bt_regexec_both(char_u *line,
c = regline[col];
if (prog->regstart == NUL
|| prog->regstart == c
- || (ireg_ic && ((
- (enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
- || (c < 255 && prog->regstart < 255 &&
- vim_tolower(prog->regstart) == vim_tolower(c)))))
+ || (ireg_ic
+ && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
+ || (c < 255 && prog->regstart < 255
+ && vim_tolower(prog->regstart) == vim_tolower(c))))) {
retval = regtry(prog, col);
- else
+ } else {
retval = 0;
+ }
} else {
int tm_count = 0;
/* Messy cases: unanchored match. */
@@ -4121,15 +4122,15 @@ regmatch (
char_u *opnd;
opnd = OPERAND(scan);
- /* Inline the first byte, for speed. */
+ // Inline the first byte, for speed.
if (*opnd != *reginput
- && (!ireg_ic || (
- !enc_utf8 &&
- vim_tolower(*opnd) != vim_tolower(*reginput))))
+ && (!ireg_ic
+ || (!enc_utf8
+ && vim_tolower(*opnd) != vim_tolower(*reginput)))) {
status = RA_NOMATCH;
- else if (*opnd == NUL) {
- /* match empty string always works; happens when "~" is
- * empty. */
+ } else if (*opnd == NUL) {
+ // match empty string always works; happens when "~" is
+ // empty.
} else {
if (opnd[1] == NUL && !(enc_utf8 && ireg_ic)) {
len = 1; /* matched a single byte above */
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index e2849fb17a..7e53b2ccd1 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -3464,13 +3464,12 @@ static char *pim_info(nfa_pim_T *pim)
#endif
-/* Used during execution: whether a match has been found. */
+// Used during execution: whether a match has been found.
static int nfa_match;
+static proftime_T *nfa_time_limit;
+static int nfa_time_count;
-
-/*
- * Copy postponed invisible match info from "from" to "to".
- */
+// Copy postponed invisible match info from "from" to "to".
static void copy_pim(nfa_pim_T *to, nfa_pim_T *from)
{
to->result = from->result;
@@ -4566,7 +4565,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T
if (log_fd != NULL) {
fprintf(log_fd, "****************************\n");
fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
- fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE");
+ fprintf(log_fd, "MATCH = %s\n", !result ? "FALSE" : "OK");
fprintf(log_fd, "****************************\n");
} else {
EMSG(_(
@@ -4778,8 +4777,8 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
int c2_len = PTR2LEN(s2);
int c2 = PTR2CHAR(s2);
- if ((c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2))) ||
- c1_len != c2_len) {
+ if ((c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2)))
+ || c1_len != c2_len) {
match = false;
break;
}
@@ -4813,22 +4812,21 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
#undef PTR2LEN
}
-/*
- * Main matching routine.
- *
- * Run NFA to determine whether it matches reginput.
- *
- * When "nfa_endp" is not NULL it is a required end-of-match position.
- *
- * Return TRUE if there is a match, FALSE otherwise.
- * When there is a match "submatch" contains the positions.
- * Note: Caller must ensure that: start != NULL.
- */
-static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *submatch, regsubs_T *m)
+/// Main matching routine.
+///
+/// Run NFA to determine whether it matches reginput.
+///
+/// When "nfa_endp" is not NULL it is a required end-of-match position.
+///
+/// Return TRUE if there is a match, FALSE otherwise.
+/// When there is a match "submatch" contains the positions.
+/// Note: Caller must ensure that: start != NULL.
+static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
+ regsubs_T *submatch, regsubs_T *m)
{
int result;
int flag = 0;
- int go_to_nextline = FALSE;
+ bool go_to_nextline = false;
nfa_thread_T *t;
nfa_list_T list[2];
int listidx;
@@ -4845,18 +4843,22 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (debug == NULL) {
EMSG2(_("(NFA) COULD NOT OPEN %s !"), NFA_REGEXP_DEBUG_LOG);
- return FALSE;
+ return false;
}
#endif
- /* Some patterns may take a long time to match, especially when using
- * recursive_regmatch(). Allow interrupting them with CTRL-C. */
+ // Some patterns may take a long time to match, especially when using
+ // recursive_regmatch(). Allow interrupting them with CTRL-C.
fast_breakcheck();
- if (got_int)
- return FALSE;
+ if (got_int) {
+ return false;
+ }
+ if (nfa_time_limit != NULL && profile_passed_limit(*nfa_time_limit)) {
+ return false;
+ }
- nfa_match = FALSE;
+ nfa_match = false;
- /* Allocate memory for the lists of nodes. */
+ // Allocate memory for the lists of nodes.
size_t size = (nstate + 1) * sizeof(nfa_thread_T);
list[0].t = xmalloc(size);
list[0].len = nstate + 1;
@@ -4924,7 +4926,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
}
if (curc == NUL) {
clen = 0;
- go_to_nextline = FALSE;
+ go_to_nextline = false;
}
/* swap lists */
@@ -5007,7 +5009,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (enc_utf8 && !ireg_icombine && utf_iscomposing(curc)) {
break;
}
- nfa_match = TRUE;
+ nfa_match = true;
copy_sub(&submatch->norm, &t->subs.norm);
if (nfa_has_zsubexpr)
copy_sub(&submatch->synt, &t->subs.synt);
@@ -5072,10 +5074,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
fprintf(log_fd, "Match found:\n");
log_subsexpr(m);
#endif
- nfa_match = TRUE;
- /* See comment above at "goto nextchar". */
- if (nextlist->n == 0)
+ nfa_match = true;
+ // See comment above at "goto nextchar".
+ if (nextlist->n == 0) {
clen = 0;
+ }
goto nextchar;
case NFA_START_INVISIBLE:
@@ -5092,8 +5095,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
failure_chance(t->state->out, 0),
failure_chance(t->state->out1->out, 0));
#endif
- /* Do it directly if there already is a PIM or when
- * nfa_postprocess() detected it will work better. */
+ // Do it directly if there already is a PIM or when
+ // nfa_postprocess() detected it will work better.
if (t->pim.result != NFA_PIM_UNUSED
|| t->state->c == NFA_START_INVISIBLE_FIRST
|| t->state->c == NFA_START_INVISIBLE_NEG_FIRST
@@ -5101,42 +5104,40 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
|| t->state->c == NFA_START_INVISIBLE_BEFORE_NEG_FIRST) {
int in_use = m->norm.in_use;
- /* Copy submatch info for the recursive call, opposite
- * of what happens on success below. */
+ // Copy submatch info for the recursive call, opposite
+ // of what happens on success below.
copy_sub_off(&m->norm, &t->subs.norm);
if (nfa_has_zsubexpr)
copy_sub_off(&m->synt, &t->subs.synt);
- /*
- * First try matching the invisible match, then what
- * follows.
- */
- result = recursive_regmatch(t->state, NULL, prog,
- submatch, m, &listids);
+ // First try matching the invisible match, then what
+ // follows.
+ result = recursive_regmatch(t->state, NULL, prog, submatch, m,
+ &listids);
if (result == NFA_TOO_EXPENSIVE) {
nfa_match = result;
goto theend;
}
- /* for \@! and \@<! it is a match when the result is
- * FALSE */
+ // for \@! and \@<! it is a match when the result is
+ // FALSE
if (result != (t->state->c == NFA_START_INVISIBLE_NEG
|| t->state->c == NFA_START_INVISIBLE_NEG_FIRST
|| t->state->c
== NFA_START_INVISIBLE_BEFORE_NEG
|| t->state->c
== NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) {
- /* Copy submatch info from the recursive call */
+ // Copy submatch info from the recursive call
copy_sub_off(&t->subs.norm, &m->norm);
if (nfa_has_zsubexpr)
copy_sub_off(&t->subs.synt, &m->synt);
- /* If the pattern has \ze and it matched in the
- * sub pattern, use it. */
+ // If the pattern has \ze and it matched in the
+ // sub pattern, use it.
copy_ze_off(&t->subs.norm, &m->norm);
- /* t->state->out1 is the corresponding
- * END_INVISIBLE node; Add its out to the current
- * list (zero-width match). */
+ // t->state->out1 is the corresponding
+ // END_INVISIBLE node; Add its out to the current
+ // list (zero-width match).
add_here = true;
add_state = t->state->out1->out;
}
@@ -5144,12 +5145,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
} else {
nfa_pim_T pim;
- /*
- * First try matching what follows. Only if a match
- * is found verify the invisible match matches. Add a
- * nfa_pim_T to the following states, it contains info
- * about the invisible match.
- */
+ // First try matching what follows. Only if a match
+ // is found verify the invisible match matches. Add a
+ // nfa_pim_T to the following states, it contains info
+ // about the invisible match.
pim.state = t->state;
pim.result = NFA_PIM_TODO;
pim.subs.norm.in_use = 0;
@@ -5160,9 +5159,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
} else
pim.end.ptr = reginput;
- /* t->state->out1 is the corresponding END_INVISIBLE
- * node; Add its out to the current list (zero-width
- * match). */
+ // t->state->out1 is the corresponding END_INVISIBLE
+ // node; Add its out to the current list (zero-width
+ // match).
addstate_here(thislist, t->state->out1->out, &t->subs,
&pim, &listidx);
}
@@ -5176,8 +5175,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
int skip_lid = 0;
#endif
- /* There is no point in trying to match the pattern if the
- * output state is not going to be added to the list. */
+ // There is no point in trying to match the pattern if the
+ // output state is not going to be added to the list.
if (state_in_list(nextlist, t->state->out1->out, &t->subs)) {
skip = t->state->out1->out;
#ifdef REGEXP_DEBUG
@@ -5206,15 +5205,16 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
#endif
break;
}
- /* Copy submatch info to the recursive call, opposite of what
- * happens afterwards. */
+ // Copy submatch info to the recursive call, opposite of what
+ // happens afterwards.
copy_sub_off(&m->norm, &t->subs.norm);
- if (nfa_has_zsubexpr)
+ if (nfa_has_zsubexpr) {
copy_sub_off(&m->synt, &t->subs.synt);
+ }
- /* First try matching the pattern. */
- result = recursive_regmatch(t->state, NULL, prog,
- submatch, m, &listids);
+ // First try matching the pattern.
+ result = recursive_regmatch(t->state, NULL, prog, submatch, m,
+ &listids);
if (result == NFA_TOO_EXPENSIVE) {
nfa_match = result;
goto theend;
@@ -5226,36 +5226,38 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
fprintf(log_fd, "NFA_START_PATTERN matches:\n");
log_subsexpr(m);
#endif
- /* Copy submatch info from the recursive call */
+ // Copy submatch info from the recursive call
copy_sub_off(&t->subs.norm, &m->norm);
- if (nfa_has_zsubexpr)
+ if (nfa_has_zsubexpr) {
copy_sub_off(&t->subs.synt, &m->synt);
- /* Now we need to skip over the matched text and then
- * continue with what follows. */
- if (REG_MULTI)
- /* TODO: multi-line match */
+ }
+ // Now we need to skip over the matched text and then
+ // continue with what follows.
+ if (REG_MULTI) {
+ // TODO(RE): multi-line match
bytelen = m->norm.list.multi[0].end_col
- (int)(reginput - regline);
- else
+ } else {
bytelen = (int)(m->norm.list.line[0].end - reginput);
+ }
#ifdef REGEXP_DEBUG
fprintf(log_fd, "NFA_START_PATTERN length: %d\n", bytelen);
#endif
if (bytelen == 0) {
- /* empty match, output of corresponding
- * NFA_END_PATTERN/NFA_SKIP to be used at current
- * position */
+ // empty match, output of corresponding
+ // NFA_END_PATTERN/NFA_SKIP to be used at current
+ // position
add_here = true;
add_state = t->state->out1->out->out;
} else if (bytelen <= clen) {
- /* match current character, output of corresponding
- * NFA_END_PATTERN to be used at next position. */
+ // match current character, output of corresponding
+ // NFA_END_PATTERN to be used at next position.
add_state = t->state->out1->out->out;
add_off = clen;
} else {
- /* skip over the matched characters, set character
- * count in NFA_SKIP */
+ // skip over the matched characters, set character
+ // count in NFA_SKIP
add_state = t->state->out1->out;
add_off = bytelen;
add_count = bytelen - clen;
@@ -5279,23 +5281,25 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
break;
case NFA_BOW:
- result = TRUE;
+ result = true;
- if (curc == NUL)
- result = FALSE;
- else if (has_mbyte) {
+ if (curc == NUL) {
+ result = false;
+ } else if (has_mbyte) {
int this_class;
- /* Get class of current and previous char (if it exists). */
+ // Get class of current and previous char (if it exists).
this_class = mb_get_class_buf(reginput, reg_buf);
- if (this_class <= 1)
- result = FALSE;
- else if (reg_prev_class() == this_class)
- result = FALSE;
+ if (this_class <= 1) {
+ result = false;
+ } else if (reg_prev_class() == this_class) {
+ result = false;
+ }
} else if (!vim_iswordc_buf(curc, reg_buf)
|| (reginput > regline
- && vim_iswordc_buf(reginput[-1], reg_buf)))
- result = FALSE;
+ && vim_iswordc_buf(reginput[-1], reg_buf))) {
+ result = false;
+ }
if (result) {
add_here = true;
add_state = t->state->out;
@@ -5303,22 +5307,24 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
break;
case NFA_EOW:
- result = TRUE;
- if (reginput == regline)
- result = FALSE;
- else if (has_mbyte) {
+ result = true;
+ if (reginput == regline) {
+ result = false;
+ } else if (has_mbyte) {
int this_class, prev_class;
- /* Get class of current and previous char (if it exists). */
+ // Get class of current and previous char (if it exists).
this_class = mb_get_class_buf(reginput, reg_buf);
prev_class = reg_prev_class();
if (this_class == prev_class
- || prev_class == 0 || prev_class == 1)
- result = FALSE;
+ || prev_class == 0 || prev_class == 1) {
+ result = false;
+ }
} else if (!vim_iswordc_buf(reginput[-1], reg_buf)
|| (reginput[0] != NUL
- && vim_iswordc_buf(curc, reg_buf)))
- result = FALSE;
+ && vim_iswordc_buf(curc, reg_buf))) {
+ result = false;
+ }
if (result) {
add_here = true;
add_state = t->state->out;
@@ -5353,30 +5359,31 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
sta = t->state->out;
len = 0;
if (utf_iscomposing(sta->c)) {
- /* Only match composing character(s), ignore base
- * character. Used for ".{composing}" and "{composing}"
- * (no preceding character). */
+ // Only match composing character(s), ignore base
+ // character. Used for ".{composing}" and "{composing}"
+ // (no preceding character).
len += mb_char2len(mc);
}
if (ireg_icombine && len == 0) {
- /* If \Z was present, then ignore composing characters.
- * When ignoring the base character this always matches. */
- if (sta->c != curc)
+ // If \Z was present, then ignore composing characters.
+ // When ignoring the base character this always matches.
+ if (sta->c != curc) {
result = FAIL;
- else
+ } else {
result = OK;
- while (sta->c != NFA_END_COMPOSING)
+ }
+ while (sta->c != NFA_END_COMPOSING) {
sta = sta->out;
- }
- /* Check base character matches first, unless ignored. */
- else if (len > 0 || mc == sta->c) {
+ }
+ } else if (len > 0 || mc == sta->c) {
+ // Check base character matches first, unless ignored.
if (len == 0) {
len += mb_char2len(mc);
sta = sta->out;
}
- /* We don't care about the order of composing characters.
- * Get them into cchars[] first. */
+ // We don't care about the order of composing characters.
+ // Get them into cchars[] first.
while (len < clen) {
mc = mb_ptr2char(reginput + len);
cchars[ccount++] = mc;
@@ -5385,9 +5392,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
break;
}
- /* Check that each composing char in the pattern matches a
- * composing char in the text. We do not check if all
- * composing chars are matched. */
+ // Check that each composing char in the pattern matches a
+ // composing char in the text. We do not check if all
+ // composing chars are matched.
result = OK;
while (sta->c != NFA_END_COMPOSING) {
for (j = 0; j < ccount; ++j)
@@ -5402,7 +5409,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
} else
result = FAIL;
- end = t->state->out1; /* NFA_END_COMPOSING */
+ end = t->state->out1; // NFA_END_COMPOSING
ADD_STATE_IF_MATCH(end);
break;
}
@@ -5410,13 +5417,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
case NFA_NEWL:
if (curc == NUL && !reg_line_lbr && REG_MULTI
&& reglnum <= reg_maxline) {
- go_to_nextline = TRUE;
- /* Pass -1 for the offset, which means taking the position
- * at the start of the next line. */
+ go_to_nextline = true;
+ // Pass -1 for the offset, which means taking the position
+ // at the start of the next line.
add_state = t->state->out;
add_off = -1;
} else if (curc == '\n' && reg_line_lbr) {
- /* match \n as if it is an ordinary character */
+ // match \n as if it is an ordinary character
add_state = t->state->out;
add_off = 1;
}
@@ -5425,16 +5432,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
case NFA_START_COLL:
case NFA_START_NEG_COLL:
{
- /* What follows is a list of characters, until NFA_END_COLL.
- * One of them must match or none of them must match. */
+ // What follows is a list of characters, until NFA_END_COLL.
+ // One of them must match or none of them must match.
nfa_state_T *state;
int result_if_matched;
int c1, c2;
- /* Never match EOL. If it's part of the collection it is added
- * as a separate state with an OR. */
- if (curc == NUL)
+ // Never match EOL. If it's part of the collection it is added
+ // as a separate state with an OR.
+ if (curc == NUL) {
break;
+ }
state = t->state->out;
result_if_matched = (t->state->c == NFA_START_COLL);
@@ -5445,7 +5453,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
}
if (state->c == NFA_RANGE_MIN) {
c1 = state->val;
- state = state->out; /* advance to NFA_RANGE_MAX */
+ state = state->out; // advance to NFA_RANGE_MAX
c2 = state->val;
#ifdef REGEXP_DEBUG
fprintf(log_fd, "NFA_RANGE_MIN curc=%d c1=%d c2=%d\n",
@@ -5478,8 +5486,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
state = state->out;
}
if (result) {
- /* next state is in out of the NFA_END_COLL, out1 of
- * START points to the END state */
+ // next state is in out of the NFA_END_COLL, out1 of
+ // START points to the END state
add_state = t->state->out1->out;
add_off = clen;
}
@@ -5487,7 +5495,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
}
case NFA_ANY:
- /* Any char except '\0', (end of input) does not match. */
+ // Any char except '\0', (end of input) does not match.
if (curc > 0) {
add_state = t->state->out;
add_off = clen;
@@ -5506,157 +5514,155 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
add_state = t->state->out;
break;
- /*
- * Character classes like \a for alpha, \d for digit etc.
- */
- case NFA_IDENT: /* \i */
+ // Character classes like \a for alpha, \d for digit etc.
+ case NFA_IDENT: // \i
result = vim_isIDc(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_SIDENT: /* \I */
+ case NFA_SIDENT: // \I
result = !ascii_isdigit(curc) && vim_isIDc(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_KWORD: /* \k */
+ case NFA_KWORD: // \k
result = vim_iswordp_buf(reginput, reg_buf);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_SKWORD: /* \K */
+ case NFA_SKWORD: // \K
result = !ascii_isdigit(curc)
&& vim_iswordp_buf(reginput, reg_buf);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_FNAME: /* \f */
+ case NFA_FNAME: // \f
result = vim_isfilec(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_SFNAME: /* \F */
+ case NFA_SFNAME: // \F
result = !ascii_isdigit(curc) && vim_isfilec(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_PRINT: /* \p */
+ case NFA_PRINT: // \p
result = vim_isprintc(PTR2CHAR(reginput));
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_SPRINT: /* \P */
+ case NFA_SPRINT: // \P
result = !ascii_isdigit(curc) && vim_isprintc(PTR2CHAR(reginput));
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_WHITE: /* \s */
+ case NFA_WHITE: // \s
result = ascii_iswhite(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NWHITE: /* \S */
+ case NFA_NWHITE: // \S
result = curc != NUL && !ascii_iswhite(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_DIGIT: /* \d */
+ case NFA_DIGIT: // \d
result = ri_digit(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NDIGIT: /* \D */
+ case NFA_NDIGIT: // \D
result = curc != NUL && !ri_digit(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_HEX: /* \x */
+ case NFA_HEX: // \x
result = ri_hex(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NHEX: /* \X */
+ case NFA_NHEX: // \X
result = curc != NUL && !ri_hex(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_OCTAL: /* \o */
+ case NFA_OCTAL: // \o
result = ri_octal(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NOCTAL: /* \O */
+ case NFA_NOCTAL: // \O
result = curc != NUL && !ri_octal(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_WORD: /* \w */
+ case NFA_WORD: // \w
result = ri_word(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NWORD: /* \W */
+ case NFA_NWORD: // \W
result = curc != NUL && !ri_word(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_HEAD: /* \h */
+ case NFA_HEAD: // \h
result = ri_head(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NHEAD: /* \H */
+ case NFA_NHEAD: // \H
result = curc != NUL && !ri_head(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_ALPHA: /* \a */
+ case NFA_ALPHA: // \a
result = ri_alpha(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NALPHA: /* \A */
+ case NFA_NALPHA: // \A
result = curc != NUL && !ri_alpha(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_LOWER: /* \l */
+ case NFA_LOWER: // \l
result = ri_lower(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NLOWER: /* \L */
+ case NFA_NLOWER: // \L
result = curc != NUL && !ri_lower(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_UPPER: /* \u */
+ case NFA_UPPER: // \u
result = ri_upper(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NUPPER: /* \U */
+ case NFA_NUPPER: // \U
result = curc != NUL && !ri_upper(curc);
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_LOWER_IC: /* [a-z] */
+ case NFA_LOWER_IC: // [a-z]
result = ri_lower(curc) || (ireg_ic && ri_upper(curc));
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NLOWER_IC: /* [^a-z] */
+ case NFA_NLOWER_IC: // [^a-z]
result = curc != NUL
&& !(ri_lower(curc) || (ireg_ic && ri_upper(curc)));
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_UPPER_IC: /* [A-Z] */
+ case NFA_UPPER_IC: // [A-Z]
result = ri_upper(curc) || (ireg_ic && ri_lower(curc));
ADD_STATE_IF_MATCH(t->state);
break;
- case NFA_NUPPER_IC: /* ^[A-Z] */
+ case NFA_NUPPER_IC: // [^A-Z]
result = curc != NUL
&& !(ri_upper(curc) || (ireg_ic && ri_lower(curc)));
ADD_STATE_IF_MATCH(t->state);
@@ -5680,7 +5686,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
case NFA_ZREF7:
case NFA_ZREF8:
case NFA_ZREF9:
- /* \1 .. \9 \z1 .. \z9 */
+ // \1 .. \9 \z1 .. \z9
{
int subidx;
int bytelen;
@@ -5695,18 +5701,18 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (result) {
if (bytelen == 0) {
- /* empty match always works, output of NFA_SKIP to be
- * used next */
+ // empty match always works, output of NFA_SKIP to be
+ // used next
add_here = true;
add_state = t->state->out->out;
} else if (bytelen <= clen) {
- /* match current character, jump ahead to out of
- * NFA_SKIP */
+ // match current character, jump ahead to out of
+ // NFA_SKIP
add_state = t->state->out->out;
add_off = clen;
} else {
- /* skip over the matched characters, set character
- * count in NFA_SKIP */
+ // skip over the matched characters, set character
+ // count in NFA_SKIP
add_state = t->state->out;
add_off = bytelen;
add_count = bytelen - clen;
@@ -5715,13 +5721,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
break;
}
case NFA_SKIP:
- /* character of previous matching \1 .. \9 or \@> */
+ // character of previous matching \1 .. \9 or \@>
if (t->count - clen <= 0) {
- /* end of match, go to what follows */
+ // end of match, go to what follows
add_state = t->state->out;
add_off = clen;
} else {
- /* add state again with decremented count */
+ // add state again with decremented count
add_state = t->state;
add_off = 0;
add_count = t->count - clen;
@@ -5773,7 +5779,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
break;
}
- result = FALSE;
+ result = false;
win_T *wp = reg_win == NULL ? curwin : reg_win;
if (op == 1 && col - 1 > t->state->val && col > 100) {
long ts = wp->w_buffer->b_p_ts;
@@ -5803,9 +5809,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
{
pos_T *pos = getmark_buf(reg_buf, t->state->val, FALSE);
- /* Compare the mark position to the match position. */
- result = (pos != NULL /* mark doesn't exist */
- && pos->lnum > 0 /* mark isn't set in reg_buf */
+ // Compare the mark position to the match position.
+ result = (pos != NULL // mark doesn't exist
+ && pos->lnum > 0 // mark isn't set in reg_buf
&& (pos->lnum == reglnum + reg_firstlnum
? (pos->col == (colnr_T)(reginput - regline)
? t->state->c == NFA_MARK
@@ -5862,11 +5868,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
case NFA_ZOPEN9:
case NFA_NOPEN:
case NFA_ZSTART:
- /* These states are only added to be able to bail out when
- * they are added again, nothing is to be done. */
+ // These states are only added to be able to bail out when
+ // they are added again, nothing is to be done.
break;
- default: /* regular character */
+ default: // regular character
{
int c = t->state->c;
@@ -5888,8 +5894,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
ADD_STATE_IF_MATCH(t->state);
break;
}
-
- } /* switch (t->state->c) */
+ } // switch (t->state->c)
if (add_state != NULL) {
nfa_pim_T *pim;
@@ -5900,8 +5905,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
else
pim = &t->pim;
- /* Handle the postponed invisible match if the match might end
- * without advancing and before the end of the line. */
+ // Handle the postponed invisible match if the match might end
+ // without advancing and before the end of the line.
if (pim != NULL && (clen == 0 || match_follows(add_state, 0))) {
if (pim->result == NFA_PIM_TODO) {
#ifdef REGEXP_DEBUG
@@ -5913,15 +5918,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
result = recursive_regmatch(pim->state, pim,
prog, submatch, m, &listids);
pim->result = result ? NFA_PIM_MATCH : NFA_PIM_NOMATCH;
- /* for \@! and \@<! it is a match when the result is
- * FALSE */
+ // for \@! and \@<! it is a match when the result is
+ // FALSE
if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
|| pim->state->c == NFA_START_INVISIBLE_NEG_FIRST
|| pim->state->c
== NFA_START_INVISIBLE_BEFORE_NEG
|| pim->state->c
== NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) {
- /* Copy submatch info from the recursive call */
+ // Copy submatch info from the recursive call
copy_sub_off(&pim->subs.norm, &m->norm);
if (nfa_has_zsubexpr)
copy_sub_off(&pim->subs.synt, &m->synt);
@@ -5934,34 +5939,35 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
log_fd,
"Using previous recursive nfa_regmatch() result, result == %d\n",
pim->result);
- fprintf(log_fd, "MATCH = %s\n", result == TRUE ? "OK" : "FALSE");
+ fprintf(log_fd, "MATCH = %s\n", result ? "OK" : "FALSE");
fprintf(log_fd, "\n");
#endif
}
- /* for \@! and \@<! it is a match when result is FALSE */
+ // for \@! and \@<! it is a match when result is FALSE
if (result != (pim->state->c == NFA_START_INVISIBLE_NEG
|| pim->state->c == NFA_START_INVISIBLE_NEG_FIRST
|| pim->state->c
== NFA_START_INVISIBLE_BEFORE_NEG
|| pim->state->c
== NFA_START_INVISIBLE_BEFORE_NEG_FIRST)) {
- /* Copy submatch info from the recursive call */
+ // Copy submatch info from the recursive call
copy_sub_off(&t->subs.norm, &pim->subs.norm);
if (nfa_has_zsubexpr)
copy_sub_off(&t->subs.synt, &pim->subs.synt);
- } else
- /* look-behind match failed, don't add the state */
+ } else {
+ // look-behind match failed, don't add the state
continue;
+ }
- /* Postponed invisible match was handled, don't add it to
- * following states. */
+ // Postponed invisible match was handled, don't add it to
+ // following states.
pim = NULL;
}
- /* If "pim" points into l->t it will become invalid when
- * adding the state causes the list to be reallocated. Make a
- * local copy to avoid that. */
+ // If "pim" points into l->t it will become invalid when
+ // adding the state causes the list to be reallocated. Make a
+ // local copy to avoid that.
if (pim == &t->pim) {
copy_pim(&pim_copy, pim);
pim = &pim_copy;
@@ -5975,18 +5981,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
nextlist->t[nextlist->n - 1].count = add_count;
}
}
-
- } /* for (thislist = thislist; thislist->state; thislist++) */
-
- /* Look for the start of a match in the current position by adding the
- * start state to the list of states.
- * The first found match is the leftmost one, thus the order of states
- * matters!
- * Do not add the start state in recursive calls of nfa_regmatch(),
- * because recursive calls should only start in the first position.
- * Unless "nfa_endp" is not NULL, then we match the end position.
- * Also don't start a match past the first line. */
- if (nfa_match == FALSE
+ } // for (thislist = thislist; thislist->state; thislist++)
+
+ // Look for the start of a match in the current position by adding the
+ // start state to the list of states.
+ // The first found match is the leftmost one, thus the order of states
+ // matters!
+ // Do not add the start state in recursive calls of nfa_regmatch(),
+ // because recursive calls should only start in the first position.
+ // Unless "nfa_endp" is not NULL, then we match the end position.
+ // Also don't start a match past the first line.
+ if (!nfa_match
&& ((toplevel
&& reglnum == 0
&& clen != 0
@@ -6002,8 +6007,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
#ifdef REGEXP_DEBUG
fprintf(log_fd, "(---) STARTSTATE\n");
#endif
- /* Inline optimized code for addstate() if we know the state is
- * the first MOPEN. */
+ // Inline optimized code for addstate() if we know the state is
+ // the first MOPEN.
if (toplevel) {
int add = TRUE;
int c;
@@ -6012,18 +6017,19 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
if (nextlist->n == 0) {
colnr_T col = (colnr_T)(reginput - regline) + clen;
- /* Nextlist is empty, we can skip ahead to the
- * character that must appear at the start. */
- if (skip_to_start(prog->regstart, &col) == FAIL)
+ // Nextlist is empty, we can skip ahead to the
+ // character that must appear at the start.
+ if (skip_to_start(prog->regstart, &col) == FAIL) {
break;
+ }
#ifdef REGEXP_DEBUG
fprintf(log_fd, " Skipping ahead %d bytes to regstart\n",
col - ((colnr_T)(reginput - regline) + clen));
#endif
reginput = regline + col - clen;
} else {
- /* Checking if the required start character matches is
- * cheaper than adding a state that won't match. */
+ // Checking if the required start character matches is
+ // cheaper than adding a state that won't match.
c = PTR2CHAR(reginput + clen);
if (c != prog->regstart && (!ireg_ic || vim_tolower(c)
!= vim_tolower(prog->regstart))) {
@@ -6060,21 +6066,29 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
#endif
nextchar:
- /* Advance to the next character, or advance to the next line, or
- * finish. */
- if (clen != 0)
+ // Advance to the next character, or advance to the next line, or
+ // finish.
+ if (clen != 0) {
reginput += clen;
- else if (go_to_nextline || (nfa_endp != NULL && REG_MULTI
- && reglnum < nfa_endp->se_u.pos.lnum))
+ } else if (go_to_nextline || (nfa_endp != NULL && REG_MULTI
+ && reglnum < nfa_endp->se_u.pos.lnum)) {
reg_nextline();
- else
+ } else {
break;
+ }
// Allow interrupting with CTRL-C.
- fast_breakcheck();
+ line_breakcheck();
if (got_int) {
break;
}
+ // Check for timeout once every twenty times to avoid overhead.
+ if (nfa_time_limit != NULL && ++nfa_time_count == 20) {
+ nfa_time_count = 0;
+ if (profile_passed_limit(*nfa_time_limit)) {
+ break;
+ }
+ }
}
#ifdef REGEXP_DEBUG
@@ -6084,7 +6098,7 @@ nextchar:
#endif
theend:
- /* Free memory */
+ // Free memory
xfree(list[0].t);
xfree(list[1].t);
xfree(listids);
@@ -6096,11 +6110,9 @@ theend:
return nfa_match;
}
-/*
- * Try match of "prog" with at regline["col"].
- * Returns <= 0 for failure, number of lines contained in the match otherwise.
- */
-static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
+// Try match of "prog" with at regline["col"].
+// Returns <= 0 for failure, number of lines contained in the match otherwise.
+static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
{
int i;
regsubs_T subs, m;
@@ -6110,6 +6122,8 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
#endif
reginput = regline + col;
+ nfa_time_limit = tm;
+ nfa_time_count = 0;
#ifdef REGEXP_DEBUG
f = fopen(NFA_REGEXP_RUN_LOG, "a");
@@ -6134,7 +6148,7 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
clear_sub(&m.synt);
int result = nfa_regmatch(prog, start, &subs, &m);
- if (result == FALSE) {
+ if (!result) {
return 0;
} else if (result == NFA_TOO_EXPENSIVE) {
return result;
@@ -6207,17 +6221,16 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col)
return 1 + reglnum;
}
-/*
- * Match a regexp against a string ("line" points to the string) or multiple
- * lines ("line" is NULL, use reg_getline()).
- *
- * Returns <= 0 for failure, number of lines contained in the match otherwise.
- */
-static long
-nfa_regexec_both (
- char_u *line,
- colnr_T startcol /* column to start looking for match */
-)
+/// Match a regexp against a string ("line" points to the string) or multiple
+/// lines ("line" is NULL, use reg_getline()).
+///
+/// @param line String in which to search or NULL
+/// @param startcol Column to start looking for match
+/// @param tm Timeout limit or NULL
+///
+/// @return <= 0 if there is no match and number of lines contained in the
+/// match otherwise.
+static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
{
nfa_regprog_T *prog;
long retval = 0L;
@@ -6297,7 +6310,7 @@ nfa_regexec_both (
prog->state[i].lastlist[1] = 0;
}
- retval = nfa_regtry(prog, col);
+ retval = nfa_regtry(prog, col, tm);
nfa_regengine.expr = NULL;
@@ -6449,7 +6462,7 @@ nfa_regexec_nl (
ireg_ic = rmp->rm_ic;
ireg_icombine = FALSE;
ireg_maxcol = 0;
- return nfa_regexec_both(line, col);
+ return nfa_regexec_both(line, col, NULL);
}
/// Matches a regexp against multiple lines.
@@ -6500,5 +6513,5 @@ static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
ireg_icombine = FALSE;
ireg_maxcol = rmp->rmm_maxcol;
- return nfa_regexec_both(NULL, col);
+ return nfa_regexec_both(NULL, col, tm);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index cd440fe8dc..10b5b6bba4 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -387,14 +387,15 @@ void update_screen(int type)
if (wp->w_buffer->b_mod_set) {
win_T *wwp;
- /* Check if we already did this buffer. */
- for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)
- if (wwp->w_buffer == wp->w_buffer)
+ // Check if we already did this buffer.
+ for (wwp = firstwin; wwp != wp; wwp = wwp->w_next) {
+ if (wwp->w_buffer == wp->w_buffer) {
break;
- if (
- wwp == wp &&
- syntax_present(wp))
+ }
+ }
+ if (wwp == wp && syntax_present(wp)) {
syn_stack_apply_changes(wp->w_buffer);
+ }
}
}
@@ -1231,16 +1232,16 @@ static void win_update(win_T *wp)
|| did_update == DID_FOLD
|| (did_update == DID_LINE
&& syntax_present(wp)
- && (
- (foldmethodIsSyntax(wp)
- && hasAnyFolding(wp)) ||
- syntax_check_changed(lnum)))
+ && ((foldmethodIsSyntax(wp)
+ && hasAnyFolding(wp))
+ || syntax_check_changed(lnum)))
// match in fixed position might need redraw
// if lines were inserted or deleted
- || (wp->w_match_head != NULL && buf->b_mod_xlines != 0)
- ))))) {
- if (lnum == mod_top)
- top_to_mod = FALSE;
+ || (wp->w_match_head != NULL
+ && buf->b_mod_xlines != 0)))))) {
+ if (lnum == mod_top) {
+ top_to_mod = false;
+ }
/*
* When at start of changed lines: May scroll following lines
@@ -2472,21 +2473,16 @@ win_line (
mb_ptr_adv(ptr);
}
- /* When:
- * - 'cuc' is set, or
- * - 'colorcolumn' is set, or
- * - 'virtualedit' is set, or
- * - the visual mode is active,
- * the end of the line may be before the start of the displayed part.
- */
- if (vcol < v && (
- wp->w_p_cuc
- || draw_color_col
- ||
- virtual_active()
- ||
- (VIsual_active && wp->w_buffer == curwin->w_buffer)
- )) {
+ // When:
+ // - 'cuc' is set, or
+ // - 'colorcolumn' is set, or
+ // - 'virtualedit' is set, or
+ // - the visual mode is active,
+ // the end of the line may be before the start of the displayed part.
+ if (vcol < v && (wp->w_p_cuc
+ || draw_color_col
+ || virtual_active()
+ || (VIsual_active && wp->w_buffer == curwin->w_buffer))) {
vcol = v;
}
@@ -3273,12 +3269,12 @@ win_line (
* contains the @Spell cluster. */
if (has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0;
- if (!attr_pri)
+ if (!attr_pri) {
char_attr = syntax_attr;
- if (c != 0 && (
- !has_syntax ||
- can_spell)) {
- char_u *prev_ptr, *p;
+ }
+ if (c != 0 && (!has_syntax || can_spell)) {
+ char_u *prev_ptr;
+ char_u *p;
int len;
hlf_T spell_hlf = HLF_COUNT;
if (has_mbyte) {
@@ -3607,25 +3603,22 @@ win_line (
wp->w_p_rl ? (col >= 0) :
(col < wp->w_width))) {
c = ' ';
- --ptr; /* put it back at the NUL */
- } else if ((
- diff_hlf != (hlf_T)0 ||
- line_attr != 0
- ) && (
- wp->w_p_rl ? (col >= 0) :
- (col
- - boguscols
- < wp->w_width))) {
- /* Highlight until the right side of the window */
+ ptr--; // put it back at the NUL
+ } else if ((diff_hlf != (hlf_T)0 || line_attr != 0)
+ && (wp->w_p_rl
+ ? (col >= 0)
+ : (col - boguscols < wp->w_width))) {
+ // Highlight until the right side of the window
c = ' ';
- --ptr; /* put it back at the NUL */
+ ptr--; // put it back at the NUL
- /* Remember we do the char for line highlighting. */
- ++did_line_attr;
+ // Remember we do the char for line highlighting.
+ did_line_attr++;
- /* don't do search HL for the rest of the line */
- if (line_attr != 0 && char_attr == search_attr && col > 0)
+ // don't do search HL for the rest of the line
+ if (line_attr != 0 && char_attr == search_attr && col > 0) {
char_attr = line_attr;
+ }
if (diff_hlf == HLF_TXD) {
diff_hlf = HLF_CHD;
if (attr == 0 || char_attr != attr) {
@@ -3639,8 +3632,8 @@ win_line (
}
if (wp->w_p_cole > 0
- && (wp != curwin || lnum != wp->w_cursor.lnum ||
- conceal_cursor_line(wp))
+ && (wp != curwin || lnum != wp->w_cursor.lnum
+ || conceal_cursor_line(wp))
&& ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc)
&& !(lnum_in_visual_area
&& vim_strchr(wp->w_p_cocu, 'v') == NULL)) {
@@ -3700,9 +3693,13 @@ win_line (
&& wp == curwin && lnum == wp->w_cursor.lnum
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= vcol + n_skip) {
- wp->w_wcol = col - boguscols;
+ if (wp->w_p_rl) {
+ wp->w_wcol = wp->w_width - col + boguscols - 1;
+ } else {
+ wp->w_wcol = col - boguscols;
+ }
wp->w_wrow = row;
- did_wcol = TRUE;
+ did_wcol = true;
}
/* Don't override visual selection highlighting. */
@@ -6780,8 +6777,8 @@ int showmode(void)
if (Recording
&& edit_submode == NULL /* otherwise it gets too long */
) {
- MSG_PUTS_ATTR(_("recording"), attr);
- need_clear = TRUE;
+ recording_mode(attr);
+ need_clear = true;
}
mode_displayed = TRUE;
@@ -6820,26 +6817,33 @@ static void msg_pos_mode(void)
msg_row = Rows - 1;
}
-/*
- * Delete mode message. Used when ESC is typed which is expected to end
- * Insert mode (but Insert mode didn't end yet!).
- * Caller should check "mode_displayed".
- */
-void unshowmode(int force)
+/// Delete mode message. Used when ESC is typed which is expected to end
+/// Insert mode (but Insert mode didn't end yet!).
+/// Caller should check "mode_displayed".
+void unshowmode(bool force)
{
- /*
- * Don't delete it right now, when not redrawing or inside a mapping.
- */
- if (!redrawing() || (!force && char_avail() && !KeyTyped))
- redraw_cmdline = TRUE; /* delete mode later */
- else {
+ // Don't delete it right now, when not redrawing or inside a mapping.
+ if (!redrawing() || (!force && char_avail() && !KeyTyped)) {
+ redraw_cmdline = true; // delete mode later
+ } else {
msg_pos_mode();
- if (Recording)
- MSG_PUTS_ATTR(_("recording"), hl_attr(HLF_CM));
+ if (Recording) {
+ recording_mode(hl_attr(HLF_CM));
+ }
msg_clr_eos();
}
}
+static void recording_mode(int attr)
+{
+ MSG_PUTS_ATTR(_("recording"), attr);
+ if (!shortmess(SHM_RECORDING)) {
+ char_u s[4];
+ vim_snprintf((char *)s, ARRAY_SIZE(s), " @%c", Recording);
+ MSG_PUTS_ATTR(s, attr);
+ }
+}
+
/*
* Draw the tab pages line at the top of the Vim window.
*/
diff --git a/src/nvim/search.c b/src/nvim/search.c
index fffae1ecb2..6e2b69fff7 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -453,25 +453,24 @@ void last_pat_prog(regmmatch_T *regmatch)
--emsg_off;
}
-/*
- * lowest level search function.
- * Search for 'count'th occurrence of pattern 'pat' in direction 'dir'.
- * Start at position 'pos' and return the found position in 'pos'.
- *
- * if (options & SEARCH_MSG) == 0 don't give any messages
- * if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
- * if (options & SEARCH_MSG) == SEARCH_MSG give all messages
- * if (options & SEARCH_HIS) put search pattern in history
- * if (options & SEARCH_END) return position at end of match
- * if (options & SEARCH_START) accept match at pos itself
- * if (options & SEARCH_KEEP) keep previous search pattern
- * if (options & SEARCH_FOLD) match only once in a closed fold
- * if (options & SEARCH_PEEK) check for typed char, cancel search
- *
- * Return FAIL (zero) for failure, non-zero for success.
- * Returns the index of the first matching
- * subpattern plus one; one if there was none.
- */
+/// lowest level search function.
+/// Search for 'count'th occurrence of pattern 'pat' in direction 'dir'.
+/// Start at position 'pos' and return the found position in 'pos'.
+///
+/// if (options & SEARCH_MSG) == 0 don't give any messages
+/// if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
+/// if (options & SEARCH_MSG) == SEARCH_MSG give all messages
+/// if (options & SEARCH_HIS) put search pattern in history
+/// if (options & SEARCH_END) return position at end of match
+/// if (options & SEARCH_START) accept match at pos itself
+/// if (options & SEARCH_KEEP) keep previous search pattern
+/// if (options & SEARCH_FOLD) match only once in a closed fold
+/// if (options & SEARCH_PEEK) check for typed char, cancel search
+/// if (options & SEARCH_COL) start at pos->col instead of zero
+///
+/// @returns FAIL (zero) for failure, non-zero for success.
+/// the index of the first matching
+/// subpattern plus one; one if there was none.
int searchit(
win_T *win, /* window to search in, can be NULL for a
buffer without a window! */
@@ -571,16 +570,14 @@ int searchit(
if (tm != NULL && profile_passed_limit(*tm))
break;
- /*
- * Look for a match somewhere in line "lnum".
- */
+ // Look for a match somewhere in line "lnum".
+ colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
nmatched = vim_regexec_multi(&regmatch, win, buf,
- lnum, (colnr_T)0,
- tm
- );
- /* Abort searching on an error (e.g., out of stack). */
- if (called_emsg)
+ lnum, col, tm);
+ // Abort searching on an error (e.g., out of stack).
+ if (called_emsg) {
break;
+ }
if (nmatched > 0) {
/* match may actually be in another line when using \zs */
matchpos = regmatch.startpos[0];
@@ -641,9 +638,9 @@ int searchit(
break;
}
- if (ptr[matchcol] == NUL ||
- (nmatched = vim_regexec_multi(&regmatch, win, buf, lnum,
- matchcol, tm)) == 0) {
+ if (ptr[matchcol] == NUL
+ || (nmatched = vim_regexec_multi(&regmatch, win, buf, lnum,
+ matchcol, tm)) == 0) {
match_ok = false;
break;
}
@@ -881,9 +878,8 @@ static void set_vv_searchforward(void)
set_vim_var_nr(VV_SEARCHFORWARD, (long)(spats[0].off.dir == '/'));
}
-/*
- * Return the number of the first subpat that matched.
- */
+// Return the number of the first subpat that matched.
+// Return zero if none of them matched.
static int first_submatch(regmmatch_T *rp)
{
int submatch;
@@ -1031,19 +1027,18 @@ int do_search(
spats[0].off.line = FALSE;
spats[0].off.end = FALSE;
spats[0].off.off = 0;
- /*
- * Check for a line offset or a character offset.
- * For get_address (echo off) we don't check for a character
- * offset, because it is meaningless and the 's' could be a
- * substitute command.
- */
- if (*p == '+' || *p == '-' || ascii_isdigit(*p))
- spats[0].off.line = TRUE;
- else if ((options & SEARCH_OPT) &&
- (*p == 'e' || *p == 's' || *p == 'b')) {
- if (*p == 'e') /* end */
+ // Check for a line offset or a character offset.
+ // For get_address (echo off) we don't check for a character
+ // offset, because it is meaningless and the 's' could be a
+ // substitute command.
+ if (*p == '+' || *p == '-' || ascii_isdigit(*p)) {
+ spats[0].off.line = true;
+ } else if ((options & SEARCH_OPT)
+ && (*p == 'e' || *p == 's' || *p == 'b')) {
+ if (*p == 'e') { // end
spats[0].off.end = true;
- ++p;
+ }
+ p++;
}
if (ascii_isdigit(*p) || *p == '+' || *p == '-') { /* got an offset */
/* 'nr' or '+nr' or '-nr' */
@@ -1651,8 +1646,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
/*
* Look for matching #if, #else, #elif, or #endif
*/
- if (oap != NULL)
- oap->motion_type = MLINE; /* Linewise for this case only */
+ if (oap != NULL) {
+ oap->motion_type = kMTLineWise; // Linewise for this case only
+ }
if (initc != '#') {
ptr = skipwhite(skipwhite(linep) + 1);
if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0)
@@ -1787,14 +1783,13 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
}
- /*
- * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
- */
- if (pos.col == 0 && (flags & FM_BLOCKSTOP) &&
- (linep[0] == '{' || linep[0] == '}')) {
- if (linep[0] == findc && count == 0) /* match! */
+ // If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
+ if (pos.col == 0 && (flags & FM_BLOCKSTOP)
+ && (linep[0] == '{' || linep[0] == '}')) {
+ if (linep[0] == findc && count == 0) { // match!
return &pos;
- break; /* out of scope */
+ }
+ break; // out of scope
}
if (comment_dir) {
@@ -1963,15 +1958,15 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
if (linep[pos.col - 2] == '\'') {
pos.col -= 2;
break;
- } else if (linep[pos.col - 2] == '\\' &&
- pos.col > 2 && linep[pos.col - 3] == '\'') {
+ } else if (linep[pos.col - 2] == '\\'
+ && pos.col > 2 && linep[pos.col - 3] == '\'') {
pos.col -= 3;
break;
}
}
- } else if (linep[pos.col + 1]) { /* forward search */
- if (linep[pos.col + 1] == '\\' &&
- linep[pos.col + 2] && linep[pos.col + 3] == '\'') {
+ } else if (linep[pos.col + 1]) { // forward search
+ if (linep[pos.col + 1] == '\\'
+ && linep[pos.col + 2] && linep[pos.col + 3] == '\'') {
pos.col += 3;
break;
} else if (linep[pos.col + 2] == '\'') {
@@ -2188,30 +2183,32 @@ int findsent(int dir, long count)
* if on an empty line, skip up to a non-empty line
*/
if (gchar_pos(&pos) == NUL) {
- do
- if ((*func)(&pos) == -1)
+ do {
+ if ((*func)(&pos) == -1) {
break;
- while (gchar_pos(&pos) == NUL);
- if (dir == FORWARD)
+ }
+ } while (gchar_pos(&pos) == NUL);
+ if (dir == FORWARD) {
goto found;
- }
- /*
- * if on the start of a paragraph or a section and searching forward,
- * go to the next line
- */
- else if (dir == FORWARD && pos.col == 0 &&
- startPS(pos.lnum, NUL, FALSE)) {
- if (pos.lnum == curbuf->b_ml.ml_line_count)
+ }
+ // if on the start of a paragraph or a section and searching forward,
+ // go to the next line
+ } else if (dir == FORWARD && pos.col == 0
+ && startPS(pos.lnum, NUL, false)) {
+ if (pos.lnum == curbuf->b_ml.ml_line_count) {
return FAIL;
- ++pos.lnum;
+ }
+ pos.lnum++;
goto found;
- } else if (dir == BACKWARD)
+ } else if (dir == BACKWARD) {
decl(&pos);
+ }
- /* go back to the previous non-blank char */
- found_dot = FALSE;
- while ((c = gchar_pos(&pos)) == ' ' || c == '\t' ||
- (dir == BACKWARD && vim_strchr((char_u *)".!?)]\"'", c) != NULL)) {
+ // go back to the previous non-blank char
+ found_dot = false;
+ while ((c = gchar_pos(&pos)) == ' ' || c == '\t'
+ || (dir == BACKWARD
+ && vim_strchr((char_u *)".!?)]\"'", c) != NULL)) {
if (vim_strchr((char_u *)".!?", c) != NULL) {
/* Only skip over a '.', '!' and '?' once. */
if (found_dot)
@@ -2375,12 +2372,14 @@ int startPS(linenr_T lnum, int para, int both)
char_u *s;
s = ml_get(lnum);
- if (*s == para || *s == '\f' || (both && *s == '}'))
- return TRUE;
- if (*s == '.' && (inmacro(p_sections, s + 1) ||
- (!para && inmacro(p_para, s + 1))))
- return TRUE;
- return FALSE;
+ if (*s == para || *s == '\f' || (both && *s == '}')) {
+ return true;
+ }
+ if (*s == '.' && (inmacro(p_sections, s + 1)
+ || (!para && inmacro(p_para, s + 1)))) {
+ return true;
+ }
+ return false;
}
/*
@@ -2797,7 +2796,7 @@ current_word (
redraw_curbuf_later(INVERTED); /* update the inversion */
} else {
oap->start = start_pos;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
}
--count;
}
@@ -3032,7 +3031,7 @@ extend:
else
oap->inclusive = false;
oap->start = start_pos;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
}
return OK;
}
@@ -3156,7 +3155,7 @@ current_block (
showmode();
} else {
oap->start = start_pos;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
oap->inclusive = false;
if (sol)
incl(&curwin->w_cursor);
@@ -3403,7 +3402,7 @@ again:
showmode();
} else {
oap->start = start_pos;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
if (lt(end_pos, start_pos)) {
/* End is before the start: there is no text between tags; operate
* on an empty area. */
@@ -3568,7 +3567,7 @@ extend:
} else {
oap->start.lnum = start_lnum;
oap->start.col = 0;
- oap->motion_type = MLINE;
+ oap->motion_type = kMTLineWise;
}
curwin->w_cursor.lnum = end_lnum;
curwin->w_cursor.col = 0;
@@ -3810,7 +3809,7 @@ current_quote (
}
} else {
oap->start = curwin->w_cursor;
- oap->motion_type = MCHAR;
+ oap->motion_type = kMTCharWise;
}
/* Set end position. */
@@ -4154,19 +4153,20 @@ find_pattern_in_path (
FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL);
already_searched = FALSE;
if (new_fname != NULL) {
- /* Check whether we have already searched in this file */
+ // Check whether we have already searched in this file
for (i = 0;; i++) {
- if (i == depth + 1)
+ if (i == depth + 1) {
i = old_files;
- if (i == max_path_depth)
+ }
+ if (i == max_path_depth) {
break;
- if (path_full_compare(new_fname, files[i].name, TRUE) & kEqualFiles) {
- if (type != CHECK_PATH &&
- action == ACTION_SHOW_ALL && files[i].matched) {
- msg_putchar('\n'); /* cursor below last one */
- if (!got_int) { /* don't display if 'q'
- typed at "--more--"
- message */
+ }
+ if (path_full_compare(new_fname, files[i].name, true) & kEqualFiles) {
+ if (type != CHECK_PATH
+ && action == ACTION_SHOW_ALL && files[i].matched) {
+ msg_putchar('\n'); // cursor below last one */
+ if (!got_int) { // don't display if 'q' typed at "--more--"
+ // message
msg_home_replace_hl(new_fname);
MSG_PUTS(_(" (includes previously listed match)"));
prev_fname = NULL;
@@ -4181,15 +4181,15 @@ find_pattern_in_path (
}
if (type == CHECK_PATH && (action == ACTION_SHOW_ALL
- || (new_fname == NULL &&
- !already_searched))) {
- if (did_show)
- msg_putchar('\n'); /* cursor below last one */
- else {
- gotocmdline(TRUE); /* cursor at status line */
+ || (new_fname == NULL && !already_searched))) {
+ if (did_show) {
+ msg_putchar('\n'); // cursor below last one
+ } else {
+ gotocmdline(true); // cursor at status line
MSG_PUTS_TITLE(_("--- Included files "));
- if (action != ACTION_SHOW_ALL)
+ if (action != ACTION_SHOW_ALL) {
MSG_PUTS_TITLE(_("not found "));
+ }
MSG_PUTS_TITLE(_("in path ---\n"));
}
did_show = TRUE;
@@ -4348,16 +4348,15 @@ search_line:
&& vim_regexec(&regmatch, line, (colnr_T)(p - line))) {
matched = TRUE;
startp = regmatch.startp[0];
- /*
- * Check if the line is not a comment line (unless we are
- * looking for a define). A line starting with "# define"
- * is not considered to be a comment line.
- */
+ // Check if the line is not a comment line (unless we are
+ // looking for a define). A line starting with "# define"
+ // is not considered to be a comment line.
if (skip_comments) {
- if ((*line != '#' ||
- STRNCMP(skipwhite(line + 1), "define", 6) != 0)
- && get_leader_len(line, NULL, FALSE, TRUE))
- matched = FALSE;
+ if ((*line != '#'
+ || STRNCMP(skipwhite(line + 1), "define", 6) != 0)
+ && get_leader_len(line, NULL, false, true)) {
+ matched = false;
+ }
/*
* Also check for a "/ *" or "/ /" before the match.
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 6947f79d49..d4e40cb287 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -15,19 +15,20 @@
#define ACTION_SHOW_ALL 4
#define ACTION_EXPAND 5
-/* Values for 'options' argument in do_search() and searchit() */
-#define SEARCH_REV 0x01 /* go in reverse of previous dir. */
-#define SEARCH_ECHO 0x02 /* echo the search command and handle options */
-#define SEARCH_MSG 0x0c /* give messages (yes, it's not 0x04) */
-#define SEARCH_NFMSG 0x08 /* give all messages except not found */
-#define SEARCH_OPT 0x10 /* interpret optional flags */
-#define SEARCH_HIS 0x20 /* put search pattern in history */
-#define SEARCH_END 0x40 /* put cursor at end of match */
-#define SEARCH_NOOF 0x80 /* don't add offset to position */
-#define SEARCH_START 0x100 /* start search without col offset */
-#define SEARCH_MARK 0x200 /* set previous context mark */
-#define SEARCH_KEEP 0x400 /* keep previous search pattern */
-#define SEARCH_PEEK 0x800 /* peek for typed char, cancel search */
+// Values for 'options' argument in do_search() and searchit()
+#define SEARCH_REV 0x01 ///< go in reverse of previous dir.
+#define SEARCH_ECHO 0x02 ///< echo the search command and handle options
+#define SEARCH_MSG 0x0c ///< give messages (yes, it's not 0x04)
+#define SEARCH_NFMSG 0x08 ///< give all messages except not found
+#define SEARCH_OPT 0x10 ///< interpret optional flags
+#define SEARCH_HIS 0x20 ///< put search pattern in history
+#define SEARCH_END 0x40 ///< put cursor at end of match
+#define SEARCH_NOOF 0x80 ///< don't add offset to position
+#define SEARCH_START 0x100 ///< start search without col offset
+#define SEARCH_MARK 0x200 ///< set previous context mark
+#define SEARCH_KEEP 0x400 ///< keep previous search pattern
+#define SEARCH_PEEK 0x800 ///< peek for typed char, cancel search
+#define SEARCH_COL 0x1000 ///< start at specified column instead of zero
/* Values for flags argument for findmatchlimit() */
#define FM_BACKWARD 0x01 /* search backwards */
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index def2de9b1a..51c8597d53 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -31,7 +31,6 @@
#include "nvim/misc2.h"
#include "nvim/ex_getln.h"
#include "nvim/search.h"
-#include "nvim/eval.h"
#include "nvim/regexp.h"
#include "nvim/eval_defs.h"
#include "nvim/version.h"
@@ -39,13 +38,15 @@
#include "nvim/fileio.h"
#include "nvim/strings.h"
#include "nvim/quickfix.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/decode.h"
#include "nvim/lib/khash.h"
#include "nvim/lib/kvec.h"
#ifdef HAVE_BE64TOH
# define _BSD_SOURCE 1
# define _DEFAULT_SOURCE 1
-# include <endian.h>
+# include ENDIAN_INCLUDE_FILE
#endif
// Note: when using bufset hash pointers are intentionally casted to uintptr_t
@@ -65,9 +66,6 @@ KHASH_SET_INIT_STR(strset)
((char *) copy_option_part((char_u **) src, (char_u *) dest, __VA_ARGS__))
#define find_shada_parameter(...) \
((const char *) find_shada_parameter(__VA_ARGS__))
-#define emsg2(a, b) emsg2((char_u *) a, (char_u *) b)
-#define emsg3(a, b, c) emsg3((char_u *) a, (char_u *) b, (char_u *) c)
-#define emsgu(a, ...) emsgu((char_u *) a, __VA_ARGS__)
#define home_replace_save(a, b) \
((char *)home_replace_save(a, (char_u *)b))
#define home_replace(a, b, c, d, e) \
@@ -285,7 +283,7 @@ typedef struct {
} history_item;
struct reg {
char name;
- uint8_t type;
+ MotionType type;
char **contents;
size_t contents_size;
size_t width;
@@ -477,7 +475,7 @@ static const ShadaEntry sd_default_values[] = {
.additional_elements = NULL),
DEF_SDE(Register, reg,
.name = NUL,
- .type = MCHAR,
+ .type = kMTCharWise,
.contents = NULL,
.contents_size = 0,
.width = 0,
@@ -761,7 +759,7 @@ static void close_sd_writer(ShaDaWriteDef *const sd_writer)
{
const int fd = (int)(intptr_t) sd_writer->cookie;
if (os_fsync(fd) < 0) {
- emsg2(_(SERR "System error while synchronizing ShaDa file: %s"),
+ emsgf(_(SERR "System error while synchronizing ShaDa file: %s"),
os_strerror(errno));
errno = 0;
}
@@ -811,11 +809,11 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
{
if (sd_reader->skip(sd_reader, offset) != OK) {
if (sd_reader->error != NULL) {
- emsg2(_(SERR "System error while skipping in ShaDa file: %s"),
+ emsgf(_(SERR "System error while skipping in ShaDa file: %s"),
sd_reader->error);
return kSDReadStatusReadError;
} else if (sd_reader->eof) {
- emsgu(_(RCERR "Error while reading ShaDa file: "
+ emsgf(_(RCERR "Error while reading ShaDa file: "
"last entry specified that it occupies %" PRIu64 " bytes, "
"but file ended earlier"),
(uint64_t) offset);
@@ -849,7 +847,7 @@ open_file_start:
goto open_file_start;
}
if (fd != UV_EEXIST) {
- emsg3(_(SERR "System error while opening ShaDa file %s: %s"),
+ emsgf(_(SERR "System error while opening ShaDa file %s: %s"),
fname, os_strerror(fd));
}
return fd;
@@ -897,7 +895,7 @@ close_file_start:
errno = 0;
goto close_file_start;
} else {
- emsg2(_(SERR "System error while closing ShaDa file: %s"),
+ emsgf(_(SERR "System error while closing ShaDa file: %s"),
strerror(errno));
errno = 0;
}
@@ -934,7 +932,7 @@ static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *) data;
ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
if (written_bytes == -1) {
- emsg2(_(SERR "System error while writing ShaDa file: %s"),
+ emsgf(_(SERR "System error while writing ShaDa file: %s"),
sd_writer->error);
return -1;
}
@@ -981,7 +979,7 @@ static int shada_read_file(const char *const file, const int flags)
if (of_ret != 0) {
if (of_ret == UV_ENOENT && (flags & kShaDaMissingError)) {
- emsg3(_(SERR "System error while opening ShaDa file %s for reading: %s"),
+ emsgf(_(SERR "System error while opening ShaDa file %s for reading: %s"),
fname, os_strerror(of_ret));
}
xfree(fname);
@@ -1409,9 +1407,9 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
break;
}
case kSDItemRegister: {
- if (cur_entry.data.reg.type != MCHAR
- && cur_entry.data.reg.type != MLINE
- && cur_entry.data.reg.type != MBLOCK) {
+ if (cur_entry.data.reg.type != kMTCharWise
+ && cur_entry.data.reg.type != kMTLineWise
+ && cur_entry.data.reg.type != kMTBlockWise) {
shada_free_shada_entry(&cur_entry);
break;
}
@@ -1687,8 +1685,9 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
do { \
if ((src) != NULL) { \
for (listitem_T *li = (src)->lv_first; li != NULL; li = li->li_next) { \
- if (vim_to_msgpack(spacker, &li->li_tv, \
- _("additional elements of ShaDa " what)) == FAIL) { \
+ if (encode_vim_to_msgpack(spacker, &li->li_tv, \
+ _("additional elements of ShaDa " what)) \
+ == FAIL) { \
goto shada_pack_entry_error; \
} \
} \
@@ -1706,8 +1705,9 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
const size_t key_len = strlen((const char *) hi->hi_key); \
msgpack_pack_str(spacker, key_len); \
msgpack_pack_str_body(spacker, (const char *) hi->hi_key, key_len); \
- if (vim_to_msgpack(spacker, &di->di_tv, \
- _("additional data of ShaDa " what)) == FAIL) { \
+ if (encode_vim_to_msgpack(spacker, &di->di_tv, \
+ _("additional data of ShaDa " what)) \
+ == FAIL) { \
goto shada_pack_entry_error; \
} \
} \
@@ -1757,7 +1757,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
char vardesc[256] = "variable g:";
memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
varname.size + 1);
- if (vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
+ if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
== FAIL) {
ret = kSDWriteIgnError;
EMSG2(_(WERR "Failed to write variable %s"),
@@ -1882,7 +1882,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
msgpack_pack_char(spacker, entry.data.reg.name);
if (!CHECK_DEFAULT(entry, reg.type)) {
PACK_STATIC_STR(REG_KEY_TYPE);
- msgpack_pack_uint8(spacker, entry.data.reg.type);
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
}
if (!CHECK_DEFAULT(entry, reg.width)) {
PACK_STATIC_STR(REG_KEY_WIDTH);
@@ -2159,7 +2159,7 @@ shada_parse_msgpack_read_next: {}
break;
}
case MSGPACK_UNPACK_PARSE_ERROR: {
- emsgu(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
+ emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
"at position %" PRIu64),
(uint64_t) initial_fpos);
ret = kSDReadStatusNotShaDa;
@@ -2176,7 +2176,7 @@ shada_parse_msgpack_read_next: {}
break;
}
case MSGPACK_UNPACK_CONTINUE: {
- emsgu(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
+ emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
"at position %" PRIu64),
(uint64_t) initial_fpos);
ret = kSDReadStatusNotShaDa;
@@ -2184,7 +2184,7 @@ shada_parse_msgpack_read_next: {}
}
case MSGPACK_UNPACK_EXTRA_BYTES: {
shada_parse_msgpack_extra_bytes:
- emsgu(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
+ emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
"at position %" PRIu64),
(uint64_t) initial_fpos);
ret = kSDReadStatusNotShaDa;
@@ -2757,8 +2757,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.reg = {
.contents = (char **) reg.y_array,
.contents_size = (size_t) reg.y_size,
- .type = (uint8_t) reg.y_type,
- .width = (size_t) (reg.y_type == MBLOCK ? reg.y_width : 0),
+ .type = reg.y_type,
+ .width = (size_t) (reg.y_type == kMTBlockWise ? reg.y_width : 0),
.additional_data = reg.additional_data,
.name = name,
}
@@ -3265,11 +3265,11 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
(void) read_bytes;
if (sd_reader->error != NULL) {
- emsg2(_(SERR "System error while reading ShaDa file: %s"),
+ emsgf(_(SERR "System error while reading ShaDa file: %s"),
sd_reader->error);
return kSDReadStatusReadError;
} else if (sd_reader->eof) {
- emsgu(_(RCERR "Error while reading ShaDa file: "
+ emsgf(_(RCERR "Error while reading ShaDa file: "
"last entry specified that it occupies %" PRIu64 " bytes, "
"but file ended earlier"),
(uint64_t) length);
@@ -3304,11 +3304,11 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
if (first_char == EOF) {
if (sd_reader->error) {
- emsg2(_(SERR "System error while reading integer from ShaDa file: %s"),
+ emsgf(_(SERR "System error while reading integer from ShaDa file: %s"),
sd_reader->error);
return kSDReadStatusReadError;
} else if (sd_reader->eof) {
- emsgu(_(RCERR "Error while reading ShaDa file: "
+ emsgf(_(RCERR "Error while reading ShaDa file: "
"expected positive integer at position %" PRIu64
", but got nothing"),
(uint64_t) fpos);
@@ -3339,7 +3339,7 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
break;
}
default: {
- emsgu(_(RCERR "Error while reading ShaDa file: "
+ emsgf(_(RCERR "Error while reading ShaDa file: "
"expected positive integer at position %" PRIu64),
(uint64_t) fpos);
return kSDReadStatusNotShaDa;
@@ -3403,18 +3403,18 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
proc) \
do { \
if (!(condition)) { \
- emsgu(_(READERR(entry_name, error_desc)), initial_fpos); \
+ emsgf(_(READERR(entry_name, error_desc)), initial_fpos); \
CLEAR_GA_AND_ERROR_OUT(ad_ga); \
} \
tgt = proc(obj.via.attr); \
} while (0)
#define CHECK_KEY_IS_STR(entry_name) \
if (unpacked.data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \
- emsgu(_(READERR(entry_name, "has key which is not a string")), \
+ emsgf(_(READERR(entry_name, "has key which is not a string")), \
initial_fpos); \
CLEAR_GA_AND_ERROR_OUT(ad_ga); \
} else if (unpacked.data.via.map.ptr[i].key.via.str.size == 0) { \
- emsgu(_(READERR(entry_name, "has empty key")), initial_fpos); \
+ emsgf(_(READERR(entry_name, "has empty key")), initial_fpos); \
CLEAR_GA_AND_ERROR_OUT(ad_ga); \
}
#define CHECKED_KEY(entry_name, name, error_desc, tgt, condition, attr, proc) \
@@ -3477,7 +3477,7 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
typval_T adtv; \
if (msgpack_to_vim(obj, &adtv) == FAIL \
|| adtv.v_type != VAR_DICT) { \
- emsgu(_(READERR(name, \
+ emsgf(_(READERR(name, \
"cannot be converted to a VimL dictionary")), \
initial_fpos); \
ga_clear(&ad_ga); \
@@ -3502,7 +3502,7 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
}; \
typval_T aetv; \
if (msgpack_to_vim(obj, &aetv) == FAIL) { \
- emsgu(_(READERR(name, "cannot be converted to a VimL list")), \
+ emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
initial_fpos); \
clear_tv(&aetv); \
goto shada_read_next_item_error; \
@@ -3570,7 +3570,7 @@ shada_read_next_item_start:
// kSDItemUnknown cannot possibly pass that far because it is -1 and that
// will fail in msgpack_read_uint64. But kSDItemMissing may and it will
// otherwise be skipped because (1 << 0) will never appear in flags.
- emsgu(_(RCERR "Error while reading ShaDa file: "
+ emsgf(_(RCERR "Error while reading ShaDa file: "
"there is an item at position %" PRIu64 " "
"that must not be there: Missing items are "
"for internal uses only"),
@@ -3640,14 +3640,14 @@ shada_read_next_item_start:
switch ((ShadaEntryType) type_u64) {
case kSDItemHeader: {
if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
- emsgu(_(READERR("header", "is not a dictionary")), initial_fpos);
+ emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
goto shada_read_next_item_error;
}
break;
}
case kSDItemSearchPattern: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgu(_(READERR("search pattern", "is not a dictionary")),
+ emsgf(_(READERR("search pattern", "is not a dictionary")),
initial_fpos);
goto shada_read_next_item_error;
}
@@ -3678,7 +3678,7 @@ shada_read_next_item_start:
ADDITIONAL_KEY
}
if (entry->data.search_pattern.pat == NULL) {
- emsgu(_(READERR("search pattern", "has no pattern")), initial_fpos);
+ emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
@@ -3690,7 +3690,7 @@ shada_read_next_item_start:
case kSDItemGlobalMark:
case kSDItemLocalMark: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgu(_(READERR("mark", "is not a dictionary")), initial_fpos);
+ emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
goto shada_read_next_item_error;
}
garray_T ad_ga;
@@ -3699,7 +3699,7 @@ shada_read_next_item_start:
CHECK_KEY_IS_STR("mark")
if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
- emsgu(_(READERR("mark", "has n key which is only valid for "
+ emsgf(_(READERR("mark", "has n key which is only valid for "
"local and global mark entries")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
@@ -3716,15 +3716,15 @@ shada_read_next_item_start:
ADDITIONAL_KEY
}
if (entry->data.filemark.fname == NULL) {
- emsgu(_(READERR("mark", "is missing file name")), initial_fpos);
+ emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
if (entry->data.filemark.mark.lnum <= 0) {
- emsgu(_(READERR("mark", "has invalid line number")), initial_fpos);
+ emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
if (entry->data.filemark.mark.col < 0) {
- emsgu(_(READERR("mark", "has invalid column number")), initial_fpos);
+ emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
@@ -3732,7 +3732,7 @@ shada_read_next_item_start:
}
case kSDItemRegister: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgu(_(READERR("register", "is not a dictionary")), initial_fpos);
+ emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
goto shada_read_next_item_error;
}
garray_T ad_ga;
@@ -3742,14 +3742,14 @@ shada_read_next_item_start:
if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
REG_KEY_CONTENTS)) {
if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
- emsgu(_(READERR("register",
+ emsgf(_(READERR("register",
"has " REG_KEY_CONTENTS
" key with non-array value")),
initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
- emsgu(_(READERR("register",
+ emsgf(_(READERR("register",
"has " REG_KEY_CONTENTS " key with empty array")),
initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
@@ -3758,7 +3758,7 @@ shada_read_next_item_start:
unpacked.data.via.map.ptr[i].val.via.array;
for (size_t i = 0; i < arr.size; i++) {
if (arr.ptr[i].type != MSGPACK_OBJECT_BIN) {
- emsgu(_(READERR("register", "has " REG_KEY_CONTENTS " array "
+ emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
"with non-binary value")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
@@ -3778,7 +3778,7 @@ shada_read_next_item_start:
ADDITIONAL_KEY
}
if (entry->data.reg.contents == NULL) {
- emsgu(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
+ emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
@@ -3787,29 +3787,29 @@ shada_read_next_item_start:
}
case kSDItemHistoryEntry: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgu(_(READERR("history", "is not an array")), initial_fpos);
+ emsgf(_(READERR("history", "is not an array")), initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.size < 2) {
- emsgu(_(READERR("history", "does not have enough elements")),
+ emsgf(_(READERR("history", "does not have enough elements")),
initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.ptr[0].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgu(_(READERR("history", "has wrong history type type")),
+ emsgf(_(READERR("history", "has wrong history type type")),
initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.ptr[1].type
!= MSGPACK_OBJECT_BIN) {
- emsgu(_(READERR("history", "has wrong history string type")),
+ emsgf(_(READERR("history", "has wrong history string type")),
initial_fpos);
goto shada_read_next_item_error;
}
if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
- emsgu(_(READERR("history", "contains string with zero byte inside")),
+ emsgf(_(READERR("history", "contains string with zero byte inside")),
initial_fpos);
goto shada_read_next_item_error;
}
@@ -3819,13 +3819,13 @@ shada_read_next_item_start:
entry->data.history_item.histtype == HIST_SEARCH;
if (is_hist_search) {
if (unpacked.data.via.array.size < 3) {
- emsgu(_(READERR("search history",
+ emsgf(_(READERR("search history",
"does not have separator character")), initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.ptr[2].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgu(_(READERR("search history",
+ emsgf(_(READERR("search history",
"has wrong history separator type")), initial_fpos);
goto shada_read_next_item_error;
}
@@ -3867,22 +3867,16 @@ shada_read_next_item_hist_no_conv:
}
case kSDItemVariable: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgu(_(READERR("variable", "is not an array")), initial_fpos);
+ emsgf(_(READERR("variable", "is not an array")), initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.size < 2) {
- emsgu(_(READERR("variable", "does not have enough elements")),
+ emsgf(_(READERR("variable", "does not have enough elements")),
initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgu(_(READERR("variable", "has wrong variable name type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_NIL
- || unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_EXT) {
- emsgu(_(READERR("variable", "has wrong variable value type")),
+ emsgf(_(READERR("variable", "has wrong variable name type")),
initial_fpos);
goto shada_read_next_item_error;
}
@@ -3891,7 +3885,7 @@ shada_read_next_item_hist_no_conv:
unpacked.data.via.array.ptr[0].via.bin.size);
if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
&(entry->data.global_var.value)) == FAIL) {
- emsgu(_(READERR("variable", "has value that cannot "
+ emsgf(_(READERR("variable", "has value that cannot "
"be converted to the VimL value")), initial_fpos);
goto shada_read_next_item_error;
}
@@ -3912,16 +3906,16 @@ shada_read_next_item_hist_no_conv:
}
case kSDItemSubString: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgu(_(READERR("sub string", "is not an array")), initial_fpos);
+ emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.size < 1) {
- emsgu(_(READERR("sub string", "does not have enough elements")),
+ emsgf(_(READERR("sub string", "does not have enough elements")),
initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgu(_(READERR("sub string", "has wrong sub string type")),
+ emsgf(_(READERR("sub string", "has wrong sub string type")),
initial_fpos);
goto shada_read_next_item_error;
}
@@ -3934,7 +3928,7 @@ shada_read_next_item_hist_no_conv:
}
case kSDItemBufferList: {
if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgu(_(READERR("buffer list", "is not an array")), initial_fpos);
+ emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
goto shada_read_next_item_error;
}
if (unpacked.data.via.array.size == 0) {
@@ -3951,7 +3945,7 @@ shada_read_next_item_hist_no_conv:
{
msgpack_unpacked unpacked = unpacked_2;
if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgu(_(RERR "Error while reading ShaDa file: "
+ emsgf(_(RERR "Error while reading ShaDa file: "
"buffer list at position %" PRIu64 " "
"contains entry that is not a dictionary"),
initial_fpos);
@@ -3976,21 +3970,21 @@ shada_read_next_item_hist_no_conv:
}
}
if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
- emsgu(_(RERR "Error while reading ShaDa file: "
+ emsgf(_(RERR "Error while reading ShaDa file: "
"buffer list at position %" PRIu64 " "
"contains entry with invalid line number"),
initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
if (entry->data.buffer_list.buffers[i].pos.col < 0) {
- emsgu(_(RERR "Error while reading ShaDa file: "
+ emsgf(_(RERR "Error while reading ShaDa file: "
"buffer list at position %" PRIu64 " "
"contains entry with invalid column number"),
initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
if (entry->data.buffer_list.buffers[i].fname == NULL) {
- emsgu(_(RERR "Error while reading ShaDa file: "
+ emsgf(_(RERR "Error while reading ShaDa file: "
"buffer list at position %" PRIu64 " "
"contains entry that does not have a file name"),
initial_fpos);
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index cc7dc6210c..0acaa9ae2b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -319,7 +319,6 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
-#include "nvim/tempfile.h"
#include "nvim/undo.h"
#include "nvim/os/os.h"
#include "nvim/os/input.h"
@@ -2332,14 +2331,17 @@ static void spell_load_lang(char_u *lang)
if (r == FAIL) {
if (starting) {
- // Some startup file sets &spell, but the necessary files don't exist:
- // try to prompt the user at VimEnter. Also set spell again. #3027
- do_cmdline_cmd(
- "autocmd VimEnter * call spellfile#LoadFile(&spelllang)|set spell");
+ // Prompt the user at VimEnter if spell files are missing. #3027
+ // Plugins aren't loaded yet, so spellfile.vim cannot handle this case.
+ char autocmd_buf[128] = { 0 };
+ snprintf(autocmd_buf, sizeof(autocmd_buf),
+ "autocmd VimEnter * call spellfile#LoadFile('%s')|set spell",
+ lang);
+ do_cmdline_cmd(autocmd_buf);
} else {
smsg(
_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
- lang, spell_enc(), lang);
+ lang, spell_enc(), lang);
}
} else if (sl.sl_slang != NULL) {
// At least one file was loaded, now load ALL the additions.
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 478fa973a1..9a5484704e 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -62,8 +62,10 @@ struct hl_group {
int sg_gui; // "gui=" highlighting attributes
RgbValue sg_rgb_fg; // RGB foreground color
RgbValue sg_rgb_bg; // RGB background color
+ RgbValue sg_rgb_sp; // RGB special color
uint8_t *sg_rgb_fg_name; // RGB foreground color name
uint8_t *sg_rgb_bg_name; // RGB background color name
+ uint8_t *sg_rgb_sp_name; // RGB special color name
};
#define SG_CTERM 2 // cterm has been set
@@ -2615,33 +2617,37 @@ find_endpos (
IF_SYN_TIME(&spp_skip->sp_time));
spp_skip->sp_prog = regmatch.regprog;
if (r && regmatch.startpos[0].col <= best_regmatch.startpos[0].col) {
- /* Add offset to skip pattern match */
+ // Add offset to skip pattern match
syn_add_end_off(&pos, &regmatch, spp_skip, SPO_ME_OFF, 1);
- /* If the skip pattern goes on to the next line, there is no
- * match with an end pattern in this line. */
- if (pos.lnum > startpos->lnum)
+ // If the skip pattern goes on to the next line, there is no
+ // match with an end pattern in this line.
+ if (pos.lnum > startpos->lnum) {
break;
+ }
- line = ml_get_buf(syn_buf, startpos->lnum, FALSE);
+ line = ml_get_buf(syn_buf, startpos->lnum, false);
+ int line_len = (int)STRLEN(line);
- /* take care of an empty match or negative offset */
- if (pos.col <= matchcol)
- ++matchcol;
- else if (pos.col <= regmatch.endpos[0].col)
+ // take care of an empty match or negative offset
+ if (pos.col <= matchcol) {
+ matchcol++;
+ } else if (pos.col <= regmatch.endpos[0].col) {
matchcol = pos.col;
- else
- /* Be careful not to jump over the NUL at the end-of-line */
+ } else {
+ // Be careful not to jump over the NUL at the end-of-line
for (matchcol = regmatch.endpos[0].col;
- line[matchcol] != NUL && matchcol < pos.col;
- ++matchcol)
- ;
+ matchcol < line_len && matchcol < pos.col;
+ matchcol++) {
+ }
+ }
- /* if the skip pattern includes end-of-line, break here */
- if (line[matchcol] == NUL)
+ // if the skip pattern includes end-of-line, break here
+ if (matchcol >= line_len) {
break;
+ }
- continue; /* start with first end pattern again */
+ continue; // start with first end pattern again
}
}
@@ -4478,12 +4484,10 @@ syn_cmd_region (
if (illegal || not_enough)
rest = NULL;
- /*
- * Must have a "start" and "end" pattern.
- */
- if (rest != NULL && (pat_ptrs[ITEM_START] == NULL ||
- pat_ptrs[ITEM_END] == NULL)) {
- not_enough = TRUE;
+ // Must have a "start" and "end" pattern.
+ if (rest != NULL && (pat_ptrs[ITEM_START] == NULL
+ || pat_ptrs[ITEM_END] == NULL)) {
+ not_enough = true;
rest = NULL;
}
@@ -5006,6 +5010,10 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
curwin->w_s->b_syn_sync_maxlines = 0;
}
} else if (STRCMP(key, "LINECONT") == 0) {
+ if (*next_arg == NUL) { // missing pattern
+ illegal = true;
+ break;
+ }
if (curwin->w_s->b_syn_linecont_pat != NULL) {
EMSG(_("E403: syntax sync: line continuations pattern specified twice"));
finished = TRUE;
@@ -5533,25 +5541,29 @@ char_u *get_syntax_name(expand_T *xp, int idx)
}
-/*
- * Function called for expression evaluation: get syntax ID at file position.
- */
-int
-syn_get_id (
+// Function called for expression evaluation: get syntax ID at file position.
+int syn_get_id(
win_T *wp,
long lnum,
colnr_T col,
- int trans, /* remove transparency */
- bool *spellp, /* return: can do spell checking */
- int keep_state /* keep state of char at "col" */
+ int trans, // remove transparency
+ bool *spellp, // return: can do spell checking
+ int keep_state // keep state of char at "col"
)
{
- /* When the position is not after the current position and in the same
- * line of the same buffer, need to restart parsing. */
+ // When the position is not after the current position and in the same
+ // line of the same buffer, need to restart parsing.
if (wp->w_buffer != syn_buf
|| lnum != current_lnum
- || col < current_col)
+ || col < current_col) {
syntax_start(wp, lnum);
+ } else if (wp->w_buffer == syn_buf
+ && lnum == current_lnum
+ && col > current_col) {
+ // next_match may not be correct when moving around, e.g. with the
+ // "skip" expression in searchpair()
+ next_match_idx = -1;
+ }
(void)get_syntax_attr(col, spellp, keep_state);
@@ -6159,12 +6171,11 @@ do_highlight (
break;
}
- /*
- * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
- * "guibg").
- */
- while (*linep && !ascii_iswhite(*linep) && *linep != '=')
- ++linep;
+ // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg",
+ // "guibg" or "guisp").
+ while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
+ linep++;
+ }
xfree(key);
key = vim_strnsave_up(key_start, (int)(linep - key_start));
linep = skipwhite(linep);
@@ -6360,18 +6371,14 @@ do_highlight (
} else
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
}
- color &= 7; /* truncate to 8 colors */
- } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) {
- switch (t_colors) {
- case 16:
- color = color_numbers_8[i];
- break;
- case 88:
- color = color_numbers_88[i];
- break;
- case 256:
- color = color_numbers_256[i];
- break;
+ color &= 7; // truncate to 8 colors
+ } else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) {
+ if (t_colors == 88) {
+ color = color_numbers_88[i];
+ } else if (t_colors >= 256) {
+ color = color_numbers_256[i];
+ } else {
+ color = color_numbers_8[i];
}
}
}
@@ -6391,7 +6398,7 @@ do_highlight (
HL_TABLE()[idx].sg_cterm_bg = color + 1;
if (is_normal_group) {
cterm_normal_bg_color = color + 1;
- {
+ if (!ui_rgb_attached()) {
must_redraw = CLEAR;
if (color >= 0) {
if (t_colors < 16)
@@ -6446,7 +6453,23 @@ do_highlight (
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
} else if (STRCMP(key, "GUISP") == 0) {
- // Ignored for now
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ if (STRCMP(arg, "NONE") != 0) {
+ HL_TABLE()[idx].sg_rgb_sp_name = (uint8_t *)xstrdup((char *)arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
+ } else {
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_sp = HL_TABLE()[idx].sg_rgb_sp;
+ }
} else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) {
// Ignored for now
} else {
@@ -6510,6 +6533,7 @@ void restore_cterm_colors(void)
{
normal_fg = -1;
normal_bg = -1;
+ normal_sp = -1;
cterm_normal_fg_color = 0;
cterm_normal_fg_bold = 0;
cterm_normal_bg_color = 0;
@@ -6526,6 +6550,7 @@ static int hl_has_settings(int idx, int check_link)
|| HL_TABLE()[idx].sg_cterm_bg != 0
|| HL_TABLE()[idx].sg_rgb_fg_name != NULL
|| HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
|| (check_link && (HL_TABLE()[idx].sg_set & SG_LINK));
}
@@ -6542,14 +6567,18 @@ static void highlight_clear(int idx)
HL_TABLE()[idx].sg_gui = 0;
HL_TABLE()[idx].sg_rgb_fg = -1;
HL_TABLE()[idx].sg_rgb_bg = -1;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
xfree(HL_TABLE()[idx].sg_rgb_fg_name);
HL_TABLE()[idx].sg_rgb_fg_name = NULL;
xfree(HL_TABLE()[idx].sg_rgb_bg_name);
HL_TABLE()[idx].sg_rgb_bg_name = NULL;
- /* Clear the script ID only when there is no link, since that is not
- * cleared. */
- if (HL_TABLE()[idx].sg_link == 0)
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ // Clear the script ID only when there is no link, since that is not
+ // cleared.
+ if (HL_TABLE()[idx].sg_link == 0) {
HL_TABLE()[idx].sg_scriptID = 0;
+ }
}
@@ -6591,7 +6620,8 @@ int get_attr_entry(attrentry_T *aep)
&& aep->cterm_bg_color == taep->cterm_bg_color
&& aep->rgb_ae_attr == taep->rgb_ae_attr
&& aep->rgb_fg_color == taep->rgb_fg_color
- && aep->rgb_bg_color == taep->rgb_bg_color) {
+ && aep->rgb_bg_color == taep->rgb_bg_color
+ && aep->rgb_sp_color == taep->rgb_sp_color) {
return i + ATTR_OFF;
}
}
@@ -6629,6 +6659,7 @@ int get_attr_entry(attrentry_T *aep)
taep->rgb_ae_attr = aep->rgb_ae_attr;
taep->rgb_fg_color = aep->rgb_fg_color;
taep->rgb_bg_color = aep->rgb_bg_color;
+ taep->rgb_sp_color = aep->rgb_sp_color;
return table->ga_len - 1 + ATTR_OFF;
}
@@ -6690,6 +6721,10 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (spell_aep->rgb_bg_color >= 0) {
new_en.rgb_bg_color = spell_aep->rgb_bg_color;
}
+
+ if (spell_aep->rgb_sp_color >= 0) {
+ new_en.rgb_sp_color = spell_aep->rgb_sp_color;
+ }
}
return get_attr_entry(&new_en);
}
@@ -6727,7 +6762,7 @@ static void highlight_list_one(int id)
didh = highlight_list_arg(id, didh, LIST_STRING,
0, sgp->sg_rgb_bg_name, "guibg");
didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, NULL, "guisp");
+ 0, sgp->sg_rgb_sp_name, "guisp");
if (sgp->sg_link && !got_int) {
(void)syn_list_header(didh, 9999, id);
@@ -6841,8 +6876,9 @@ highlight_color (
if (modec == 'g') {
if (fg)
return HL_TABLE()[id - 1].sg_rgb_fg_name;
- if (sp)
- return NULL;
+ if (sp) {
+ return HL_TABLE()[id - 1].sg_rgb_sp_name;
+ }
return HL_TABLE()[id - 1].sg_rgb_bg_name;
}
if (font || sp)
@@ -6929,7 +6965,14 @@ set_hl_attr (
// before setting attr_entry->{f,g}g_color to a other than -1
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
- sgp->sg_attr = get_attr_entry(&at_en);
+ at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
+
+ if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0
+ || at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1
+ || at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0
+ || at_en.rgb_ae_attr != 0) {
+ sgp->sg_attr = get_attr_entry(&at_en);
+ }
}
/*
@@ -7260,6 +7303,10 @@ int highlight_changed(void)
hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
}
+ if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) {
+ hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp;
+ }
+
highlight_ga.ga_len = hlcnt + i + 1;
set_hl_attr(hlcnt + i); /* At long last we can apply */
highlight_stlnc[i] = syn_id2attr(hlcnt + i + 1);
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 67cf672ef2..8d207e6286 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -69,8 +69,8 @@ struct syn_state {
// Structure shared between syntax.c, screen.c
typedef struct attr_entry {
- short rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
- RgbValue rgb_fg_color, rgb_bg_color;
+ int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
+ RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
int cterm_fg_color, cterm_bg_color;
} attrentry_T;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 8fcb02c3b6..7885d467d8 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -526,19 +526,17 @@ do_tag (
taglen_advance(taglen);
MSG_PUTS_ATTR(_("file\n"), hl_attr(HLF_T));
- for (i = 0; i < num_matches && !got_int; ++i) {
+ for (i = 0; i < num_matches && !got_int; i++) {
parse_match(matches[i], &tagp);
- if (!new_tag && (
- (g_do_tagpreview != 0
- && i == ptag_entry.cur_match) ||
- (use_tagstack
- && i == tagstack[tagstackidx].cur_match)))
+ if (!new_tag && ((g_do_tagpreview != 0 && i == ptag_entry.cur_match)
+ || (use_tagstack
+ && i == tagstack[tagstackidx].cur_match))) {
*IObuff = '>';
- else
+ } else {
*IObuff = ' ';
- vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
- "%2d %s ", i + 1,
- mt_names[matches[i][0] & MT_MASK]);
+ }
+ vim_snprintf((char *)IObuff + 1, IOSIZE - 1, "%2d %s ", i + 1,
+ mt_names[matches[i][0] & MT_MASK]);
msg_puts(IObuff);
if (tagp.tagkind != NULL)
msg_outtrans_len(tagp.tagkind,
@@ -872,7 +870,7 @@ do_tag (
/* Let the SwapExists event know what tag we are jumping to. */
vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name);
- set_vim_var_string(VV_SWAPCOMMAND, IObuff, -1);
+ set_vim_var_string(VV_SWAPCOMMAND, (char *) IObuff, -1);
/*
* Jump to the desired match.
@@ -1147,6 +1145,22 @@ find_tags (
int get_it_again = FALSE;
int use_cscope = (flags & TAG_CSCOPE);
int verbose = (flags & TAG_VERBOSE);
+ int save_p_ic = p_ic;
+
+ // Change the value of 'ignorecase' according to 'tagcase' for the
+ // duration of this function.
+ switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) {
+ case TC_FOLLOWIC:
+ break;
+ case TC_IGNORE:
+ p_ic = true;
+ break;
+ case TC_MATCH:
+ p_ic = false;
+ break;
+ default:
+ assert(false);
+ }
help_save = curbuf->b_help;
orgpat.pat = pat;
@@ -1210,20 +1224,15 @@ find_tags (
for (round = 1; round <= 2; ++round) {
linear = (orgpat.headlen == 0 || !p_tbs || round == 2);
- /*
- * Try tag file names from tags option one by one.
- */
- for (first_file = TRUE;
- use_cscope ||
- get_tagfname(&tn, first_file, tag_fname) == OK;
- first_file = FALSE) {
- /*
- * A file that doesn't exist is silently ignored. Only when not a
- * single file is found, an error message is given (further on).
- */
- if (use_cscope)
- fp = NULL; /* avoid GCC warning */
- else {
+ // Try tag file names from tags option one by one.
+ for (first_file = true;
+ use_cscope || get_tagfname(&tn, first_file, tag_fname) == OK;
+ first_file = false) {
+ // A file that doesn't exist is silently ignored. Only when not a
+ // single file is found, an error message is given (further on).
+ if (use_cscope) {
+ fp = NULL; // avoid GCC warning
+ } else {
if (curbuf->b_help) {
/* Prefer help tags according to 'helplang'. Put the
* two-letter language name in help_lang[]. */
@@ -1955,6 +1964,8 @@ findtag_end:
curbuf->b_help = help_save;
xfree(saved_pat);
+ p_ic = save_p_ic;
+
return retval;
}
diff --git a/src/nvim/tempfile.c b/src/nvim/tempfile.c
deleted file mode 100644
index a218c03fdb..0000000000
--- a/src/nvim/tempfile.c
+++ /dev/null
@@ -1,138 +0,0 @@
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "nvim/ascii.h"
-#include "nvim/memory.h"
-#include "nvim/misc1.h"
-#include "nvim/os/os.h"
-#include "nvim/os/os_defs.h"
-#include "nvim/path.h"
-#include "nvim/strings.h"
-#include "nvim/tempfile.h"
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "tempfile.c.generated.h"
-#endif
-
-/// Name of Vim's own temp dir. Ends in a slash.
-static char_u *vim_tempdir = NULL;
-
-/// Create a directory for private use by this instance of Neovim.
-/// This is done once, and the same directory is used for all temp files.
-/// This method avoids security problems because of symlink attacks et al.
-/// It's also a bit faster, because we only need to check for an existing
-/// file when creating the directory and not for each temp file.
-static void vim_maketempdir(void)
-{
- static const char *temp_dirs[] = TEMP_DIR_NAMES;
- // Try the entries in `TEMP_DIR_NAMES` to create the temp directory.
- char_u template[TEMP_FILE_PATH_MAXLEN];
- char_u path[TEMP_FILE_PATH_MAXLEN];
- for (size_t i = 0; i < ARRAY_SIZE(temp_dirs); ++i) {
- // Expand environment variables, leave room for "/nvimXXXXXX/999999999"
- expand_env((char_u *)temp_dirs[i], template, TEMP_FILE_PATH_MAXLEN - 22);
- if (!os_isdir(template)) { // directory doesn't exist
- continue;
- }
-
- add_pathsep((char *)template);
- // Concatenate with temporary directory name pattern
- STRCAT(template, "nvimXXXXXX");
-
- if (os_mkdtemp((const char *)template, (char *)path) != 0) {
- continue;
- }
-
- if (vim_settempdir((char *)path)) {
- // Successfully created and set temporary directory so stop trying.
- break;
- } else {
- // Couldn't set `vim_tempdir` to `path` so remove created directory.
- os_rmdir((char *)path);
- }
- }
-}
-
-/// Delete the temp directory and all files it contains.
-void vim_deltempdir(void)
-{
- if (vim_tempdir != NULL) {
- snprintf((char *)NameBuff, MAXPATHL, "%s*", vim_tempdir);
-
- char_u **files;
- int file_count;
-
- // Note: We cannot just do `&NameBuff` because it is a statically
- // sized array so `NameBuff == &NameBuff` according to C semantics.
- char_u *buff_list[1] = {NameBuff};
- if (gen_expand_wildcards(1, buff_list, &file_count, &files,
- EW_DIR|EW_FILE|EW_SILENT) == OK) {
- for (int i = 0; i < file_count; ++i) {
- os_remove((char *)files[i]);
- }
- FreeWild(file_count, files);
- }
- path_tail(NameBuff)[-1] = NUL;
- os_rmdir((char *)NameBuff);
-
- xfree(vim_tempdir);
- vim_tempdir = NULL;
- }
-}
-
-/// Get the name of temp directory. This directory would be created on the first
-/// call to this function.
-char_u *vim_gettempdir(void)
-{
- if (vim_tempdir == NULL) {
- vim_maketempdir();
- }
-
- return vim_tempdir;
-}
-
-/// Set Neovim own temporary directory name to `tempdir`. This directory should
-/// be already created. Expand this name to a full path and put it in
-/// `vim_tempdir`. This avoids that using `:cd` would confuse us.
-///
-/// @param tempdir must be no longer than MAXPATHL.
-///
-/// @return false if we run out of memory.
-static bool vim_settempdir(char *tempdir)
-{
- char *buf = verbose_try_malloc(MAXPATHL + 2);
- if (!buf) {
- return false;
- }
- vim_FullName(tempdir, buf, MAXPATHL, false);
- add_pathsep(buf);
- vim_tempdir = (char_u *)xstrdup(buf);
- xfree(buf);
- return true;
-}
-
-/// Return a unique name that can be used for a temp file.
-///
-/// @note The temp file is NOT created.
-///
-/// @return pointer to the temp file name or NULL if Neovim can't create
-/// temporary directory for its own temporary files.
-char_u *vim_tempname(void)
-{
- // Temp filename counter.
- static uint32_t temp_count;
-
- char_u *tempdir = vim_gettempdir();
- if (!tempdir) {
- return NULL;
- }
-
- // There is no need to check if the file exists, because we own the directory
- // and nobody else creates a file in it.
- char_u template[TEMP_FILE_PATH_MAXLEN];
- snprintf((char *)template, TEMP_FILE_PATH_MAXLEN,
- "%s%" PRIu32, tempdir, temp_count++);
- return vim_strsave(template);
-}
diff --git a/src/nvim/tempfile.h b/src/nvim/tempfile.h
deleted file mode 100644
index c030a70eeb..0000000000
--- a/src/nvim/tempfile.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef NVIM_TEMPFILE_H
-#define NVIM_TEMPFILE_H
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "tempfile.h.generated.h"
-#endif
-
-#endif // NVIM_TEMPFILE_H
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 42fd81f643..104cc47cda 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -175,7 +175,16 @@ void terminal_init(void)
for (int color_index = 0; color_index < 256; color_index++) {
VTermColor color;
- vterm_state_get_palette_color(state, color_index, &color);
+ // Some of the default 16 colors has the same color as the later
+ // 240 colors. To avoid collisions, we will use the custom colors
+ // below in non true color mode.
+ if (color_index < 16) {
+ color.red = 0;
+ color.green = 0;
+ color.blue = (uint8_t)(color_index + 1);
+ } else {
+ vterm_state_get_palette_color(state, color_index, &color);
+ }
map_put(int, int)(color_indexes,
RGB(color.red, color.green, color.blue), color_index + 1);
}
@@ -248,6 +257,15 @@ Terminal *terminal_open(TerminalOptions opts)
rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size);
if (!true_color) {
+ // Change the first 16 colors so we can easily get the correct color
+ // index from them.
+ for (int i = 0; i < 16; i++) {
+ VTermColor color;
+ color.red = 0;
+ color.green = 0;
+ color.blue = (uint8_t)(i + 1);
+ vterm_state_set_palette_color(state, i, &color);
+ }
return rv;
}
@@ -411,6 +429,10 @@ static int terminal_execute(VimState *state, int key)
apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf);
break;
+ // Temporary fix until paste events gets implemented
+ case K_PASTE:
+ break;
+
case K_LEFTMOUSE:
case K_LEFTDRAG:
case K_LEFTRELEASE:
@@ -544,9 +566,9 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
// Since libvterm does not expose the color index used by the program, we
// use the rgb value to find the appropriate index in the cache computed by
// `terminal_init`.
- int vt_fg_idx = vt_fg != default_vt_fg ?
+ int vt_fg_idx = vt_fg != -1 ?
map_get(int, int)(color_indexes, vt_fg) : 0;
- int vt_bg_idx = vt_bg != default_vt_bg ?
+ int vt_bg_idx = vt_bg != -1 ?
map_get(int, int)(color_indexes, vt_bg) : 0;
int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0)
@@ -623,6 +645,7 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
api_free_object(dict_set_value(buf->b_vars,
cstr_as_string("term_title"),
STRING_OBJ(cstr_as_string(val->string)),
+ false,
&err));
break;
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index d16e28a377..90542a6a6c 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -28,17 +28,21 @@ SCRIPTS := \
test53.out \
test55.out \
test64.out \
- test68.out \
test69.out \
test73.out \
test79.out \
- test88.out \
test_listlbr.out \
test_close_count.out \
test_marks.out \
- test_match_conceal.out \
-NEW_TESTS =
+# Tests using runtest.vim.vim.
+# Keep test_alot*.res as the last one, sort the others.
+NEW_TESTS = \
+ test_cursor_func.res \
+ test_help_tagjump.res \
+ test_menu.res \
+ test_viml.res \
+ test_alot.res
SCRIPTS_GUI := test16.out
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 8314a45d0c..6601dcf52f 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -33,6 +33,15 @@ if &lines < 24 || &columns < 80
cquit
endif
+" This also enables use of line continuation.
+set viminfo+=nviminfo
+
+" Avoid stopping at the "hit enter" prompt
+set nomore
+
+" Output all messages in English.
+lang mess C
+
" Source the test script. First grab the file name, in case the script
" navigates away.
let testname = expand('%')
@@ -40,14 +49,20 @@ let done = 0
let fail = 0
let errors = []
let messages = []
-try
+if expand('%') =~ 'test_viml.vim'
+ " this test has intentional errors, don't use try/catch.
source %
-catch
- let fail += 1
- call add(errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
-endtry
+else
+ try
+ source %
+ catch
+ let fail += 1
+ call add(errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
+ endtry
+endif
" Locate Test_ functions and execute them.
+set nomore
redir @q
function /^Test_
redir END
diff --git a/src/nvim/testdir/test17.in b/src/nvim/testdir/test17.in
index 7fef87d383..a8c81b832d 100644
--- a/src/nvim/testdir/test17.in
+++ b/src/nvim/testdir/test17.in
@@ -41,17 +41,17 @@ STARTTEST
:!mkdir Xdir1
:!mkdir "Xdir1/dir2"
:e! Xdir1/dir2/foo.a
-i#include "bar.a"
+i#include "bar.a":
:w
:e Xdir1/dir2/bar.a
-i#include "baz.a"
+i#include "baz.a":
:w
:e Xdir1/dir2/baz.a
-i#include "foo.a"
+i#include "foo.a":
:w
:e Xbase.a
:set path=Xdir1/dir2
-i#include <foo.a>
+i#include <foo.a>:
:w
:redir! >>test.out
:checkpath!
@@ -71,17 +71,17 @@ STARTTEST
:endfunction
:let &includeexpr='DotsToSlashes()'
:e! Xdir1/dir2/foo.b
-i%inc /bar/
+i%inc /bar/:
:w
:e Xdir1/dir2/bar.b
-i%inc /baz/
+i%inc /baz/:
:w
:e Xdir1/dir2/baz.b
-i%inc /foo/
+i%inc /foo/:
:w
:e Xbase.b
:set path=Xdir1/dir2
-i%inc /foo/
+i%inc /foo/:
:w
:redir! >>test.out
:checkpath!
@@ -104,20 +104,20 @@ STARTTEST
:endfunction
:let &includeexpr='StripNewlineChar()'
:e! Xdir1/dir2/foo.c
-i%inc bar.c
+i%inc bar.c:
:w
:e Xdir1/dir2/bar.c
-i%inc baz.c
+i%inc baz.c:
:w
:e Xdir1/dir2/baz.c
-i%inc foo.c
+i%inc foo.c:
:w
:e Xdir1/dir2/FALSE.c
-i%inc foo.c
+i%inc foo.c:
:w
:e Xbase.c
:set path=Xdir1/dir2
-i%inc FALSE.c foo.c
+i%inc FALSE.c foo.c:
:w
:redir! >>test.out
:checkpath!
diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in
index 1ce57246ee..d95052e14c 100644
--- a/src/nvim/testdir/test49.in
+++ b/src/nvim/testdir/test49.in
@@ -8,7 +8,9 @@ STARTTEST
:se nomore
:lang mess C
:so test49.vim
-GGGGGGGGGGGGGG"rp:.-,$w! test.out
+:" Go back to this file and append the results from register r.
+:buf test49.in
+G"rp:/^Results/,$w! test.out
:"
:" make valgrind happy
:redir => funclist
diff --git a/src/nvim/testdir/test49.ok b/src/nvim/testdir/test49.ok
index bf1ceed9af..50fc5d2cef 100644
--- a/src/nvim/testdir/test49.ok
+++ b/src/nvim/testdir/test49.ok
@@ -1,19 +1,4 @@
Results of test49.vim:
-*** Test 1: OK (34695)
-*** Test 2: OK (34695)
-*** Test 3: OK (1384648195)
-*** Test 4: OK (32883)
-*** Test 5: OK (32883)
-*** Test 6: OK (603978947)
-*** Test 7: OK (90563)
-*** Test 8: OK (562493431)
-*** Test 9: OK (363)
-*** Test 10: OK (559615)
-*** Test 11: OK (2049)
-*** Test 12: OK (352256)
-*** Test 13: OK (145)
-*** Test 14: OK (42413)
-*** Test 15: OK (42413)
*** Test 16: OK (8722)
*** Test 17: OK (285127993)
*** Test 18: OK (67224583)
diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim
index 70d388b06a..edd49a2b63 100644
--- a/src/nvim/testdir/test49.vim
+++ b/src/nvim/testdir/test49.vim
@@ -1,6 +1,6 @@
" Vim script language tests
" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
-" Last Change: 2015 Sep 25
+" Last Change: 2016 Feb 07
"-------------------------------------------------------------------------------
" Test environment {{{1
@@ -608,850 +608,8 @@ com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
-"-------------------------------------------------------------------------------
-" Test 1: :endwhile in function {{{1
-"
-" Detect if a broken loop is (incorrectly) reactivated by the
-" :endwhile. Use a :return to prevent an endless loop, and make
-" this test first to get a meaningful result on an error before other
-" tests will hang.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F()
- Xpath 1 " X: 1
- let first = 1
- XloopINIT 2 8
- while 1
- Xloop 1 " X: 2 + 0 * 16
- if first
- Xloop 2 " X: 4 + 0 * 32
- let first = 0
- XloopNEXT
- break
- else
- Xloop 4 " X: 0 + 0 * 64
- return
- endif
- endwhile
-endfunction
-
-call F()
-Xpath 128 " X: 128
-
-function! G()
- Xpath 256 " X: 256 + 0 * 2048
- let first = 1
- XloopINIT 512 8
- while 1
- Xloop 1 " X: 512 + 0 * 4096
- if first
- Xloop 2 " X: 1024 + 0 * 8192
- let first = 0
- XloopNEXT
- break
- else
- Xloop 4 " X: 0 + 0 * 16384
- return
- endif
- if 1 " unmatched :if
- endwhile
-endfunction
-
-call G()
-Xpath 32768 " X: 32768
-
-Xcheck 34695
-
-" Leave F and G for execution as scripts in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 2: :endwhile in script {{{1
-"
-" Detect if a broken loop is (incorrectly) reactivated by the
-" :endwhile. Use a :finish to prevent an endless loop, and place
-" this test before others that might hang to get a meaningful result
-" on an error.
-"
-" This test executes the bodies of the functions F and G from the
-" previous test as script files (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-ExecAsScript F " X: 1 + 2 + 4
-Xpath 128 " X: 128
-
-ExecAsScript G " X: 256 + 512 + 1024
-Xpath 32768 " X: 32768
-
-unlet first
-delfunction F
-delfunction G
-
-Xcheck 34695
-
-
-"-------------------------------------------------------------------------------
-" Test 3: :if, :elseif, :while, :continue, :break {{{1
-"-------------------------------------------------------------------------------
-
-XpathINIT
-if 1
- Xpath 1 " X: 1
- let loops = 3
- XloopINIT 2 512
- while loops > -1 " main loop: loops == 3, 2, 1 (which breaks)
- if loops <= 0
- let break_err = 1
- let loops = -1
- else " 3: 2: 1:
- Xloop 1 " X: 2 + 2*512 + 2*512*512
- endif
- if (loops == 2)
- while loops == 2 " dummy loop
- Xloop 2 " X: 4*512
- let loops = loops - 1
- continue " stop dummy loop
- Xloop 4 " X: 0
- endwhile
- XloopNEXT
- continue " continue main loop
- Xloop 8 " X: 0
- elseif (loops == 1)
- let p = 1
- while p " dummy loop
- Xloop 16 " X: 32*512*512
- let p = 0
- break " break dummy loop
- Xloop 32 " X: 0
- endwhile
- Xloop 64 " X: 128*512*512
- unlet p
- break " break main loop
- Xloop 128 " X: 0
- endif
- if (loops > 0)
- Xloop 256 " X: 512
- endif
- while loops == 3 " dummy loop
- let loops = loops - 1
- endwhile " end dummy loop
- XloopNEXT
- endwhile " end main loop
- Xpath 268435456 " X: 1024*512*512
-else
- Xpath 536870912 " X: 0
-endif
-Xpath 1073741824 " X: 4096*512*512
-if exists("break_err")
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- unlet break_err
-endif
-
-unlet loops
-
-Xcheck 1384648195
-
-
-"-------------------------------------------------------------------------------
-" Test 4: :return {{{1
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F()
- if 1
- Xpath 1 " X: 1
- let loops = 3
- XloopINIT 2 16
- while loops > 0 " 3: 2: 1:
- Xloop 1 " X: 2 + 2*16 + 0*16*16
- if (loops == 2)
- Xloop 2 " X: 4*16
- return
- Xloop 4 " X: 0
- endif
- Xloop 8 " X: 16
- let loops = loops - 1
- XloopNEXT
- endwhile
- Xpath 8192 " X: 0
- else
- Xpath 16384 " X: 0
- endif
-endfunction
-
-call F()
-Xpath 32768 " X: 8*16*16*16
-
-Xcheck 32883
-
-" Leave F for execution as a script in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 5: :finish {{{1
-"
-" This test executes the body of the function F from the previous test
-" as a script file (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-ExecAsScript F " X: 1 + 2 + 2*16 + 4*16 + 16
-Xpath 32768 " X: 32768
-
-unlet loops
-delfunction F
-
-Xcheck 32883
-
-
-"-------------------------------------------------------------------------------
-" Test 6: Defining functions in :while loops {{{1
-"
-" Functions can be defined inside other functions. An inner function
-" gets defined when the outer function is executed. Functions may
-" also be defined inside while loops. Expressions in braces for
-" defining the function name are allowed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- " The command CALL collects the argument of all its invocations in "calls"
- " when used from a function (that is, when the global variable "calls" needs
- " the "g:" prefix). This is to check that the function code is skipped when
- " the function is defined. For inner functions, do so only if the outer
- " function is not being executed.
- "
- let calls = ""
- com! -nargs=1 CALL
- \ if !exists("calls") && !exists("outer") |
- \ let g:calls = g:calls . <args> |
- \ endif
-
-
- XloopINIT! 1 16
-
- let i = 0
- while i < 3
-
- XloopNEXT
- let i = i + 1
-
- if i == 1
- Xloop 1 " X: 1
- function! F1(arg)
- CALL a:arg
- let outer = 1
-
- XloopINIT! 4096 4
- let j = 0
- while j < 1
- XloopNEXT
- Xloop 1 " X: 4096
- let j = j + 1
- function! G1(arg)
- CALL a:arg
- endfunction
- Xloop 2 " X: 8192
- endwhile
- endfunction
- Xloop 2 " X: 2
-
- continue
- endif
-
- Xloop 4 " X: 4 * (16 + 256)
- function! F{i}(i, arg)
- CALL a:arg
- let outer = 1
-
- XloopINIT! 16384 4
- if a:i == 3
- XloopNEXT
- XloopNEXT
- XloopNEXT
- endif
- let k = 0
- while k < 3
- XloopNEXT
- Xloop 1 " X: 16384*(1+4+16+64+256+1024)
- let k = k + 1
- function! G{a:i}{k}(arg)
- CALL a:arg
- endfunction
- Xloop 2 " X: 32768*(1+4+16+64+256+1024)
- endwhile
- endfunction
- Xloop 8 " X: 8 * (16 + 256)
-
- endwhile
-
- if exists("*G1")
- Xpath 67108864 " X: 0
- endif
- if exists("*F1")
- call F1("F1")
- if exists("*G1")
- call G1("G1")
- endif
- endif
-
- if exists("G21") || exists("G21") || exists("G21")
- Xpath 134217728 " X: 0
- endif
- if exists("*F2")
- call F2(2, "F2")
- if exists("*G21")
- call G21("G21")
- endif
- if exists("*G22")
- call G22("G22")
- endif
- if exists("*G23")
- call G23("G23")
- endif
- endif
-
- if exists("G31") || exists("G31") || exists("G31")
- Xpath 268435456 " X: 0
- endif
- if exists("*F3")
- call F3(3, "F3")
- if exists("*G31")
- call G31("G31")
- endif
- if exists("*G32")
- call G32("G32")
- endif
- if exists("*G33")
- call G33("G33")
- endif
- endif
-
- Xpath 536870912 " X: 536870912
-
- if calls != "F1G1F2G21G22G23F3G31G32G33"
- Xpath 1073741824 " X: 0
- Xout "calls is" calls
- endif
-
- delfunction F1
- delfunction G1
- delfunction F2
- delfunction G21
- delfunction G22
- delfunction G23
- delfunction G31
- delfunction G32
- delfunction G33
-
-endif
-
-Xcheck 603978947
-
-
-"-------------------------------------------------------------------------------
-" Test 7: Continuing on errors outside functions {{{1
-"
-" On an error outside a function, the script processing continues
-" at the line following the outermost :endif or :endwhile. When not
-" inside an :if or :while, the script processing continues at the next
-" line.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if 1
- Xpath 1 " X: 1
- while 1
- Xpath 2 " X: 2
- asdf
- Xpath 4 " X: 0
- break
- endwhile | Xpath 8 " X: 0
- Xpath 16 " X: 0
-endif | Xpath 32 " X: 0
-Xpath 64 " X: 64
-
-while 1
- Xpath 128 " X: 128
- if 1
- Xpath 256 " X: 256
- asdf
- Xpath 512 " X: 0
- endif | Xpath 1024 " X: 0
- Xpath 2048 " X: 0
- break
-endwhile | Xpath 4096 " X: 0
-Xpath 8192 " X: 8192
-
-asdf
-Xpath 16384 " X: 16384
-
-asdf | Xpath 32768 " X: 0
-Xpath 65536 " X: 65536
-
-Xcheck 90563
-
-
-"-------------------------------------------------------------------------------
-" Test 8: Aborting and continuing on errors inside functions {{{1
-"
-" On an error inside a function without the "abort" attribute, the
-" script processing continues at the next line (unless the error was
-" in a :return command). On an error inside a function with the
-" "abort" attribute, the function is aborted and the script processing
-" continues after the function call; the value -1 is returned then.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F()
- if 1
- Xpath 1 " X: 1
- while 1
- Xpath 2 " X: 2
- asdf
- Xpath 4 " X: 4
- asdf | Xpath 8 " X: 0
- Xpath 16 " X: 16
- break
- endwhile
- Xpath 32 " X: 32
- endif | Xpath 64 " X: 64
- Xpath 128 " X: 128
-
- while 1
- Xpath 256 " X: 256
- if 1
- Xpath 512 " X: 512
- asdf
- Xpath 1024 " X: 1024
- asdf | Xpath 2048 " X: 0
- Xpath 4096 " X: 4096
- endif
- Xpath 8192 " X: 8192
- break
- endwhile | Xpath 16384 " X: 16384
- Xpath 32768 " X: 32768
-
- return novar " returns (default return value 0)
- Xpath 65536 " X: 0
- return 1 " not reached
-endfunction
-
-function! G() abort
- if 1
- Xpath 131072 " X: 131072
- while 1
- Xpath 262144 " X: 262144
- asdf " returns -1
- Xpath 524288 " X: 0
- break
- endwhile
- Xpath 1048576 " X: 0
- endif | Xpath 2097152 " X: 0
- Xpath Xpath 4194304 " X: 0
-
- return -4 " not reached
-endfunction
-
-function! H() abort
- while 1
- Xpath 8388608 " X: 8388608
- if 1
- Xpath 16777216 " X: 16777216
- asdf " returns -1
- Xpath 33554432 " X: 0
- endif
- Xpath 67108864 " X: 0
- break
- endwhile | Xpath 134217728 " X: 0
- Xpath 268435456 " X: 0
-
- return -4 " not reached
-endfunction
-
-" Aborted functions (G and H) return -1.
-let sum = (F() + 1) - 4*G() - 8*H()
-Xpath 536870912 " X: 536870912
-if sum != 13
- Xpath 1073741824 " X: 0
- Xout "sum is" sum
-endif
-
-unlet sum
-delfunction F
-delfunction G
-delfunction H
-
-Xcheck 562493431
-
-
-"-------------------------------------------------------------------------------
-" Test 9: Continuing after aborted functions {{{1
-"
-" When a function with the "abort" attribute is aborted due to an
-" error, the next function back in the call hierarchy without an
-" "abort" attribute continues; the value -1 is returned then.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F() abort
- Xpath 1 " X: 1
- let result = G() " not aborted
- Xpath 2 " X: 2
- if result != 2
- Xpath 4 " X: 0
- endif
- return 1
-endfunction
-
-function! G() " no abort attribute
- Xpath 8 " X: 8
- if H() != -1 " aborted
- Xpath 16 " X: 0
- endif
- Xpath 32 " X: 32
- return 2
-endfunction
-
-function! H() abort
- Xpath 64 " X: 64
- call I() " aborted
- Xpath 128 " X: 0
- return 4
-endfunction
-
-function! I() abort
- Xpath 256 " X: 256
- asdf " error
- Xpath 512 " X: 0
- return 8
-endfunction
-
-if F() != 1
- Xpath 1024 " X: 0
-endif
-
-delfunction F
-delfunction G
-delfunction H
-delfunction I
-
-Xcheck 363
-
-
-"-------------------------------------------------------------------------------
-" Test 10: :if, :elseif, :while argument parsing {{{1
-"
-" A '"' or '|' in an argument expression must not be mixed up with
-" a comment or a next command after a bar. Parsing errors should
-" be recognized.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-if 1 || strlen("\"") | Xpath 1 " X: 1
- Xpath 2 " X: 2
-endif
-Xpath 4 " X: 4
-
-if 0
-elseif 1 || strlen("\"") | Xpath 8 " X: 8
- Xpath 16 " X: 16
-endif
-Xpath 32 " X: 32
-
-while 1 || strlen("\"") | Xpath 64 " X: 64
- Xpath 128 " X: 128
- break
-endwhile
-Xpath 256 " X: 256
-
-let v:errmsg = ""
-if 1 ||| strlen("\"") | Xpath 512 " X: 0
- Xpath 1024 " X: 0
-endif
-Xpath 2048 " X: 2048
-if !MSG('E15', "Invalid expression")
- Xpath 4096 " X: 0
-endif
-
-let v:errmsg = ""
-if 0
-elseif 1 ||| strlen("\"") | Xpath 8192 " X: 0
- Xpath 16384 " X: 0
-endif
-Xpath 32768 " X: 32768
-if !MSG('E15', "Invalid expression")
- Xpath 65536 " X: 0
-endif
-
-let v:errmsg = ""
-while 1 ||| strlen("\"") | Xpath 131072 " X: 0
- Xpath 262144 " X: 0
- break
-endwhile
-Xpath 524288 " X: 524288
-if !MSG('E15', "Invalid expression")
- Xpath 1048576 " X: 0
-endif
-
-delfunction MSG
-
-Xcheck 559615
-
-
-"-------------------------------------------------------------------------------
-" Test 11: :if, :elseif, :while argument evaluation after abort {{{1
-"
-" When code is skipped over due to an error, the boolean argument to
-" an :if, :elseif, or :while must not be evaluated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let calls = 0
-
-function! P(num)
- let g:calls = g:calls + a:num " side effect on call
- return 0
-endfunction
-
-if 1
- Xpath 1 " X: 1
- asdf " error
- Xpath 2 " X: 0
- if P(1) " should not be called
- Xpath 4 " X: 0
- elseif !P(2) " should not be called
- Xpath 8 " X: 0
- else
- Xpath 16 " X: 0
- endif
- Xpath 32 " X: 0
- while P(4) " should not be called
- Xpath 64 " X: 0
- endwhile
- Xpath 128 " X: 0
-endif
-
-if calls % 2
- Xpath 256 " X: 0
-endif
-if (calls/2) % 2
- Xpath 512 " X: 0
-endif
-if (calls/4) % 2
- Xpath 1024 " X: 0
-endif
-Xpath 2048 " X: 2048
-
-unlet calls
-delfunction P
-
-Xcheck 2049
-
-
-"-------------------------------------------------------------------------------
-" Test 12: Expressions in braces in skipped code {{{1
-"
-" In code skipped over due to an error or inactive conditional,
-" an expression in braces as part of a variable or function name
-" should not be evaluated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT 1 8
-
-function! NULL()
- Xloop 1 " X: 0
- return 0
-endfunction
-
-function! ZERO()
- Xloop 2 " X: 0
- return 0
-endfunction
-
-function! F0()
- Xloop 4 " X: 0
-endfunction
-
-function! F1(arg)
- Xpath 4096 " X: 0
-endfunction
-
-let V0 = 1
-
-Xpath 8192 " X: 8192
-echo 0 ? F{NULL() + V{ZERO()}}() : 1
-XloopNEXT
-
-Xpath 16384 " X: 16384
-if 0
- Xpath 32768 " X: 0
- call F{NULL() + V{ZERO()}}()
-endif
-XloopNEXT
-
-Xpath 65536 " X: 65536
-if 1
- asdf " error
- Xpath 131072 " X: 0
- call F1(F{NULL() + V{ZERO()}}())
-endif
-XloopNEXT
-
-Xpath 262144 " X: 262144
-if 1
- asdf " error
- Xpath 524288 " X: 0
- call F{NULL() + V{ZERO()}}()
-endif
-
-Xcheck 352256
-
-
-"-------------------------------------------------------------------------------
-" Test 13: Failure in argument evaluation for :while {{{1
-"
-" A failure in the expression evaluation for the condition of a :while
-" causes the whole :while loop until the matching :endwhile being
-" ignored. Continuation is at the next following line.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-Xpath 1 " X: 1
-while asdf
- Xpath 2 " X: 0
- while 1
- Xpath 4 " X: 0
- break
- endwhile
- Xpath 8 " X: 0
- break
-endwhile
-Xpath 16 " X: 16
-
-while asdf | Xpath 32 | endwhile | Xpath 64 " X: 0
-Xpath 128 " X: 128
-
-Xcheck 145
-
-
-"-------------------------------------------------------------------------------
-" Test 14: Failure in argument evaluation for :if {{{1
-"
-" A failure in the expression evaluation for the condition of an :if
-" does not cause the corresponding :else or :endif being matched to
-" a previous :if/:elseif. Neither of both branches of the failed :if
-" are executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-XloopINIT 1 256
-
-function! F()
- Xloop 1 " X: 1 + 256 * 1
- let x = 0
- if x " false
- Xloop 2 " X: 0 + 256 * 0
- elseif !x " always true
- Xloop 4 " X: 4 + 256 * 4
- let x = 1
- if g:boolvar " possibly undefined
- Xloop 8 " X: 8 + 256 * 0
- else
- Xloop 16 " X: 0 + 256 * 0
- endif
- Xloop 32 " X: 32 + 256 * 32
- elseif x " never executed
- Xloop 64 " X: 0 + 256 * 0
- endif
- Xloop 128 " X: 128 + 256 * 128
-endfunction
-
-let boolvar = 1
-call F()
-
-XloopNEXT
-unlet boolvar
-call F()
-
-delfunction F
-
-Xcheck 42413
-
-
-"-------------------------------------------------------------------------------
-" Test 15: Failure in argument evaluation for :if (bar) {{{1
-"
-" Like previous test, except that the failing :if ... | ... | :endif
-" is in a single line.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-XloopINIT 1 256
-
-function! F()
- Xloop 1 " X: 1 + 256 * 1
- let x = 0
- if x " false
- Xloop 2 " X: 0 + 256 * 0
- elseif !x " always true
- Xloop 4 " X: 4 + 256 * 4
- let x = 1
- if g:boolvar | Xloop 8 | else | Xloop 16 | endif " X: 8
- Xloop 32 " X: 32 + 256 * 32
- elseif x " never executed
- Xloop 64 " X: 0 + 256 * 0
- endif
- Xloop 128 " X: 128 + 256 * 128
-endfunction
-
-let boolvar = 1
-call F()
-
-XloopNEXT
-unlet boolvar
-call F()
-
-delfunction F
-
-Xcheck 42413
-
+" Tests 1 to 15 were moved to test_viml.vim
+let Xtest = 16
"-------------------------------------------------------------------------------
" Test 16: Double :else or :elseif after :else {{{1
@@ -6591,8 +5749,7 @@ function! F()
if !caught && !$VIMNOERRTHROW
Xpath 8192 " X: 0
endif
- if caught ? !MSG('E55', 'Unmatched \\)')
- \ : !MSG('E475', "Invalid argument")
+ if !MSG('E475', "Invalid argument")
Xpath 16384 " X: 0
endif
if !caught
diff --git a/src/nvim/testdir/test68.in b/src/nvim/testdir/test68.in
deleted file mode 100644
index ca54e942b5..0000000000
--- a/src/nvim/testdir/test68.in
+++ /dev/null
@@ -1,131 +0,0 @@
-Test for text formatting.
-
-Results of test68:
-
-STARTTEST
-:so small.vim
-/^{/+1
-:set noai tw=2 fo=t
-gRa b
-ENDTEST
-
-{
-
-
-}
-
-STARTTEST
-/^{/+1
-:set ai tw=2 fo=tw
-gqgqjjllab
-ENDTEST
-
-{
-a b
-
-a
-}
-
-STARTTEST
-/^{/+1
-:set tw=3 fo=t
-gqgqo
-a 
-ENDTEST
-
-{
-a 
-}
-
-STARTTEST
-/^{/+1
-:set tw=2 fo=tcq1 comments=:#
-gqgqjgqgqo
-a b
-#a b
-ENDTEST
-
-{
-a b
-#a b
-}
-
-STARTTEST
-/^{/+1
-:set tw=5 fo=tcn comments=:#
-A bjA b
-ENDTEST
-
-{
- 1 a
-# 1 a
-}
-
-STARTTEST
-/^{/+3
-:set tw=5 fo=t2a si
-i A_
-ENDTEST
-
-{
-
- x a
- b
- c
-
-}
-
-STARTTEST
-/^{/+1
-:set tw=5 fo=qn comments=:#
-gwap
-ENDTEST
-
-{
-# 1 a b
-}
-
-STARTTEST
-/^{/+1
-:set tw=5 fo=q2 comments=:#
-gwap
-ENDTEST
-
-{
-# x
-# a b
-}
-
-STARTTEST
-/^{/+2
-:set tw& fo=a
-I^^
-ENDTEST
-
-{
- 1aa
- 2bb
-}
-
-STARTTEST
-/mno pqr/
-:setl tw=20 fo=an12wcq comments=s1:/*,mb:*,ex:*/
-A vwx yz
-ENDTEST
-
-/* abc def ghi jkl
- * mno pqr stu
- */
-
-STARTTEST
-/^#/
-:setl tw=12 fo=tqnc comments=:#
-A foobar
-ENDTEST
-
-# 1 xxxxx
-
-STARTTEST
-:g/^STARTTEST/.,/^ENDTEST/d
-:1;/^Results/,$wq! test.out
-ENDTEST
diff --git a/src/nvim/testdir/test68.ok b/src/nvim/testdir/test68.ok
deleted file mode 100644
index b3726a0a27..0000000000
--- a/src/nvim/testdir/test68.ok
+++ /dev/null
@@ -1,77 +0,0 @@
-Results of test68:
-
-
-{
-a
-b
-}
-
-
-{
-a
-b
-
-a
-b
-}
-
-
-{
-a
-
-
-a
-
-}
-
-
-{
-a b
-#a b
-
-a b
-#a b
-}
-
-
-{
- 1 a
- b
-# 1 a
-# b
-}
-
-
-{
-
- x a
- b_
- c
-
-}
-
-
-{
-# 1 a
-# b
-}
-
-
-{
-# x a
-# b
-}
-
-
-{ 1aa ^^2bb }
-
-
-/* abc def ghi jkl
- * mno pqr stu
- * vwx yz
- */
-
-
-# 1 xxxxx
-# foobar
-
diff --git a/src/nvim/testdir/test88.in b/src/nvim/testdir/test88.in
deleted file mode 100644
index 9e43f703e9..0000000000
--- a/src/nvim/testdir/test88.in
+++ /dev/null
@@ -1,99 +0,0 @@
-vim: set ft=vim
-
-Tests for correct display (cursor column position) with +conceal and
-tabulators.
-
-STARTTEST
-:so small.vim
-:if !has('conceal')
- e! test.ok
- wq! test.out
-:endif
-:" Conceal settings.
-:set conceallevel=2
-:set concealcursor=nc
-:syntax match test /|/ conceal
-:" Save current cursor position. Only works in <expr> mode, can't be used
-:" with :normal because it moves the cursor to the command line. Thanks to ZyX
-:" <zyx.vim@gmail.com> for the idea to use an <expr> mapping.
-:let positions = []
-:nnoremap <expr> GG ":let positions += ['".screenrow().":".screencol()."']\n"
-:" Start test.
-/^start:
-:normal ztj
-GGk
-:" We should end up in the same column when running these commands on the two
-:" lines.
-:normal ft
-GGk
-:normal $
-GGk
-:normal 0j
-GGk
-:normal ft
-GGk
-:normal $
-GGk
-:normal 0j0j
-GGk
-:" Same for next test block.
-:normal ft
-GGk
-:normal $
-GGk
-:normal 0j
-GGk
-:normal ft
-GGk
-:normal $
-GGk
-:normal 0j0j
-GGk
-:" And check W with multiple tabs and conceals in a line.
-:normal W
-GGk
-:normal W
-GGk
-:normal W
-GGk
-:normal $
-GGk
-:normal 0j
-GGk
-:normal W
-GGk
-:normal W
-GGk
-:normal W
-GGk
-:normal $
-GGk
-:set lbr
-:normal $
-GGk
-:set list listchars=tab:>-
-:normal 0
-GGk
-:normal W
-GGk
-:normal W
-GGk
-:normal W
-GGk
-:normal $
-GGk
-:" Display result.
-:call append('$', 'end:')
-:call append('$', positions)
-:/^end/,$wq! test.out
-ENDTEST
-
-start:
-.concealed. text
-|concealed| text
-
- .concealed. text
- |concealed| text
-
-.a. .b. .c. .d.
-|a| |b| |c| |d|
diff --git a/src/nvim/testdir/test88.ok b/src/nvim/testdir/test88.ok
deleted file mode 100644
index 12949f274a..0000000000
--- a/src/nvim/testdir/test88.ok
+++ /dev/null
@@ -1,29 +0,0 @@
-end:
-2:1
-2:17
-2:20
-3:1
-3:17
-3:20
-5:8
-5:25
-5:28
-6:8
-6:25
-6:28
-8:1
-8:9
-8:17
-8:25
-8:27
-9:1
-9:9
-9:17
-9:25
-9:26
-9:26
-9:1
-9:9
-9:17
-9:25
-9:26
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
new file mode 100644
index 0000000000..1d1da94bac
--- /dev/null
+++ b/src/nvim/testdir/test_alot.vim
@@ -0,0 +1,3 @@
+" A series of tests that can run in one Vim invocation.
+" This makes testing go faster, since Vim doesn't need to restart.
+
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
new file mode 100644
index 0000000000..d819b7b092
--- /dev/null
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -0,0 +1,52 @@
+" Tests for cursor().
+
+func Test_wrong_arguments()
+ try
+ call cursor(1. 3)
+ " not reached
+ call assert_false(1)
+ catch
+ call assert_exception('E474:')
+ endtry
+endfunc
+
+func Test_move_cursor()
+ new
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+
+ call cursor([1, 1, 0, 1])
+ call assert_equal([1, 1, 0, 1], getcurpos()[1:])
+ call cursor([4, 3, 0, 3])
+ call assert_equal([4, 3, 0, 3], getcurpos()[1:])
+
+ call cursor(2, 2)
+ call assert_equal([2, 2, 0, 2], getcurpos()[1:])
+ " line number zero keeps the line number
+ call cursor(0, 1)
+ call assert_equal([2, 1, 0, 1], getcurpos()[1:])
+ " col number zero keeps the column
+ call cursor(3, 0)
+ call assert_equal([3, 1, 0, 1], getcurpos()[1:])
+ " below last line goes to last line
+ call cursor(9, 1)
+ call assert_equal([4, 1, 0, 1], getcurpos()[1:])
+
+ quit!
+endfunc
+
+" Very short version of what matchparen does.
+function s:Highlight_Matching_Pair()
+ let save_cursor = getcurpos()
+ call setpos('.', save_cursor)
+endfunc
+
+func Test_curswant_with_autocommand()
+ new
+ call setline(1, ['func()', '{', '}', '----'])
+ autocmd! CursorMovedI * call s:Highlight_Matching_Pair()
+ exe "normal! 3Ga\<Down>X\<Esc>"
+ call assert_equal('-X---', getline(4))
+ autocmd! CursorMovedI *
+ quit!
+endfunc
+
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
new file mode 100644
index 0000000000..9f9207d27d
--- /dev/null
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -0,0 +1,40 @@
+" Tests for :help! {subject}
+
+func SetUp()
+ " v:progpath is …/build/bin/nvim and we need …/build/runtime
+ " to be added to &rtp
+ let builddir = fnamemodify(exepath(v:progpath), ':h:h')
+ let s:rtp = &rtp
+ let &rtp .= printf(',%s/runtime', builddir)
+endfunc
+
+func TearDown()
+ let &rtp = s:rtp
+endfunc
+
+func Test_help_tagjump()
+ help
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*help.txt\*')
+ helpclose
+
+ exec "help! ('textwidth'"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'textwidth'\\*")
+ helpclose
+
+ exec "help! ('buflisted'),"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'buflisted'\\*")
+ helpclose
+
+ exec "help! abs({expr})"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*abs()\*')
+ helpclose
+
+ exec "help! arglistid([{winnr})"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*arglistid()\*')
+ helpclose
+endfunc
diff --git a/src/nvim/testdir/test_marks.in b/src/nvim/testdir/test_marks.in
deleted file mode 100644
index 23c2fb65fe..0000000000
--- a/src/nvim/testdir/test_marks.in
+++ /dev/null
@@ -1,34 +0,0 @@
-Tests for marks.
-
-STARTTEST
-:so small.vim
-:" test that a deleted mark is restored after delete-undo-redo-undo
-:/^\t/+1
-:set nocp viminfo+=nviminfo
-madduu
-:let a = string(getpos("'a"))
-:$put ='Mark after delete-undo-redo-undo: '.a
-:''
-ENDTEST
-
- textline A
- textline B
- textline C
-
-STARTTEST
-:" test that CTRL-A and CTRL-X updates last changed mark '[, '].
-:/^123/
-:execute "normal! \<C-A>`[v`]rAjwvjw\<C-X>`[v`]rX"
-ENDTEST
-
-CTRL-A CTRL-X:
-123 123 123
-123 123 123
-123 123 123
-
-STARTTEST
-:g/^STARTTEST/.,/^ENDTEST/d
-:wq! test.out
-ENDTEST
-
-Results:
diff --git a/src/nvim/testdir/test_marks.ok b/src/nvim/testdir/test_marks.ok
deleted file mode 100644
index e6c02ee7b0..0000000000
--- a/src/nvim/testdir/test_marks.ok
+++ /dev/null
@@ -1,16 +0,0 @@
-Tests for marks.
-
-
- textline A
- textline B
- textline C
-
-
-CTRL-A CTRL-X:
-AAA 123 123
-123 XXXXXXX
-XXX 123 123
-
-
-Results:
-Mark after delete-undo-redo-undo: [0, 15, 2, 0]
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
new file mode 100644
index 0000000000..be559467c8
--- /dev/null
+++ b/src/nvim/testdir/test_menu.vim
@@ -0,0 +1,9 @@
+" Test that the system menu can be loaded.
+
+func Test_load_menu()
+ try
+ source $VIMRUNTIME/menu.vim
+ catch
+ call assert_false(1, 'error while loading menus: ' . v:exception)
+ endtry
+endfunc
diff --git a/src/nvim/testdir/test_viml.vim b/src/nvim/testdir/test_viml.vim
new file mode 100644
index 0000000000..9f0618bd45
--- /dev/null
+++ b/src/nvim/testdir/test_viml.vim
@@ -0,0 +1,930 @@
+" Test various aspects of the Vim language.
+" Most of this was formerly in test49.
+
+"-------------------------------------------------------------------------------
+" Test environment {{{1
+"-------------------------------------------------------------------------------
+
+com! XpathINIT let g:Xpath = ''
+com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args>
+
+" Append a message to the "messages" file
+func! Xout(text)
+ split messages
+ $put =a:text
+ wq
+endfunc
+
+com! -nargs=1 Xout call Xout(<args>)
+
+" MakeScript() - Make a script file from a function. {{{2
+"
+" Create a script that consists of the body of the function a:funcname.
+" Replace any ":return" by a ":finish", any argument variable by a global
+" variable, and and every ":call" by a ":source" for the next following argument
+" in the variable argument list. This function is useful if similar tests are
+" to be made for a ":return" from a function call or a ":finish" in a script
+" file.
+function! MakeScript(funcname, ...)
+ let script = tempname()
+ execute "redir! >" . script
+ execute "function" a:funcname
+ redir END
+ execute "edit" script
+ " Delete the "function" and the "endfunction" lines. Do not include the
+ " word "function" in the pattern since it might be translated if LANG is
+ " set. When MakeScript() is being debugged, this deletes also the debugging
+ " output of its line 3 and 4.
+ exec '1,/.*' . a:funcname . '(.*)/d'
+ /^\d*\s*endfunction\>/,$d
+ %s/^\d*//e
+ %s/return/finish/e
+ %s/\<a:\(\h\w*\)/g:\1/ge
+ normal gg0
+ let cnt = 0
+ while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
+ let cnt = cnt + 1
+ s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
+ endwhile
+ g/^\s*$/d
+ write
+ bwipeout
+ return script
+endfunction
+
+" ExecAsScript - Source a temporary script made from a function. {{{2
+"
+" Make a temporary script file from the function a:funcname, ":source" it, and
+" delete it afterwards.
+function! ExecAsScript(funcname)
+ " Make a script from the function passed as argument.
+ let script = MakeScript(a:funcname)
+
+ " Source and delete the script.
+ exec "source" script
+ call delete(script)
+endfunction
+
+com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
+
+
+"-------------------------------------------------------------------------------
+" Test 1: :endwhile in function {{{1
+"
+" Detect if a broken loop is (incorrectly) reactivated by the
+" :endwhile. Use a :return to prevent an endless loop, and make
+" this test first to get a meaningful result on an error before other
+" tests will hang.
+"-------------------------------------------------------------------------------
+
+function! T1_F()
+ Xpath 'a'
+ let first = 1
+ while 1
+ Xpath 'b'
+ if first
+ Xpath 'c'
+ let first = 0
+ break
+ else
+ Xpath 'd'
+ return
+ endif
+ endwhile
+endfunction
+
+function! T1_G()
+ Xpath 'h'
+ let first = 1
+ while 1
+ Xpath 'i'
+ if first
+ Xpath 'j'
+ let first = 0
+ break
+ else
+ Xpath 'k'
+ return
+ endif
+ if 1 " unmatched :if
+ endwhile
+endfunction
+
+func Test_endwhile_function()
+ XpathINIT
+ call T1_F()
+ Xpath 'F'
+
+ try
+ call T1_G()
+ catch
+ " Catch missing :endif
+ call assert_true(v:exception =~ 'E171')
+ Xpath 'x'
+ endtry
+ Xpath 'G'
+
+ call assert_equal('abcFhijxG', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 2: :endwhile in script {{{1
+"
+" Detect if a broken loop is (incorrectly) reactivated by the
+" :endwhile. Use a :finish to prevent an endless loop, and place
+" this test before others that might hang to get a meaningful result
+" on an error.
+"
+" This test executes the bodies of the functions T1_F and T1_G from
+" the previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+func Test_endwhile_script()
+ XpathINIT
+ ExecAsScript T1_F
+ Xpath 'F'
+
+ try
+ ExecAsScript T1_G
+ catch
+ " Catch missing :endif
+ call assert_true(v:exception =~ 'E171')
+ Xpath 'x'
+ endtry
+ Xpath 'G'
+
+ call assert_equal('abcFhijxG', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 3: :if, :elseif, :while, :continue, :break {{{1
+"-------------------------------------------------------------------------------
+
+function Test_if_while()
+ XpathINIT
+ if 1
+ Xpath 'a'
+ let loops = 3
+ while loops > -1 " main loop: loops == 3, 2, 1 (which breaks)
+ if loops <= 0
+ let break_err = 1
+ let loops = -1
+ else
+ Xpath 'b' . loops
+ endif
+ if (loops == 2)
+ while loops == 2 " dummy loop
+ Xpath 'c' . loops
+ let loops = loops - 1
+ continue " stop dummy loop
+ Xpath 'd' . loops
+ endwhile
+ continue " continue main loop
+ Xpath 'e' . loops
+ elseif (loops == 1)
+ let p = 1
+ while p " dummy loop
+ Xpath 'f' . loops
+ let p = 0
+ break " break dummy loop
+ Xpath 'g' . loops
+ endwhile
+ Xpath 'h' . loops
+ unlet p
+ break " break main loop
+ Xpath 'i' . loops
+ endif
+ if (loops > 0)
+ Xpath 'j' . loops
+ endif
+ while loops == 3 " dummy loop
+ let loops = loops - 1
+ endwhile " end dummy loop
+ endwhile " end main loop
+ Xpath 'k'
+ else
+ Xpath 'l'
+ endif
+ Xpath 'm'
+ if exists("break_err")
+ Xpath 'm'
+ unlet break_err
+ endif
+
+ unlet loops
+
+ call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 4: :return {{{1
+"-------------------------------------------------------------------------------
+
+function! T4_F()
+ if 1
+ Xpath 'a'
+ let loops = 3
+ while loops > 0 " 3: 2: 1:
+ Xpath 'b' . loops
+ if (loops == 2)
+ Xpath 'c' . loops
+ return
+ Xpath 'd' . loops
+ endif
+ Xpath 'e' . loops
+ let loops = loops - 1
+ endwhile
+ Xpath 'f'
+ else
+ Xpath 'g'
+ endif
+endfunction
+
+function Test_return()
+ XpathINIT
+ call T4_F()
+ Xpath '4'
+
+ call assert_equal('ab3e3b2c24', g:Xpath)
+endfunction
+
+
+"-------------------------------------------------------------------------------
+" Test 5: :finish {{{1
+"
+" This test executes the body of the function T4_F from the previous
+" test as a script file (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+function Test_finish()
+ XpathINIT
+ ExecAsScript T4_F
+ Xpath '5'
+
+ call assert_equal('ab3e3b2c25', g:Xpath)
+endfunction
+
+
+
+"-------------------------------------------------------------------------------
+" Test 6: Defining functions in :while loops {{{1
+"
+" Functions can be defined inside other functions. An inner function
+" gets defined when the outer function is executed. Functions may
+" also be defined inside while loops. Expressions in braces for
+" defining the function name are allowed.
+"
+" The functions are defined when sourcing the script, only the
+" resulting path is checked in the test function.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+" The command CALL collects the argument of all its invocations in "calls"
+" when used from a function (that is, when the global variable "calls" needs
+" the "g:" prefix). This is to check that the function code is skipped when
+" the function is defined. For inner functions, do so only if the outer
+" function is not being executed.
+"
+let calls = ""
+com! -nargs=1 CALL
+ \ if !exists("calls") && !exists("outer") |
+ \ let g:calls = g:calls . <args> |
+ \ endif
+
+let i = 0
+while i < 3
+ let i = i + 1
+ if i == 1
+ Xpath 'a'
+ function! F1(arg)
+ CALL a:arg
+ let outer = 1
+
+ let j = 0
+ while j < 1
+ Xpath 'b'
+ let j = j + 1
+ function! G1(arg)
+ CALL a:arg
+ endfunction
+ Xpath 'c'
+ endwhile
+ endfunction
+ Xpath 'd'
+
+ continue
+ endif
+
+ Xpath 'e' . i
+ function! F{i}(i, arg)
+ CALL a:arg
+ let outer = 1
+
+ if a:i == 3
+ Xpath 'f'
+ endif
+ let k = 0
+ while k < 3
+ Xpath 'g' . k
+ let k = k + 1
+ function! G{a:i}{k}(arg)
+ CALL a:arg
+ endfunction
+ Xpath 'h' . k
+ endwhile
+ endfunction
+ Xpath 'i'
+
+endwhile
+
+if exists("*G1")
+ Xpath 'j'
+endif
+if exists("*F1")
+ call F1("F1")
+ if exists("*G1")
+ call G1("G1")
+ endif
+endif
+
+if exists("G21") || exists("G22") || exists("G23")
+ Xpath 'k'
+endif
+if exists("*F2")
+ call F2(2, "F2")
+ if exists("*G21")
+ call G21("G21")
+ endif
+ if exists("*G22")
+ call G22("G22")
+ endif
+ if exists("*G23")
+ call G23("G23")
+ endif
+endif
+
+if exists("G31") || exists("G32") || exists("G33")
+ Xpath 'l'
+endif
+if exists("*F3")
+ call F3(3, "F3")
+ if exists("*G31")
+ call G31("G31")
+ endif
+ if exists("*G32")
+ call G32("G32")
+ endif
+ if exists("*G33")
+ call G33("G33")
+ endif
+endif
+
+Xpath 'm'
+
+let g:test6_result = g:Xpath
+let g:test6_calls = calls
+
+unlet calls
+delfunction F1
+delfunction G1
+delfunction F2
+delfunction G21
+delfunction G22
+delfunction G23
+delfunction G31
+delfunction G32
+delfunction G33
+
+function Test_defining_functions()
+ call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
+ call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 7: Continuing on errors outside functions {{{1
+"
+" On an error outside a function, the script processing continues
+" at the line following the outermost :endif or :endwhile. When not
+" inside an :if or :while, the script processing continues at the next
+" line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ break
+ endwhile | Xpath 'd'
+ Xpath 'e'
+endif | Xpath 'f'
+Xpath 'g'
+
+while 1
+ Xpath 'h'
+ if 1
+ Xpath 'i'
+ asdf
+ Xpath 'j'
+ endif | Xpath 'k'
+ Xpath 'l'
+ break
+endwhile | Xpath 'm'
+Xpath 'n'
+
+asdf
+Xpath 'o'
+
+asdf | Xpath 'p'
+Xpath 'q'
+
+let g:test7_result = g:Xpath
+
+func Test_error_in_script()
+ call assert_equal('abghinoq', g:test7_result)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 8: Aborting and continuing on errors inside functions {{{1
+"
+" On an error inside a function without the "abort" attribute, the
+" script processing continues at the next line (unless the error was
+" in a :return command). On an error inside a function with the
+" "abort" attribute, the function is aborted and the script processing
+" continues after the function call; the value -1 is returned then.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! T8_F()
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ asdf | Xpath 'd'
+ Xpath 'e'
+ break
+ endwhile
+ Xpath 'f'
+ endif | Xpath 'g'
+ Xpath 'h'
+
+ while 1
+ Xpath 'i'
+ if 1
+ Xpath 'j'
+ asdf
+ Xpath 'k'
+ asdf | Xpath 'l'
+ Xpath 'm'
+ endif
+ Xpath 'n'
+ break
+ endwhile | Xpath 'o'
+ Xpath 'p'
+
+ return novar " returns (default return value 0)
+ Xpath 'q'
+ return 1 " not reached
+endfunction
+
+function! T8_G() abort
+ if 1
+ Xpath 'r'
+ while 1
+ Xpath 's'
+ asdf " returns -1
+ Xpath 't'
+ break
+ endwhile
+ Xpath 'v'
+ endif | Xpath 'w'
+ Xpath 'x'
+
+ return -4 " not reached
+endfunction
+
+function! T8_H() abort
+ while 1
+ Xpath 'A'
+ if 1
+ Xpath 'B'
+ asdf " returns -1
+ Xpath 'C'
+ endif
+ Xpath 'D'
+ break
+ endwhile | Xpath 'E'
+ Xpath 'F'
+
+ return -4 " not reached
+endfunction
+
+" Aborted functions (T8_G and T8_H) return -1.
+let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
+Xpath 'X'
+let g:test8_result = g:Xpath
+
+func Test_error_in_function()
+ call assert_equal(13, g:test8_sum)
+ call assert_equal('abcefghijkmnoprsABX', g:test8_result)
+
+ delfunction T8_F
+ delfunction T8_G
+ delfunction T8_H
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 9: Continuing after aborted functions {{{1
+"
+" When a function with the "abort" attribute is aborted due to an
+" error, the next function back in the call hierarchy without an
+" "abort" attribute continues; the value -1 is returned then.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F() abort
+ Xpath 'a'
+ let result = G() " not aborted
+ Xpath 'b'
+ if result != 2
+ Xpath 'c'
+ endif
+ return 1
+endfunction
+
+function! G() " no abort attribute
+ Xpath 'd'
+ if H() != -1 " aborted
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ return 2
+endfunction
+
+function! H() abort
+ Xpath 'g'
+ call I() " aborted
+ Xpath 'h'
+ return 4
+endfunction
+
+function! I() abort
+ Xpath 'i'
+ asdf " error
+ Xpath 'j'
+ return 8
+endfunction
+
+if F() != 1
+ Xpath 'k'
+endif
+
+let g:test9_result = g:Xpath
+
+delfunction F
+delfunction G
+delfunction H
+delfunction I
+
+func Test_func_abort()
+ call assert_equal('adgifb', g:test9_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 10: :if, :elseif, :while argument parsing {{{1
+"
+" A '"' or '|' in an argument expression must not be mixed up with
+" a comment or a next command after a bar. Parsing errors should
+" be recognized.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! MSG(enr, emsg)
+ let english = v:lang == "C" || v:lang =~ '^[Ee]n'
+ if a:enr == ""
+ Xout "TODO: Add message number for:" a:emsg
+ let v:errmsg = ":" . v:errmsg
+ endif
+ let match = 1
+ if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
+ let match = 0
+ if v:errmsg == ""
+ Xout "Message missing."
+ else
+ let v:errmsg = escape(v:errmsg, '"')
+ Xout "Unexpected message:" v:errmsg
+ endif
+ endif
+ return match
+endfunction
+
+if 1 || strlen("\"") | Xpath 'a'
+ Xpath 'b'
+endif
+Xpath 'c'
+
+if 0
+elseif 1 || strlen("\"") | Xpath 'd'
+ Xpath 'e'
+endif
+Xpath 'f'
+
+while 1 || strlen("\"") | Xpath 'g'
+ Xpath 'h'
+ break
+endwhile
+Xpath 'i'
+
+let v:errmsg = ""
+if 1 ||| strlen("\"") | Xpath 'j'
+ Xpath 'k'
+endif
+Xpath 'l'
+if !MSG('E15', "Invalid expression")
+ Xpath 'm'
+endif
+
+let v:errmsg = ""
+if 0
+elseif 1 ||| strlen("\"") | Xpath 'n'
+ Xpath 'o'
+endif
+Xpath 'p'
+if !MSG('E15', "Invalid expression")
+ Xpath 'q'
+endif
+
+let v:errmsg = ""
+while 1 ||| strlen("\"") | Xpath 'r'
+ Xpath 's'
+ break
+endwhile
+Xpath 't'
+if !MSG('E15', "Invalid expression")
+ Xpath 'u'
+endif
+
+let g:test10_result = g:Xpath
+delfunction MSG
+
+func Test_expr_parsing()
+ call assert_equal('abcdefghilpt', g:test10_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 11: :if, :elseif, :while argument evaluation after abort {{{1
+"
+" When code is skipped over due to an error, the boolean argument to
+" an :if, :elseif, or :while must not be evaluated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+let calls = 0
+
+function! P(num)
+ let g:calls = g:calls + a:num " side effect on call
+ return 0
+endfunction
+
+if 1
+ Xpath 'a'
+ asdf " error
+ Xpath 'b'
+ if P(1) " should not be called
+ Xpath 'c'
+ elseif !P(2) " should not be called
+ Xpath 'd'
+ else
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ while P(4) " should not be called
+ Xpath 'g'
+ endwhile
+ Xpath 'h'
+endif
+Xpath 'x'
+
+let g:test11_calls = calls
+let g:test11_result = g:Xpath
+
+unlet calls
+delfunction P
+
+func Test_arg_abort()
+ call assert_equal(0, g:test11_calls)
+ call assert_equal('ax', g:test11_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 12: Expressions in braces in skipped code {{{1
+"
+" In code skipped over due to an error or inactive conditional,
+" an expression in braces as part of a variable or function name
+" should not be evaluated.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! NULL()
+ Xpath 'a'
+ return 0
+endfunction
+
+function! ZERO()
+ Xpath 'b'
+ return 0
+endfunction
+
+function! F0()
+ Xpath 'c'
+endfunction
+
+function! F1(arg)
+ Xpath 'e'
+endfunction
+
+let V0 = 1
+
+Xpath 'f'
+echo 0 ? F{NULL() + V{ZERO()}}() : 1
+
+Xpath 'g'
+if 0
+ Xpath 'h'
+ call F{NULL() + V{ZERO()}}()
+endif
+
+Xpath 'i'
+if 1
+ asdf " error
+ Xpath 'j'
+ call F1(F{NULL() + V{ZERO()}}())
+endif
+
+Xpath 'k'
+if 1
+ asdf " error
+ Xpath 'l'
+ call F{NULL() + V{ZERO()}}()
+endif
+
+let g:test12_result = g:Xpath
+
+func Test_braces_skipped()
+ call assert_equal('fgik', g:test12_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 13: Failure in argument evaluation for :while {{{1
+"
+" A failure in the expression evaluation for the condition of a :while
+" causes the whole :while loop until the matching :endwhile being
+" ignored. Continuation is at the next following line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+Xpath 'a'
+while asdf
+ Xpath 'b'
+ while 1
+ Xpath 'c'
+ break
+ endwhile
+ Xpath 'd'
+ break
+endwhile
+Xpath 'e'
+
+while asdf | Xpath 'f' | endwhile | Xpath 'g'
+Xpath 'h'
+let g:test13_result = g:Xpath
+
+func Test_while_fail()
+ call assert_equal('aeh', g:test13_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 14: Failure in argument evaluation for :if {{{1
+"
+" A failure in the expression evaluation for the condition of an :if
+" does not cause the corresponding :else or :endif being matched to
+" a previous :if/:elseif. Neither of both branches of the failed :if
+" are executed.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 'a'
+ let x = 0
+ if x " false
+ Xpath 'b'
+ elseif !x " always true
+ Xpath 'c'
+ let x = 1
+ if g:boolvar " possibly undefined
+ Xpath 'd'
+ else
+ Xpath 'e'
+ endif
+ Xpath 'f'
+ elseif x " never executed
+ Xpath 'g'
+ endif
+ Xpath 'h'
+endfunction
+
+let boolvar = 1
+call F()
+Xpath '-'
+
+unlet boolvar
+call F()
+let g:test14_result = g:Xpath
+
+delfunction F
+
+func Test_if_fail()
+ call assert_equal('acdfh-acfh', g:test14_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 15: Failure in argument evaluation for :if (bar) {{{1
+"
+" Like previous test, except that the failing :if ... | ... | :endif
+" is in a single line.
+"-------------------------------------------------------------------------------
+
+XpathINIT
+
+function! F()
+ Xpath 'a'
+ let x = 0
+ if x " false
+ Xpath 'b'
+ elseif !x " always true
+ Xpath 'c'
+ let x = 1
+ if g:boolvar | Xpath 'd' | else | Xpath 'e' | endif
+ Xpath 'f'
+ elseif x " never executed
+ Xpath 'g'
+ endif
+ Xpath 'h'
+endfunction
+
+let boolvar = 1
+call F()
+Xpath '-'
+
+unlet boolvar
+call F()
+let g:test15_result = g:Xpath
+
+delfunction F
+
+func Test_if_bar_fail()
+ call assert_equal('acdfh-acfh', g:test15_result)
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Test 16: Recognizing {} in variable name. {{{1
+"-------------------------------------------------------------------------------
+
+func Test_curlies()
+ let s:var = 66
+ let ns = 's'
+ call assert_equal(66, {ns}:var)
+
+ let g:a = {}
+ let g:b = 't'
+ let g:a[g:b] = 77
+ call assert_equal(77, g:a['t'])
+endfunc
+
+
+"-------------------------------------------------------------------------------
+" Modelines {{{1
+" vim: ts=8 sw=4 tw=80 fdm=marker
+" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "")
+"-------------------------------------------------------------------------------
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index b41e4d2fba..99eb230a88 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -224,9 +224,9 @@ static void tk_getkeys(TermInput *input, bool force)
while ((result = tk_getkey(input->tk, &key, force)) == TERMKEY_RES_KEY) {
if (key.type == TERMKEY_TYPE_UNICODE && !key.modifiers) {
forward_simple_utf8(input, &key);
- } else if (key.type == TERMKEY_TYPE_UNICODE ||
- key.type == TERMKEY_TYPE_FUNCTION ||
- key.type == TERMKEY_TYPE_KEYSYM) {
+ } else if (key.type == TERMKEY_TYPE_UNICODE
+ || key.type == TERMKEY_TYPE_FUNCTION
+ || key.type == TERMKEY_TYPE_KEYSYM) {
forward_modified_utf8(input, &key);
} else if (key.type == TERMKEY_TYPE_MOUSE) {
forward_mouse_event(input, &key);
@@ -282,9 +282,9 @@ static bool handle_focus_event(TermInput *input)
static bool handle_bracketed_paste(TermInput *input)
{
- if (rbuffer_size(input->read_stream.buffer) > 5 &&
- (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6) ||
- !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) {
+ if (rbuffer_size(input->read_stream.buffer) > 5
+ && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[200~", 6)
+ || !rbuffer_cmp(input->read_stream.buffer, "\x1b[201~", 6))) {
bool enable = *rbuffer_get(input->read_stream.buffer, 4) == '0';
// Advance past the sequence
rbuffer_consumed(input->read_stream.buffer, 6);
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 00e2821075..62bc81ba64 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -81,7 +81,7 @@ UI *tui_start(void)
{
UI *ui = xcalloc(1, sizeof(UI));
ui->stop = tui_stop;
- ui->rgb = os_getenv("NVIM_TUI_ENABLE_TRUE_COLOR") != NULL;
+ ui->rgb = p_tgc;
ui->resize = tui_resize;
ui->clear = tui_clear;
ui->eol_clear = tui_eol_clear;
@@ -100,6 +100,7 @@ UI *tui_start(void)
ui->visual_bell = tui_visual_bell;
ui->update_fg = tui_update_fg;
ui->update_bg = tui_update_bg;
+ ui->update_sp = tui_update_sp;
ui->flush = tui_flush;
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
@@ -573,6 +574,11 @@ static void tui_update_bg(UI *ui, int bg)
((TUIData *)ui->data)->grid.bg = bg;
}
+static void tui_update_sp(UI *ui, int sp)
+{
+ // Do nothing; 'special' color is for GUI only
+}
+
static void tui_flush(UI *ui)
{
TUIData *data = ui->data;
@@ -628,8 +634,8 @@ static void tui_suspend(UI *ui)
static void tui_set_title(UI *ui, char *title)
{
TUIData *data = ui->data;
- if (!(title && unibi_get_str(data->ut, unibi_to_status_line) &&
- unibi_get_str(data->ut, unibi_from_status_line))) {
+ if (!(title && unibi_get_str(data->ut, unibi_to_status_line)
+ && unibi_get_str(data->ut, unibi_from_status_line))) {
return;
}
unibi_out(ui, unibi_to_status_line);
@@ -694,8 +700,8 @@ static void update_size(UI *ui)
}
// 2 - try from a system call(ioctl/TIOCGWINSZ on unix)
- if (data->out_isatty &&
- !uv_tty_get_winsize(&data->output_handle.tty, &width, &height)) {
+ if (data->out_isatty
+ && !uv_tty_get_winsize(&data->output_handle.tty, &width, &height)) {
goto end;
}
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index df51e1fced..ad6d96a168 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -21,7 +21,7 @@ struct ugrid {
UCell **cells;
};
-#define EMPTY_ATTRS ((HlAttrs){false, false, false, false, false, -1, -1})
+#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
do { \
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index d32969f149..05322a6f64 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -155,6 +155,7 @@ void ui_resize(int new_width, int new_height)
UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1));
UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1));
+ UI_CALL(update_sp, (ui->rgb ? normal_sp : -1));
sr.top = 0;
sr.bot = height - 1;
@@ -388,7 +389,7 @@ static void parse_control_character(uint8_t c)
static void set_highlight_args(int attr_code)
{
- HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 };
+ HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 };
HlAttrs cterm_attrs = rgb_attrs;
if (attr_code == HL_NORMAL) {
@@ -425,6 +426,10 @@ static void set_highlight_args(int attr_code)
rgb_attrs.background = aep->rgb_bg_color;
}
+ if (aep->rgb_sp_color != normal_sp) {
+ rgb_attrs.special = aep->rgb_sp_color;
+ }
+
if (cterm_normal_fg_color != aep->cterm_fg_color) {
cterm_attrs.foreground = aep->cterm_fg_color - 1;
}
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 4c051fcfbf..5934d2fee9 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -7,7 +7,7 @@
typedef struct {
bool bold, underline, undercurl, italic, reverse;
- int foreground, background;
+ int foreground, background, special;
} HlAttrs;
typedef struct ui_t UI;
@@ -35,6 +35,7 @@ struct ui_t {
void (*flush)(UI *ui);
void (*update_fg)(UI *ui, int fg);
void (*update_bg)(UI *ui, int bg);
+ void (*update_sp)(UI *ui, int sp);
void (*suspend)(UI *ui);
void (*set_title)(UI *ui, char *title);
void (*set_icon)(UI *ui, char *icon);
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 359fffe3bf..fd9d4671e3 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -49,6 +49,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.visual_bell = ui_bridge_visual_bell;
rv->bridge.update_fg = ui_bridge_update_fg;
rv->bridge.update_bg = ui_bridge_update_bg;
+ rv->bridge.update_sp = ui_bridge_update_sp;
rv->bridge.flush = ui_bridge_flush;
rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title;
@@ -305,6 +306,16 @@ static void ui_bridge_update_bg_event(void **argv)
ui->update_bg(ui, PTR2INT(argv[1]));
}
+static void ui_bridge_update_sp(UI *b, int sp)
+{
+ UI_CALL(b, update_sp, 2, b, INT2PTR(sp));
+}
+static void ui_bridge_update_sp_event(void **argv)
+{
+ UI *ui = UI(argv[0]);
+ ui->update_sp(ui, PTR2INT(argv[1]));
+}
+
static void ui_bridge_flush(UI *b)
{
UI_CALL(b, flush, 1, b);
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 4a8a24d79d..f16b4264d7 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -1782,7 +1782,13 @@ void undo_time(long step, int sec, int file, int absolute)
/* "target" is the node below which we want to be.
* Init "closest" to a value we can't reach. */
if (absolute) {
- target = step;
+ if (step == 0) {
+ // target 0 does not exist, got to 1 and above it.
+ target = 1;
+ above = true;
+ } else {
+ target = step;
+ }
closest = -1;
} else {
/* When doing computations with time_t subtract starttime, because
@@ -2870,9 +2876,7 @@ static char_u *u_save_line(linenr_T lnum)
/// @return true if the buffer has changed
bool bufIsChanged(buf_T *buf)
{
- return
- !bt_dontwrite(buf) &&
- (buf->b_changed || file_ff_differs(buf, true));
+ return !bt_dontwrite(buf) && (buf->b_changed || file_ff_differs(buf, true));
}
/// Check if the 'modified' flag is set, or 'ff' has changed (only need to
@@ -2882,9 +2886,8 @@ bool bufIsChanged(buf_T *buf)
/// @return true if the current buffer has changed
bool curbufIsChanged(void)
{
- return
- !bt_dontwrite(curbuf) &&
- (curbuf->b_changed || file_ff_differs(curbuf, true));
+ return (!bt_dontwrite(curbuf)
+ && (curbuf->b_changed || file_ff_differs(curbuf, true)));
}
/*
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 80b1b236dd..be66ba14fa 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,8 +69,402 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
- 1366,
+ 1832,
+ 1809,
+ 1808,
+ 1806,
+ 1799,
+ 1757,
+ 1755,
+ 1753,
+ 1728,
+ 1654,
+ 1652,
+ 1643,
+ 1641,
+
+ // 1600 NA
+ // 1599 NA
+ // 1598 NA
+ // 1597 NA
+ // 1596,
+ // 1595 NA
+ // 1594 NA
+ // 1593 NA
+ // 1592,
+ // 1591,
+ // 1590,
+ // 1589,
+ // 1588,
+ // 1587 NA
+ // 1586,
+ // 1585,
+ // 1584 NA
+ // 1583 NA
+ // 1582,
+ // 1581,
+ // 1580,
+ // 1579,
+ // 1578,
+ // 1577,
+ 1576,
+ // 1575 NA
+ 1574,
+ // 1573,
+ // 1572 NA
+ 1571,
+ 1570,
+ 1569,
+ 1568,
+ // 1567,
+ // 1566 NA
+ // 1565,
+ // 1564,
+ // 1563,
+ // 1562 NA
+ // 1561 NA
+ // 1560,
+ // 1559,
+ // 1558,
+ // 1557,
+ // 1556,
+ // 1555,
+ // 1554,
+ // 1553,
+ // 1552,
+ // 1551,
+ // 1550,
+ // 1549,
+ // 1548,
+ // 1547,
+ // 1546,
+ // 1545 NA
+ // 1544 NA
+ // 1543 NA
+ // 1542 NA
+ // 1541 NA
+ // 1540 NA
+ // 1539 NA
+ // 1538 NA
+ // 1537 NA
+ // 1536 NA
+ // 1535,
+ // 1534 NA
+ // 1533,
+ // 1532 NA
+ // 1531 NA
+ // 1530 NA
+ // 1529 NA
+ // 1528,
+ // 1527 NA
+ // 1526 NA
+ // 1525 NA
+ // 1524 NA
+ // 1523 NA
+ // 1522 NA
+ // 1521,
+ // 1520 NA
+ // 1519 NA
+ // 1518 NA
+ // 1517 NA
+ // 1516,
+ // 1515 NA
+ // 1514 NA
+ 1513,
+ // 1512 NA
+ 1511,
+ // 1510 NA
+ // 1509 NA
+ // 1508 NA
+ // 1507 NA
+ // 1506 NA
+ // 1505 NA
+ // 1504 NA
+ // 1503 NA
+ // 1502 NA
+ // 1501 NA
+ 1500,
+ // 1499,
+ // 1498 NA
+ // 1497 NA
+ // 1496 NA
+ // 1495 NA
+ // 1494,
+ // 1493 NA
+ // 1492,
+ // 1491,
+ // 1490 NA
+ // 1489 NA
+ // 1488 NA
+ // 1487 NA
+ // 1486,
+ // 1485 NA
+ // 1484 NA
+ // 1483 NA
+ // 1482 NA
+ // 1481 NA
+ // 1480,
+ // 1479,
+ // 1478,
+ // 1477,
+ // 1476 NA
+ // 1475 NA
+ // 1474 NA
+ // 1473 NA
+ // 1472 NA
+ // 1471 NA
+ // 1470 NA
+ // 1469 NA
+ // 1468,
+ // 1467 NA
+ // 1466 NA
+ // 1465 NA
+ // 1464,
+ // 1463 NA
+ // 1462 NA
+ // 1461 NA
+ // 1460 NA
+ // 1459 NA
+ // 1458 NA
+ // 1457 NA
+ // 1456,
+ // 1455 NA
+ // 1454 NA
+ // 1453 NA
+ // 1452 NA
+ // 1451 NA
+ // 1450 NA
+ // 1449 NA
+ // 1448 NA
+ // 1447 NA
+ // 1446 NA
+ // 1445 NA
+ // 1444 NA
+ // 1443 NA
+ // 1442 NA
+ // 1441 NA
+ // 1440 NA
+ // 1439 NA
+ // 1438 NA
+ // 1437 NA
+ // 1436 NA
+ // 1435 NA
+ // 1434 NA
+ // 1433 NA
+ // 1432 NA
+ // 1431 NA
+ // 1430 NA
+ // 1429 NA
+ // 1428 NA
+ // 1427 NA
+ // 1426 NA
+ 1425,
+ // 1424 NA
+ // 1423 NA
+ // 1422 NA
+ // 1421 NA
+ // 1420 NA
+ // 1419 NA
+ // 1418 NA
+ // 1417 NA
+ // 1416 NA
+ // 1415 NA
+ // 1414 NA
+ // 1413 NA
+ // 1412 NA
+ // 1411 NA
+ 1410,
+ // 1409 NA
+ // 1408 NA
+ // 1407 NA
+ 1406,
+ 1405,
+ // 1404 NA
+ // 1403 NA
+ // 1402 NA
+ 1401,
+ // 1400 NA
+ // 1399 NA
+ // 1398 NA
+ // 1397,
+ // 1396,
+ // 1395 NA
+ // 1394,
+ // 1393 NA
+ // 1392 NA
+ // 1391 NA
+ // 1390 NA
+ // 1389 NA
+ // 1388,
+ // 1387 NA
+ // 1386 NA
+ // 1385 NA
+ // 1384,
+ // 1383 NA
+ // 1382 NA
+ // 1381 NA
+ // 1380 NA
+ // 1379 NA
+ // 1378 NA
+ // 1377 NA
+ // 1376 NA
+ // 1375 NA
+ // 1374 NA
+ // 1373 NA
+ // 1372 NA
+ // 1371 NA
+ // 1370 NA
+ // 1369 NA
+ // 1368 NA
+ // 1367 NA
+ 1366,
+ // 1365,
+ // 1364 NA
+ // 1363 NA
+ // 1362 NA
+ // 1361 NA
+ // 1360 NA
+ // 1359 NA
+ // 1358 NA
+ // 1357 NA
+ // 1356 NA
+ // 1355 NA
+ // 1354 NA
+ // 1353 NA
+ // 1352,
+ // 1351 NA
+ // 1350 NA
+ // 1349 NA
+ // 1348 NA
+ 1347,
+ 1346,
+ // 1345 NA
+ // 1344 NA
+ // 1343 NA
+ // 1342 NA
+ // 1341 NA
+ // 1340 NA
+ // 1339 NA
+ // 1338 NA
+ // 1337 NA
+ // 1336 NA
+ // 1335 NA
+ // 1334 NA
+ // 1333 NA
+ // 1332 NA
+ // 1331 NA
+ // 1330 NA
+ // 1329 NA
+ // 1328 NA
+ // 1327 NA
+ // 1326 NA
+ // 1325 NA
+ // 1324 NA
+ // 1323 NA
+ // 1322 NA
+ // 1321 NA
+ // 1320 NA
+ // 1319 NA
+ // 1318 NA
+ // 1317 NA
+ // 1316 NA
+ // 1315 NA
+ // 1314 NA
+ // 1313 NA
+ // 1312 NA
+ // 1311 NA
+ // 1310 NA
+ 1309,
+ // 1308 NA
+ // 1307 NA
+ // 1306 NA
+ // 1305,
+ 1304,
+ // 1303 NA
+ // 1302 NA
+ // 1301 NA
+ // 1300 NA
+ // 1299 NA
+ // 1298 NA
+ // 1297 NA
+ 1296,
+ // 1295 NA
+ // 1294 NA
+ // 1293 NA
+ 1292,
+ // 1291 NA
+ // 1290 NA
+ // 1289 NA
+ // 1288 NA
+ // 1287 NA
+ // 1286 NA
+ 1285,
+ 1284,
+ // 1283 NA
+ 1282,
+ // 1281,
+ // 1280 NA
+ // 1279 NA
+ // 1278 NA
+ // 1277 NA
+ // 1276,
+ // 1275 NA
+ // 1274 NA
+ // 1273,
+ // 1272 NA
+ 1271,
+ // 1270 NA
+ 1269,
+ // 1268 NA
+ 1267,
+ // 1266
+ // 1265 NA
+ // 1264 NA
+ // 1263 NA
+ // 1262 NA
+ // 1261 NA
+ // 1260 NA
+ 1259,
+ // 1258 NA
+ // 1257 NA
+ // 1256 NA
+ // 1255 NA
+ // 1254 NA
+ // 1253 NA
+ // 1252 NA
+ // 1251 NA
+ // 1250 NA
+ // 1249 NA
+ // 1248 NA
+ // 1247 NA
+ // 1246 NA
+ // 1245 NA
+ // 1244 NA
+ // 1243 NA
+ // 1242 NA
+ // 1241 NA
+ // 1240 NA
+ // 1239 NA
+ // 1238 NA
+ // 1237,
+ 1236,
+ // 1235 NA
+ // 1234 NA
+ // 1233 NA
+ // 1232 NA
+ // 1231 NA
+ // 1230 NA
+ // 1229 NA
+ 1228,
+ // 1227 NA
+ // 1226 NA
+ // 1225 NA
+ // 1224 NA
+ // 1223,
+ // 1222 NA
+ // 1221 NA
+ // 1220 NA
// 1219 NA
// 1218 NA
// 1217 NA
@@ -102,41 +496,41 @@ static int included_patches[] = {
// 1191 NA
// 1190 NA
// 1189 NA
- // 1188,
+ // 1188 NA
// 1187 NA
// 1186,
// 1185 NA
// 1184 NA
// 1183 NA
// 1182 NA
- // 1181,
+ 1181,
1180,
// 1179,
- // 1178,
+ 1178,
// 1177 NA
// 1176 NA
// 1175 NA
// 1174 NA
- // 1173,
+ 1173,
// 1172 NA
// 1171 NA
// 1170 NA
// 1169 NA
- // 1168,
- // 1167,
- // 1166,
+ 1168,
+ 1167,
+ 1166,
// 1165 NA
- // 1164,
- // 1163,
+ 1164,
+ 1163,
// 1162 NA
// 1161,
- // 1160,
+ 1160,
// 1159 NA
// 1158 NA
- // 1157,
- // 1156,
+ 1157,
+ // 1156 NA
// 1155 NA
- // 1154,
+ // 1154 NA
// 1153,
// 1152 NA
// 1151,
@@ -146,17 +540,17 @@ static int included_patches[] = {
// 1147,
// 1146 NA
// 1145 NA
- // 1144 NA
- // 1143,
+ 1144,
+ 1143,
// 1142,
- // 1141,
+ 1141,
// 1140,
// 1139 NA
// 1138 NA
1137,
// 1136,
- // 1135 NA,
- // 1134 NA,
+ // 1135 NA
+ // 1134 NA
// 1133 NA
// 1132,
// 1131 NA
@@ -170,26 +564,26 @@ static int included_patches[] = {
// 1123,
// 1122 NA
// 1121,
- // 1120,
+ 1120,
// 1119,
- // 1118,
- // 1117,
- // 1116,
+ 1118,
+ 1117,
+ 1116,
// 1115 NA
- // 1114,
- // 1113,
- // 1112,
+ 1114,
+ 1113,
+ 1112,
// 1111,
- // 1110,
+ 1110,
// 1109 NA
// 1108,
- // 1107,
+ 1107,
// 1106 NA
- // 1105,
+ 1105,
// 1104 NA
// 1103 NA
- // 1102,
- // 1101,
+ 1102,
+ 1101,
// 1100 NA
// 1099 NA
// 1098 NA
@@ -197,107 +591,107 @@ static int included_patches[] = {
// 1096,
// 1095 NA
// 1094,
- // 1093,
- // 1092,
- // 1091,
+ 1093,
+ 1092,
+ 1091,
// 1090,
1089,
1088,
1087,
- // 1086,
+ 1086,
1085,
1084,
- // 1083 NA,
- // 1082 NA,
+ // 1083 NA
+ // 1082 NA
1081,
- // 1080 NA,
+ // 1080 NA
// 1079,
- // 1078 NA,
- // 1077 NA,
+ // 1078 NA
+ // 1077 NA
1076,
- // 1075,
+ 1075,
// 1074 NA,
// 1073,
1072,
// 1071,
- // 1070 NA,
- // 1069 NA,
+ // 1070 NA
+ // 1069 NA
// 1068,
- // 1067 NA,
- // 1066 NA,
+ // 1067 NA
+ // 1066 NA
1065,
// 1064,
- // 1063 NA,
- // 1062 NA,
+ // 1063 NA
+ // 1062 NA
// 1061,
- // 1060 NA,
+ // 1060 NA
// 1059,
// 1058,
- // 1057,
+ 1057,
// 1056,
1055,
- // 1054,
+ 1054,
// 1053,
- // 1052,
+ 1052,
// 1051,
// 1050,
- // 1049,
- // 1048,
- // 1047,
- // 1046,
- // 1045 NA,
- // 1044 NA,
- // 1043 NA,
- // 1042,
+ 1049,
+ 1048,
+ 1047,
+ 1046,
+ // 1045 NA
+ // 1044 NA
+ // 1043 NA
+ 1042,
1041,
- // 1040 NA,
+ // 1040 NA
// 1039,
- // 1038 NA,
- // 1037,
- // 1036,
- // 1035,
+ // 1038 NA
+ 1037,
+ 1036,
+ 1035,
// 1034,
- // 1033 NA,
+ // 1033 NA
1032,
// 1031 NA,
- // 1030,
+ 1030,
1029,
- // 1028 NA,
+ // 1028 NA
1027,
- // 1026 NA,
- // 1025 NA,
- // 1024 NA,
- // 1023 NA,
- // 1022 NA,
- // 1021 NA,
- // 1020 NA,
- // 1019 NA,
+ // 1026 NA
+ // 1025 NA
+ // 1024 NA
+ // 1023 NA
+ // 1022 NA
+ // 1021 NA
+ // 1020 NA
+ // 1019 NA
// 1018,
// 1017,
- // 1016 NA,
- // 1015,
- // 1014 NA,
+ // 1016 NA
+ 1015,
+ // 1014 NA
1013,
- // 1012 NA,
- // 1011 NA,
- // 1010,
- // 1009 NA,
- // 1008 NA,
- // 1007,
- // 1006,
- // 1005,
+ // 1012 NA
+ // 1011 NA
+ // 1010 NA,
+ // 1009 NA
+ // 1008 NA
+ 1007,
+ 1006,
+ // 1005 NA,
// 1004 NA,
// 1003 NA,
// 1002 NA,
- // 1001,
- // 1000,
+ 1001,
+ 1000,
// 999 NA
- // 998,
+ 998,
// 997 NA
// 996 NA
// 995 NA
// 994 NA
- // 993,
+ // 993 NA
// 992 NA
991,
// 990 NA
@@ -306,8 +700,8 @@ static int included_patches[] = {
// 987 NA
// 986 NA
// 985 NA
- // 984,
- // 983,
+ 984,
+ // 983 NA
// 982 NA
981,
980,
@@ -316,12 +710,12 @@ static int included_patches[] = {
977,
// 976 NA
975,
- // 974,
- // 973,
+ 974,
+ 973,
972,
// 971 NA
// 970 NA
- // 969,
+ // 969 NA
// 968 NA
// 967 NA
// 966 NA
@@ -329,27 +723,27 @@ static int included_patches[] = {
// 964 NA
963,
// 962 NA
- // 961,
+ 961,
// 960 NA
// 959 NA
- // 958,
- // 957,
- // 956,
+ 958,
+ 957,
+ // 956 NA
955,
// 954 NA
953,
- // 952,
- // 951,
+ 952,
+ 951,
950,
949,
// 948 NA
- // 947,
+ // 947 NA
946,
945,
944,
- // 943,
- // 942,
- // 941,
+ // 943 NA
+ 942,
+ 941,
// 940 NA
939,
// 938 NA
@@ -365,7 +759,7 @@ static int included_patches[] = {
// 928 NA
// 927 NA
926,
- // 925,
+ 925,
// 924 NA
// 923 NA
922,
@@ -376,17 +770,17 @@ static int included_patches[] = {
// 917 NA
916,
915,
- // 914,
+ // 914 NA
// 913 NA
912,
// 911 NA
// 910 NA
- // 909,
+ // 909 NA
// 908 NA
// 907 NA
// 906 NA
- // 905,
- // 904,
+ // 905 NA
+ // 904 NA
903,
// 902 NA
901,
@@ -394,21 +788,21 @@ static int included_patches[] = {
// 899 NA
898,
// 897 NA
- // 896,
+ 896,
895,
// 894 NA
893,
- // 892,
+ // 892 NA
891,
// 890 NA
- // 889,
+ 889,
888,
887,
// 886 NA
885,
// 884 NA
883,
- // 882,
+ 882,
881,
// 880 NA
879,
@@ -419,7 +813,7 @@ static int included_patches[] = {
// 874 NA
// 873 NA
// 872 NA
- // 871,
+ 871,
870,
// 869 NA
868,
@@ -433,7 +827,7 @@ static int included_patches[] = {
// 860 NA
859,
858,
- // 857,
+ 857,
856,
// 855 NA
// 854 NA
@@ -468,10 +862,10 @@ static int included_patches[] = {
825,
// 824 NA
823,
- // 822,
+ 822,
// 821 NA
820,
- // 819,
+ 819,
818,
817,
816,
@@ -493,7 +887,7 @@ static int included_patches[] = {
800,
799,
798,
- // 797,
+ // 797 NA
// 796 NA
795,
// 794 NA
@@ -557,7 +951,7 @@ static int included_patches[] = {
736,
// 735 NA
734,
- // 733,
+ // 733 NA
732,
// 731 NA
// 730 NA
@@ -618,7 +1012,7 @@ static int included_patches[] = {
675,
// 674 NA
673,
- // 672,
+ 672,
671,
670,
// 669 NA
@@ -677,7 +1071,7 @@ static int included_patches[] = {
616,
615,
614,
- // 613,
+ 613,
612,
// 611 NA
// 610 NA
@@ -1046,13 +1440,13 @@ static int included_patches[] = {
247,
// 246 NA
245,
- // 244,
+ // 244 NA
243,
242,
241,
240,
239,
- // 238,
+ // 238 NA
237,
236,
235,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 762d349470..165a44a148 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -27,12 +27,6 @@ Error: configure did not run properly.Check auto/config.log.
# endif
#endif
-
-/* Can't use "PACKAGE" here, conflicts with a Perl include file. */
-#ifndef VIMPACKAGE
-# define VIMPACKAGE "nvim"
-#endif
-
#include "nvim/os/os_defs.h" /* bring lots of system header files */
/// length of a buffer to store a number in ASCII (64 bits binary + NUL)
@@ -207,15 +201,6 @@ enum {
#define MAYBE 2 /* sometimes used for a variant on TRUE */
-/*
- * Motion types, used for operators and for yank/delete registers.
- */
-#define MCHAR 0 /* character-wise movement/register */
-#define MLINE 1 /* line-wise movement/register */
-#define MBLOCK 2 /* block-wise register */
-
-#define MAUTO 0xff /* Decide between MLINE/MCHAR */
-
#define STATUS_HEIGHT 1 /* height of a status line under a window */
#define QF_WINHEIGHT 10 /* default height for quickfix window */
@@ -277,26 +262,11 @@ enum {
# define vim_strpbrk(s, cs) (char_u *)strpbrk((char *)(s), (char *)(cs))
-#define MSG(s) msg((char_u *)(s))
-#define MSG_ATTR(s, attr) msg_attr((char_u *)(s), (attr))
-#define EMSG(s) emsg((char_u *)(s))
-#define EMSG2(s, p) emsg2((char_u *)(s), (char_u *)(p))
-#define EMSG3(s, p, q) emsg3((char_u *)(s), (char_u *)(p), \
- (char_u *)(q))
-#define EMSGN(s, n) emsgn((char_u *)(s), (int64_t)(n))
-#define EMSGU(s, n) emsgu((char_u *)(s), (uint64_t)(n))
-#define OUT_STR(s) out_str((char_u *)(s))
-#define OUT_STR_NF(s) out_str_nf((char_u *)(s))
-#define MSG_PUTS(s) msg_puts((char_u *)(s))
-#define MSG_PUTS_ATTR(s, a) msg_puts_attr((char_u *)(s), (a))
-#define MSG_PUTS_TITLE(s) msg_puts_title((char_u *)(s))
-#define MSG_PUTS_LONG(s) msg_puts_long_attr((char_u *)(s), 0)
-#define MSG_PUTS_LONG_ATTR(s, a) msg_puts_long_attr((char_u *)(s), (a))
-
-/* Prefer using emsg3(), because perror() may send the output to the wrong
- * destination and mess up the screen. */
-#define PERROR(msg) \
- (void) emsg3((char_u *) "%s: %s", (char_u *)msg, (char_u *)strerror(errno))
+#include "nvim/message.h"
+
+// Prefer using emsgf(), because perror() may send the output to the wrong
+// destination and mess up the screen.
+#define PERROR(msg) (void) emsgf("%s: %s", msg, strerror(errno))
#define SHOWCMD_COLS 10 /* columns needed by shown command */
#define STL_MAX_ITEM 80 /* max nr of %<flag> in statusline */
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 39106a7b8d..bea55c465f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -97,7 +97,7 @@ do_window (
* don't replicate the quickfix buffer. */
if (bt_quickfix(curbuf))
goto newwindow;
- win_split((int)Prenum, 0);
+ (void)win_split((int)Prenum, 0);
break;
/* split current window in two parts, vertically */
@@ -108,7 +108,7 @@ do_window (
* don't replicate the quickfix buffer. */
if (bt_quickfix(curbuf))
goto newwindow;
- win_split((int)Prenum, WSP_VERT);
+ (void)win_split((int)Prenum, WSP_VERT);
break;
/* split current window and edit alternate file */
@@ -248,7 +248,7 @@ newwindow:
/* First create a new tab with the window, then go back to
* the old tab and close the window there. */
wp = curwin;
- if (win_new_tabpage((int)Prenum) == OK
+ if (win_new_tabpage((int)Prenum, NULL) == OK
&& valid_tabpage(oldtab)) {
newtab = curtab;
goto_tabpage_tp(oldtab, TRUE, TRUE);
@@ -2948,18 +2948,19 @@ void free_tabpage(tabpage_T *tp)
unref_var_dict(tp->tp_vars);
-
+ xfree(tp->localdir); // Free tab-local working directory
xfree(tp);
}
-/*
- * Create a new Tab page with one window.
- * It will edit the current buffer, like after ":split".
- * When "after" is 0 put it just after the current Tab page.
- * Otherwise put it just before tab page "after".
- * Return FAIL or OK.
- */
-int win_new_tabpage(int after)
+/// Create a new tabpage with one window.
+///
+/// It will edit the current buffer, like after :split.
+///
+/// @param after Put new tabpage after tabpage "after", or after the current
+/// tabpage in case of 0.
+/// @param filename Will be passed to apply_autocmds().
+/// @return Was the new tabpage created successfully? FAIL or OK.
+int win_new_tabpage(int after, char_u *filename)
{
tabpage_T *tp = curtab;
tabpage_T *newtp;
@@ -2999,10 +3000,12 @@ int win_new_tabpage(int after)
newtp->tp_topframe = topframe;
last_status(FALSE);
-
redraw_all_later(CLEAR);
- apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
- apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
+
+ apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
+ apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
+
return OK;
}
@@ -3023,7 +3026,7 @@ int may_open_tabpage(void)
if (n != 0) {
cmdmod.tab = 0; /* reset it to avoid doing it twice */
postponed_split_tab = 0;
- return win_new_tabpage(n);
+ return win_new_tabpage(n, NULL);
}
return FAIL;
}
@@ -3047,9 +3050,11 @@ int make_tabpages(int maxcount)
*/
block_autocmds();
- for (todo = count - 1; todo > 0; --todo)
- if (win_new_tabpage(0) == FAIL)
+ for (todo = count - 1; todo > 0; --todo) {
+ if (win_new_tabpage(0, NULL) == FAIL) {
break;
+ }
+ }
unblock_autocmds();
@@ -3555,18 +3560,24 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); /* assume cursor position needs updating */
- if (curwin->w_localdir != NULL) {
- /* Window has a local directory: Save current directory as global
- * directory (unless that was done already) and change to the local
- * directory. */
+ // The new directory is either the local directory of the window, of the tab
+ // or NULL.
+ char_u *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->localdir;
+
+ if (new_dir) {
+ // Window/tab has a local directory: Save current directory as global
+ // directory (unless that was done already) and change to the local
+ // directory.
if (globaldir == NULL) {
char_u cwd[MAXPATHL];
- if (os_dirname(cwd, MAXPATHL) == OK)
+ if (os_dirname(cwd, MAXPATHL) == OK) {
globaldir = vim_strsave(cwd);
+ }
+ }
+ if (os_chdir((char *)new_dir) == 0) {
+ shorten_fnames(true);
}
- if (os_chdir((char *)curwin->w_localdir) == 0)
- 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. */
@@ -4619,10 +4630,8 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
#define FRACTION_MULT 16384L
-/*
- * Set wp->w_fraction for the current w_wrow and w_height.
- */
-static void set_fraction(win_T *wp)
+// Set wp->w_fraction for the current w_wrow and w_height.
+void set_fraction(win_T *wp)
{
wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + wp->w_height / 2)
/ (long)wp->w_height;