diff options
43 files changed, 572 insertions, 733 deletions
@@ -141,6 +141,11 @@ lualint: | build/.ran-cmake deps 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,11 +187,7 @@ appimage: appimage-%: bash scripts/genappimage.sh $* -lint: check-single-includes clint lualint - @# Run pylint only if flake8 is installed. - @command -v flake8 \ - && { $(MAKE) pylint; exit $$?; } \ - || echo "SKIP: pylint (flake8 not found)" +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/config/CMakeLists.txt b/config/CMakeLists.txt index 82cb4d31ad..0ca41d5dfd 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -20,7 +20,6 @@ endif() check_symbol_exists(_NSGetEnviron crt_externs.h HAVE__NSGETENVIRON) # Headers -check_include_files(iconv.h HAVE_ICONV_H) check_include_files(langinfo.h HAVE_LANGINFO_H) check_include_files(locale.h HAVE_LOCALE_H) check_include_files(pwd.h HAVE_PWD_H) diff --git a/config/config.h.in b/config/config.h.in index 40baff95e8..3216ab7556 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -22,7 +22,6 @@ #cmakedefine HAVE_GETPWNAM #cmakedefine HAVE_GETPWUID #cmakedefine HAVE_ICONV -#cmakedefine HAVE_ICONV_H #cmakedefine HAVE_LANGINFO_H #cmakedefine HAVE_LOCALE_H #cmakedefine HAVE_NL_LANGINFO_CODESET 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/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/runtime/doc/job_control.txt b/runtime/doc/job_control.txt index e5cd765e83..ae208c0755 100644 --- a/runtime/doc/job_control.txt +++ b/runtime/doc/job_control.txt @@ -67,7 +67,7 @@ For |on_stdout| and |on_stderr| see |channel-callback|. *on_exit* Arguments passed to on_exit callback: 0: |job-id| - 1: Exit-code of the process. + 1: Exit-code of the process, or 128+SIGNUM if by signal (e.g. 143 on SIGTERM). 2: Event type: "exit" diff --git a/src/nvim/eval.c b/src/nvim/eval.c index fabd26ce47..31a49faaf3 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11260,7 +11260,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "fork", #endif "gettext", -#if defined(HAVE_ICONV_H) && defined(USE_ICONV) +#if defined(HAVE_ICONV) "iconv", #endif "insert_expand", @@ -11373,10 +11373,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) n = stdout_isatty; } else if (STRICMP(name, "multi_byte_encoding") == 0) { n = has_mbyte != 0; -#if defined(USE_ICONV) && defined(DYNAMIC_ICONV) - } else if (STRICMP(name, "iconv") == 0) { - n = iconv_enabled(false); -#endif } else if (STRICMP(name, "syntax_items") == 0) { n = syntax_present(curwin); #ifdef UNIX @@ -12359,7 +12355,6 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) return; } - Channel *data = find_job(argvars[0].vval.v_number, true); if (!data) { return; @@ -16764,6 +16759,8 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; } str += len; + capcol -= len; + len = 0; } } } diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index ffe2db9b76..63efee59a8 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -101,6 +101,10 @@ static void close_cb(uv_handle_t *handle) static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) { Process *proc = handle->data; - proc->status = (int)status; +#if defined(WIN32) + // Use stored/expected signal. + term_signal = proc->exit_signal; +#endif + proc->status = term_signal ? 128 + term_signal : (int)status; proc->internal_exit_cb(proc); } diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 4410deadef..c31ecdaddf 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -159,7 +159,7 @@ void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL /// 0 for no wait. -1 to wait until the process quits. /// @return Exit code of the process. proc->status will have the same value. /// -1 if the timeout expired while the process is still running. -/// -2 if the user interruped the wait. +/// -2 if the user interrupted the wait. int process_wait(Process *proc, int ms, MultiQueue *events) FUNC_ATTR_NONNULL_ARG(1) { @@ -220,6 +220,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL return; } proc->stopped_time = os_hrtime(); + proc->exit_signal = SIGTERM; switch (proc->type) { case kProcessTypeUv: @@ -253,8 +254,10 @@ static void children_kill_cb(uv_timer_t *handle) } uint64_t term_sent = UINT64_MAX == proc->stopped_time; if (kProcessTypePty != proc->type || term_sent) { + proc->exit_signal = SIGKILL; os_proc_tree_kill(proc->pid, SIGKILL); } else { + proc->exit_signal = SIGTERM; os_proc_tree_kill(proc->pid, SIGTERM); proc->stopped_time = UINT64_MAX; // Flag: SIGTERM was sent. // Restart timer. @@ -403,4 +406,3 @@ static void on_process_stream_close(Stream *stream, void *data) Process *proc = data; decref(proc); } - diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 13dc3839ce..ef9d953ab7 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -19,6 +19,7 @@ struct process { Loop *loop; void *data; int pid, status, refcount; + uint8_t exit_signal; // Signal used when killing (on Windows). uint64_t stopped_time; // process_stop() timestamp const char *cwd; char **argv; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 85952a6cbf..0f345df22b 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4061,10 +4061,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 9531c13356..d2620376c6 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -164,22 +164,22 @@ typedef struct AutoPatCmd { * Structure to pass arguments from buf_write() to buf_write_bytes(). */ struct bw_info { - int bw_fd; /* file descriptor */ - char_u *bw_buf; /* buffer with data to be written */ - int bw_len; /* length of data */ + int bw_fd; // file descriptor + char_u *bw_buf; // buffer with data to be written + int bw_len; // length of data #ifdef HAS_BW_FLAGS - int bw_flags; /* FIO_ flags */ + int bw_flags; // FIO_ flags #endif - char_u bw_rest[CONV_RESTLEN]; /* not converted bytes */ - int bw_restlen; /* nr of bytes in bw_rest[] */ - int bw_first; /* first write call */ - char_u *bw_conv_buf; /* buffer for writing converted chars */ - int bw_conv_buflen; /* size of bw_conv_buf */ - int bw_conv_error; /* set for conversion error */ - linenr_T bw_conv_error_lnum; /* first line with error or zero */ - linenr_T bw_start_lnum; /* line number at start of buffer */ -# ifdef USE_ICONV - iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */ + char_u bw_rest[CONV_RESTLEN]; // not converted bytes + int bw_restlen; // nr of bytes in bw_rest[] + int bw_first; // first write call + char_u *bw_conv_buf; // buffer for writing converted chars + int bw_conv_buflen; // size of bw_conv_buf + int bw_conv_error; // set for conversion error + linenr_T bw_conv_error_lnum; // first line with error or zero + linenr_T bw_start_lnum; // line number at start of buffer +# ifdef HAVE_ICONV + iconv_t bw_iconv_fd; // descriptor for iconv() or -1 # endif }; @@ -328,10 +328,10 @@ readfile( char_u *fenc_next = NULL; // next item in 'fencs' or NULL bool advance_fenc = false; long real_size = 0; -# ifdef USE_ICONV - iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */ - int did_iconv = FALSE; /* TRUE when iconv() failed and trying - 'charconvert' next */ +# ifdef HAVE_ICONV + iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1 + int did_iconv = false; // TRUE when iconv() failed and trying + // 'charconvert' next # endif int converted = FALSE; /* TRUE if conversion done */ int notconverted = FALSE; /* TRUE if conversion wanted but it @@ -842,7 +842,7 @@ retry: fileformat = EOL_UNKNOWN; /* detect from file */ } -# ifdef USE_ICONV +# ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { /* aborted conversion with iconv(), close the descriptor */ iconv_close(iconv_fd); @@ -909,15 +909,14 @@ retry: -# ifdef USE_ICONV - /* - * Try using iconv() if we can't convert internally. - */ +# ifdef HAVE_ICONV + // Try using iconv() if we can't convert internally. if (fio_flags == 0 && !did_iconv - ) + ) { iconv_fd = (iconv_t)my_iconv_open( enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc); + } # endif /* @@ -926,12 +925,12 @@ retry: */ if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL && !read_fifo -# ifdef USE_ICONV +# ifdef HAVE_ICONV && iconv_fd == (iconv_t)-1 # endif ) { -# ifdef USE_ICONV - did_iconv = FALSE; +# ifdef HAVE_ICONV + did_iconv = false; # endif /* Skip conversion when it's already done (retry for wrong * "fileformat"). */ @@ -951,7 +950,7 @@ retry: } } else { if (fio_flags == 0 -# ifdef USE_ICONV +# ifdef HAVE_ICONV && iconv_fd == (iconv_t)-1 # endif ) { @@ -1024,20 +1023,23 @@ retry: * ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be * multiple of 4 */ real_size = (int)size; -# ifdef USE_ICONV - if (iconv_fd != (iconv_t)-1) +# ifdef HAVE_ICONV + if (iconv_fd != (iconv_t)-1) { size = size / ICONV_MULT; - else + } else { # endif - if (fio_flags & FIO_LATIN1) + if (fio_flags & FIO_LATIN1) { size = size / 2; - else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) + } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) { size = (size * 2 / 3) & ~1; - else if (fio_flags & FIO_UCS4) + } else if (fio_flags & FIO_UCS4) { size = (size * 2 / 3) & ~3; - else if (fio_flags == FIO_UCSBOM) - size = size / ICONV_MULT; /* worst case */ - + } else if (fio_flags == FIO_UCSBOM) { + size = size / ICONV_MULT; // worst case + } +# ifdef HAVE_ICONV + } +# endif if (conv_restlen > 0) { // Insert unconverted bytes from previous line. memmove(ptr, conv_rest, conv_restlen); // -V614 @@ -1113,7 +1115,7 @@ retry: /* When we did a conversion report an error. */ if (fio_flags != 0 -# ifdef USE_ICONV +# ifdef HAVE_ICONV || iconv_fd != (iconv_t)-1 # endif ) { @@ -1136,7 +1138,7 @@ retry: * leave the UTF8 checking code to do it, as it * works slightly differently. */ if (bad_char_behavior != BAD_KEEP && (fio_flags != 0 -# ifdef USE_ICONV +# ifdef HAVE_ICONV || iconv_fd != (iconv_t)-1 # endif )) { @@ -1145,8 +1147,8 @@ retry: --conv_restlen; } } - fio_flags = 0; /* don't convert this */ -# ifdef USE_ICONV + fio_flags = 0; // don't convert this +# ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); iconv_fd = (iconv_t)-1; @@ -1217,7 +1219,7 @@ retry: if (size <= 0) break; -# ifdef USE_ICONV +# ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { /* * Attempt conversion of the read bytes to 'encoding' using @@ -1475,10 +1477,11 @@ retry: * file is more likely than a conversion error. */ if (can_retry && !incomplete_tail) break; -# ifdef USE_ICONV - /* When we did a conversion report an error. */ - if (iconv_fd != (iconv_t)-1 && conv_error == 0) +# ifdef HAVE_ICONV + // When we did a conversion report an error. + if (iconv_fd != (iconv_t)-1 && conv_error == 0) { conv_error = readfile_linenr(linecnt, ptr, p); + } # endif /* Remember the first linenr with an illegal byte */ if (conv_error == 0 && illegal_byte == 0) @@ -1498,15 +1501,18 @@ retry: if (p < ptr + size && !incomplete_tail) { /* Detected a UTF-8 error. */ rewind_retry: - /* Retry reading with another conversion. */ -# ifdef USE_ICONV - if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) - /* iconv() failed, try 'charconvert' */ - did_iconv = TRUE; - else + // Retry reading with another conversion. +# ifdef HAVE_ICONV + if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) { + // iconv() failed, try 'charconvert' + did_iconv = true; + } else { # endif // use next item from 'fileencodings' advance_fenc = true; +# ifdef HAVE_ICONV + } +# endif file_rewind = true; goto retry; } @@ -1711,7 +1717,7 @@ failed: } if (fenc_alloced) xfree(fenc); -# ifdef USE_ICONV +# ifdef HAVE_ICONV if (iconv_fd != (iconv_t)-1) { iconv_close(iconv_fd); # ifndef __clang_analyzer__ @@ -2295,7 +2301,7 @@ buf_write( write_info.bw_conv_error = FALSE; write_info.bw_conv_error_lnum = 0; write_info.bw_restlen = 0; -# ifdef USE_ICONV +# ifdef HAVE_ICONV write_info.bw_iconv_fd = (iconv_t)-1; # endif @@ -3016,7 +3022,7 @@ nobackup: if (converted && wb_flags == 0) { -# ifdef USE_ICONV +# ifdef HAVE_ICONV // Use iconv() conversion when conversion is needed and it's not done // internally. write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, @@ -3046,7 +3052,7 @@ nobackup: } } if (converted && wb_flags == 0 -# ifdef USE_ICONV +# ifdef HAVE_ICONV && write_info.bw_iconv_fd == (iconv_t)-1 # endif && wfname == fname @@ -3574,7 +3580,7 @@ nofail: xfree(buffer); xfree(fenc_tofree); xfree(write_info.bw_conv_buf); -# ifdef USE_ICONV +# ifdef HAVE_ICONV if (write_info.bw_iconv_fd != (iconv_t)-1) { iconv_close(write_info.bw_iconv_fd); write_info.bw_iconv_fd = (iconv_t)-1; @@ -3949,7 +3955,7 @@ static int buf_write_bytes(struct bw_info *ip) } } -# ifdef USE_ICONV +# ifdef HAVE_ICONV if (ip->bw_iconv_fd != (iconv_t)-1) { const char *from; size_t fromlen; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 4524c4b2c0..b095e759d9 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -655,16 +655,6 @@ EXTERN int inhibit_delete_count INIT(= 0); /// Encoding used when 'fencs' is set to "default" EXTERN char_u *fenc_default INIT(= NULL); -# if defined(USE_ICONV) && defined(DYNAMIC_ICONV) -/* Pointers to functions and variables to be loaded at runtime */ -EXTERN size_t (*iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, - char **outbuf, size_t *outbytesleft); -EXTERN iconv_t (*iconv_open)(const char *tocode, const char *fromcode); -EXTERN int (*iconv_close)(iconv_t cd); -EXTERN int (*iconvctl)(iconv_t cd, int request, void *argument); -EXTERN int* (*iconv_errno)(void); -# endif - /// "State" is the main state of Vim. /// There are other variables that modify the state: /// Visual_mode: When State is NORMAL or INSERT. diff --git a/src/nvim/iconv.h b/src/nvim/iconv.h index d7234090c4..a7c9ad4040 100644 --- a/src/nvim/iconv.h +++ b/src/nvim/iconv.h @@ -1,52 +1,20 @@ #ifndef NVIM_ICONV_H #define NVIM_ICONV_H -// iconv can be linked at compile-time as well as loaded at runtime. In the -// latter case, some function pointers need to be initialized after loading -// the library (see `iconv_enabled()` in mbyte.c). These function pointers -// are stored in globals.h. Since globals.h includes iconv.h to get the -// definition of USE_ICONV, we can't include it from iconv.h. One way to -// solve this conundrum would be perhaps to let cmake decide the value of -// USE_ICONV, or to put the USE_ICONV definition in config.h.in directly. As -// it stands, globals.h needs to be included alongside iconv.h. - #include "auto/config.h" -// Use iconv() when it's available, either by linking to the library at -// compile time or by loading it at runtime. -#if (defined(HAVE_ICONV_H) && defined(HAVE_ICONV)) || defined(DYNAMIC_ICONV) -# define USE_ICONV -#endif - -// If we don't have the actual iconv header files present but USE_ICONV was -// defined, we provide a type shim (pull in errno.h and define iconv_t). -// This enables us to still load and use iconv dynamically at runtime. -#ifdef USE_ICONV +#ifdef HAVE_ICONV # include <errno.h> -# ifdef HAVE_ICONV_H -# include <iconv.h> -# else -typedef void *iconv_t; -# endif -#endif +# include <iconv.h> // define some missing constants if necessary -# ifdef USE_ICONV # ifndef EILSEQ # define EILSEQ 123 # endif -# ifdef DYNAMIC_ICONV -// on win32 iconv.dll is dynamically loaded -# define ICONV_ERRNO (*iconv_errno()) -# define ICONV_E2BIG 7 -# define ICONV_EINVAL 22 -# define ICONV_EILSEQ 42 -# else -# define ICONV_ERRNO errno -# define ICONV_E2BIG E2BIG -# define ICONV_EINVAL EINVAL -# define ICONV_EILSEQ EILSEQ -# endif -# endif +# define ICONV_ERRNO errno +# define ICONV_E2BIG E2BIG +# define ICONV_EINVAL EINVAL +# define ICONV_EILSEQ EILSEQ +#endif #endif // NVIM_ICONV_H diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 6f1d7996a5..3de1b531e6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -113,6 +113,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]; @@ -221,6 +280,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/main.c b/src/nvim/main.c index 9c342e62c0..6bb3c37b92 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -664,9 +664,6 @@ void getout(int exitval) ui_call_set_title(cstr_as_string((char *)p_titleold)); } -#if defined(USE_ICONV) && defined(DYNAMIC_ICONV) - iconv_end(); -#endif cs_end(); if (garbage_collect_at_exit) { garbage_collect(false); diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index bf8ce46113..fae7635d34 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1470,6 +1470,31 @@ void mb_utflen(const char_u *s, size_t len, size_t *codepoints, *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. @@ -2037,7 +2062,7 @@ enc_locale_copy_enc: return enc_canonize((char_u *)buf); } -# if defined(USE_ICONV) +# if defined(HAVE_ICONV) /* @@ -2058,13 +2083,6 @@ void * my_iconv_open(char_u *to, char_u *from) if (iconv_working == kBroken) return (void *)-1; /* detected a broken iconv() previously */ -#ifdef DYNAMIC_ICONV - // Check if the iconv.dll can be found. - if (!iconv_enabled(true)) { - return (void *)-1; - } -#endif - fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from)); if (fd != (iconv_t)-1 && iconv_working == kUnknown) { @@ -2171,152 +2189,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, return result; } -# if defined(DYNAMIC_ICONV) -// Dynamically load the "iconv.dll" on Win32. - -#ifndef DYNAMIC_ICONV // just generating prototypes -# define HINSTANCE int -#endif -static HINSTANCE hIconvDLL = 0; -static HINSTANCE hMsvcrtDLL = 0; - -# ifndef DYNAMIC_ICONV_DLL -# define DYNAMIC_ICONV_DLL "iconv.dll" -# define DYNAMIC_ICONV_DLL_ALT "libiconv-2.dll" -# endif -# ifndef DYNAMIC_MSVCRT_DLL -# define DYNAMIC_MSVCRT_DLL "msvcrt.dll" -# endif - -/* - * Get the address of 'funcname' which is imported by 'hInst' DLL. - */ -static void * get_iconv_import_func(HINSTANCE hInst, - const char *funcname) -{ - PBYTE pImage = (PBYTE)hInst; - PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst; - PIMAGE_NT_HEADERS pPE; - PIMAGE_IMPORT_DESCRIPTOR pImpDesc; - PIMAGE_THUNK_DATA pIAT; /* Import Address Table */ - PIMAGE_THUNK_DATA pINT; /* Import Name Table */ - PIMAGE_IMPORT_BY_NAME pImpName; - - if (pDOS->e_magic != IMAGE_DOS_SIGNATURE) - return NULL; - pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew); - if (pPE->Signature != IMAGE_NT_SIGNATURE) - return NULL; - pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage - + pPE->OptionalHeader.DataDirectory[ - IMAGE_DIRECTORY_ENTRY_IMPORT] - .VirtualAddress); - for (; pImpDesc->FirstThunk; ++pImpDesc) { - if (!pImpDesc->OriginalFirstThunk) - continue; - pIAT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->FirstThunk); - pINT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->OriginalFirstThunk); - for (; pIAT->u1.Function; ++pIAT, ++pINT) { - if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal)) - continue; - pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage - + (UINT_PTR)(pINT->u1.AddressOfData)); - if (strcmp(pImpName->Name, funcname) == 0) - return (void *)pIAT->u1.Function; - } - } - return NULL; -} - -// Load library "name". -HINSTANCE vimLoadLib(char *name) -{ - HINSTANCE dll = NULL; - - // NOTE: Do not use mch_dirname() and mch_chdir() here, they may call - // vimLoadLib() recursively, which causes a stack overflow. - wchar_t old_dirw[MAXPATHL]; - - // Path to exe dir. - char *buf = xstrdup((char *)get_vim_var_str(VV_PROGPATH)); - // ptrdiff_t len = ; - // assert(len > 0); - buf[path_tail_with_sep(buf) - buf] = '\0'; - - if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0) { - // Change directory to where the executable is, both to make - // sure we find a .dll there and to avoid looking for a .dll - // in the current directory. - SetCurrentDirectory((LPCSTR)buf); - // TODO(justinmk): use uv_dlopen instead. see os_libcall - dll = LoadLibrary(name); - SetCurrentDirectoryW(old_dirw); - } - - return dll; -} - - -/* - * Try opening the iconv.dll and return TRUE if iconv() can be used. - */ -bool iconv_enabled(bool verbose) -{ - if (hIconvDLL != 0 && hMsvcrtDLL != 0) - return true; - hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL); - if (hIconvDLL == 0) /* sometimes it's called libiconv.dll */ - hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL_ALT); - if (hIconvDLL != 0) - hMsvcrtDLL = vimLoadLib(DYNAMIC_MSVCRT_DLL); - if (hIconvDLL == 0 || hMsvcrtDLL == 0) { - /* Only give the message when 'verbose' is set, otherwise it might be - * done whenever a conversion is attempted. */ - if (verbose && p_verbose > 0) { - verbose_enter(); - EMSG2(_(e_loadlib), - hIconvDLL == 0 ? DYNAMIC_ICONV_DLL : DYNAMIC_MSVCRT_DLL); - verbose_leave(); - } - iconv_end(); - return false; - } - - iconv = (void *)GetProcAddress(hIconvDLL, "libiconv"); - iconv_open = (void *)GetProcAddress(hIconvDLL, "libiconv_open"); - iconv_close = (void *)GetProcAddress(hIconvDLL, "libiconv_close"); - iconvctl = (void *)GetProcAddress(hIconvDLL, "libiconvctl"); - iconv_errno = get_iconv_import_func(hIconvDLL, "_errno"); - if (iconv_errno == NULL) - iconv_errno = (void *)GetProcAddress(hMsvcrtDLL, "_errno"); - if (iconv == NULL || iconv_open == NULL || iconv_close == NULL - || iconvctl == NULL || iconv_errno == NULL) { - iconv_end(); - if (verbose && p_verbose > 0) { - verbose_enter(); - EMSG2(_(e_loadfunc), "for libiconv"); - verbose_leave(); - } - return false; - } - return true; -} - -void iconv_end(void) -{ - if (hIconvDLL != 0) { - // TODO(justinmk): use uv_dlclose instead. - FreeLibrary(hIconvDLL); - } - if (hMsvcrtDLL != 0) { - FreeLibrary(hMsvcrtDLL); - } - hIconvDLL = 0; - hMsvcrtDLL = 0; -} - -# endif /* DYNAMIC_ICONV */ -# endif /* USE_ICONV */ +# endif // HAVE_ICONV @@ -2347,10 +2220,11 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, int from_is_utf8; int to_is_utf8; - /* Reset to no conversion. */ -# ifdef USE_ICONV - if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) + // Reset to no conversion. +# ifdef HAVE_ICONV + if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) { iconv_close(vcp->vc_fd); + } # endif *vcp = (vimconv_T)MBYTE_NONE_CONV; @@ -2385,9 +2259,9 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, /* Internal utf-8 -> latin9 conversion. */ vcp->vc_type = CONV_TO_LATIN9; } -# ifdef USE_ICONV - else { - /* Use iconv() for conversion. */ +# ifdef HAVE_ICONV + else { // NOLINT(readability/braces) + // Use iconv() for conversion. vcp->vc_fd = (iconv_t)my_iconv_open( to_is_utf8 ? (char_u *)"utf-8" : to, from_is_utf8 ? (char_u *)"utf-8" : from); @@ -2539,8 +2413,8 @@ char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr, *lenp = (size_t)(d - retval); break; -# ifdef USE_ICONV - case CONV_ICONV: /* conversion with vcp->vc_fd */ +# ifdef HAVE_ICONV + case CONV_ICONV: // conversion with vcp->vc_fd retval = iconv_string(vcp, ptr, len, unconvlenp, lenp); break; # endif diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h index ed48705c6d..536d58be1f 100644 --- a/src/nvim/mbyte.h +++ b/src/nvim/mbyte.h @@ -63,7 +63,7 @@ typedef enum { typedef struct { int vc_type; ///< Zero or more ConvFlags. int vc_factor; ///< Maximal expansion factor. -# ifdef USE_ICONV +# ifdef HAVE_ICONV iconv_t vc_fd; ///< Value for CONV_ICONV. # endif bool vc_fail; ///< What to do with invalid characters: if true, fail, diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 5fdf0e6181..f0bc13783c 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -288,7 +288,7 @@ static void chld_handler(uv_signal_t *handle, int signum) if (WIFEXITED(stat)) { proc->status = WEXITSTATUS(stat); } else if (WIFSIGNALED(stat)) { - proc->status = WTERMSIG(stat); + proc->status = 128 + WTERMSIG(stat); } proc->internal_exit_cb(proc); } diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index c5f8efadff..290668bca3 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -252,7 +252,7 @@ static void pty_process_finish2(PtyProcess *ptyproc) DWORD exit_code = 0; GetExitCodeProcess(ptyproc->process_handle, &exit_code); - proc->status = (int)exit_code; + proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code; CloseHandle(ptyproc->process_handle); ptyproc->process_handle = NULL; diff --git a/src/nvim/search.c b/src/nvim/search.c index 7d46b3b4d5..fe4fdf57ba 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4242,6 +4242,7 @@ static void search_stat(int dirc, pos_T *pos, // STRNICMP ignores case, but we should not ignore case. // Unfortunately, there is no STRNICMP function. if (!(chgtick == buf_get_changedtick(curbuf) + && lastpat != NULL // supress clang/NULL passed as nonnull parameter && STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0 && STRLEN(lastpat) == STRLEN(spats[last_idx].pat) && equalpos(lastpos, curwin->w_cursor) diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 5bf315cdc3..8d800843f8 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1808,9 +1808,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 e503efe46e..5aeea3223b 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -1307,7 +1307,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..230cb72335 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 @@ -68,6 +69,47 @@ func Test_z_equal_on_invalid_utf8_word() bwipe! endfunc +" Test spellbadword() with argument +func Test_spellbadword() + set spell + + call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.')) + call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence')) + + set spelllang=en + call assert_equal(['', ''], spellbadword('centre')) + call assert_equal(['', ''], spellbadword('center')) + set spelllang=en_us + call assert_equal(['centre', 'local'], spellbadword('centre')) + call assert_equal(['', ''], spellbadword('center')) + set spelllang=en_gb + call assert_equal(['', ''], spellbadword('centre')) + call assert_equal(['center', 'local'], spellbadword('center')) + + " Create a small word list to test that spellbadword('...') + " can return ['...', 'rare']. + e Xwords + insert +foo +foobar/? +. + w! + mkspell! Xwords.spl Xwords + set spelllang=Xwords.spl + call assert_equal(['foobar', 'rare'], spellbadword('foo foobar')) + + " Typo should not be detected without the 'spell' option. + set spelllang=en_gb nospell + call assert_equal(['', ''], spellbadword('centre')) + call assert_equal(['', ''], spellbadword('My bycycle.')) + call assert_equal(['', ''], spellbadword('A sentence. another sentence')) + + call delete('Xwords.spl') + call delete('Xwords') + set spelllang& + set spell& +endfunc + func Test_spellreall() new set spell @@ -351,6 +393,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 e07865a410..74a4852def 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -52,12 +52,8 @@ static char *features[] = { "-acl", #endif -#if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) || defined(DYNAMIC_ICONV) -# ifdef DYNAMIC_ICONV -"+iconv/dyn", -# else +#if defined(HAVE_ICONV) "+iconv", -# endif #else "-iconv", #endif diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 212b76b5d9..180ed9aa02 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -183,7 +183,7 @@ describe('jobs', function() ) nvim('command', "call jobstop(j)") eq({'notification', 'stdout', {0, {''}}}, next_msg()) - eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) + eq({'notification', 'exit', {0, 143}}, next_msg()) end) it('preserves NULs', function() @@ -217,7 +217,7 @@ describe('jobs', function() eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg()) nvim('command', "call jobstop(j)") eq({'notification', 'stdout', {0, {''}}}, next_msg()) - eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) + eq({'notification', 'exit', {0, 143}}, next_msg()) end) it('preserves newlines', function() @@ -234,7 +234,7 @@ describe('jobs', function() next_msg()) nvim('command', "call jobstop(j)") eq({'notification', 'stdout', {0, {''}}}, next_msg()) - eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) + eq({'notification', 'exit', {0, 143}}, next_msg()) end) it('avoids sending final newline', function() @@ -244,7 +244,7 @@ describe('jobs', function() next_msg()) nvim('command', "call jobstop(j)") eq({'notification', 'stdout', {0, {''}}}, next_msg()) - eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) + eq({'notification', 'exit', {0, 143}}, next_msg()) end) it('closes the job streams with jobclose', function() @@ -284,18 +284,7 @@ describe('jobs', function() neq(NIL, meths.get_proc(pid)) nvim('command', 'call jobstop(j)') eq({'notification', 'stdout', {0, {''}}}, next_msg()) - if iswin() then - expect_msg_seq( - -- win64 - { {'notification', 'exit', {0, 1}} - }, - -- win32 - { {'notification', 'exit', {0, 15}} - } - ) - else - eq({'notification', 'exit', {0, 0}}, next_msg()) - end + eq({'notification', 'exit', {0, 143}}, next_msg()) eq(NIL, meths.get_proc(pid)) end) 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..d4ace3030c 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 @@ -157,11 +165,12 @@ local function expect_msg_seq(...) end return string.format('%s\n%s\n%s', err1, string.rep('=', 78), err2) end + local msg_timeout = module.load_adjust(10000) -- Big timeout for ASAN/valgrind. for anum = 1, #seqs do 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(msg_timeout) local msg_type = msg and msg[2] or nil if msg == nil then error(cat_err(final_error, @@ -192,11 +201,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 +241,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 +287,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 +370,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 +387,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 +419,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 +467,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 +493,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 +512,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 +601,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 +617,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 +633,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 +660,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 +673,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 +687,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 +695,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 +763,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 @@ -754,23 +771,23 @@ local function alter_slashes(obj) end end - -local load_factor = nil -local function 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') - end +local load_factor = 1 +if global_helpers.isCI() then + -- Compute load factor only once (but outside of any tests). + module.clear() + module.request('nvim_command', 'source src/nvim/testdir/load.vim') + load_factor = module.request('nvim_eval', 'g:test_load_factor') +end +function module.load_adjust(num) 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 +798,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/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/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 --} | |