aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt13
-rw-r--r--Makefile11
-rw-r--r--ci/build.ps12
-rw-r--r--cmake/FindLibLUV.cmake6
-rw-r--r--cmake/FindLibTermkey.cmake6
-rw-r--r--cmake/FindLibUV.cmake9
-rw-r--r--cmake/FindLibVterm.cmake33
-rw-r--r--cmake/FindLuaJit.cmake7
-rw-r--r--cmake/FindMsgpack.cmake7
-rw-r--r--contrib/local.mk.example12
-rw-r--r--runtime/doc/api.txt19
-rw-r--r--runtime/doc/if_lua.txt18
-rw-r--r--src/nvim/api/buffer.c34
-rw-r--r--src/nvim/buffer_defs.h20
-rw-r--r--src/nvim/buffer_updates.c18
-rw-r--r--src/nvim/ex_docmd.c7
-rw-r--r--src/nvim/fileio.c3
-rw-r--r--src/nvim/getchar.c1
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/lua/executor.c65
-rw-r--r--src/nvim/mbyte.c58
-rw-r--r--src/nvim/memline.c53
-rw-r--r--src/nvim/misc1.c3
-rw-r--r--src/nvim/spell.c6
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/testdir/test_spell.vim13
-rw-r--r--src/nvim/version.c17
-rw-r--r--test/functional/fixtures/shell-test.c19
-rw-r--r--test/functional/helpers.lua356
-rw-r--r--test/functional/lua/buffer_updates_spec.lua162
-rw-r--r--test/functional/lua/utility_functions_spec.lua55
-rw-r--r--test/functional/plugin/shada_spec.lua11
-rw-r--r--test/functional/shada/buffers_spec.lua42
-rw-r--r--test/functional/shada/helpers.lua59
-rw-r--r--test/functional/shada/marks_spec.lua34
-rw-r--r--test/functional/shada/registers_spec.lua11
-rw-r--r--test/functional/shada/shada_spec.lua4
-rw-r--r--test/functional/shada/variables_spec.lua19
-rw-r--r--test/functional/ui/output_spec.lua15
-rw-r--r--test/unit/helpers.lua4
40 files changed, 749 insertions, 487 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 947de61988..1edaa63de6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -250,7 +250,7 @@ check_c_source_compiles("
int main(void)
{
void *trace[1];
- int trace_size = backtrace(trace, 1);
+ backtrace(trace, 1);
return 0;
}
" HAVE_EXECINFO_BACKTRACE)
@@ -258,7 +258,7 @@ int main(void)
check_c_source_compiles("
int main(void)
{
- int a;
+ int a = 42;
__builtin_add_overflow(a, a, &a);
__builtin_sub_overflow(a, a, &a);
return 0;
@@ -668,15 +668,6 @@ else()
COMMENT "lualint: LUACHECK_PRG not defined")
endif()
-if(FLAKE8_PRG)
- add_custom_target(pylint
- COMMAND ${FLAKE8_PRG} contrib/ scripts/ src/ test/
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-else()
- add_custom_target(pylint false
- COMMENT "flake8: FLAKE8_PRG not defined")
-endif()
-
set(CPACK_PACKAGE_NAME "Neovim")
set(CPACK_PACKAGE_VENDOR "neovim.io")
set(CPACK_PACKAGE_VERSION ${NVIM_VERSION_MEDIUM})
diff --git a/Makefile b/Makefile
index e2cf4a3b29..fff0ffef28 100644
--- a/Makefile
+++ b/Makefile
@@ -138,8 +138,13 @@ functionaltest-lua: | nvim
lualint: | build/.ran-cmake deps
$(BUILD_CMD) -C build lualint
-pylint: | build/.ran-cmake deps
- $(BUILD_CMD) -C build pylint
+pylint:
+ flake8 contrib/ scripts/ src/ test/
+
+# Run pylint only if flake8 is installed.
+_opt_pylint:
+ @command -v flake8 && { $(MAKE) pylint; exit $$?; } \
+ || echo "SKIP: pylint (flake8 not found)"
unittest: | nvim
+$(BUILD_CMD) -C build unittest
@@ -182,7 +187,7 @@ appimage:
appimage-%:
bash scripts/genappimage.sh $*
-lint: check-single-includes clint lualint pylint
+lint: check-single-includes clint lualint _opt_pylint
# Generic pattern rules, allowing for `make build/bin/nvim` etc.
# Does not work with "Unix Makefiles".
diff --git a/ci/build.ps1 b/ci/build.ps1
index da1ad2f4b6..42066c462b 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -137,8 +137,10 @@ if ($uploadToCodecov) {
# Old tests
# Add MSYS to path, required for e.g. `find` used in test scripts.
# But would break functionaltests, where its `more` would be used then.
+$OldPath = $env:PATH
$env:PATH = "C:\msys64\usr\bin;$env:PATH"
& "C:\msys64\mingw$bits\bin\mingw32-make.exe" -C $(Convert-Path ..\src\nvim\testdir) VERBOSE=1
+$env:PATH = $OldPath
if ($uploadToCodecov) {
bash -l /c/projects/neovim/ci/common/submit_coverage.sh oldtest
diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibLUV.cmake
index 66f827214e..784e3fd249 100644
--- a/cmake/FindLibLUV.cmake
+++ b/cmake/FindLibLUV.cmake
@@ -14,12 +14,6 @@ set(LIBLUV_DEFINITIONS ${PC_LIBLUV_CFLAGS_OTHER})
find_path(LIBLUV_INCLUDE_DIR luv/luv.h
PATHS ${PC_LIBLUV_INCLUDEDIR} ${PC_LIBLUV_INCLUDE_DIRS})
-# If we're asked to use static linkage, add libluv.a as a preferred library name.
-if(LIBLUV_USE_STATIC)
- list(APPEND LIBLUV_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}luv${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
list(APPEND LIBLUV_NAMES luv)
find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES}
diff --git a/cmake/FindLibTermkey.cmake b/cmake/FindLibTermkey.cmake
index 6e09a692c8..3e0c7f1bfd 100644
--- a/cmake/FindLibTermkey.cmake
+++ b/cmake/FindLibTermkey.cmake
@@ -14,12 +14,6 @@ set(LIBTERMKEY_DEFINITIONS ${PC_LIBTERMKEY_CFLAGS_OTHER})
find_path(LIBTERMKEY_INCLUDE_DIR termkey.h
PATHS ${PC_LIBTERMKEY_INCLUDEDIR} ${PC_LIBTERMKEY_INCLUDE_DIRS})
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBTERMKEY_USE_STATIC)
- list(APPEND LIBTERMKEY_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}termkey${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
list(APPEND LIBTERMKEY_NAMES termkey)
find_library(LIBTERMKEY_LIBRARY NAMES ${LIBTERMKEY_NAMES}
diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake
index e94a243ec6..951fb0435e 100644
--- a/cmake/FindLibUV.cmake
+++ b/cmake/FindLibUV.cmake
@@ -4,9 +4,6 @@
# LIBUV_FOUND - system has libuv
# LIBUV_INCLUDE_DIRS - the libuv include directories
# LIBUV_LIBRARIES - link these to use libuv
-#
-# Set the LIBUV_USE_STATIC variable to specify if static libraries should
-# be preferred to shared ones.
find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
@@ -16,12 +13,6 @@ endif()
find_path(LIBUV_INCLUDE_DIR uv.h
HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS})
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBUV_USE_STATIC)
- list(APPEND LIBUV_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}uv${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif(LIBUV_USE_STATIC)
-
list(APPEND LIBUV_NAMES uv)
find_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES}
diff --git a/cmake/FindLibVterm.cmake b/cmake/FindLibVterm.cmake
index e11d1caddc..469494ddfd 100644
--- a/cmake/FindLibVterm.cmake
+++ b/cmake/FindLibVterm.cmake
@@ -4,34 +4,7 @@
# LIBVTERM_INCLUDE_DIRS - The libvterm include directories
# LIBVTERM_LIBRARIES - The libraries needed to use libvterm
-find_package(PkgConfig)
-if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_LIBVTERM QUIET vterm)
-endif()
+include(LibFindMacros)
-set(LIBVTERM_DEFINITIONS ${PC_LIBVTERM_CFLAGS_OTHER})
-
-find_path(LIBVTERM_INCLUDE_DIR vterm.h
- PATHS ${PC_LIBVTERM_INCLUDEDIR} ${PC_LIBVTERM_INCLUDE_DIRS})
-
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBVTERM_USE_STATIC)
- list(APPEND LIBVTERM_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}vterm${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
-list(APPEND LIBVTERM_NAMES vterm)
-
-find_library(LIBVTERM_LIBRARY NAMES ${LIBVTERM_NAMES}
- HINTS ${PC_LIBVTERM_LIBDIR} ${PC_LIBVTERM_LIBRARY_DIRS})
-
-set(LIBVTERM_LIBRARIES ${LIBVTERM_LIBRARY})
-set(LIBVTERM_INCLUDE_DIRS ${LIBVTERM_INCLUDE_DIR})
-
-include(FindPackageHandleStandardArgs)
-# handle the QUIETLY and REQUIRED arguments and set LIBVTERM_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(LibVterm DEFAULT_MSG
- LIBVTERM_LIBRARY LIBVTERM_INCLUDE_DIR)
-
-mark_as_advanced(LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY)
+libfind_pkg_detect(LIBVTERM vterm FIND_PATH vterm.h FIND_LIBRARY vterm)
+libfind_process(LIBVTERM REQUIRED)
diff --git a/cmake/FindLuaJit.cmake b/cmake/FindLuaJit.cmake
index d60b6f09be..72795afefd 100644
--- a/cmake/FindLuaJit.cmake
+++ b/cmake/FindLuaJit.cmake
@@ -15,13 +15,6 @@ find_path(LUAJIT_INCLUDE_DIR luajit.h
PATHS ${PC_LUAJIT_INCLUDEDIR} ${PC_LUAJIT_INCLUDE_DIRS}
PATH_SUFFIXES luajit-2.0 luajit-2.1)
-# If we're asked to use static linkage, add libluajit-5.1.a as a preferred
-# library name.
-if(LUAJIT_USE_STATIC)
- list(APPEND LUAJIT_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}luajit-5.1${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
if(MSVC)
list(APPEND LUAJIT_NAMES lua51)
elseif(MINGW)
diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake
index df4efa9c41..26eb19d498 100644
--- a/cmake/FindMsgpack.cmake
+++ b/cmake/FindMsgpack.cmake
@@ -26,13 +26,6 @@ else()
set(MSGPACK_VERSION_STRING)
endif()
-# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name.
-if(MSGPACK_USE_STATIC)
- list(APPEND MSGPACK_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}"
- "${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
if(MSVC)
# The import library for the msgpack DLL has a different name
list(APPEND MSGPACK_NAMES msgpackc_import)
diff --git a/contrib/local.mk.example b/contrib/local.mk.example
index a8c8e9cefb..5a31ded59b 100644
--- a/contrib/local.mk.example
+++ b/contrib/local.mk.example
@@ -47,18 +47,6 @@
#
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED=OFF
-# By default, bundled libraries are statically linked to nvim.
-# This has no effect for non-bundled deps, which are always dynamically linked.
-# Uncomment these entries to instead use dynamic linking.
-#
-# CMAKE_EXTRA_FLAGS += -DLIBTERMKEY_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBUNIBILIUM_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBUV_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBVTERM_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLUAJIT_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DMSGPACK_USE_STATIC=OFF
-#
-#
# .DEFAULT_GOAL := nvim
#
# Run doxygen over the source code.
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 709e5885e4..2c6b053994 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -200,17 +200,26 @@ User reloads the buffer with ":edit", emits: >
nvim_buf_detach_event[{buf}]
*api-buffer-updates-lua*
-In-process lua plugins can also recieve buffer updates, in the form of lua
+In-process lua plugins can also receive buffer updates, in the form of lua
callbacks. These callbacks are called frequently in various contexts, buffer
contents or window layout should not be changed inside these |textlock|.
|vim.schedule| can be used to defer these operations to the main loop, where
they are allowed.
|nvim_buf_attach| will take keyword args for the callbacks. "on_lines" will
-receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline}, {new_lastline}).
-Unlike remote channels the text contents are not passed. The new text can be
-accessed inside the callback as
-`vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, true)`
+receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline},
+{new_lastline}, {old_byte_size}[, {old_utf32_size}, {old_utf16_size}]).
+Unlike remote channel events the text contents are not passed. The new text can
+be accessed inside the callback as
+
+ `vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, true)`
+
+{old_byte_size} is the total size of the replaced region {firstline} to
+{lastline} in bytes, including the final newline after {lastline}. if
+`utf_sizes` is set to true in |nvim_buf_attach()| keyword args, then the
+UTF-32 and UTF-16 sizes of the deleted region is also passed as additional
+arguments {old_utf32_size} and {old_utf16_size}.
+
"on_changedtick" is invoked when |b:changedtick| was incremented but no text
was changed. The parameters recieved are ("changedtick", {buf}, {changedtick}).
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt
index 7ddcb6cc92..a9b8c5fae8 100644
--- a/runtime/doc/if_lua.txt
+++ b/runtime/doc/if_lua.txt
@@ -459,6 +459,24 @@ vim.stricmp({a}, {b}) *vim.stricmp()*
are equal, {a} is greater than {b} or {a} is lesser than {b},
respectively.
+vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()*
+ Convert byte index to UTF-32 and UTF-16 indicies. If {index} is not
+ supplied, the length of the string is used. All indicies are zero-based.
+ Returns two values: the UTF-32 and UTF-16 indicies respectively.
+
+ Embedded NUL bytes are treated as terminating the string. Invalid
+ UTF-8 bytes, and embedded surrogates are counted as one code
+ point each. An {index} in the middle of a UTF-8 sequence is rounded
+ upwards to the end of that sequence.
+
+vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()*
+ Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
+ supplied, it defaults to false (use UTF-32). Returns the byte index.
+
+ Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|. An {index}
+ in the middle of a UTF-16 sequence is rounded upwards to the end of that
+ sequence.
+
vim.schedule({callback}) *vim.schedule()*
Schedules {callback} to be invoked soon by the main event-loop. Useful
to avoid |textlock| or other temporary restrictions.
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index b0b65545ab..c6f82e9d85 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -109,9 +109,11 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// `nvim_buf_lines_event`. Otherwise, the first notification will be
/// a `nvim_buf_changedtick_event`. Not used for lua callbacks.
/// @param opts Optional parameters.
-/// `on_lines`: lua callback received on change.
+/// `on_lines`: lua callback received on change.
/// `on_changedtick`: lua callback received on changedtick
/// increment without text change.
+/// `utf_sizes`: include UTF-32 and UTF-16 size of
+/// the replaced region.
/// See |api-buffer-updates-lua| for more information
/// @param[out] err Error details, if any
/// @return False when updates couldn't be enabled because the buffer isn't
@@ -156,6 +158,12 @@ Boolean nvim_buf_attach(uint64_t channel_id,
}
cb.on_detach = v->data.luaref;
v->data.integer = LUA_NOREF;
+ } else if (is_lua && strequal("utf_sizes", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
+ goto error;
+ }
+ cb.utf_sizes = v->data.boolean;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
@@ -1176,6 +1184,30 @@ free_exit:
return 0;
}
+Dictionary nvim__buf_stats(Buffer buffer, Error *err)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (!buf) {
+ return rv;
+ }
+
+ // Number of times the cached line was flushed.
+ // This should generally not increase while editing the same
+ // line in the same mode.
+ PUT(rv, "flush_count", INTEGER_OBJ(buf->flush_count));
+ // lnum of current line
+ PUT(rv, "current_lnum", INTEGER_OBJ(buf->b_ml.ml_line_lnum));
+ // whether the line has unflushed changes.
+ PUT(rv, "line_dirty", BOOLEAN_OBJ(buf->b_ml.ml_flags & ML_LINE_DIRTY));
+ // NB: this should be zero at any time API functions are called,
+ // this exists to debug issues
+ PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes));
+
+ return rv;
+}
+
// Check if deleting lines made the cursor position invalid.
// Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted).
static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 143737b478..b11eaefdd0 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -459,8 +459,9 @@ typedef struct {
LuaRef on_lines;
LuaRef on_changedtick;
LuaRef on_detach;
+ bool utf_sizes;
} BufUpdateCallbacks;
-#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF }
+#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF, false }
#define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2
@@ -802,11 +803,26 @@ struct file_buffer {
kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
- // array of channelids which have asked to receive updates for this
+ // array of channel_id:s which have asked to receive updates for this
// buffer.
kvec_t(uint64_t) update_channels;
+ // array of lua callbacks for buffer updates.
kvec_t(BufUpdateCallbacks) update_callbacks;
+ // whether an update callback has requested codepoint size of deleted regions.
+ bool update_need_codepoints;
+
+ // Measurements of the deleted or replaced region since the last update
+ // event. Some consumers of buffer changes need to know the byte size (like
+ // tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
+ // deleted text.
+ size_t deleted_bytes;
+ size_t deleted_codepoints;
+ size_t deleted_codeunits;
+
+ // The number for times the current line has been flushed in the memline.
+ int flush_count;
+
int b_diff_failed; // internal diff failed for this buffer
};
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 21efda9fd9..3604578b50 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -26,6 +26,9 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
if (channel_id == LUA_INTERNAL_CALL) {
kv_push(buf->update_callbacks, cb);
+ if (cb.utf_sizes) {
+ buf->update_need_codepoints = true;
+ }
return true;
}
@@ -169,6 +172,10 @@ void buf_updates_send_changes(buf_T *buf,
int64_t num_removed,
bool send_tick)
{
+ size_t deleted_codepoints, deleted_codeunits;
+ size_t deleted_bytes = ml_flush_deleted_bytes(buf, &deleted_codepoints,
+ &deleted_codeunits);
+
if (!buf_updates_active(buf)) {
return;
}
@@ -231,8 +238,8 @@ void buf_updates_send_changes(buf_T *buf,
bool keep = true;
if (cb.on_lines != LUA_NOREF) {
Array args = ARRAY_DICT_INIT;
- Object items[5];
- args.size = 5;
+ Object items[8];
+ args.size = 6; // may be increased to 8 below
args.items = items;
// the first argument is always the buffer handle
@@ -250,6 +257,13 @@ void buf_updates_send_changes(buf_T *buf,
// the last line in the updated range
args.items[4] = INTEGER_OBJ(firstline - 1 + num_added);
+ // byte count of previous contents
+ args.items[5] = INTEGER_OBJ((Integer)deleted_bytes);
+ if (cb.utf_sizes) {
+ args.size = 8;
+ args.items[6] = INTEGER_OBJ((Integer)deleted_codepoints);
+ args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits);
+ }
textlock++;
Object res = executor_exec_lua_cb(cb.on_lines, "lines", args, true);
textlock--;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b315639681..bad844e9d5 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -4060,10 +4060,9 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
return p;
}
-/*
- * Expand file name in Ex command argument.
- * Return FAIL for failure, OK otherwise.
- */
+// Expand file name in Ex command argument.
+// When an error is detected, "errormsgp" is set to a non-NULL pointer.
+// Return FAIL for failure, OK otherwise.
int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
{
int has_wildcards; /* need to expand wildcards */
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 410c68017d..882bf1b830 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1761,6 +1761,9 @@ failed:
ml_delete(curbuf->b_ml.ml_line_count, false);
linecnt--;
}
+ curbuf->deleted_bytes = 0;
+ curbuf->deleted_codepoints = 0;
+ curbuf->deleted_codeunits = 0;
linecnt = curbuf->b_ml.ml_line_count - linecnt;
if (filesize == 0)
linecnt = 0;
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index f7614fd3e1..03f64c2019 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1945,6 +1945,7 @@ static int vgetorpeek(int advance)
// No matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched
keylen = 0;
+ (void)keylen; // suppress clang/dead assignment
// If there was no mapping, use the character from the typeahead
// buffer right here. Otherwise, use the mapping (loop around).
if (mp == NULL) {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index d13b121562..b095e759d9 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -627,6 +627,8 @@ EXTERN pos_T Insstart_orig;
EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */
EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
+// increase around internal delete/replace
+EXTERN int inhibit_delete_count INIT(= 0);
/*
* These flags are set based upon 'fileencoding'.
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 4051354d65..29682e8add 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -112,6 +112,65 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
+/// convert byte index to UTF-32 and UTF-16 indicies
+///
+/// Expects a string and an optional index. If no index is supplied, the length
+/// of the string is returned.
+///
+/// Returns two values: the UTF-32 and UTF-16 indicies.
+static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx;
+ if (lua_gettop(lstate) >= 2) {
+ idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0 || idx > (intptr_t)s1_len) {
+ return luaL_error(lstate, "index out of range");
+ }
+ } else {
+ idx = (intptr_t)s1_len;
+ }
+
+ size_t codepoints = 0, codeunits = 0;
+ mb_utflen((const char_u *)s1, (size_t)idx, &codepoints, &codeunits);
+
+ lua_pushinteger(lstate, (long)codepoints);
+ lua_pushinteger(lstate, (long)codeunits);
+
+ return 2;
+}
+
+/// convert UTF-32 or UTF-16 indicies to byte index.
+///
+/// Expects up to three args: string, index and use_utf16.
+/// If use_utf16 is not supplied it defaults to false (use UTF-32)
+///
+/// Returns the byte index.
+static int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0) {
+ return luaL_error(lstate, "index out of range");
+ }
+ bool use_utf16 = false;
+ if (lua_gettop(lstate) >= 3) {
+ use_utf16 = lua_toboolean(lstate, 3);
+ }
+
+ ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len,
+ (size_t)idx, use_utf16);
+ if (byteidx == -1) {
+ return luaL_error(lstate, "index out of range");
+ }
+
+ lua_pushinteger(lstate, (long)byteidx);
+
+ return 1;
+}
+
static void nlua_luv_error_event(void **argv)
{
char *error = (char *)argv[0];
@@ -220,6 +279,12 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// stricmp
lua_pushcfunction(lstate, &nlua_stricmp);
lua_setfield(lstate, -2, "stricmp");
+ // str_utfindex
+ lua_pushcfunction(lstate, &nlua_str_utfindex);
+ lua_setfield(lstate, -2, "str_utfindex");
+ // str_byteindex
+ lua_pushcfunction(lstate, &nlua_str_byteindex);
+ lua_setfield(lstate, -2, "str_byteindex");
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 3017f3c855..fae7635d34 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1438,6 +1438,64 @@ int utf16_to_utf8(const wchar_t *strw, char **str)
#endif
+/// Measure the length of a string in corresponding UTF-32 and UTF-16 units.
+///
+/// Invalid UTF-8 bytes, or embedded surrogates, count as one code point/unit
+/// each.
+///
+/// The out parameters are incremented. This is used to measure the size of
+/// a buffer region consisting of multiple line segments.
+///
+/// @param s the string
+/// @param len maximum length (an earlier NUL terminates)
+/// @param[out] codepoints incremented with UTF-32 code point size
+/// @param[out] codeunits incremented with UTF-16 code unit size
+void mb_utflen(const char_u *s, size_t len, size_t *codepoints,
+ size_t *codeunits)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t count = 0, extra = 0;
+ size_t clen;
+ for (size_t i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (c > 0xFFFF) {
+ extra++;
+ }
+ }
+ *codepoints += count;
+ *codeunits += count + extra;
+}
+
+ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len,
+ size_t index, bool use_utf16_units)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t count = 0;
+ size_t clen, i;
+ if (index == 0) {
+ return 0;
+ }
+ for (i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (use_utf16_units && c > 0xFFFF) {
+ count++;
+ }
+ if (count >= index) {
+ return i+clen;
+ }
+ }
+ return -1;
+}
+
+
/*
* Version of strnicmp() that handles multi-byte characters.
* Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index b027459706..3220c7d9b8 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -2383,6 +2383,23 @@ static int ml_append_int(
return OK;
}
+void ml_add_deleted_len(char_u *ptr, ssize_t len)
+{
+ if (inhibit_delete_count) {
+ return;
+ }
+ if (len == -1) {
+ len = STRLEN(ptr);
+ }
+ curbuf->deleted_bytes += len+1;
+ if (curbuf->update_need_codepoints) {
+ mb_utflen(ptr, len, &curbuf->deleted_codepoints,
+ &curbuf->deleted_codeunits);
+ curbuf->deleted_codepoints++; // NL char
+ curbuf->deleted_codeunits++;
+ }
+}
+
/*
* Replace line lnum, with buffering, in current buffer.
*
@@ -2403,13 +2420,24 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
return FAIL;
+ bool readlen = true;
+
if (copy) {
line = vim_strsave(line);
}
- if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
- ml_flush_line(curbuf); /* flush it */
- else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
- xfree(curbuf->b_ml.ml_line_ptr); /* free it */
+ if (curbuf->b_ml.ml_line_lnum != lnum) { // other line buffered
+ ml_flush_line(curbuf); // flush it
+ } else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, -1);
+ readlen = false; // already added the length
+
+ xfree(curbuf->b_ml.ml_line_ptr); // free it
+ }
+
+ if (readlen && kv_size(curbuf->update_callbacks)) {
+ ml_add_deleted_len(ml_get_buf(curbuf, lnum, false), -1);
+ }
+
curbuf->b_ml.ml_line_ptr = line;
curbuf->b_ml.ml_line_lnum = lnum;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
@@ -2491,6 +2519,10 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
else
line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+ // Line should always have an NL char internally (represented as NUL),
+ // even if 'noeol' is set.
+ assert(line_size >= 1);
+ ml_add_deleted_len((char_u *)dp + line_start, line_size-1);
/*
* special case: If there is only one line in the data block it becomes empty.
@@ -2676,6 +2708,17 @@ void ml_clearmarked(void)
return;
}
+size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits)
+{
+ size_t ret = buf->deleted_bytes;
+ *codepoints = buf->deleted_codepoints;
+ *codeunits = buf->deleted_codeunits;
+ buf->deleted_bytes = 0;
+ buf->deleted_codepoints = 0;
+ buf->deleted_codeunits = 0;
+ return ret;
+}
+
/*
* flush ml_line if necessary
*/
@@ -2704,6 +2747,8 @@ static void ml_flush_line(buf_T *buf)
return;
entered = TRUE;
+ buf->flush_count++;
+
lnum = buf->b_ml.ml_line_lnum;
new_line = buf->b_ml.ml_line_ptr;
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index db0d56b5fd..a62fa6d585 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -780,6 +780,7 @@ open_line (
did_append = FALSE;
}
+ inhibit_delete_count++;
if (newindent
|| did_si
) {
@@ -821,6 +822,7 @@ open_line (
did_si = false;
}
}
+ inhibit_delete_count--;
/*
* In REPLACE mode, for each character in the extra leader, there must be
@@ -1685,6 +1687,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
bool was_alloced = ml_line_alloced(); // check if oldp was allocated
char_u *newp;
if (was_alloced) {
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen);
newp = oldp; // use same allocated memory
} else { // need to allocate a new line
newp = xmalloc((size_t)(oldlen + 1 - count));
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index cc214616f4..404f279e73 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1807,9 +1807,11 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
char_u buf[MAXWLEN];
char_u *p;
- if (len == -1)
+ if (len == -1) {
p = word;
- else {
+ } else if (len >= MAXWLEN) {
+ return;
+ } else {
STRLCPY(buf, word, len + 1);
p = buf;
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index d8d529d0f6..3b0f42aacd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1306,7 +1306,7 @@ static void refresh_screen(Terminal *term, buf_T *buf)
static void adjust_topline(Terminal *term, buf_T *buf, long added)
{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
linenr_T ml_end = buf->b_ml.ml_line_count;
bool following = ml_end == wp->w_cursor.lnum + added; // cursor at end?
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index b3438cc649..d7b8ca9e9c 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -1,4 +1,5 @@
" Test spell checking
+" Note: this file uses latin1 encoding, but is used with utf-8 encoding.
if !has('spell')
finish
@@ -351,6 +352,18 @@ func Test_zeq_crash()
bwipe!
endfunc
+" Check handling a word longer than MAXWLEN.
+func Test_spell_long_word()
+ set enc=utf-8
+ new
+ call setline(1, "d\xCC\xB4\xCC\xBD\xCD\x88\xCD\x94a\xCC\xB5\xCD\x84\xCD\x84\xCC\xA8\xCD\x9Cr\xCC\xB5\xCC\x8E\xCD\x85\xCD\x85k\xCC\xB6\xCC\x89\xCC\x9D \xCC\xB6\xCC\x83\xCC\x8F\xCC\xA4\xCD\x8Ef\xCC\xB7\xCC\x81\xCC\x80\xCC\xA9\xCC\xB0\xCC\xAC\xCC\xA2\xCD\x95\xCD\x87\xCD\x8D\xCC\x9E\xCD\x99\xCC\xAD\xCC\xAB\xCC\x97\xCC\xBBo\xCC\xB6\xCC\x84\xCC\x95\xCC\x8C\xCC\x8B\xCD\x9B\xCD\x9C\xCC\xAFr\xCC\xB7\xCC\x94\xCD\x83\xCD\x97\xCC\x8C\xCC\x82\xCD\x82\xCD\x80\xCD\x91\xCC\x80\xCC\xBE\xCC\x82\xCC\x8F\xCC\xA3\xCD\x85\xCC\xAE\xCD\x8D\xCD\x99\xCC\xBC\xCC\xAB\xCC\xA7\xCD\x88c\xCC\xB7\xCD\x83\xCC\x84\xCD\x92\xCC\x86\xCC\x83\xCC\x88\xCC\x92\xCC\x94\xCC\xBE\xCC\x9D\xCC\xAF\xCC\x98\xCC\x9D\xCC\xBB\xCD\x8E\xCC\xBB\xCC\xB3\xCC\xA3\xCD\x8E\xCD\x99\xCC\xA5\xCC\xAD\xCC\x99\xCC\xB9\xCC\xAE\xCC\xA5\xCC\x9E\xCD\x88\xCC\xAE\xCC\x9E\xCC\xA9\xCC\x97\xCC\xBC\xCC\x99\xCC\xA5\xCD\x87\xCC\x97\xCD\x8E\xCD\x94\xCC\x99\xCC\x9D\xCC\x96\xCD\x94\xCC\xAB\xCC\xA7\xCC\xA5\xCC\x98\xCC\xBB\xCC\xAF\xCC\xABe\xCC\xB7\xCC\x8E\xCC\x82\xCD\x86\xCD\x9B\xCC\x94\xCD\x83\xCC\x85\xCD\x8A\xCD\x8C\xCC\x8B\xCD\x92\xCD\x91\xCC\x8F\xCC\x81\xCD\x95\xCC\xA2\xCC\xB9\xCC\xB2\xCD\x9C\xCC\xB1\xCC\xA6\xCC\xB3\xCC\xAF\xCC\xAE\xCC\x9C\xCD\x99s\xCC\xB8\xCC\x8C\xCC\x8E\xCC\x87\xCD\x81\xCD\x82\xCC\x86\xCD\x8C\xCD\x8C\xCC\x8B\xCC\x84\xCC\x8C\xCD\x84\xCD\x9B\xCD\x86\xCC\x93\xCD\x90\xCC\x85\xCC\x94\xCD\x98\xCD\x84\xCD\x92\xCD\x8B\xCC\x90\xCC\x83\xCC\x8F\xCD\x84\xCD\x81\xCD\x9B\xCC\x90\xCD\x81\xCC\x8F\xCC\xBD\xCC\x88\xCC\xBF\xCC\x88\xCC\x84\xCC\x8E\xCD\x99\xCD\x94\xCC\x99\xCD\x99\xCC\xB0\xCC\xA8\xCC\xA3\xCC\xA8\xCC\x96\xCC\x99\xCC\xAE\xCC\xBC\xCC\x99\xCD\x9A\xCC\xB2\xCC\xB1\xCC\x9F\xCC\xBB\xCC\xA6\xCD\x85\xCC\xAA\xCD\x89\xCC\x9D\xCC\x99\xCD\x96\xCC\xB1\xCC\xB1\xCC\x99\xCC\xA6\xCC\xA5\xCD\x95\xCC\xB2\xCC\xA0\xCD\x99 within")
+ set spell spelllang=en
+ redraw
+ redraw!
+ bwipe!
+ set nospell
+endfunc
+
func LoadAffAndDic(aff_contents, dic_contents)
throw 'skipped: Nvim does not support enc=latin1'
set enc=latin1
diff --git a/src/nvim/version.c b/src/nvim/version.c
index f3326beb4c..74a4852def 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -2030,14 +2030,19 @@ static void version_msg(char *s)
version_msg_wrap((char_u *)s, false);
}
-/// List all features aligned in columns, dictionary style.
+/// List all features.
+/// This does not use list_in_columns (as in Vim), because there are only a
+/// few, and we do not start at a new line.
static void list_features(void)
{
- list_in_columns((char_u **)features, -1, -1);
- if (msg_col > 0) {
- msg_putchar('\n');
+ version_msg(_("\n\nFeatures: "));
+ for (int i = 0; features[i] != NULL; i++) {
+ version_msg(features[i]);
+ if (features[i+1] != NULL) {
+ version_msg(" ");
+ }
}
- MSG_PUTS("See \":help feature-compile\"\n\n");
+ version_msg("\nSee \":help feature-compile\"\n\n");
}
/// List string items nicely aligned in columns.
@@ -2146,8 +2151,6 @@ void list_version(void)
}
#endif // ifdef HAVE_PATHDEF
- version_msg(_("\n\nFeatures: "));
-
list_features();
#ifdef SYS_VIMRC_FILE
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index f1357c5dbb..550e5dd997 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -40,6 +40,7 @@ static void help(void)
puts(" 0: foo bar");
puts(" ...");
puts(" 96: foo bar");
+ puts(" shell-test REP_NODELAY N {text}");
puts(" shell-test INTERACT");
puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input.");
}
@@ -66,7 +67,8 @@ int main(int argc, char **argv)
if (argc >= 3) {
fprintf(stderr, "%s\n", argv[2]);
}
- } else if (strcmp(argv[1], "REP") == 0) {
+ } else if (strcmp(argv[1], "REP") == 0 ||
+ strcmp(argv[1], "REP_NODELAY") == 0) {
if (argc != 4) {
fprintf(stderr, "REP expects exactly 3 arguments\n");
return 4;
@@ -76,10 +78,17 @@ int main(int argc, char **argv)
fprintf(stderr, "Invalid count: %s\n", argv[2]);
return 4;
}
- for (int i = 0; i < count; i++) {
- printf("%d: %s\n", i, argv[3]);
- fflush(stdout);
- usleep(1000); // Wait 1 ms (simulate typical output).
+ if (strcmp(argv[1], "REP_NODELAY") == 0) {
+ for (int i = 0; i < count; i++) {
+ printf("%d: %s\n", i, argv[3]);
+ fflush(stdout);
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ printf("%d: %s\n", i, argv[3]);
+ fflush(stdout);
+ usleep(1000); // Wait 1 ms (simulate typical output).
+ }
}
} else if (strcmp(argv[1], "UTF-8") == 0) {
// test split-up UTF-8 sequence
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 8223290760..4dde733e1e 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -1,6 +1,7 @@
require('coxpcall')
local luv = require('luv')
local lfs = require('lfs')
+local mpack = require('mpack')
local global_helpers = require('test.helpers')
-- nvim client: Found in .deps/usr/share/lua/<version>/nvim/ if "bundled".
@@ -20,26 +21,32 @@ local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
local write_file = global_helpers.write_file
+local module = {
+ NIL = mpack.NIL,
+ mkdir = lfs.mkdir,
+}
+
local start_dir = lfs.currentdir()
-- XXX: NVIM_PROG takes precedence, QuickBuild sets it.
-local nvim_prog = (
+module.nvim_prog = (
os.getenv('NVIM_PROG')
or os.getenv('NVIM_PRG')
or global_helpers.test_build_dir .. '/bin/nvim'
)
-- Default settings for the test session.
-local nvim_set = 'set shortmess+=IS background=light noswapfile noautoindent'
- ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
- ..' belloff= wildoptions-=pum noshowcmd noruler nomore'
-local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE',
- '--cmd', nvim_set, '--embed'}
+module.nvim_set = (
+ 'set shortmess+=IS background=light noswapfile noautoindent'
+ ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
+ ..' belloff= wildoptions-=pum noshowcmd noruler nomore')
+module.nvim_argv = {
+ module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
+ '--cmd', module.nvim_set, '--embed'}
-- Directory containing nvim.
-local nvim_dir = nvim_prog:gsub("[/\\][^/\\]+$", "")
-if nvim_dir == nvim_prog then
- nvim_dir = "."
+module.nvim_dir = module.nvim_prog:gsub("[/\\][^/\\]+$", "")
+if module.nvim_dir == module.nvim_prog then
+ module.nvim_dir = "."
end
-local mpack = require('mpack')
local tmpname = global_helpers.tmpname
local uname = global_helpers.uname
local prepend_argv
@@ -69,26 +76,27 @@ if prepend_argv then
for i = 1, len do
new_nvim_argv[i] = prepend_argv[i]
end
- for i = 1, #nvim_argv do
- new_nvim_argv[i + len] = nvim_argv[i]
+ for i = 1, #module.nvim_argv do
+ new_nvim_argv[i + len] = module.nvim_argv[i]
end
- nvim_argv = new_nvim_argv
+ module.nvim_argv = new_nvim_argv
+ module.prepend_argv = prepend_argv
end
local session, loop_running, last_error, method_error
-local function get_session()
+function module.get_session()
return session
end
-local function set_session(s, keep)
+function module.set_session(s, keep)
if session and not keep then
session:close()
end
session = s
end
-local function request(method, ...)
+function module.request(method, ...)
local status, rv = session:request(method, ...)
if not status then
if loop_running then
@@ -101,14 +109,14 @@ local function request(method, ...)
return rv
end
-local function next_msg(timeout)
+function module.next_msg(timeout)
return session:next_message(timeout and timeout or 10000)
end
-local function expect_twostreams(msgs1, msgs2)
+function module.expect_twostreams(msgs1, msgs2)
local pos1, pos2 = 1, 1
while pos1 <= #msgs1 or pos2 <= #msgs2 do
- local msg = next_msg()
+ local msg = module.next_msg()
if pos1 <= #msgs1 and pcall(eq, msgs1[pos1], msg) then
pos1 = pos1 + 1
elseif pos2 <= #msgs2 then
@@ -131,7 +139,7 @@ end
--
-- ignore: List of ignored event names.
-- seqs: List of one or more potential event sequences.
-local function expect_msg_seq(...)
+function module.expect_msg_seq(...)
if select('#', ...) < 1 then
error('need at least 1 argument')
end
@@ -161,7 +169,7 @@ local function expect_msg_seq(...)
local expected_seq = seqs[anum]
-- Collect enough messages to compare the next expected sequence.
while #actual_seq < #expected_seq do
- local msg = next_msg(10000) -- Big timeout for ASAN/valgrind.
+ local msg = module.next_msg(10000) -- Big timeout for ASAN/valgrind.
local msg_type = msg and msg[2] or nil
if msg == nil then
error(cat_err(final_error,
@@ -192,11 +200,11 @@ local function call_and_stop_on_error(lsession, ...)
return result
end
-local function set_method_error(err)
+function module.set_method_error(err)
method_error = err
end
-local function run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
+function module.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
local on_request, on_notification, on_setup
if request_cb then
@@ -232,43 +240,43 @@ local function run_session(lsession, request_cb, notification_cb, setup_cb, time
end
end
-local function run(request_cb, notification_cb, setup_cb, timeout)
- run_session(session, request_cb, notification_cb, setup_cb, timeout)
+function module.run(request_cb, notification_cb, setup_cb, timeout)
+ module.run_session(session, request_cb, notification_cb, setup_cb, timeout)
end
-local function stop()
+function module.stop()
session:stop()
end
-local function nvim_prog_abs()
+function module.nvim_prog_abs()
-- system(['build/bin/nvim']) does not work for whatever reason. It must
-- be executable searched in $PATH or something starting with / or ./.
- if nvim_prog:match('[/\\]') then
- return request('nvim_call_function', 'fnamemodify', {nvim_prog, ':p'})
+ if module.nvim_prog:match('[/\\]') then
+ return module.request('nvim_call_function', 'fnamemodify', {module.nvim_prog, ':p'})
else
- return nvim_prog
+ return module.nvim_prog
end
end
-- Executes an ex-command. VimL errors manifest as client (lua) errors, but
-- v:errmsg will not be updated.
-local function nvim_command(cmd)
- request('nvim_command', cmd)
+function module.command(cmd)
+ module.request('nvim_command', cmd)
end
-- Evaluates a VimL expression.
-- Fails on VimL error, but does not update v:errmsg.
-local function nvim_eval(expr)
- return request('nvim_eval', expr)
+function module.eval(expr)
+ return module.request('nvim_eval', expr)
end
-local os_name = (function()
+module.os_name = (function()
local name = nil
return (function()
if not name then
- if nvim_eval('has("win32")') == 1 then
+ if module.eval('has("win32")') == 1 then
name = 'windows'
- elseif nvim_eval('has("macunix")') == 1 then
+ elseif module.eval('has("macunix")') == 1 then
name = 'osx'
else
name = 'unix'
@@ -278,38 +286,38 @@ local os_name = (function()
end)
end)()
-local function iswin()
+function module.iswin()
return package.config:sub(1,1) == '\\'
end
-- Executes a VimL function.
-- Fails on VimL error, but does not update v:errmsg.
-local function nvim_call(name, ...)
- return request('nvim_call_function', name, {...})
+function module.call(name, ...)
+ return module.request('nvim_call_function', name, {...})
end
-- Sends user input to Nvim.
-- Does not fail on VimL error, but v:errmsg will be updated.
local function nvim_feed(input)
while #input > 0 do
- local written = request('nvim_input', input)
+ local written = module.request('nvim_input', input)
input = input:sub(written + 1)
end
end
-local function feed(...)
+function module.feed(...)
for _, v in ipairs({...}) do
nvim_feed(dedent(v))
end
end
-local function rawfeed(...)
+function module.rawfeed(...)
for _, v in ipairs({...}) do
nvim_feed(dedent(v))
end
end
-local function merge_args(...)
+function module.merge_args(...)
local i = 1
local argv = {}
for anum = 1,select('#', ...) do
@@ -361,15 +369,15 @@ local function remove_args(args, args_rm)
return new_args
end
-local function spawn(argv, merge, env)
+function module.spawn(argv, merge, env)
local child_stream = ChildProcessStream.spawn(
- merge and merge_args(prepend_argv, argv) or argv,
+ merge and module.merge_args(prepend_argv, argv) or argv,
env)
return Session.new(child_stream)
end
-- Creates a new Session connected by domain socket (named pipe) or TCP.
-local function connect(file_or_address)
+function module.connect(file_or_address)
local addr, port = string.match(file_or_address, "(.*):(%d+)")
local stream = (addr and port) and TcpStream.open(addr, port) or
SocketStream.open(file_or_address)
@@ -378,7 +386,7 @@ end
-- Calls fn() until it succeeds, up to `max` times or until `max_ms`
-- milliseconds have passed.
-local function retry(max, max_ms, fn)
+function module.retry(max, max_ms, fn)
assert(max == nil or max > 0)
assert(max_ms == nil or max_ms > 0)
local tries = 1
@@ -410,8 +418,16 @@ end
-- Example:
-- clear('-e')
-- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
-local function clear(...)
- local args = {unpack(nvim_argv)}
+function module.clear(...)
+ local argv, env = module.new_argv(...)
+ module.set_session(module.spawn(argv, nil, env))
+end
+
+-- Builds an argument list for use in clear().
+--
+--@see clear() for parameters.
+function module.new_argv(...)
+ local args = {unpack(module.nvim_argv)}
table.insert(args, '--headless')
local new_args
local env = nil
@@ -450,21 +466,21 @@ local function clear(...)
for _, arg in ipairs(new_args) do
table.insert(args, arg)
end
- set_session(spawn(args, nil, env))
+ return args, env
end
-local function insert(...)
+function module.insert(...)
nvim_feed('i')
for _, v in ipairs({...}) do
local escaped = v:gsub('<', '<lt>')
- rawfeed(escaped)
+ module.rawfeed(escaped)
end
nvim_feed('<ESC>')
end
-- Executes an ex-command by user input. Because nvim_input() is used, VimL
-- errors will not manifest as client (lua) errors. Use command() for that.
-local function feed_command(...)
+function module.feed_command(...)
for _, v in ipairs({...}) do
if v:sub(1, 1) ~= '/' then
-- not a search command, prefix with colon
@@ -476,10 +492,10 @@ local function feed_command(...)
end
local sourced_fnames = {}
-local function source(code)
+function module.source(code)
local fname = tmpname()
write_file(fname, code)
- nvim_command('source '..fname)
+ module.command('source '..fname)
-- DO NOT REMOVE FILE HERE.
-- do_source() has a habit of checking whether files are “same” by using inode
-- and device IDs. If you run two source() calls in quick succession there is
@@ -495,76 +511,76 @@ local function source(code)
return fname
end
-local function set_shell_powershell()
- source([[
+function module.set_shell_powershell()
+ module.source([[
set shell=powershell shellquote=( shellpipe=\| shellredir=> shellxquote=
let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command Remove-Item -Force alias:sleep; Remove-Item -Force alias:cat;'
]])
end
-local function nvim(method, ...)
- return request('nvim_'..method, ...)
+function module.nvim(method, ...)
+ return module.request('nvim_'..method, ...)
end
local function ui(method, ...)
- return request('nvim_ui_'..method, ...)
+ return module.request('nvim_ui_'..method, ...)
end
-local function nvim_async(method, ...)
+function module.nvim_async(method, ...)
session:notify('nvim_'..method, ...)
end
-local function buffer(method, ...)
- return request('nvim_buf_'..method, ...)
+function module.buffer(method, ...)
+ return module.request('nvim_buf_'..method, ...)
end
-local function window(method, ...)
- return request('nvim_win_'..method, ...)
+function module.window(method, ...)
+ return module.request('nvim_win_'..method, ...)
end
-local function tabpage(method, ...)
- return request('nvim_tabpage_'..method, ...)
+function module.tabpage(method, ...)
+ return module.request('nvim_tabpage_'..method, ...)
end
-local function curbuf(method, ...)
+function module.curbuf(method, ...)
if not method then
- return nvim('get_current_buf')
+ return module.nvim('get_current_buf')
end
- return buffer(method, 0, ...)
+ return module.buffer(method, 0, ...)
end
-local function wait()
+function module.wait()
-- Execute 'nvim_eval' (a deferred function) to block
-- until all pending input is processed.
session:request('nvim_eval', '1')
end
-local function curbuf_contents()
- wait() -- Before inspecting the buffer, process all input.
- return table.concat(curbuf('get_lines', 0, -1, true), '\n')
+function module.curbuf_contents()
+ module.wait() -- Before inspecting the buffer, process all input.
+ return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
end
-local function curwin(method, ...)
+function module.curwin(method, ...)
if not method then
- return nvim('get_current_win')
+ return module.nvim('get_current_win')
end
- return window(method, 0, ...)
+ return module.window(method, 0, ...)
end
-local function curtab(method, ...)
+function module.curtab(method, ...)
if not method then
- return nvim('get_current_tabpage')
+ return module.nvim('get_current_tabpage')
end
- return tabpage(method, 0, ...)
+ return module.tabpage(method, 0, ...)
end
-local function expect(contents)
- return eq(dedent(contents), curbuf_contents())
+function module.expect(contents)
+ return eq(dedent(contents), module.curbuf_contents())
end
-local function expect_any(contents)
+function module.expect_any(contents)
contents = dedent(contents)
- return ok(nil ~= string.find(curbuf_contents(), contents, 1, true))
+ return ok(nil ~= string.find(module.curbuf_contents(), contents, 1, true))
end
local function do_rmdir(path)
@@ -584,8 +600,8 @@ local function do_rmdir(path)
else
-- Try Nvim delete(): it handles `readonly` attribute on Windows,
-- and avoids Lua cross-version/platform incompatibilities.
- if -1 == nvim_call('delete', abspath) then
- local hint = (os_name() == 'windows'
+ if -1 == module.call('delete', abspath) then
+ local hint = (module.os_name() == 'windows'
and ' (hint: try :%bwipeout! before rmdir())' or '')
error('delete() failed'..hint..': '..abspath)
end
@@ -600,12 +616,12 @@ local function do_rmdir(path)
end
end
-local function rmdir(path)
+function module.rmdir(path)
local ret, _ = pcall(do_rmdir, path)
- if not ret and os_name() == "windows" then
+ if not ret and module.os_name() == "windows" then
-- Maybe "Permission denied"; try again after changing the nvim
-- process to the top-level directory.
- nvim_command([[exe 'cd '.fnameescape(']]..start_dir.."')")
+ module.command([[exe 'cd '.fnameescape(']]..start_dir.."')")
ret, _ = pcall(do_rmdir, path)
end
-- During teardown, the nvim process may not exit quickly enough, then rmdir()
@@ -616,20 +632,20 @@ local function rmdir(path)
end
end
-local exc_exec = function(cmd)
- nvim_command(([[
+function module.exc_exec(cmd)
+ module.command(([[
try
execute "%s"
catch
let g:__exception = v:exception
endtry
]]):format(cmd:gsub('\n', '\\n'):gsub('[\\"]', '\\%0')))
- local ret = nvim_eval('get(g:, "__exception", 0)')
- nvim_command('unlet! g:__exception')
+ local ret = module.eval('get(g:, "__exception", 0)')
+ module.command('unlet! g:__exception')
return ret
end
-local function create_callindex(func)
+function module.create_callindex(func)
local table = {}
setmetatable(table, {
__index = function(tbl, arg1)
@@ -643,7 +659,7 @@ end
-- Helper to skip tests. Returns true in Windows systems.
-- pending_fn is pending() from busted
-local function pending_win32(pending_fn)
+function module.pending_win32(pending_fn)
if uname() == 'Windows' then
if pending_fn ~= nil then
pending_fn('FIXME: Windows', function() end)
@@ -656,7 +672,7 @@ end
-- Calls pending() and returns `true` if the system is too slow to
-- run fragile or expensive tests. Else returns `false`.
-local function skip_fragile(pending_fn, cond)
+function module.skip_fragile(pending_fn, cond)
if pending_fn == nil or type(pending_fn) ~= type(function()end) then
error("invalid pending_fn")
end
@@ -670,7 +686,7 @@ local function skip_fragile(pending_fn, cond)
return false
end
-local function meth_pcall(...)
+function module.meth_pcall(...)
local ret = {pcall(...)}
if type(ret[2]) == 'string' then
ret[2] = ret[2]:gsub('^[^:]+:%d+: ', '')
@@ -678,66 +694,66 @@ local function meth_pcall(...)
return ret
end
-local funcs = create_callindex(nvim_call)
-local meths = create_callindex(nvim)
-local uimeths = create_callindex(ui)
-local bufmeths = create_callindex(buffer)
-local winmeths = create_callindex(window)
-local tabmeths = create_callindex(tabpage)
-local curbufmeths = create_callindex(curbuf)
-local curwinmeths = create_callindex(curwin)
-local curtabmeths = create_callindex(curtab)
+module.funcs = module.create_callindex(module.call)
+module.meths = module.create_callindex(module.nvim)
+module.uimeths = module.create_callindex(ui)
+module.bufmeths = module.create_callindex(module.buffer)
+module.winmeths = module.create_callindex(module.window)
+module.tabmeths = module.create_callindex(module.tabpage)
+module.curbufmeths = module.create_callindex(module.curbuf)
+module.curwinmeths = module.create_callindex(module.curwin)
+module.curtabmeths = module.create_callindex(module.curtab)
-local function exec_lua(code, ...)
- return meths.execute_lua(code, {...})
+function module.exec_lua(code, ...)
+ return module.meths.execute_lua(code, {...})
end
-local function redir_exec(cmd)
- meths.set_var('__redir_exec_cmd', cmd)
- nvim_command([[
+function module.redir_exec(cmd)
+ module.meths.set_var('__redir_exec_cmd', cmd)
+ module.command([[
redir => g:__redir_exec_output
silent! execute g:__redir_exec_cmd
redir END
]])
- local ret = meths.get_var('__redir_exec_output')
- meths.del_var('__redir_exec_output')
- meths.del_var('__redir_exec_cmd')
+ local ret = module.meths.get_var('__redir_exec_output')
+ module.meths.del_var('__redir_exec_output')
+ module.meths.del_var('__redir_exec_cmd')
return ret
end
-local function get_pathsep()
- return iswin() and '\\' or '/'
+function module.get_pathsep()
+ return module.iswin() and '\\' or '/'
end
-local function pathroot()
+function module.pathroot()
local pathsep = package.config:sub(1,1)
- return iswin() and (nvim_dir:sub(1,2)..pathsep) or '/'
+ return module.iswin() and (module.nvim_dir:sub(1,2)..pathsep) or '/'
end
-- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
-- Useful for communicating with child instances.
-local function new_pipename()
+function module.new_pipename()
-- HACK: Start a server temporarily, get the name, then stop it.
- local pipename = nvim_eval('serverstart()')
- funcs.serverstop(pipename)
+ local pipename = module.eval('serverstart()')
+ module.funcs.serverstop(pipename)
return pipename
end
-local function missing_provider(provider)
+function module.missing_provider(provider)
if provider == 'ruby' or provider == 'node' then
- local prog = funcs['provider#' .. provider .. '#Detect']()
+ local prog = module.funcs['provider#' .. provider .. '#Detect']()
return prog == '' and (provider .. ' not detected') or false
elseif provider == 'python' or provider == 'python3' then
local py_major_version = (provider == 'python3' and 3 or 2)
- local errors = funcs['provider#pythonx#Detect'](py_major_version)[2]
+ local errors = module.funcs['provider#pythonx#Detect'](py_major_version)[2]
return errors ~= '' and errors or false
else
assert(false, 'Unknown provider: ' .. provider)
end
end
-local function alter_slashes(obj)
- if not iswin() then
+function module.alter_slashes(obj)
+ if not module.iswin() then
return obj
end
if type(obj) == 'string' then
@@ -746,7 +762,7 @@ local function alter_slashes(obj)
elseif type(obj) == 'table' then
local ret = {}
for k, v in pairs(obj) do
- ret[k] = alter_slashes(v)
+ ret[k] = module.alter_slashes(v)
end
return ret
else
@@ -756,21 +772,21 @@ end
local load_factor = nil
-local function load_adjust(num)
+function module.load_adjust(num)
if load_factor == nil then -- Compute load factor only once.
- clear()
- request('nvim_command', 'source src/nvim/testdir/load.vim')
- load_factor = request('nvim_eval', 'g:test_load_factor')
+ module.clear()
+ module.request('nvim_command', 'source src/nvim/testdir/load.vim')
+ load_factor = module.request('nvim_eval', 'g:test_load_factor')
end
return math.ceil(num * load_factor)
end
-local function parse_context(ctx)
+function module.parse_context(ctx)
local parsed = {}
for _, item in ipairs({'regs', 'jumps', 'buflist', 'gvars'}) do
parsed[item] = filter(function(v)
return type(v) == 'table'
- end, nvim_call('msgpackparse', ctx[item]))
+ end, module.call('msgpackparse', ctx[item]))
end
parsed['buflist'] = parsed['buflist'][1]
return map(function(v)
@@ -781,78 +797,6 @@ local function parse_context(ctx)
end, parsed)
end
-local module = {
- NIL = mpack.NIL,
- alter_slashes = alter_slashes,
- buffer = buffer,
- bufmeths = bufmeths,
- call = nvim_call,
- create_callindex = create_callindex,
- clear = clear,
- command = nvim_command,
- connect = connect,
- curbuf = curbuf,
- curbuf_contents = curbuf_contents,
- curbufmeths = curbufmeths,
- curtab = curtab,
- curtabmeths = curtabmeths,
- curwin = curwin,
- curwinmeths = curwinmeths,
- eval = nvim_eval,
- exc_exec = exc_exec,
- exec_lua = exec_lua,
- expect = expect,
- expect_any = expect_any,
- expect_msg_seq = expect_msg_seq,
- expect_twostreams = expect_twostreams,
- feed = feed,
- feed_command = feed_command,
- funcs = funcs,
- get_pathsep = get_pathsep,
- get_session = get_session,
- insert = insert,
- iswin = iswin,
- merge_args = merge_args,
- meth_pcall = meth_pcall,
- meths = meths,
- missing_provider = missing_provider,
- mkdir = lfs.mkdir,
- load_adjust = load_adjust,
- new_pipename = new_pipename,
- next_msg = next_msg,
- nvim = nvim,
- nvim_argv = nvim_argv,
- nvim_async = nvim_async,
- nvim_dir = nvim_dir,
- nvim_prog = nvim_prog,
- nvim_prog_abs = nvim_prog_abs,
- nvim_set = nvim_set,
- os_name = os_name,
- parse_context = parse_context,
- pathroot = pathroot,
- pending_win32 = pending_win32,
- prepend_argv = prepend_argv,
- rawfeed = rawfeed,
- redir_exec = redir_exec,
- request = request,
- retry = retry,
- rmdir = rmdir,
- run = run,
- run_session = run_session,
- set_session = set_session,
- set_method_error = set_method_error,
- set_shell_powershell = set_shell_powershell,
- skip_fragile = skip_fragile,
- source = source,
- spawn = spawn,
- stop = stop,
- tabmeths = tabmeths,
- tabpage = tabpage,
- uimeths = uimeths,
- wait = wait,
- window = window,
- winmeths = winmeths,
-}
module = global_helpers.tbl_extend('error', module, global_helpers)
return function(after_each)
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index c419d89be3..990cb97fec 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -5,28 +5,31 @@ local command = helpers.command
local meths = helpers.meths
local clear = helpers.clear
local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
local origlines = {"original line 1",
"original line 2",
"original line 3",
"original line 4",
"original line 5",
- "original line 6"}
+ "original line 6",
+ " indented line"}
describe('lua: buffer event callbacks', function()
before_each(function()
clear()
- meths.execute_lua([[
+ exec_lua([[
local events = {}
- function test_register(bufnr, id, changedtick)
+ function test_register(bufnr, id, changedtick, utf_sizes)
local function callback(...)
table.insert(events, {id, ...})
if test_unreg == id then
return true
end
end
- local opts = {on_lines=callback, on_detach=callback}
+ local opts = {on_lines=callback, on_detach=callback, utf_sizes=utf_sizes}
if changedtick then
opts.on_changedtick = callback
end
@@ -38,55 +41,166 @@ describe('lua: buffer event callbacks', function()
events = {}
return ret_events
end
- ]], {})
+ ]])
end)
- it('works', function()
+
+ -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
+ -- assert the wrong thing), but masks errors with unflushed lines (as
+ -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
+ -- test both ways.
+ local function check(verify,utf_sizes)
+ local lastsize
meths.buf_set_lines(0, 0, -1, true, origlines)
- meths.execute_lua("return test_register(...)", {0, "test1"})
+ if verify then
+ lastsize = meths.buf_get_offset(0, meths.buf_line_count(0))
+ end
+ exec_lua("return test_register(...)", 0, "test1",false,utf_sizes)
local tick = meths.buf_get_changedtick(0)
+ local verify_name = "test1"
+ local function check_events(expected)
+ local events = exec_lua("return get_events(...)" )
+ if utf_sizes then
+ -- this test case uses ASCII only, so sizes sshould be the same.
+ -- Unicode is tested below.
+ for _, event in ipairs(expected) do
+ event[9] = event[8]
+ event[10] = event[8]
+ end
+ end
+ eq(expected, events)
+ if verify then
+ for _, event in ipairs(events) do
+ if event[1] == verify_name and event[2] == "lines" then
+ local startline, endline = event[5], event[7]
+ local newrange = meths.buf_get_offset(0, endline) - meths.buf_get_offset(0, startline)
+ local newsize = meths.buf_get_offset(0, meths.buf_line_count(0))
+ local oldrange = newrange + lastsize - newsize
+ eq(oldrange, event[8])
+ lastsize = newsize
+ end
+ end
+ end
+ end
+
+ command('set autoindent')
command('normal! GyyggP')
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 0, 0, 1 }},
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test1", "lines", 1, tick, 0, 0, 1, 0}})
meths.buf_set_lines(0, 3, 5, true, {"changed line"})
tick = tick + 1
- eq({{ "test1", "lines", 1, tick, 3, 5, 4 }},
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test1", "lines", 1, tick, 3, 5, 4, 32 }})
- meths.execute_lua("return test_register(...)", {0, "test2", true})
+ exec_lua("return test_register(...)", 0, "test2", true, utf_sizes)
tick = tick + 1
command('undo')
-- plugins can opt in to receive changedtick events, or choose
-- to only recieve actual changes.
- eq({{ "test1", "lines", 1, tick, 3, 4, 5 },
- { "test2", "lines", 1, tick, 3, 4, 5 },
- { "test2", "changedtick", 1, tick+1 } },
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 },
+ { "test2", "lines", 1, tick, 3, 4, 5, 13 },
+ { "test2", "changedtick", 1, tick+1 } })
tick = tick + 1
-- simulate next callback returning true
- meths.execute_lua("test_unreg = 'test1'", {})
+ exec_lua("test_unreg = 'test1'")
meths.buf_set_lines(0, 6, 7, true, {"x1","x2","x3"})
tick = tick + 1
-- plugins can opt in to receive changedtick events, or choose
-- to only recieve actual changes.
- eq({{ "test1", "lines", 1, tick, 6, 7, 9 },
- { "test2", "lines", 1, tick, 6, 7, 9 }},
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 },
+ { "test2", "lines", 1, tick, 6, 7, 9, 16 }})
+
+ verify_name = "test2"
meths.buf_set_lines(0, 1, 1, true, {"added"})
tick = tick + 1
- eq({{ "test2", "lines", 1, tick, 1, 1, 2 }},
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test2", "lines", 1, tick, 1, 1, 2, 0 }})
+
+ feed('wix')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 16 }})
+
+ -- check hot path for multiple insert
+ feed('yz')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 17 }})
+
+ feed('<bs>')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 19 }})
+
+ feed('<esc>Go')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 11, 11, 12, 0 }})
+
+ feed('x')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 11, 12, 12, 5 }})
command('bwipe!')
- eq({{ "test2", "detach", 1 }},
- meths.execute_lua("return get_events(...)", {}))
+ check_events({{ "test2", "detach", 1 }})
+ end
+
+ it('works', function()
+ check(false)
end)
+
+ it('works with verify', function()
+ check(true)
+ end)
+
+ it('works with utf_sizes and ASCII text', function()
+ check(false,true)
+ end)
+
+ it('works with utf_sizes and unicode text', function()
+ local unicode_text = {"ascii text",
+ "latin text åäö",
+ "BMP text ɧ αλφά",
+ "BMP text 汉语 ↥↧",
+ "SMP 🤦 🦄🦃",
+ "combining å بِيَّة"}
+ meths.buf_set_lines(0, 0, -1, true, unicode_text)
+ feed('gg')
+ exec_lua("return test_register(...)", 0, "test1", false, true)
+ local tick = meths.buf_get_changedtick(0)
+
+ feed('dd')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}, exec_lua("return get_events(...)" ))
+
+ feed('A<bs>')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}, exec_lua("return get_events(...)" ))
+
+ feed('<esc>jylp')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}, exec_lua("return get_events(...)" ))
+
+ feed('+eea<cr>')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}, exec_lua("return get_events(...)" ))
+
+ feed('<esc>jdw')
+ tick = tick + 1
+ -- non-BMP chars count as 2 UTF-2 codeunits
+ eq({{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}, exec_lua("return get_events(...)" ))
+
+ feed('+rx')
+ tick = tick + 1
+ -- count the individual codepoints of a composed character.
+ eq({{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+
+ feed('kJ')
+ tick = tick + 1
+ -- NB: this is inefficient (but not really wrong).
+ eq({{ "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 },
+ { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ end)
+
end)
diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua
index 780d3a1565..0d93914119 100644
--- a/test/functional/lua/utility_functions_spec.lua
+++ b/test/functional/lua/utility_functions_spec.lua
@@ -2,12 +2,12 @@
local helpers = require('test.functional.helpers')(after_each)
local funcs = helpers.funcs
-local meths = helpers.meths
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local meth_pcall = helpers.meth_pcall
+local exec_lua = helpers.exec_lua
before_each(clear)
@@ -110,28 +110,53 @@ describe('lua function', function()
eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
end)
+ it("vim.str_utfindex/str_byteindex", function()
+ exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
+ local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48}
+ local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48}
+ for i,k in pairs(indicies32) do
+ eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i)
+ end
+ for i,k in pairs(indicies16) do
+ eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i)
+ end
+ local i32, i16 = 0, 0
+ for k = 0,48 do
+ if indicies32[i32] < k then
+ i32 = i32 + 1
+ end
+ if indicies16[i16] < k then
+ i16 = i16 + 1
+ if indicies16[i16+1] == indicies16[i16] then
+ i16 = i16 + 1
+ end
+ end
+ eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k)
+ end
+ end)
+
it("vim.schedule", function()
- meths.execute_lua([[
+ exec_lua([[
test_table = {}
vim.schedule(function()
table.insert(test_table, "xx")
end)
table.insert(test_table, "yy")
- ]], {})
- eq({"yy","xx"}, meths.execute_lua("return test_table", {}))
+ ]])
+ eq({"yy","xx"}, exec_lua("return test_table"))
-- type checked args
eq({false, 'Error executing lua: vim.schedule: expected function'},
- meth_pcall(meths.execute_lua, "vim.schedule('stringly')", {}))
+ meth_pcall(exec_lua, "vim.schedule('stringly')"))
eq({false, 'Error executing lua: vim.schedule: expected function'},
- meth_pcall(meths.execute_lua, "vim.schedule()", {}))
+ meth_pcall(exec_lua, "vim.schedule()"))
- meths.execute_lua([[
+ exec_lua([[
vim.schedule(function()
error("big failure\nvery async")
end)
- ]], {})
+ ]])
feed("<cr>")
eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg"))
@@ -139,7 +164,7 @@ describe('lua function', function()
it("vim.split", function()
local split = function(str, sep)
- return meths.execute_lua('return vim.split(...)', {str, sep})
+ return exec_lua('return vim.split(...)', str, sep)
end
local tests = {
@@ -172,7 +197,7 @@ describe('lua function', function()
it('vim.trim', function()
local trim = function(s)
- return meths.execute_lua('return vim.trim(...)', { s })
+ return exec_lua('return vim.trim(...)', s)
end
local trims = {
@@ -194,7 +219,7 @@ describe('lua function', function()
it('vim.inspect', function()
-- just make sure it basically works, it has its own test suite
local inspect = function(t, opts)
- return meths.execute_lua('return vim.inspect(...)', { t, opts })
+ return exec_lua('return vim.inspect(...)', t, opts)
end
eq('2', inspect(2))
@@ -202,18 +227,18 @@ describe('lua function', function()
inspect({ a = { b = 1 } }, { newline = '+', indent = '' }))
-- special value vim.inspect.KEY works
- eq('{ KEY_a = "x", KEY_b = "y"}', meths.execute_lua([[
+ eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[
return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path)
if path[#path] == vim.inspect.KEY then
return 'KEY_'..item
end
return item
end})
- ]], {}))
+ ]]))
end)
it("vim.deepcopy", function()
- local is_dc = meths.execute_lua([[
+ local is_dc = exec_lua([[
local a = { x = { 1, 2 }, y = 5}
local b = vim.deepcopy(a)
@@ -222,7 +247,7 @@ describe('lua function', function()
return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2
and tostring(a) ~= tostring(b)
- ]], {})
+ ]])
assert(is_dc)
end)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 778dc4e219..c0104a58f7 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,4 +1,3 @@
-local paths = require('test.config.paths')
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
@@ -13,14 +12,8 @@ local shada_helpers = require('test.functional.shada.helpers')
local get_shada_rw = shada_helpers.get_shada_rw
local function reset(shada_file)
- -- TODO(justinmk): why is this needed?
- local rtp_value = ('\'%s/runtime\''):format(
- paths.test_source_path:gsub('\'', '\'\''))
- clear{args_rm={'-u', '-i'},
- args={'-u', 'NORC',
+ clear{ args={'-u', 'NORC',
'-i', shada_file or 'NONE',
- '--cmd', 'set laststatus&',
- '--cmd', 'let &runtimepath='..rtp_value,
}}
end
@@ -2554,6 +2547,7 @@ describe('syntax/shada.vim', function()
it('works', function()
nvim_command('syntax on')
nvim_command('setlocal syntax=shada')
+ nvim_command('set laststatus&')
curbuf('set_lines', 0, 1, true, {
'Header with timestamp ' .. epoch .. ':',
' % Key Value',
@@ -2890,4 +2884,3 @@ describe('syntax/shada.vim', function()
eq(exp, act)
end)
end)
-
diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua
index a4746c2205..04c9c01d7c 100644
--- a/test/functional/shada/buffers_spec.lua
+++ b/test/functional/shada/buffers_spec.lua
@@ -1,26 +1,22 @@
--- ShaDa buffer list saving/reading support
+-- shada buffer list saving/reading support
local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, eq, curbufmeths =
helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
-describe('ShaDa support code', function()
+describe('shada support code', function()
local testfilename = 'Xtestfile-functional-shada-buffers'
local testfilename_2 = 'Xtestfile-functional-shada-buffers-2'
- before_each(reset)
after_each(clear)
it('is able to dump and restore buffer list', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(3, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
@@ -28,11 +24,9 @@ describe('ShaDa support code', function()
end)
it('does not restore buffer list without % in &shada', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- set_additional_cmd('')
nvim_command('qall')
reset()
eq(1, funcs.bufnr('$'))
@@ -40,61 +34,57 @@ describe('ShaDa support code', function()
end)
it('does not dump buffer list without % in &shada', function()
+ reset()
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- set_additional_cmd('set shada+=%')
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
end)
it('does not dump unlisted buffer', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buflisted', false)
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
end)
it('does not dump quickfix buffer', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buftype', 'quickfix')
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
end)
it('does not dump unnamed buffers', function()
- set_additional_cmd('set shada+=% hidden')
- reset()
+ reset('set shada+=% hidden')
curbufmeths.set_lines(0, 1, true, {'foo'})
nvim_command('enew')
curbufmeths.set_lines(0, 1, true, {'bar'})
eq(2, funcs.bufnr('$'))
nvim_command('qall!')
- reset()
+ reset('set shada+=% hidden')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
end)
it('restores 1 buffer with %1 in &shada, #5759', function()
- set_additional_cmd('set shada+=%1')
- reset()
+ reset('set shada+=%1')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
nvim_command('qall')
- reset()
+ reset('set shada+=%1')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua
index d5e061bb50..fb3ec4a87c 100644
--- a/test/functional/shada/helpers.lua
+++ b/test/functional/shada/helpers.lua
@@ -1,47 +1,39 @@
local helpers = require('test.functional.helpers')(nil)
-local spawn, set_session, meths, nvim_prog =
- helpers.spawn, helpers.set_session, helpers.meths, helpers.nvim_prog
-local write_file, merge_args = helpers.write_file, helpers.merge_args
+local meths = helpers.meths
+local write_file = helpers.write_file
+local concat_tables = helpers.concat_tables
local mpack = require('mpack')
local tmpname = helpers.tmpname()
-local append_argv = nil
-local function nvim_argv(shada_file, embed)
- if embed == nil then
- embed = true
+-- o={
+-- args=…,
+-- args_rm=…,
+-- shadafile=…,
+-- }
+local function reset(o)
+ assert(o == nil or type(o) == 'table' or type(o) == 'string')
+ o = o and o or {}
+ local args_rm = o.args_rm or {}
+ table.insert(args_rm, '-i')
+ local args={
+ '-i', o.shadafile or tmpname,
+ }
+ if type(o) == 'string' then
+ args = concat_tables(args, {'--cmd', o})
+ elseif o.args then
+ args = concat_tables(args, o.args)
end
- local argv = {nvim_prog, '-u', 'NONE', '-i', shada_file or tmpname, '-N',
- '--cmd', 'set shortmess+=I background=light noswapfile',
- '--headless', embed and '--embed' or nil}
- if helpers.prepend_argv or append_argv then
- return merge_args(helpers.prepend_argv, argv, append_argv)
- else
- return argv
- end
-end
-
-local reset = function(shada_file)
- set_session(spawn(nvim_argv(shada_file)))
+ helpers.clear{
+ args_rm=args_rm,
+ args=args,
+ }
meths.set_var('tmpname', tmpname)
end
-local set_additional_cmd = function(s)
- append_argv = {'--cmd', s}
-end
-
-local function add_argv(...)
- if select('#', ...) == 0 then
- append_argv = nil
- else
- append_argv = {...}
- end
-end
-
local clear = function()
os.remove(tmpname)
- append_argv = nil
end
local get_shada_rw = function(fname)
@@ -89,10 +81,7 @@ end
return {
reset=reset,
- set_additional_cmd=set_additional_cmd,
- add_argv=add_argv,
clear=clear,
get_shada_rw=get_shada_rw,
read_shada_file=read_shada_file,
- nvim_argv=nvim_argv,
}
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index e6450e68b3..e319fd9e6b 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -6,11 +6,7 @@ local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq =
local exc_exec, redir_exec = helpers.exc_exec, helpers.redir_exec
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
-local add_argv = shada_helpers.add_argv
-local nvim_argv = shada_helpers.nvim_argv
+local reset, clear = shada_helpers.reset, shada_helpers.clear
local nvim_current_line = function()
return curwinmeths.get_cursor()[1]
@@ -71,8 +67,7 @@ describe('ShaDa support code', function()
nvim_command('2')
nvim_command('kB')
nvim_command('wshada')
- set_additional_cmd('set shada=\'0,f0')
- reset()
+ reset('set shada=\'0,f0')
nvim_command('language C')
nvim_command('normal! `A')
eq(testfilename, funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -223,17 +218,32 @@ describe('ShaDa support code', function()
-- during -c used to add item with zero lnum to jump list.
it('does not create incorrect file for non-existent buffers when writing from -c',
function()
- add_argv('--cmd', 'silent edit ' .. non_existent_testfilename, '-c', 'qall')
- local argv = nvim_argv(nil, false) -- no --embed
+ local argv = helpers.new_argv{
+ args_rm={
+ '-i',
+ '--embed', -- no --embed
+ },
+ args={
+ '-i', meths.get_var('tmpname'), -- Use same shada file as parent.
+ '--cmd', 'silent edit '..non_existent_testfilename,
+ '-c', 'qall'},
+ }
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
it('does not create incorrect file for non-existent buffers opened from -c',
function()
- add_argv('-c', 'silent edit ' .. non_existent_testfilename,
- '-c', 'autocmd VimEnter * qall')
- local argv = nvim_argv(nil, false) -- no --embed
+ local argv = helpers.new_argv{
+ args_rm={
+ '-i',
+ '--embed', -- no --embed
+ },
+ args={
+ '-i', meths.get_var('tmpname'), -- Use same shada file as parent.
+ '-c', 'silent edit '..non_existent_testfilename,
+ '-c', 'autocmd VimEnter * qall'},
+ }
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua
index 71af14aba8..1f06cbe350 100644
--- a/test/functional/shada/registers_spec.lua
+++ b/test/functional/shada/registers_spec.lua
@@ -3,9 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, eq = helpers.command, helpers.funcs, helpers.eq
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
local setreg = function(name, contents, typ)
if type(contents) == 'string' then
@@ -52,9 +50,8 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- set_additional_cmd('set shada=\'0,<0')
nvim_command('qall')
- reset()
+ reset('set shada=\'0,<0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
eq({{'bca', 'abc', 'cba'}, '\0223'}, getreg('b'))
@@ -76,9 +73,8 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- set_additional_cmd('set shada=\'0,\\"0')
nvim_command('qall')
- reset()
+ reset('set shada=\'0,\\"0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
eq({{'bca', 'abc', 'cba'}, '\0223'}, getreg('b'))
@@ -142,7 +138,6 @@ describe('ShaDa support code', function()
reset()
-- \171 is U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK in latin1
setreg('e', {'\171«'}, 'c')
- set_additional_cmd('')
nvim_command('qall')
reset()
eq({{'\171«'}, 'v'}, getreg('e'))
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 5f7daf73e5..ff63aed235 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -15,7 +15,6 @@ local shada_helpers = require('test.functional.shada.helpers')
local reset, clear, get_shada_rw =
shada_helpers.reset, shada_helpers.clear, shada_helpers.get_shada_rw
local read_shada_file = shada_helpers.read_shada_file
-local set_additional_cmd = shada_helpers.set_additional_cmd
local wshada, _, shada_fname, clean =
get_shada_rw('Xtest-functional-shada-shada.shada')
@@ -244,8 +243,7 @@ describe('ShaDa support code', function()
funcs.mkdir(dirname, '', 0)
eq(0, funcs.filewritable(dirname))
- set_additional_cmd('set shada=')
- reset(dirshada)
+ reset{shadafile=dirshada, args={'--cmd', 'set shada='}}
meths.set_option('shada', '\'10')
eq('Vim(wshada):E886: System error while opening ShaDa file '
.. 'Xtest-functional-shada-shada.d/main.shada for reading to merge '
diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua
index f817bcef74..74bbceddcc 100644
--- a/test/functional/shada/variables_spec.lua
+++ b/test/functional/shada/variables_spec.lua
@@ -4,9 +4,7 @@ local meths, funcs, nvim_command, eq, exc_exec =
helpers.meths, helpers.funcs, helpers.command, helpers.eq, helpers.exc_exec
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
describe('ShaDa support code', function()
before_each(reset)
@@ -25,8 +23,7 @@ describe('ShaDa support code', function()
local autotest = function(tname, varname, varval, val_is_expr)
it('is able to dump and read back ' .. tname .. ' variable automatically',
function()
- set_additional_cmd('set shada+=!')
- reset()
+ reset('set shada+=!')
if val_is_expr then
nvim_command('let g:' .. varname .. ' = ' .. varval)
varval = meths.get_var(varname)
@@ -36,7 +33,7 @@ describe('ShaDa support code', function()
-- Exit during `reset` is not a regular exit: it does not write shada
-- automatically
nvim_command('qall')
- reset()
+ reset('set shada+=!')
eq(varval, meths.get_var(varname))
end)
end
@@ -55,8 +52,7 @@ describe('ShaDa support code', function()
meths.set_var('STRVAR', 'foo')
nvim_command('set shada+=!')
nvim_command('wshada')
- set_additional_cmd('set shada-=!')
- reset()
+ reset('set shada-=!')
nvim_command('rshada')
eq(0, funcs.exists('g:STRVAR'))
end)
@@ -98,7 +94,6 @@ describe('ShaDa support code', function()
meths.set_var('LSTVAR', {'«'})
meths.set_var('DCTVAR', {['«']='«'})
meths.set_var('NESTEDVAR', {['«']={{'«'}, {['«']='«'}, {a='Test'}}})
- set_additional_cmd('')
nvim_command('qall')
reset()
eq('«', meths.get_var('STRVAR'))
@@ -131,11 +126,10 @@ describe('ShaDa support code', function()
nvim_command('let F = function("tr")')
meths.set_var('U', '10')
nvim_command('set shada+=!')
- set_additional_cmd('set shada+=!')
eq('Vim(wshada):E5004: Error while dumping variable g:F, itself: attempt to dump function reference',
exc_exec('wshada'))
meths.set_option('shada', '')
- reset()
+ reset('set shada+=!')
eq('10', meths.get_var('U'))
end)
@@ -148,8 +142,7 @@ describe('ShaDa support code', function()
eq('Vim(wshada):E5005: Unable to dump variable g:L: container references itself in index 0',
exc_exec('wshada'))
meths.set_option('shada', '')
- set_additional_cmd('set shada+=!')
- reset()
+ reset('set shada+=!')
eq('10', meths.get_var('U'))
end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 9a30ea73c4..24bf66e2d8 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -51,12 +51,7 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
- if helpers.skip_fragile(pending,
- (helpers.isCI('travis') and helpers.os_name() == 'osx')) then
- return
- end
- child_session.feed_data(
- ":!for i in $(seq 2 30000); do echo XXXXXXXXXX $i; done\n")
+ child_session.feed_data(":!"..nvim_dir.."/shell-test REP_NODELAY 30001 foo\n")
-- If we observe any line starting with a dot, then throttling occurred.
-- Avoid false failure on slow systems.
@@ -65,10 +60,10 @@ describe("shell command :!", function()
-- Final chunk of output should always be displayed, never skipped.
-- (Throttling is non-deterministic, this test is merely a sanity check.)
screen:expect([[
- XXXXXXXXXX 29997 |
- XXXXXXXXXX 29998 |
- XXXXXXXXXX 29999 |
- XXXXXXXXXX 30000 |
+ 29997: foo |
+ 29998: foo |
+ 29999: foo |
+ 30000: foo |
|
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index b5d3dd9f47..24dbc65bd0 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -456,8 +456,8 @@ else
if bytes_written == -1 then
local err = ffi.errno(0)
if err ~= ffi.C.kPOSIXErrnoEINTR then
- assert(false, ("write() error: %u: %s"):format(
- err, ffi.string(ffi.C.strerror(err))))
+ assert(false, ("write() error: %u: %s ('%s')"):format(
+ err, ffi.string(ffi.C.strerror(err)), s))
end
elseif bytes_written == 0 then
break