aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.builds/openbsd.yml38
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml5
-rw-r--r--ci/build.ps12
-rw-r--r--ci/common/build.sh7
-rw-r--r--ci/common/test.sh8
-rw-r--r--cmake/FindLibLUV.cmake3
-rw-r--r--cmake/GetCompileFlags.cmake10
-rw-r--r--config/config.h.in1
-rw-r--r--runtime/autoload/provider/clipboard.vim18
-rw-r--r--runtime/doc/intro.txt3
-rw-r--r--runtime/doc/ui.txt2
-rw-r--r--src/nvim/CMakeLists.txt22
-rw-r--r--src/nvim/README.md16
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c10
-rw-r--r--src/nvim/charset.c3
-rw-r--r--src/nvim/edit.c478
-rw-r--r--src/nvim/edit.h9
-rw-r--r--src/nvim/eval.c26
-rw-r--r--src/nvim/event/stream.c7
-rw-r--r--src/nvim/ex_cmds.c3
-rw-r--r--src/nvim/ex_cmds2.c20
-rw-r--r--src/nvim/ex_docmd.c13
-rw-r--r--src/nvim/ex_getln.c29
-rw-r--r--src/nvim/fileio.c25
-rw-r--r--src/nvim/fold.c26
-rw-r--r--src/nvim/globals.h5
-rw-r--r--src/nvim/highlight.c7
-rw-r--r--src/nvim/keymap.c2
-rw-r--r--src/nvim/main.c29
-rw-r--r--src/nvim/mbyte.c129
-rw-r--r--src/nvim/message.c117
-rw-r--r--src/nvim/misc1.c2
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/option.c48
-rw-r--r--src/nvim/os/env.c25
-rw-r--r--src/nvim/os/fs.c18
-rw-r--r--src/nvim/os/fs_defs.h6
-rw-r--r--src/nvim/os/os_defs.h7
-rw-r--r--src/nvim/os/pty_process_win.c30
-rw-r--r--src/nvim/path.c12
-rw-r--r--src/nvim/screen.c2
-rw-r--r--src/nvim/search.c18
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/testdir/Makefile40
-rw-r--r--src/nvim/testdir/load.vim2
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh2
-rw-r--r--src/nvim/testdir/runnvim.vim12
-rw-r--r--src/nvim/testdir/runtest.vim39
-rw-r--r--src/nvim/testdir/shared.vim26
-rw-r--r--src/nvim/testdir/summarize.vim56
-rw-r--r--src/nvim/testdir/test42.inbin2354 -> 2438 bytes
-rw-r--r--src/nvim/testdir/test52.in64
-rw-r--r--src/nvim/testdir/test52.ok18
-rw-r--r--src/nvim/testdir/test_alot_utf8.vim3
-rw-r--r--src/nvim/testdir/test_arabic.vim4
-rw-r--r--src/nvim/testdir/test_autochdir.vim2
-rw-r--r--src/nvim/testdir/test_breakindent.vim2
-rw-r--r--src/nvim/testdir/test_cd.vim3
-rw-r--r--src/nvim/testdir/test_charsearch_utf8.vim3
-rw-r--r--src/nvim/testdir/test_checkpath.vim9
-rw-r--r--src/nvim/testdir/test_clientserver.vim2
-rw-r--r--src/nvim/testdir/test_cmdline.vim11
-rw-r--r--src/nvim/testdir/test_debugger.vim2
-rw-r--r--src/nvim/testdir/test_diffmode.vim4
-rw-r--r--src/nvim/testdir/test_digraph.vim2
-rw-r--r--src/nvim/testdir/test_display.vim2
-rw-r--r--src/nvim/testdir/test_edit.vim14
-rw-r--r--src/nvim/testdir/test_erasebackword.vim6
-rw-r--r--src/nvim/testdir/test_expr_utf8.vim3
-rw-r--r--src/nvim/testdir/test_find_complete.vim3
-rw-r--r--src/nvim/testdir/test_fold.vim18
-rw-r--r--src/nvim/testdir/test_functions.vim32
-rw-r--r--src/nvim/testdir/test_ga.vim4
-rw-r--r--src/nvim/testdir/test_highlight.vim4
-rw-r--r--src/nvim/testdir/test_increment_dbcs.vim4
-rw-r--r--src/nvim/testdir/test_let.vim115
-rw-r--r--src/nvim/testdir/test_listdict.vim79
-rw-r--r--src/nvim/testdir/test_makeencoding.vim3
-rw-r--r--src/nvim/testdir/test_maparg.vim3
-rw-r--r--src/nvim/testdir/test_mapping.vim12
-rw-r--r--src/nvim/testdir/test_marks.vim3
-rw-r--r--src/nvim/testdir/test_match.vim57
-rw-r--r--src/nvim/testdir/test_matchadd_conceal_utf8.vim2
-rw-r--r--src/nvim/testdir/test_mksession.vim5
-rw-r--r--src/nvim/testdir/test_mksession_utf8.vim2
-rw-r--r--src/nvim/testdir/test_normal.vim63
-rw-r--r--src/nvim/testdir/test_options.vim3
-rw-r--r--src/nvim/testdir/test_plus_arg_edit.vim4
-rw-r--r--src/nvim/testdir/test_popup.vim166
-rw-r--r--src/nvim/testdir/test_profile.vim2
-rw-r--r--src/nvim/testdir/test_put.vim3
-rw-r--r--src/nvim/testdir/test_quickfix.vim3
-rw-r--r--src/nvim/testdir/test_regex_char_classes.vim3
-rw-r--r--src/nvim/testdir/test_search.vim7
-rw-r--r--src/nvim/testdir/test_source_utf8.vim3
-rw-r--r--src/nvim/testdir/test_spell.vim6
-rw-r--r--src/nvim/testdir/test_startup_utf8.vim5
-rw-r--r--src/nvim/testdir/test_statusline.vim3
-rw-r--r--src/nvim/testdir/test_syntax.vim35
-rw-r--r--src/nvim/testdir/test_tabpage.vim2
-rw-r--r--src/nvim/testdir/test_timers.vim2
-rw-r--r--src/nvim/testdir/test_true_false.vim9
-rw-r--r--src/nvim/testdir/test_undo.vim5
-rw-r--r--src/nvim/testdir/test_usercommands.vim1
-rw-r--r--src/nvim/testdir/test_utf8.vim3
-rw-r--r--src/nvim/testdir/test_utf8_comparisons.vim4
-rw-r--r--src/nvim/testdir/test_virtualedit.vim8
-rw-r--r--src/nvim/testdir/test_visual.vim3
-rw-r--r--src/nvim/testdir/test_window_cmd.vim19
-rw-r--r--src/nvim/testdir/test_wordcount.vim4
-rw-r--r--src/nvim/testdir/test_writefile.vim2
-rw-r--r--src/nvim/tui/tui.c40
-rw-r--r--src/nvim/ui_compositor.c22
-rw-r--r--src/nvim/vim.h7
-rw-r--r--src/nvim/window.c2
-rw-r--r--test/functional/api/proc_spec.lua7
-rw-r--r--test/functional/api/server_requests_spec.lua3
-rw-r--r--test/functional/api/vim_spec.lua14
-rw-r--r--test/functional/core/job_spec.lua76
-rw-r--r--test/functional/core/startup_spec.lua25
-rw-r--r--test/functional/eval/timer_spec.lua116
-rw-r--r--test/functional/fixtures/tty-test.c3
-rw-r--r--test/functional/helpers.lua2
-rw-r--r--test/functional/legacy/055_list_and_dict_types_spec.lua2
-rw-r--r--test/functional/provider/python3_spec.lua6
-rw-r--r--test/functional/terminal/buffer_spec.lua7
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua1
-rw-r--r--test/functional/ui/float_spec.lua91
-rw-r--r--test/functional/ui/inccommand_spec.lua16
-rw-r--r--test/functional/ui/input_spec.lua5
-rw-r--r--test/functional/ui/messages_spec.lua50
-rw-r--r--test/functional/ui/mode_spec.lua6
-rw-r--r--test/functional/ui/multigrid_spec.lua50
-rw-r--r--test/functional/ui/output_spec.lua3
-rw-r--r--test/functional/ui/popupmenu_spec.lua3
-rw-r--r--test/functional/ui/screen.lua14
-rw-r--r--test/helpers.lua4
140 files changed, 1664 insertions, 1209 deletions
diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
new file mode 100644
index 0000000000..1ac830e6ad
--- /dev/null
+++ b/.builds/openbsd.yml
@@ -0,0 +1,38 @@
+# sourcehut CI: https://builds.sr.ht/~jmk/neovim
+
+image: openbsd/6.5
+
+packages:
+- autoconf-2.69p2
+- automake-1.15.1
+- cmake
+- gettext-0.19.8.1p3
+- gettext-tools-0.19.8.1
+- gmake
+- libtool
+- ninja-1.8.2p0
+- unzip-6.0p11
+
+sources:
+- https://github.com/neovim/neovim
+
+tasks:
+- build: |
+ export AUTOCONF_VERSION=2.69
+ export AUTOMAKE_VERSION=1.15
+ cd neovim
+ mkdir .deps
+ cd .deps
+ cmake -G Ninja ../third-party/
+ cmake --build . --config Debug
+ cd ..
+ mkdir build
+ cd build
+ cmake -G Ninja ..
+ cmake --build . --config Debug
+ ./bin/nvim --version
+- test: |
+ export LC_CTYPE=en_US.UTF-8
+ cd neovim
+ # oldtests
+ gmake -C src/nvim/testdir NVIM_PRG=`pwd`/build/bin/nvim
diff --git a/.gitignore b/.gitignore
index 68dbb7588a..7db3d96e2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,8 @@ tags
/src/nvim/testdir/valgrind.*
/src/nvim/testdir/.gdbinit
/runtime/indent/testdir/*.out
+# Generated by src/nvim/testdir/runnvim.sh.
+/src/nvim/testdir/*.tlog
# Generated by unit tests.
/test/includes/post/
diff --git a/.travis.yml b/.travis.yml
index f234c89c26..325b5e7b56 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -76,7 +76,7 @@ addons:
- valgrind
- xclip
homebrew:
- update: true
+ update: false
packages:
- ccache
- ninja
@@ -164,6 +164,9 @@ cache:
directories:
- "$CACHE_NVIM_DEPS_DIR"
+git:
+ quiet: true
+
notifications:
webhooks:
urls:
diff --git a/ci/build.ps1 b/ci/build.ps1
index 42066c462b..d533d7b4e0 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -139,7 +139,7 @@ if ($uploadToCodecov) {
# 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
+& "C:\msys64\mingw$bits\bin\mingw32-make.exe" -C $(Convert-Path ..\src\nvim\testdir) VERBOSE=1 ; exitIfFailed
$env:PATH = $OldPath
if ($uploadToCodecov) {
diff --git a/ci/common/build.sh b/ci/common/build.sh
index bdbe012ca6..8e9b2f8ebb 100644
--- a/ci/common/build.sh
+++ b/ci/common/build.sh
@@ -84,12 +84,11 @@ build_nvim() {
fi
# Invoke nvim to trigger *San early.
- if ! (bin/nvim --version && bin/nvim -u NONE -e -c ':qall') ; then
- asan_check "${LOG_DIR}"
+ if ! (bin/nvim --version && bin/nvim -u NONE -e -cq | cat -vet) ; then
+ check_sanitizer "${LOG_DIR}"
exit 1
fi
- asan_check "${LOG_DIR}"
-
+ check_sanitizer "${LOG_DIR}"
cd "${TRAVIS_BUILD_DIR}"
}
diff --git a/ci/common/test.sh b/ci/common/test.sh
index fb2dcc077e..0233d62c96 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -80,8 +80,8 @@ valgrind_check() {
check_logs "${1}" "valgrind-*"
}
-asan_check() {
- if test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
+check_sanitizer() {
+ if test -n "${CLANG_SANITIZER}"; then
check_logs "${1}" "*san.*"
fi
}
@@ -104,7 +104,7 @@ run_functionaltests() {(
fail 'functionaltests' F 'Functional tests failed'
fi
submit_coverage functionaltest
- asan_check "${LOG_DIR}"
+ check_sanitizer "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
exit_suite
@@ -118,7 +118,7 @@ run_oldtests() {(
fail 'oldtests' F 'Legacy tests failed'
fi
submit_coverage oldtest
- asan_check "${LOG_DIR}"
+ check_sanitizer "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
exit_suite
diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibLUV.cmake
index 784e3fd249..bc53d00f24 100644
--- a/cmake/FindLibLUV.cmake
+++ b/cmake/FindLibLUV.cmake
@@ -14,7 +14,8 @@ set(LIBLUV_DEFINITIONS ${PC_LIBLUV_CFLAGS_OTHER})
find_path(LIBLUV_INCLUDE_DIR luv/luv.h
PATHS ${PC_LIBLUV_INCLUDEDIR} ${PC_LIBLUV_INCLUDE_DIRS})
-list(APPEND LIBLUV_NAMES luv)
+# Explicitly look for luv.so. #10407
+list(APPEND LIBLUV_NAMES luv luv${CMAKE_SHARED_LIBRARY_SUFFIX})
find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES}
HINTS ${PC_LIBLUV_LIBDIR} ${PC_LIBLUV_LIBRARY_DIRS})
diff --git a/cmake/GetCompileFlags.cmake b/cmake/GetCompileFlags.cmake
index 482eacca16..667b97350c 100644
--- a/cmake/GetCompileFlags.cmake
+++ b/cmake/GetCompileFlags.cmake
@@ -13,6 +13,11 @@ function(get_compile_flags _compile_flags)
get_directory_property(compile_definitions
DIRECTORY "src/nvim"
COMPILE_DEFINITIONS)
+ get_target_property(compile_definitions_target nvim COMPILE_DEFINITIONS)
+ if(compile_definitions_target)
+ list(APPEND compile_definitions ${compile_definitions_target})
+ list(REMOVE_DUPLICATES compile_definitions)
+ endif()
# NOTE: list(JOIN) requires CMake 3.12, string(CONCAT) requires CMake 3.
string(REPLACE ";" " -D" compile_definitions "${compile_definitions}")
if(compile_definitions)
@@ -28,6 +33,11 @@ function(get_compile_flags _compile_flags)
get_directory_property(compile_options
DIRECTORY "src/nvim"
COMPILE_OPTIONS)
+ get_target_property(compile_options_target nvim COMPILE_OPTIONS)
+ if(compile_options_target)
+ list(APPEND compile_options ${compile_options_target})
+ list(REMOVE_DUPLICATES compile_options)
+ endif()
# NOTE: list(JOIN) requires CMake 3.12.
string(REPLACE ";" " " compile_options "${compile_options}")
string(REPLACE
diff --git a/config/config.h.in b/config/config.h.in
index 3216ab7556..0cb87c6b4d 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -13,7 +13,6 @@
#endif
#define PROJECT_NAME "@PROJECT_NAME@"
-#define LOCALE_INSTALL_DIR "@CMAKE_INSTALL_FULL_LOCALEDIR@"
#cmakedefine HAVE__NSGETENVIRON
#cmakedefine HAVE_FD_CLOEXEC
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index ce140b0948..e33dc31f6d 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -159,9 +159,7 @@ function! s:clipboard.set(lines, regtype, reg) abort
end
if s:selections[a:reg].owner > 0
- " The previous provider instance should exit when the new one takes
- " ownership, but kill it to be sure we don't fill up the job table.
- call jobstop(s:selections[a:reg].owner)
+ let prev_job = s:selections[a:reg].owner
end
let s:selections[a:reg] = copy(s:selection)
let selection = s:selections[a:reg]
@@ -175,13 +173,23 @@ function! s:clipboard.set(lines, regtype, reg) abort
call jobsend(jobid, a:lines)
call jobclose(jobid, 'stdin')
let selection.owner = jobid
+ let ret = 1
else
echohl WarningMsg
echomsg 'clipboard: failed to execute: '.(s:copy[a:reg])
echohl None
- return 0
+ let ret = 1
+ endif
+
+ " The previous provider instance should exit when the new one takes
+ " ownership, but kill it to be sure we don't fill up the job table.
+ if exists('prev_job')
+ call timer_start(1000, {... ->
+ \ jobwait([prev_job], 0)[0] == -1
+ \ && jobstop(prev_job)})
endif
- return 1
+
+ return ret
endfunction
function! provider#clipboard#Call(method, args) abort
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index 1fb06e169c..c240f08a75 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -404,6 +404,9 @@ Mapping <kHome> will not work then.
Note: If numlock is on, the |TUI| receives plain ASCII values, so
mappings to <k0> - <k9> and <kPoint> will not work.
+Note: Nvim supports mapping multibyte chars with modifiers such as `<M-Γ€>`.
+Which combinations actually are usable depends on the terminal emulator or GUI.
+
*<>*
Examples are often given in the <> notation. Sometimes this is just to make
clear what you need to type, but often it can be typed literally, e.g., with
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index 1440e2ac78..7d213f959b 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -292,6 +292,8 @@ numerical highlight ids to the actual attributes.
`bold`: bold text.
`underline`: underlined text. The line has `special` color.
`undercurl`: undercurled text. The curl has `special` color.
+ `blend`: Blend level (0-100). Could be used by UIs to support
+ blending floating windows to the background.
For absent color keys the default color should be used. Don't store
the default value in the table, rather a sentinel value, so that
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 0fc7c780ca..06957dd77d 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -381,9 +381,14 @@ if(WIN32)
list(APPEND NVIM_LINK_LIBRARIES ${WINPTY_LIBRARIES})
endif()
+# Use "luv" as imported library, to work around CMake using "-lluv" for
+# "luv.so". #10407
+add_library(luv UNKNOWN IMPORTED)
+set_property(TARGET luv PROPERTY IMPORTED_LOCATION ${LIBLUV_LIBRARIES})
+
# Put these last on the link line, since multiple things may depend on them.
list(APPEND NVIM_LINK_LIBRARIES
- ${LIBLUV_LIBRARIES}
+ luv
${LIBUV_LIBRARIES}
${MSGPACK_LIBRARIES}
${LIBVTERM_LIBRARIES}
@@ -401,6 +406,7 @@ endif()
set(NVIM_EXEC_LINK_LIBRARIES ${NVIM_LINK_LIBRARIES} ${LUA_PREFERRED_LIBRARIES})
+# Add IPO flags (for LTO), or error if CMake does not know the flags. #8654
if(POLICY CMP0069)
cmake_policy(SET CMP0069 NEW)
endif()
@@ -546,19 +552,19 @@ if(CLANG_ASAN_UBSAN)
else()
set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
endif()
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/src/.asan-blacklist")
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_DEFINITIONS EXITFREE)
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_OPTIONS ${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/src/.asan-blacklist)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ")
elseif(CLANG_MSAN)
message(STATUS "Enabling Clang memory sanitizer for nvim.")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -fno-optimize-sibling-calls ")
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_DEFINITIONS EXITFREE)
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_OPTIONS -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -fno-optimize-sibling-calls)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=memory -fsanitize-memory-track-origins ")
elseif(CLANG_TSAN)
message(STATUS "Enabling Clang thread sanitizer for nvim.")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fsanitize=thread ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fPIE ")
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_DEFINITIONS EXITFREE)
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_OPTIONS -fsanitize=thread)
+ set_property(TARGET nvim APPEND PROPERTY COMPILE_OPTIONS -fPIE)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ")
endif()
diff --git a/src/nvim/README.md b/src/nvim/README.md
index 3c956cb2e9..35ca2944e9 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -44,28 +44,30 @@ Behavior Sanitizer: UBSan, Memory Sanitizer: MSan, Thread Sanitizer: TSan) is
a good way to catch undefined behavior, leaks and other errors as soon as they
happen. It's significantly faster than Valgrind.
-Requires clang 3.4 or later:
+Requires clang 3.4 or later, and `llvm-symbolizer` must be in `$PATH`:
clang --version
-Build Nvim with sanitizer instrumentation:
+Build Nvim with sanitizer instrumentation (choose one):
CC=clang make CMAKE_EXTRA_FLAGS="-DCLANG_ASAN_UBSAN=ON"
+ CC=clang make CMAKE_EXTRA_FLAGS="-DCLANG_MSAN=ON"
+ CC=clang make CMAKE_EXTRA_FLAGS="-DCLANG_TSAN=ON"
Create a directory to store logs:
mkdir -p "$HOME/logs"
-Enable the sanitizer(s) via these environment variables:
+Configure the sanitizer(s) via these environment variables:
# Change to detect_leaks=1 to detect memory leaks (slower).
export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
- export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
+ export MSAN_OPTIONS="log_path=${HOME}/logs/tsan"
+ export TSAN_OPTIONS="log_path=${HOME}/logs/tsan"
- export MSAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
- export TSAN_OPTIONS="external_symbolizer_path=/usr/lib/llvm-5.0/bin/llvm-symbolizer log_path=${HOME}/logs/tsan"
+Logs will be written to `${HOME}/logs/*san.PID` then.
-Logs will be written to `${HOME}/logs/*san.PID`.
+For more information: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags
TUI debugging
-------------
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 41bf0af65b..9f58257e53 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -100,7 +100,7 @@ void raw_line(Integer grid, Integer row, Integer startcol,
void event(char *name, Array args, bool *args_consumed)
FUNC_API_NOEXPORT;
-void win_pos(Integer grid, Integer win, Integer startrow,
+void win_pos(Integer grid, Window win, Integer startrow,
Integer startcol, Integer width, Integer height)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void win_float_pos(Integer grid, Window win, String anchor, Integer anchor_grid,
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index ed6a28bcda..d027eca59a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -364,7 +364,7 @@ String nvim_command_output(String command, Error *err)
};
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
- memmove(s.data, s.data + 1, s.size);
+ memmove(s.data, s.data + 1, s.size - 1);
s.data[s.size - 1] = '\0';
s.size = s.size - 1;
}
@@ -1071,10 +1071,10 @@ fail:
/// disabled. This is useful when displaing a temporary
/// float where the text should not be edited. Disables
/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn',
-/// 'spell' and 'list' options. 'signcolumn' is changed to
-/// `auto`. The end-of-buffer region is hidden by setting
-/// `eob` flag of 'fillchars' to a space char, and clearing
-/// the |EndOfBuffer| region in 'winhighlight'.
+/// 'foldcolumn', 'spell' and 'list' options. 'signcolumn'
+/// is changed to `auto`. The end-of-buffer region is hidden
+/// by setting `eob` flag of 'fillchars' to a space char,
+/// and clearing the |EndOfBuffer| region in 'winhighlight'.
///
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 9060a0de82..1dec0beeee 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1900,7 +1900,8 @@ void backslash_halve(char_u *p)
/// @param p
///
/// @return String with the number of backslashes halved.
-char_u* backslash_halve_save(char_u *p)
+char_u *backslash_halve_save(const char_u *p)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
// TODO(philix): simplify and improve backslash_halve_save algorithm
char_u *res = vim_strsave(p);
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 2ac429cf9e..b53f9d0aa9 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -141,19 +141,13 @@ struct compl_S {
compl_T *cp_next;
compl_T *cp_prev;
char_u *cp_str; // matched text
- char cp_icase; // TRUE or FALSE: ignore case
- char cp_equal; // TRUE or FALSE: ins_compl_equal always ok
char_u *(cp_text[CPT_COUNT]); // text for the menu
char_u *cp_fname; // file containing the match, allocated when
- // cp_flags has FREE_FNAME
- int cp_flags; // ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME
+ // cp_flags has CP_FREE_FNAME
+ int cp_flags; // CP_ values
int cp_number; // sequence number
};
-// flags for ins_compl_add()
-#define ORIGINAL_TEXT (1) // the original text when the expansion begun
-#define FREE_FNAME (2)
-
/*
* All the current matches are stored in a list.
* "compl_first_match" points to the start of the list.
@@ -182,18 +176,18 @@ static int compl_no_insert = FALSE; /* FALSE: select & insert
static int compl_no_select = FALSE; /* FALSE: select & insert
TRUE: noselect */
-static int compl_used_match; // Selected one of the matches. When
- // FALSE the match was edited or using
- // the longest common string.
+static bool compl_used_match; // Selected one of the matches.
+ // When false the match was edited or using
+ // the longest common string.
static int compl_was_interrupted = FALSE; /* didn't finish finding
completions. */
static int compl_restarting = FALSE; /* don't insert match */
-/* When the first completion is done "compl_started" is set. When it's
- * FALSE the word to be completed must be located. */
-static int compl_started = FALSE;
+// When the first completion is done "compl_started" is set. When it's
+// false the word to be completed must be located.
+static bool compl_started = false;
// Which Ctrl-X mode are we in?
static int ctrl_x_mode = CTRL_X_NORMAL;
@@ -2062,21 +2056,24 @@ static bool ins_compl_accept_char(int c)
return vim_iswordc(c);
}
-// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
-// case of the originally typed text is used, and the case of the completed
-// text is inferred, ie this tries to work out what case you probably wanted
-// the rest of the word to be in -- webb
-int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname,
- int dir, int flags)
+/// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
+/// case of the originally typed text is used, and the case of the completed
+/// text is inferred, ie this tries to work out what case you probably wanted
+/// the rest of the word to be in -- webb
+///
+/// @param[in] cont_s_ipos next ^X<> will set initial_pos
+int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
+ int dir, bool cont_s_ipos)
+ FUNC_ATTR_NONNULL_ARG(1)
{
char_u *str = str_arg;
int i, c;
int actual_len; /* Take multi-byte characters */
int actual_compl_length; /* into account. */
int min_len;
- int *wca; /* Wide character array. */
- int has_lower = FALSE;
- int was_letter = FALSE;
+ bool has_lower = false;
+ bool was_letter = false;
+ int flags = 0;
if (p_ic && curbuf->b_p_inf && len > 0) {
// Infer case of completed part.
@@ -2108,8 +2105,8 @@ int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname,
min_len = actual_len < actual_compl_length
? actual_len : actual_compl_length;
- /* Allocate wide character array for the completion and fill it. */
- wca = xmalloc(actual_len * sizeof(*wca));
+ // Allocate wide character array for the completion and fill it.
+ int *const wca = xmalloc(actual_len * sizeof(*wca));
{
const char_u *p = str;
for (i = 0; i < actual_len; i++) {
@@ -2200,15 +2197,20 @@ int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname,
str = IObuff;
}
- return ins_compl_add(str, len, icase, fname, NULL, false, dir, flags,
- false, false);
+ if (cont_s_ipos) {
+ flags |= CP_CONT_S_IPOS;
+ }
+ if (icase) {
+ flags |= CP_ICASE;
+ }
+
+ return ins_compl_add(str, len, fname, NULL, false, dir, flags, false);
}
/// Add a match to the list of matches
///
/// @param[in] str Match to add.
/// @param[in] len Match length, -1 to use #STRLEN.
-/// @param[in] icase Whether case is to be ignored.
/// @param[in] fname File name match comes from. May be NULL.
/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
/// must have exactly #CPT_COUNT items.
@@ -2218,21 +2220,20 @@ int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname,
/// cptext itself will not be freed.
/// @param[in] cdir Completion direction.
/// @param[in] adup True if duplicate matches are to be accepted.
-/// @param[in] equal Match is always accepted by ins_compl_equal.
///
/// @return NOTDONE if the given string is already in the list of completions,
/// otherwise it is added to the list and OK is returned. FAIL will be
/// returned in case of error.
static int ins_compl_add(char_u *const str, int len,
- const bool icase, char_u *const fname,
+ char_u *const fname,
char_u *const *const cptext,
const bool cptext_allocated,
- const Direction cdir, int flags, const bool adup,
- int equal)
+ const Direction cdir, int flags_arg, const bool adup)
FUNC_ATTR_NONNULL_ARG(1)
{
compl_T *match;
int dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
+ int flags = flags_arg;
os_breakcheck();
#define FREE_CPTEXT(cptext, cptext_allocated) \
@@ -2257,7 +2258,7 @@ static int ins_compl_add(char_u *const str, int len,
if (compl_first_match != NULL && !adup) {
match = compl_first_match;
do {
- if (!(match->cp_flags & ORIGINAL_TEXT)
+ if (!(match->cp_flags & CP_ORIGINAL_TEXT)
&& STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL) {
FREE_CPTEXT(cptext, cptext_allocated);
@@ -2276,24 +2277,23 @@ static int ins_compl_add(char_u *const str, int len,
*/
match = xcalloc(1, sizeof(compl_T));
match->cp_number = -1;
- if (flags & ORIGINAL_TEXT)
+ if (flags & CP_ORIGINAL_TEXT) {
match->cp_number = 0;
+ }
match->cp_str = vim_strnsave(str, len);
- match->cp_icase = icase;
- match->cp_equal = equal;
- /* match-fname is:
- * - compl_curr_match->cp_fname if it is a string equal to fname.
- * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
- * - NULL otherwise. --Acevedo */
+ // match-fname is:
+ // - compl_curr_match->cp_fname if it is a string equal to fname.
+ // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem.
+ // - NULL otherwise. --Acevedo
if (fname != NULL
&& compl_curr_match != NULL
&& compl_curr_match->cp_fname != NULL
- && STRCMP(fname, compl_curr_match->cp_fname) == 0)
+ && STRCMP(fname, compl_curr_match->cp_fname) == 0) {
match->cp_fname = compl_curr_match->cp_fname;
- else if (fname != NULL) {
+ } else if (fname != NULL) {
match->cp_fname = vim_strsave(fname);
- flags |= FREE_FNAME;
+ flags |= CP_FREE_FNAME;
} else {
match->cp_fname = NULL;
}
@@ -2339,14 +2339,15 @@ static int ins_compl_add(char_u *const str, int len,
/*
* Find the longest common string if still doing that.
*/
- if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
+ if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0) {
ins_compl_longest_match(match);
+ }
return OK;
}
/// Check that "str[len]" matches with "match->cp_str", considering
-/// "match->cp_icase".
+/// "match->cp_flags".
///
/// @param match completion match
/// @param str character string to check
@@ -2354,10 +2355,10 @@ static int ins_compl_add(char_u *const str, int len,
static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- if (match->cp_equal) {
+ if (match->cp_flags & CP_EQUAL) {
return true;
}
- if (match->cp_icase) {
+ if (match->cp_flags & CP_ICASE) {
return STRNICMP(match->cp_str, str, len) == 0;
}
return STRNCMP(match->cp_str, str, len) == 0;
@@ -2384,7 +2385,7 @@ static void ins_compl_longest_match(compl_T *match)
* again after redrawing. */
if (!had_match)
ins_compl_delete();
- compl_used_match = FALSE;
+ compl_used_match = false;
} else {
/* Reduce the text if this match differs from compl_leader. */
p = compl_leader;
@@ -2393,7 +2394,9 @@ static void ins_compl_longest_match(compl_T *match)
c1 = utf_ptr2char(p);
c2 = utf_ptr2char(s);
- if (match->cp_icase ? (mb_tolower(c1) != mb_tolower(c2)) : (c1 != c2)) {
+ if ((match->cp_flags & CP_ICASE)
+ ? (mb_tolower(c1) != mb_tolower(c2))
+ : (c1 != c2)) {
break;
}
MB_PTR_ADV(p);
@@ -2414,7 +2417,7 @@ static void ins_compl_longest_match(compl_T *match)
ins_compl_delete();
}
- compl_used_match = FALSE;
+ compl_used_match = false;
}
}
@@ -2423,18 +2426,18 @@ static void ins_compl_longest_match(compl_T *match)
* Frees matches[].
*/
static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
+ FUNC_ATTR_NONNULL_ALL
{
- int i;
int add_r = OK;
int dir = compl_direction;
- for (i = 0; i < num_matches && add_r != FAIL; i++)
- if ((add_r = ins_compl_add(matches[i], -1, icase,
- NULL, NULL, false, dir, 0, false,
- false)) == OK) {
+ for (int i = 0; i < num_matches && add_r != FAIL; i++) {
+ if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, dir,
+ icase ? CP_ICASE : 0, false)) == OK) {
// If dir was BACKWARD then honor it just once.
dir = FORWARD;
}
+ }
FreeWild(num_matches, matches);
}
@@ -2484,6 +2487,8 @@ void completeopt_was_set(void)
*/
void set_completion(colnr_T startcol, list_T *list)
{
+ int flags = CP_ORIGINAL_TEXT;
+
// If already doing completions stop it.
if (ctrl_x_mode != CTRL_X_NORMAL) {
ins_compl_prep(' ');
@@ -2499,8 +2504,11 @@ void set_completion(colnr_T startcol, list_T *list)
/* compl_pattern doesn't need to be set */
compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
compl_length);
- if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
- ORIGINAL_TEXT, false, false) != OK) {
+ if (p_ic) {
+ flags |= CP_ICASE;
+ }
+ if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
+ flags, false) != OK) {
return;
}
@@ -2508,8 +2516,8 @@ void set_completion(colnr_T startcol, list_T *list)
ins_compl_add_list(list);
compl_matches = ins_compl_make_cyclic();
- compl_started = TRUE;
- compl_used_match = TRUE;
+ compl_started = true;
+ compl_used_match = true;
compl_cont_status = 0;
int save_w_wrow = curwin->w_wrow;
int save_w_leftcol = curwin->w_leftcol;
@@ -2569,7 +2577,8 @@ static bool pum_enough_matches(void)
compl_T *comp = compl_first_match;
int i = 0;
do {
- if (comp == NULL || ((comp->cp_flags & ORIGINAL_TEXT) == 0 && ++i == 2)) {
+ if (comp == NULL
+ || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) {
break;
}
comp = comp->cp_next;
@@ -2614,8 +2623,8 @@ void ins_compl_show_pum(void)
{
compl_T *compl;
compl_T *shown_compl = NULL;
- int did_find_shown_match = FALSE;
- int shown_match_ok = FALSE;
+ bool did_find_shown_match = false;
+ bool shown_match_ok = false;
int i;
int cur = -1;
colnr_T col;
@@ -2647,7 +2656,7 @@ void ins_compl_show_pum(void)
lead_len = (int)STRLEN(compl_leader);
}
do {
- if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
&& (compl_leader == NULL
|| ins_compl_equal(compl, compl_leader, lead_len))) {
compl_match_arraysize++;
@@ -2661,13 +2670,14 @@ void ins_compl_show_pum(void)
compl_match_array = xcalloc(compl_match_arraysize, sizeof(pumitem_T));
/* If the current match is the original text don't find the first
* match after it, don't highlight anything. */
- if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
- shown_match_ok = TRUE;
+ if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
+ shown_match_ok = true;
+ }
i = 0;
compl = compl_first_match;
do {
- if ((compl->cp_flags & ORIGINAL_TEXT) == 0
+ if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
&& (compl_leader == NULL
|| ins_compl_equal(compl, compl_leader, lead_len))) {
if (!shown_match_ok) {
@@ -2675,12 +2685,13 @@ void ins_compl_show_pum(void)
/* This item is the shown match or this is the
* first displayed item after the shown match. */
compl_shown_match = compl;
- did_find_shown_match = TRUE;
- shown_match_ok = TRUE;
- } else
- /* Remember this displayed match for when the
- * shown match is just below it. */
+ did_find_shown_match = true;
+ shown_match_ok = true;
+ } else {
+ // Remember this displayed match for when the
+ // shown match is just below it.
shown_compl = compl;
+ }
cur = i;
}
@@ -2699,18 +2710,19 @@ void ins_compl_show_pum(void)
}
if (compl == compl_shown_match) {
- did_find_shown_match = TRUE;
+ did_find_shown_match = true;
/* When the original text is the shown match don't set
* compl_shown_match. */
- if (compl->cp_flags & ORIGINAL_TEXT)
- shown_match_ok = TRUE;
+ if (compl->cp_flags & CP_ORIGINAL_TEXT) {
+ shown_match_ok = true;
+ }
if (!shown_match_ok && shown_compl != NULL) {
/* The shown match isn't displayed, set it to the
* previously displayed match. */
compl_shown_match = shown_compl;
- shown_match_ok = TRUE;
+ shown_match_ok = true;
}
}
compl = compl->cp_next;
@@ -2882,8 +2894,8 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
ptr = find_word_end(ptr);
}
add_r = ins_compl_add_infercase(regmatch->startp[0],
- (int)(ptr - regmatch->startp[0]),
- p_ic, files[i], *dir, 0);
+ (int)(ptr - regmatch->startp[0]),
+ p_ic, files[i], *dir, false);
if (thesaurus) {
char_u *wstart;
@@ -2914,11 +2926,11 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
else
ptr = find_word_end(ptr);
- /* Add the word. Skip the regexp match. */
- if (wstart != regmatch->startp[0])
- add_r = ins_compl_add_infercase(wstart,
- (int)(ptr - wstart),
- p_ic, files[i], *dir, 0);
+ // Add the word. Skip the regexp match.
+ if (wstart != regmatch->startp[0]) {
+ add_r = ins_compl_add_infercase(wstart, (int)(ptr - wstart),
+ p_ic, files[i], *dir, false);
+ }
}
}
if (add_r == OK)
@@ -2995,7 +3007,6 @@ static char_u *find_line_end(char_u *ptr)
static void ins_compl_free(void)
{
compl_T *match;
- int i;
XFREE_CLEAR(compl_pattern);
XFREE_CLEAR(compl_leader);
@@ -3011,11 +3022,13 @@ static void ins_compl_free(void)
match = compl_curr_match;
compl_curr_match = compl_curr_match->cp_next;
xfree(match->cp_str);
- /* several entries may use the same fname, free it just once. */
- if (match->cp_flags & FREE_FNAME)
+ // several entries may use the same fname, free it just once.
+ if (match->cp_flags & CP_FREE_FNAME) {
xfree(match->cp_fname);
- for (i = 0; i < CPT_COUNT; ++i)
+ }
+ for (int i = 0; i < CPT_COUNT; i++) {
xfree(match->cp_text[i]);
+ }
xfree(match);
} while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
compl_first_match = compl_curr_match = NULL;
@@ -3026,7 +3039,7 @@ static void ins_compl_free(void)
static void ins_compl_clear(void)
{
compl_cont_status = 0;
- compl_started = FALSE;
+ compl_started = false;
compl_matches = 0;
XFREE_CLEAR(compl_pattern);
XFREE_CLEAR(compl_leader);
@@ -3095,7 +3108,7 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
if (ret == OK && compl_first_match != NULL) {
compl_T *match = compl_first_match;
do {
- if (!(match->cp_flags & ORIGINAL_TEXT)) {
+ if (!(match->cp_flags & CP_ORIGINAL_TEXT)) {
dict_T *di = tv_dict_alloc();
tv_list_append_dict(li, di);
@@ -3202,7 +3215,7 @@ static void ins_compl_new_leader(void)
ins_compl_del_pum();
ins_compl_delete();
ins_bytes(compl_leader + ins_compl_len());
- compl_used_match = FALSE;
+ compl_used_match = false;
if (compl_started) {
ins_compl_set_original_text(compl_leader);
@@ -3283,7 +3296,7 @@ static void ins_compl_restart(void)
* will stay to the last popup menu and reduce flicker */
update_screen(0);
ins_compl_free();
- compl_started = FALSE;
+ compl_started = false;
compl_matches = 0;
compl_cont_status = 0;
compl_cont_mode = 0;
@@ -3293,15 +3306,16 @@ static void ins_compl_restart(void)
* Set the first match, the original text.
*/
static void ins_compl_set_original_text(char_u *str)
+ FUNC_ATTR_NONNULL_ALL
{
// Replace the original text entry.
- // The ORIGINAL_TEXT flag is either at the first item or might possibly be
+ // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly be
// at the last item for backward completion
- if (compl_first_match->cp_flags & ORIGINAL_TEXT) { // safety check
+ if (compl_first_match->cp_flags & CP_ORIGINAL_TEXT) { // safety check
xfree(compl_first_match->cp_str);
compl_first_match->cp_str = vim_strsave(str);
} else if (compl_first_match->cp_prev != NULL
- && (compl_first_match->cp_prev->cp_flags & ORIGINAL_TEXT)) {
+ && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) {
xfree(compl_first_match->cp_prev->cp_str);
compl_first_match->cp_prev->cp_str = vim_strsave(str);
}
@@ -3322,7 +3336,7 @@ static void ins_compl_addfrommatch(void)
if ((int)STRLEN(p) <= len) { /* the match is too short */
/* When still at the original match use the first entry that matches
* the leader. */
- if (compl_shown_match->cp_flags & ORIGINAL_TEXT) {
+ if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
p = NULL;
for (cp = compl_shown_match->cp_next; cp != NULL
&& cp != compl_first_match; cp = cp->cp_next) {
@@ -3371,8 +3385,7 @@ static bool ins_compl_prep(int c)
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
|| (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
- compl_used_match = TRUE;
-
+ compl_used_match = true;
}
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) {
@@ -3563,7 +3576,7 @@ static bool ins_compl_prep(int c)
auto_format(FALSE, TRUE);
ins_compl_free();
- compl_started = FALSE;
+ compl_started = false;
compl_matches = 0;
if (!shortmess(SHM_COMPLETIONMENU)) {
msg_clr_cmdline(); // necessary for "noshowmode"
@@ -3672,28 +3685,28 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
}
-/*
- * Execute user defined complete function 'completefunc' or 'omnifunc', and
- * get matches in "matches".
- */
+// Execute user defined complete function 'completefunc' or 'omnifunc', and
+// get matches in "matches".
static void
-expand_by_function (
- int type, /* CTRL_X_OMNI or CTRL_X_FUNCTION */
+expand_by_function(
+ int type, // CTRL_X_OMNI or CTRL_X_FUNCTION
char_u *base
)
{
- list_T *matchlist = NULL;
- dict_T *matchdict = NULL;
- char_u *funcname;
+ list_T *matchlist = NULL;
+ dict_T *matchdict = NULL;
+ char_u *funcname;
pos_T pos;
- win_T *curwin_save;
- buf_T *curbuf_save;
+ win_T *curwin_save;
+ buf_T *curbuf_save;
typval_T rettv;
const int save_State = State;
+ assert(curbuf != NULL);
funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
- if (*funcname == NUL)
+ if (*funcname == NUL) {
return;
+ }
// Call 'completefunc' to obtain the list of matches.
typval_T args[3];
@@ -3807,10 +3820,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
FUNC_ATTR_NONNULL_ALL
{
const char *word;
- bool icase = false;
- bool adup = false;
- bool aempty = false;
- bool aequal = false;
+ bool dup = false;
+ bool empty = false;
+ int flags = 0;
char *(cptext[CPT_COUNT]);
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
@@ -3822,46 +3834,47 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict,
"user_data", true);
- icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
- adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
- aempty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
- if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL) {
- aequal = tv_dict_get_number(tv->vval.v_dict, "equal");
+ if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
+ flags |= CP_ICASE;
+ }
+ dup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
+ empty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
+ if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL
+ && tv_dict_get_number(tv->vval.v_dict, "equal")) {
+ flags |= CP_EQUAL;
}
} else {
word = (const char *)tv_get_string_chk(tv);
memset(cptext, 0, sizeof(cptext));
}
- if (word == NULL || (!aempty && *word == NUL)) {
+ if (word == NULL || (!empty && *word == NUL)) {
for (size_t i = 0; i < CPT_COUNT; i++) {
xfree(cptext[i]);
}
return FAIL;
}
- return ins_compl_add((char_u *)word, -1, icase, NULL,
- (char_u **)cptext, true, dir, 0, adup, aequal);
+ return ins_compl_add((char_u *)word, -1, NULL,
+ (char_u **)cptext, true, dir, flags, dup);
}
-/*
- * Get the next expansion(s), using "compl_pattern".
- * The search starts at position "ini" in curbuf and in the direction
- * compl_direction.
- * When "compl_started" is FALSE start at that position, otherwise continue
- * where we stopped searching before.
- * This may return before finding all the matches.
- * Return the total number of matches or -1 if still unknown -- Acevedo
- */
+// Get the next expansion(s), using "compl_pattern".
+// The search starts at position "ini" in curbuf and in the direction
+// compl_direction.
+// When "compl_started" is false start at that position, otherwise continue
+// where we stopped searching before.
+// This may return before finding all the matches.
+// Return the total number of matches or -1 if still unknown -- Acevedo
static int ins_compl_get_exp(pos_T *ini)
{
static pos_T first_match_pos;
static pos_T last_match_pos;
- static char_u *e_cpt = (char_u *)""; /* curr. entry in 'complete' */
- static int found_all = FALSE; /* Found all matches of a
- certain type. */
- static buf_T *ins_buf = NULL; /* buffer being scanned */
+ static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
+ static int found_all = false; // Found all matches of a
+ // certain type.
+ static buf_T *ins_buf = NULL; // buffer being scanned
- pos_T *pos;
- char_u **matches;
+ pos_T *pos;
+ char_u **matches;
int save_p_scs;
bool save_p_ws;
int save_p_ic;
@@ -3870,12 +3883,14 @@ static int ins_compl_get_exp(pos_T *ini)
int len;
int found_new_match;
int type = ctrl_x_mode;
- char_u *ptr;
- char_u *dict = NULL;
+ char_u *ptr;
+ char_u *dict = NULL;
int dict_f = 0;
int set_match_pos;
int l_ctrl_x_mode = ctrl_x_mode;
+ assert(curbuf != NULL);
+
if (!compl_started) {
FOR_ALL_BUFFERS(buf) {
buf->b_scanned = false;
@@ -3899,9 +3914,9 @@ static int ins_compl_get_exp(pos_T *ini)
assert(l_ctrl_x_mode == ctrl_x_mode);
- /* For ^N/^P pick a new entry from e_cpt if compl_started is off,
- * or if found_all says this entry is done. For ^X^L only use the
- * entries from 'complete' that look in loaded buffers. */
+ // For ^N/^P pick a new entry from e_cpt if compl_started is off,
+ // or if found_all says this entry is done. For ^X^L only use the
+ // entries from 'complete' that look in loaded buffers.
if ((l_ctrl_x_mode == CTRL_X_NORMAL
|| CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
&& (!compl_started || found_all)) {
@@ -3923,23 +3938,24 @@ static int ins_compl_get_exp(pos_T *ini)
last_match_pos = first_match_pos;
type = 0;
- /* Remember the first match so that the loop stops when we
- * wrap and come back there a second time. */
- set_match_pos = TRUE;
+ // Remember the first match so that the loop stops when we
+ // wrap and come back there a second time.
+ set_match_pos = true;
} else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
&& (ins_buf =
- ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
- /* Scan a buffer, but not the current one. */
- if (ins_buf->b_ml.ml_mfp != NULL) { /* loaded buffer */
- compl_started = TRUE;
+ ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
+ // Scan a buffer, but not the current one.
+ if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
+ compl_started = true;
first_match_pos.col = last_match_pos.col = 0;
first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
last_match_pos.lnum = 0;
type = 0;
- } else { /* unloaded buffer, scan like dictionary */
- found_all = TRUE;
- if (ins_buf->b_fname == NULL)
+ } else { // unloaded buffer, scan like dictionary
+ found_all = true;
+ if (ins_buf->b_fname == NULL) {
continue;
+ }
type = CTRL_X_DICTIONARY;
dict = ins_buf->b_fname;
dict_f = DICT_EXACT;
@@ -3977,7 +3993,7 @@ static int ins_compl_get_exp(pos_T *ini)
type = -1;
}
- /* in any case e_cpt is advanced to the next entry */
+ // in any case e_cpt is advanced to the next entry
(void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
found_all = TRUE;
@@ -4024,12 +4040,12 @@ static int ins_compl_get_exp(pos_T *ini)
break;
case CTRL_X_TAGS:
- /* set p_ic according to p_ic, p_scs and pat for find_tags(). */
+ // set p_ic according to p_ic, p_scs and pat for find_tags().
save_p_ic = p_ic;
p_ic = ignorecase(compl_pattern);
- /* Find up to TAG_MANY matches. Avoids that an enormous number
- * of matches is found when compl_pattern is empty */
+ // Find up to TAG_MANY matches. Avoids that an enormous number
+ // of matches is found when compl_pattern is empty
if (find_tags(compl_pattern, &num_matches, &matches,
TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
| (l_ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0),
@@ -4041,9 +4057,8 @@ static int ins_compl_get_exp(pos_T *ini)
case CTRL_X_FILES:
if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
- EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
-
- /* May change home directory back to "~". */
+ EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
+ // May change home directory back to "~".
tilde_replace(compl_pattern, num_matches, matches);
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
}
@@ -4068,29 +4083,26 @@ static int ins_compl_get_exp(pos_T *ini)
ins_compl_add_matches(num_matches, matches, p_ic);
break;
- default: /* normal ^P/^N and ^X^L */
- /*
- * If 'infercase' is set, don't use 'smartcase' here
- */
+ default: // normal ^P/^N and ^X^L
+ // If 'infercase' is set, don't use 'smartcase' here
save_p_scs = p_scs;
assert(ins_buf);
if (ins_buf->b_p_inf)
p_scs = FALSE;
- /* Buffers other than curbuf are scanned from the beginning or the
- * end but never from the middle, thus setting nowrapscan in this
- * buffers is a good idea, on the other hand, we always set
- * wrapscan for curbuf to avoid missing matches -- Acevedo,Webb */
+ // Buffers other than curbuf are scanned from the beginning or the
+ // end but never from the middle, thus setting nowrapscan in this
+ // buffers is a good idea, on the other hand, we always set
+ // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
save_p_ws = p_ws;
if (ins_buf != curbuf)
p_ws = false;
else if (*e_cpt == '.')
p_ws = true;
for (;; ) {
- int flags = 0;
-
- ++msg_silent; /* Don't want messages for wrapscan. */
+ bool cont_s_ipos = false;
+ msg_silent++; // Don't want messages for wrapscan.
// CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode) || word-wise search that
// has added a word that was at the beginning of the line.
if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)
@@ -4107,47 +4119,52 @@ static int ins_compl_get_exp(pos_T *ini)
}
msg_silent--;
if (!compl_started || set_match_pos) {
- /* set "compl_started" even on fail */
- compl_started = TRUE;
+ // set "compl_started" even on fail
+ compl_started = true;
first_match_pos = *pos;
last_match_pos = *pos;
- set_match_pos = FALSE;
+ set_match_pos = false;
} else if (first_match_pos.lnum == last_match_pos.lnum
- && first_match_pos.col == last_match_pos.col)
+ && first_match_pos.col == last_match_pos.col) {
found_new_match = FAIL;
+ }
if (found_new_match == FAIL) {
if (ins_buf == curbuf)
found_all = TRUE;
break;
}
- /* when ADDING, the text before the cursor matches, skip it */
- if ( (compl_cont_status & CONT_ADDING) && ins_buf == curbuf
- && ini->lnum == pos->lnum
- && ini->col == pos->col)
+ // when ADDING, the text before the cursor matches, skip it
+ if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
+ && ini->lnum == pos->lnum
+ && ini->col == pos->col) {
continue;
- ptr = ml_get_buf(ins_buf, pos->lnum, FALSE) + pos->col;
+ }
+ ptr = ml_get_buf(ins_buf, pos->lnum, false) + pos->col;
if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
if (compl_cont_status & CONT_ADDING) {
- if (pos->lnum >= ins_buf->b_ml.ml_line_count)
+ if (pos->lnum >= ins_buf->b_ml.ml_line_count) {
continue;
- ptr = ml_get_buf(ins_buf, pos->lnum + 1, FALSE);
- if (!p_paste)
+ }
+ ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
+ if (!p_paste) {
ptr = skipwhite(ptr);
+ }
}
len = (int)STRLEN(ptr);
} else {
- char_u *tmp_ptr = ptr;
+ char_u *tmp_ptr = ptr;
if (compl_cont_status & CONT_ADDING) {
tmp_ptr += compl_length;
- /* Skip if already inside a word. */
- if (vim_iswordp(tmp_ptr))
+ // Skip if already inside a word.
+ if (vim_iswordp(tmp_ptr)) {
continue;
- /* Find start of next word. */
+ }
+ // Find start of next word.
tmp_ptr = find_word_start(tmp_ptr);
}
- /* Find end of this word. */
+ // Find end of this word.
tmp_ptr = find_word_end(tmp_ptr);
len = (int)(tmp_ptr - ptr);
@@ -4160,15 +4177,16 @@ static int ins_compl_get_exp(pos_T *ini)
STRNCPY(IObuff, ptr, len);
ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
tmp_ptr = ptr = skipwhite(ptr);
- /* Find start of next word. */
+ // Find start of next word.
tmp_ptr = find_word_start(tmp_ptr);
- /* Find end of next word. */
+ // Find end of next word.
tmp_ptr = find_word_end(tmp_ptr);
if (tmp_ptr > ptr) {
if (*ptr != ')' && IObuff[len - 1] != TAB) {
- if (IObuff[len - 1] != ' ')
+ if (IObuff[len - 1] != ' ') {
IObuff[len++] = ' ';
- /* IObuf =~ "\k.* ", thus len >= 2 */
+ }
+ // IObuf =~ "\k.* ", thus len >= 2
if (p_js
&& (IObuff[len - 2] == '.'
|| IObuff[len - 2] == '?'
@@ -4176,12 +4194,13 @@ static int ins_compl_get_exp(pos_T *ini)
IObuff[len++] = ' ';
}
}
- /* copy as much as possible of the new word */
- if (tmp_ptr - ptr >= IOSIZE - len)
+ // copy as much as possible of the new word
+ if (tmp_ptr - ptr >= IOSIZE - len) {
tmp_ptr = ptr + IOSIZE - len - 1;
- STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
+ }
+ STRLCPY(IObuff + len, ptr, IOSIZE - len);
len += (int)(tmp_ptr - ptr);
- flags |= CONT_S_IPOS;
+ cont_s_ipos = true;
}
IObuff[len] = NUL;
ptr = IObuff;
@@ -4190,9 +4209,9 @@ static int ins_compl_get_exp(pos_T *ini)
continue;
}
}
- if (ins_compl_add_infercase(ptr, len, p_ic,
- ins_buf == curbuf ? NULL : ins_buf->b_sfname,
- 0, flags) != NOTDONE) {
+ if (ins_compl_add_infercase(
+ ptr, len, p_ic, ins_buf == curbuf ? NULL : ins_buf->b_sfname,
+ 0, cont_s_ipos) != NOTDONE) {
found_new_match = OK;
break;
}
@@ -4214,27 +4233,28 @@ static int ins_compl_get_exp(pos_T *ini)
|| found_new_match != FAIL) {
if (got_int)
break;
- /* Fill the popup menu as soon as possible. */
- if (type != -1)
+ // Fill the popup menu as soon as possible.
+ if (type != -1) {
ins_compl_check_keys(0, false);
+ }
if ((l_ctrl_x_mode != CTRL_X_NORMAL
&& !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
|| compl_interrupted) {
break;
}
- compl_started = TRUE;
+ compl_started = true;
} else {
- /* Mark a buffer scanned when it has been scanned completely */
+ // Mark a buffer scanned when it has been scanned completely
if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
assert(ins_buf);
ins_buf->b_scanned = true;
}
- compl_started = FALSE;
+ compl_started = false;
}
}
- compl_started = TRUE;
+ compl_started = true;
if ((l_ctrl_x_mode == CTRL_X_NORMAL
|| CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
@@ -4242,7 +4262,7 @@ static int ins_compl_get_exp(pos_T *ini)
found_new_match = FAIL;
}
- i = -1; /* total of matches, unknown */
+ i = -1; // total of matches, unknown
if (found_new_match == FAIL
|| (l_ctrl_x_mode != CTRL_X_NORMAL
&& !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))) {
@@ -4263,7 +4283,7 @@ static int ins_compl_get_exp(pos_T *ini)
return i;
}
-/* Delete the old text being completed. */
+// Delete the old text being completed.
static void ins_compl_delete(void)
{
int col;
@@ -4290,10 +4310,7 @@ static void ins_compl_delete(void)
static void ins_compl_insert(int in_compl_func)
{
ins_bytes(compl_shown_match->cp_str + ins_compl_len());
- if (compl_shown_match->cp_flags & ORIGINAL_TEXT)
- compl_used_match = FALSE;
- else
- compl_used_match = TRUE;
+ compl_used_match = !(compl_shown_match->cp_flags & CP_ORIGINAL_TEXT);
dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
@@ -4358,7 +4375,7 @@ ins_compl_next (
compl_T *found_compl = NULL;
int found_end = FALSE;
int advance;
- int started = compl_started;
+ const bool started = compl_started;
/* When user complete function return -1 for findstart which is next
* time of 'always', compl_shown_match become NULL. */
@@ -4366,14 +4383,15 @@ ins_compl_next (
return -1;
if (compl_leader != NULL
- && (compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0) {
- /* Set "compl_shown_match" to the actually shown match, it may differ
- * when "compl_leader" is used to omit some of the matches. */
+ && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
+ // Set "compl_shown_match" to the actually shown match, it may differ
+ // when "compl_leader" is used to omit some of the matches.
while (!ins_compl_equal(compl_shown_match,
- compl_leader, (int)STRLEN(compl_leader))
+ compl_leader, STRLEN(compl_leader))
&& compl_shown_match->cp_next != NULL
- && compl_shown_match->cp_next != compl_first_match)
+ && compl_shown_match->cp_next != compl_first_match) {
compl_shown_match = compl_shown_match->cp_next;
+ }
/* If we didn't find it searching forward, and compl_shows_dir is
* backward, find the last match. */
@@ -4454,14 +4472,15 @@ ins_compl_next (
}
found_end = FALSE;
}
- if ((compl_shown_match->cp_flags & ORIGINAL_TEXT) == 0
+ if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
- compl_leader, (int)STRLEN(compl_leader)))
- ++todo;
- else
- /* Remember a matching item. */
+ compl_leader, STRLEN(compl_leader))) {
+ todo++;
+ } else {
+ // Remember a matching item.
found_compl = compl_shown_match;
+ }
/* Stop at the end of the list when we found a usable match. */
if (found_end) {
@@ -4476,7 +4495,7 @@ ins_compl_next (
/* Insert the text of the new completion, or the compl_leader. */
if (compl_no_insert && !started) {
ins_bytes(compl_orig_text + ins_compl_len());
- compl_used_match = FALSE;
+ compl_used_match = false;
} else if (insert_match) {
if (!compl_get_longest || compl_used_match) {
ins_compl_insert(in_compl_func);
@@ -4484,7 +4503,7 @@ ins_compl_next (
ins_bytes(compl_leader + ins_compl_len());
}
} else {
- compl_used_match = FALSE;
+ compl_used_match = false;
}
if (!allow_get_expansion) {
@@ -4692,6 +4711,7 @@ static int ins_complete(int c, bool enable_pum)
int save_w_leftcol;
int insert_match;
const bool save_did_ai = did_ai;
+ int flags = CP_ORIGINAL_TEXT;
compl_direction = ins_compl_key2dir(c);
insert_match = ins_compl_use_match(c);
@@ -5019,8 +5039,11 @@ static int ins_complete(int c, bool enable_pum)
/* Always add completion for the original text. */
xfree(compl_orig_text);
compl_orig_text = vim_strnsave(line + compl_col, compl_length);
- if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
- ORIGINAL_TEXT, false, false) != OK) {
+ if (p_ic) {
+ flags |= CP_ICASE;
+ }
+ if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
+ flags, false) != OK) {
XFREE_CLEAR(compl_pattern);
XFREE_CLEAR(compl_orig_text);
return FAIL;
@@ -5081,13 +5104,14 @@ static int ins_complete(int c, bool enable_pum)
}
}
- if (compl_curr_match->cp_flags & CONT_S_IPOS)
+ if (compl_curr_match->cp_flags & CP_CONT_S_IPOS) {
compl_cont_status |= CONT_S_IPOS;
- else
+ } else {
compl_cont_status &= ~CONT_S_IPOS;
+ }
if (edit_submode_extra == NULL) {
- if (compl_curr_match->cp_flags & ORIGINAL_TEXT) {
+ if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT) {
edit_submode_extra = (char_u *)_("Back at original");
edit_submode_highl = HLF_W;
} else if (compl_cont_status & CONT_S_IPOS) {
diff --git a/src/nvim/edit.h b/src/nvim/edit.h
index 433a941295..92dab37a70 100644
--- a/src/nvim/edit.h
+++ b/src/nvim/edit.h
@@ -13,6 +13,15 @@
#define CPT_USER_DATA 4 // "user data"
#define CPT_COUNT 5 // Number of entries
+// values for cp_flags
+typedef enum {
+ CP_ORIGINAL_TEXT = 1, // the original text when the expansion begun
+ CP_FREE_FNAME = 2, // cp_fname is allocated
+ CP_CONT_S_IPOS = 4, // use CONT_S_IPOS for compl_cont_status
+ CP_EQUAL = 8, // ins_compl_equal() always returns true
+ CP_ICASE = 16, // ins_compl_equal ignores case
+} cp_flags_T;
+
typedef int (*IndentGetter)(void);
/* Values for in_cinkeys() */
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 1d221bb600..8f6d6cd55e 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1989,7 +1989,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
}
}
if (p != NULL) {
- vim_setenv(name, p);
+ os_setenv(name, p, 1);
if (STRICMP(name, "HOME") == 0) {
init_homedir();
} else if (didset_vim && STRICMP(name, "VIM") == 0) {
@@ -2353,14 +2353,15 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
}
if (lp->ll_di == NULL) {
- /* Can't add "v:" variable. */
- if (lp->ll_dict == &vimvardict) {
+ // Can't add "v:" or "a:" variable.
+ if (lp->ll_dict == &vimvardict
+ || &lp->ll_dict->dv_hashtab == get_funccal_args_ht()) {
EMSG2(_(e_illvar), name);
tv_clear(&var1);
return NULL;
}
- /* Key does not exist in dict: may need to add it. */
+ // Key does not exist in dict: may need to add it.
if (*p == '[' || *p == '.' || unlet) {
if (!quiet) {
emsgf(_(e_dictkey), key);
@@ -13640,10 +13641,6 @@ static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_pyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (p_pyx == 0) {
- p_pyx = 2;
- }
-
script_host_eval("python", argvars, rettv);
}
@@ -13652,10 +13649,6 @@ static void f_pyeval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_py3eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (p_pyx == 0) {
- p_pyx = 3;
- }
-
script_host_eval("python3", argvars, rettv);
}
@@ -15359,7 +15352,7 @@ static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
&& argvars[1].vval.v_number == kSpecialVarNull) {
os_unsetenv(name);
} else {
- vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
+ os_setenv(name, tv_get_string_buf(&argvars[1], valbuf), 1);
}
}
@@ -20497,8 +20490,8 @@ static void set_var_const(const char *name, const size_t name_len,
}
tv_clear(&v->di_tv);
} else { // Add a new variable.
- // Can't add "v:" variable.
- if (ht == &vimvarht) {
+ // Can't add "v:" or "a:" variable.
+ if (ht == &vimvarht || ht == get_funccal_args_ht()) {
emsgf(_(e_illvar), name);
return;
}
@@ -22630,7 +22623,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
name = v->di_key;
STRCPY(name, "self");
#endif
- v->di_flags = DI_FLAGS_RO + DI_FLAGS_FIX;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
tv_dict_add(&fc->l_vars, v);
v->di_tv.v_type = VAR_DICT;
v->di_tv.v_lock = 0;
@@ -22646,6 +22639,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
init_var_dict(&fc->l_avars, &fc->l_avars_var, VAR_SCOPE);
add_nr_var(&fc->l_avars, (dictitem_T *)&fc->fixvar[fixvar_idx++], "0",
(varnumber_T)(argcount - fp->uf_args.ga_len));
+ fc->l_avars.dv_lock = VAR_FIXED;
// Use "name" to avoid a warning from some compiler that checks the
// destination size.
v = (dictitem_T *)&fc->fixvar[fixvar_idx++];
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 7c8014dead..d1a53fa4b6 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -97,6 +97,13 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data)
stream->close_cb = on_stream_close;
stream->close_cb_data = data;
+#ifdef WIN32
+ if (UV_TTY == uv_guess_handle(stream->fd)) {
+ // Undo UV_TTY_MODE_RAW from stream_init(). #10801
+ uv_tty_set_mode(&stream->uv.tty, UV_TTY_MODE_NORMAL);
+ }
+#endif
+
if (!stream->pending_reqs) {
stream_close_handle(stream);
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index e256351de2..a0fbde008b 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1392,9 +1392,6 @@ do_shell(
msg_row = Rows - 1;
msg_col = 0;
- // display any error messages now
- display_errors();
-
apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf);
}
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 7c28461f4c..df23d0630a 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2819,10 +2819,10 @@ void ex_packadd(exarg_T *eap)
/// ":options"
void ex_options(exarg_T *eap)
{
- vim_setenv("OPTWIN_CMD", cmdmod.tab ? "tab" : "");
- vim_setenv("OPTWIN_CMD",
- cmdmod.tab ? "tab" :
- (cmdmod.split & WSP_VERT) ? "vert" : "");
+ os_setenv("OPTWIN_CMD", cmdmod.tab ? "tab" : "", 1);
+ os_setenv("OPTWIN_CMD",
+ cmdmod.tab ? "tab" :
+ (cmdmod.split & WSP_VERT) ? "vert" : "", 1);
cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
}
@@ -2830,9 +2830,9 @@ void ex_options(exarg_T *eap)
void init_pyxversion(void)
{
if (p_pyx == 0) {
- if (!eval_has_provider("python3")) {
+ if (eval_has_provider("python3")) {
p_pyx = 3;
- } else if (!eval_has_provider("python")) {
+ } else if (eval_has_provider("python")) {
p_pyx = 2;
}
}
@@ -3927,19 +3927,19 @@ void ex_language(exarg_T *eap)
_nl_msg_cat_cntr++;
#endif
// Reset $LC_ALL, otherwise it would overrule everything.
- vim_setenv("LC_ALL", "");
+ os_setenv("LC_ALL", "", 1);
if (what != LC_TIME) {
// Tell gettext() what to translate to. It apparently doesn't
// use the currently effective locale.
if (what == LC_ALL) {
- vim_setenv("LANG", (char *)name);
+ os_setenv("LANG", (char *)name, 1);
// Clear $LANGUAGE because GNU gettext uses it.
- vim_setenv("LANGUAGE", "");
+ os_setenv("LANGUAGE", "", 1);
}
if (what != LC_CTYPE) {
- vim_setenv("LC_MESSAGES", (char *)name);
+ os_setenv("LC_MESSAGES", (char *)name, 1);
set_helplang_default((char *)name);
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 0f345df22b..b880ec4f6d 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5266,8 +5266,7 @@ static void ex_command(exarg_T *eap)
} else if (!ASCII_ISUPPER(*name)) {
EMSG(_("E183: User defined commands must start with an uppercase letter"));
return;
- } else if ((name_len == 1 && *name == 'X')
- || (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0)) {
+ } else if (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0) {
EMSG(_("E841: Reserved name, cannot be used for user defined command"));
return;
} else {
@@ -8432,13 +8431,15 @@ static void ex_pedit(exarg_T *eap)
{
win_T *curwin_save = curwin;
+ // Open the preview window or popup and make it the current window.
g_do_tagpreview = p_pvh;
prepare_tagpreview(true);
- keep_help_flag = bt_help(curwin_save->w_buffer);
+
+ // Edit the file.
do_exedit(eap, NULL);
- keep_help_flag = FALSE;
+
if (curwin != curwin_save && win_valid(curwin_save)) {
- /* Return cursor to where we were */
+ // Return cursor to where we were
validate_cursor();
redraw_later(VALID);
win_enter(curwin_save, true);
@@ -9181,7 +9182,7 @@ makeopens(
// Take care of tab-local working directories if applicable
if (tp->tp_localdir) {
- if (fputs("if has('nvim') | tcd ", fd) < 0
+ if (fputs("if exists(':tcd') == 2 | tcd ", fd) < 0
|| ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
|| fputs(" | endif", fd) < 0
|| put_eol(fd) == FAIL) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 38432a34db..e8d650accf 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -3483,6 +3483,7 @@ void compute_cmdrow(void)
cmdline_row = wp->w_winrow + wp->w_height
+ wp->w_status_height;
}
+ lines_left = cmdline_row;
}
static void cursorcmd(void)
@@ -4211,24 +4212,24 @@ static int showmatches(expand_T *xp, int wildmenu)
|| xp->xp_context == EXPAND_BUFFERS) {
/* highlight directories */
if (xp->xp_numfiles != -1) {
- char_u *halved_slash;
- char_u *exp_path;
-
- /* Expansion was done before and special characters
- * were escaped, need to halve backslashes. Also
- * $HOME has been replaced with ~/. */
- exp_path = expand_env_save_opt(files_found[k], TRUE);
- halved_slash = backslash_halve_save(
- exp_path != NULL ? exp_path : files_found[k]);
+ // Expansion was done before and special characters
+ // were escaped, need to halve backslashes. Also
+ // $HOME has been replaced with ~/.
+ char_u *exp_path = expand_env_save_opt(files_found[k], true);
+ char_u *path = exp_path != NULL ? exp_path : files_found[k];
+ char_u *halved_slash = backslash_halve_save(path);
j = os_isdir(halved_slash);
xfree(exp_path);
- xfree(halved_slash);
- } else
- /* Expansion was done here, file names are literal. */
+ if (halved_slash != path) {
+ xfree(halved_slash);
+ }
+ } else {
+ // Expansion was done here, file names are literal.
j = os_isdir(files_found[k]);
- if (showtail)
+ }
+ if (showtail) {
p = L_SHOWFILE(k);
- else {
+ } else {
home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
TRUE);
p = NameBuff;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index d2620376c6..8b19257d3d 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -777,9 +777,8 @@ readfile(
fenc = curbuf->b_p_fenc; // use format from buffer
fenc_alloced = false;
} else {
- fenc_next = p_fencs; /* try items in 'fileencodings' */
- fenc = next_fenc(&fenc_next);
- fenc_alloced = true;
+ fenc_next = p_fencs; // try items in 'fileencodings'
+ fenc = next_fenc(&fenc_next, &fenc_alloced);
}
/*
@@ -869,8 +868,7 @@ retry:
if (fenc_alloced)
xfree(fenc);
if (fenc_next != NULL) {
- fenc = next_fenc(&fenc_next);
- fenc_alloced = (fenc_next != NULL);
+ fenc = next_fenc(&fenc_next, &fenc_alloced);
} else {
fenc = (char_u *)"";
fenc_alloced = false;
@@ -2082,19 +2080,19 @@ void set_forced_fenc(exarg_T *eap)
}
}
-/*
- * Find next fileencoding to use from 'fileencodings'.
- * "pp" points to fenc_next. It's advanced to the next item.
- * When there are no more items, an empty string is returned and *pp is set to
- * NULL.
- * When *pp is not set to NULL, the result is in allocated memory.
- */
-static char_u *next_fenc(char_u **pp)
+// Find next fileencoding to use from 'fileencodings'.
+// "pp" points to fenc_next. It's advanced to the next item.
+// When there are no more items, an empty string is returned and *pp is set to
+// NULL.
+// When *pp is not set to NULL, the result is in allocated memory and "alloced"
+// is set to true.
+static char_u *next_fenc(char_u **pp, bool *alloced)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
char_u *p;
char_u *r;
+ *alloced = false;
if (**pp == NUL) {
*pp = NULL;
return (char_u *)"";
@@ -2110,6 +2108,7 @@ static char_u *next_fenc(char_u **pp)
xfree(r);
r = p;
}
+ *alloced = true;
return r;
}
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index ad0bfe29e2..5ce953e626 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1645,19 +1645,22 @@ deleteFoldMarkers(
foldendmarkerlen);
}
-/* foldDelMarker() {{{2 */
-/*
- * Delete marker "marker[markerlen]" at the end of line "lnum".
- * Delete 'commentstring' if it matches.
- * If the marker is not found, there is no error message. Could a missing
- * close-marker.
- */
+// foldDelMarker() {{{2
+//
+// Delete marker "marker[markerlen]" at the end of line "lnum".
+// Delete 'commentstring' if it matches.
+// If the marker is not found, there is no error message. Could be a missing
+// close-marker.
static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen)
{
char_u *newline;
char_u *cms = curbuf->b_p_cms;
char_u *cms2;
+ // end marker may be missing and fold extends below the last line
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ return;
+ }
char_u *line = ml_get(lnum);
for (char_u *p = line; *p != NUL; ++p) {
if (STRNCMP(p, marker, markerlen) != 0) {
@@ -2426,15 +2429,18 @@ static linenr_T foldUpdateIEMSRecurse(
* lvl >= level: fold continues below "bot"
*/
- /* Current fold at least extends until lnum. */
+ // Current fold at least extends until lnum.
if (fp->fd_len < flp->lnum - fp->fd_top) {
fp->fd_len = flp->lnum - fp->fd_top;
fp->fd_small = kNone;
fold_changed = true;
+ } else if (fp->fd_top + fp->fd_len > linecount) {
+ // running into the end of the buffer (deleted last line)
+ fp->fd_len = linecount - fp->fd_top + 1;
}
- /* Delete contained folds from the end of the last one found until where
- * we stopped looking. */
+ // Delete contained folds from the end of the last one found until where
+ // we stopped looking.
foldRemove(&fp->fd_nested, startlnum2 - fp->fd_top,
flp->lnum - 1 - fp->fd_top);
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index b095e759d9..3bdbff79b4 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -895,11 +895,6 @@ EXTERN disptick_T display_tick INIT(= 0);
* cursor position in Insert mode. */
EXTERN linenr_T spell_redraw_lnum INIT(= 0);
-#ifdef USE_MCH_ERRMSG
-// Grow array to collect error messages in until they can be displayed.
-EXTERN garray_T error_ga INIT(= GA_EMPTY_INIT_VALUE);
-#endif
-
/*
* The error messages that can be shared are included here.
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index f11880cb2b..3a61409dfe 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -233,6 +233,7 @@ int hl_get_underline(void)
.rgb_fg_color = -1,
.rgb_bg_color = -1,
.rgb_sp_color = -1,
+ .hl_blend = -1,
},
.kind = kHlUI,
.id1 = 0,
@@ -427,6 +428,8 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
cattrs.rgb_bg_color = rgb_blend(ratio, battrs.rgb_bg_color,
fattrs.rgb_bg_color);
+ cattrs.hl_blend = -1; // blend property was consumed
+
HlKind kind = *through ? kHlBlendThrough : kHlBlend;
id = get_attr_entry((HlEntry){ .attr = cattrs, .kind = kind,
.id1 = back_attr, .id2 = front_attr });
@@ -614,6 +617,10 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
}
}
+ if (ae.hl_blend > -1) {
+ PUT(hl, "blend", INTEGER_OBJ(ae.hl_blend));
+ }
+
return hl;
}
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 9145813525..27052da9d8 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -604,7 +604,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
// Anything accepted, like <C-?>.
// <C-"> or <M-"> are not special in strings as " is
// the string delimiter. With a backslash it works: <M-\">
- if (end - bp > l && !(in_string && bp[1] == '"') && bp[2] == '>') {
+ if (end - bp > l && !(in_string && bp[1] == '"') && bp[l+1] == '>') {
bp += l;
} else if (end - bp > 2 && in_string && bp[1] == '\\'
&& bp[2] == '"' && bp[3] == '>') {
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 6bb3c37b92..e7c45b1a7b 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -237,7 +237,7 @@ int main(int argc, char **argv)
char **argv = xmalloc((size_t)argc * sizeof(char *));
for (int i = 0; i < argc; i++) {
char *buf = NULL;
- utf16_to_utf8(argv_w[i], &buf);
+ utf16_to_utf8(argv_w[i], -1, &buf);
assert(buf);
argv[i] = buf;
}
@@ -396,8 +396,7 @@ int main(int argc, char **argv)
mch_exit(0);
}
- // Set a few option defaults after reading vimrc files: 'title', 'icon',
- // 'shellpipe', 'shellredir'.
+ // Set some option defaults after reading vimrc files.
set_init_3();
TIME_MSG("inits 3");
@@ -707,22 +706,14 @@ static void init_locale(void)
setlocale(LC_NUMERIC, "C");
# endif
-# ifdef LOCALE_INSTALL_DIR // gnu/linux standard: $prefix/share/locale
- bindtextdomain(PROJECT_NAME, LOCALE_INSTALL_DIR);
-# else // old vim style: $runtime/lang
- {
- char_u *p;
-
- // expand_env() doesn't work yet, because g_chartab[] is not
- // initialized yet, call vim_getenv() directly
- p = (char_u *)vim_getenv("VIMRUNTIME");
- if (p != NULL && *p != NUL) {
- vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
- bindtextdomain(PROJECT_NAME, (char *)NameBuff);
- }
- xfree(p);
- }
-# endif
+ char localepath[MAXPATHL] = { 0 };
+ snprintf(localepath, sizeof(localepath), "%s", get_vim_var_str(VV_PROGPATH));
+ char *tail = (char *)path_tail_with_sep((char_u *)localepath);
+ *tail = NUL;
+ tail = (char *)path_tail((char_u *)localepath);
+ xstrlcpy(tail, "share/locale",
+ sizeof(localepath) - (size_t)(tail - localepath));
+ bindtextdomain(PROJECT_NAME, localepath);
textdomain(PROJECT_NAME);
TIME_MSG("locale set");
}
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index fae7635d34..29b8dc0ef2 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1356,83 +1356,86 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
# define CP_UTF8 65001 /* magic number from winnls.h */
#endif
-/// Reassigns `strw` to a new, allocated pointer to a UTF16 string.
-int utf8_to_utf16(const char *str, wchar_t **strw)
+/// Converts string from UTF-8 to UTF-16.
+///
+/// @param utf8 UTF-8 string.
+/// @param utf8len Length of `utf8`. May be -1 if `utf8` is NUL-terminated.
+/// @param utf16[out,allocated] NUL-terminated UTF-16 string, or NULL on error
+/// @return 0 on success, or libuv error code
+int utf8_to_utf16(const char *utf8, int utf8len, wchar_t **utf16)
FUNC_ATTR_NONNULL_ALL
{
- ssize_t wchar_len = 0;
-
- // Compute the length needed to store the converted widechar string.
- wchar_len = MultiByteToWideChar(CP_UTF8,
- 0, // dwFlags: must be 0 for utf8
- str, // lpMultiByteStr: string to convert
- -1, // -1 => process up to NUL
- NULL, // lpWideCharStr: converted string
- 0); // 0 => return length, don't convert
- if (wchar_len == 0) {
- return GetLastError();
- }
-
- ssize_t buf_sz = wchar_len * sizeof(wchar_t);
-
- if (buf_sz == 0) {
- *strw = NULL;
- return 0;
+ // Compute the length needed for the converted UTF-16 string.
+ int bufsize = MultiByteToWideChar(CP_UTF8,
+ 0, // dwFlags: must be 0 for UTF-8
+ utf8, // -1: process up to NUL
+ utf8len,
+ NULL,
+ 0); // 0: get length, don't convert
+ if (bufsize == 0) {
+ *utf16 = NULL;
+ return uv_translate_sys_error(GetLastError());
}
- char *buf = xmalloc(buf_sz);
- char *pos = buf;
+ // Allocate the destination buffer adding an extra byte for the terminating
+ // NULL. If `utf8len` is not -1 MultiByteToWideChar will not add it, so
+ // we do it ourselves always, just in case.
+ *utf16 = xmalloc(sizeof(wchar_t) * (bufsize + 1));
- int r = MultiByteToWideChar(CP_UTF8,
- 0,
- str,
- -1,
- (wchar_t *)pos,
- wchar_len);
- assert(r == wchar_len);
- if (r != wchar_len) {
- EMSG2("MultiByteToWideChar failed: %d", r);
+ // Convert to UTF-16.
+ bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
+ if (bufsize == 0) {
+ XFREE_CLEAR(*utf16);
+ return uv_translate_sys_error(GetLastError());
}
- *strw = (wchar_t *)pos;
+ (*utf16)[bufsize] = L'\0';
return 0;
}
-/// Reassigns `str` to a new, allocated pointer to a UTF8 string.
-int utf16_to_utf8(const wchar_t *strw, char **str)
+/// Converts string from UTF-16 to UTF-8.
+///
+/// @param utf16 UTF-16 string.
+/// @param utf16len Length of `utf16`. May be -1 if `utf16` is NUL-terminated.
+/// @param utf8[out,allocated] NUL-terminated UTF-8 string, or NULL on error
+/// @return 0 on success, or libuv error code
+int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8)
FUNC_ATTR_NONNULL_ALL
{
- *str = NULL;
- // Compute the space required to store the string as UTF-8.
- DWORD utf8_len = WideCharToMultiByte(CP_UTF8,
- 0,
- strw,
- -1,
- NULL,
- 0,
- NULL,
- NULL);
- if (utf8_len == 0) {
- return GetLastError();
- }
-
- *str = xmallocz(utf8_len);
+ // Compute the space needed for the converted UTF-8 string.
+ DWORD bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (bufsize == 0) {
+ *utf8 = NULL;
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ // Allocate the destination buffer adding an extra byte for the terminating
+ // NULL. If `utf16len` is not -1 WideCharToMultiByte will not add it, so
+ // we do it ourselves always, just in case.
+ *utf8 = xmalloc(bufsize + 1);
// Convert to UTF-8.
- utf8_len = WideCharToMultiByte(CP_UTF8,
- 0,
- strw,
- -1,
- *str,
- utf8_len,
- NULL,
- NULL);
- if (utf8_len == 0) {
- XFREE_CLEAR(*str);
- return GetLastError();
- }
- (*str)[utf8_len] = '\0';
-
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ *utf8,
+ bufsize,
+ NULL,
+ NULL);
+ if (bufsize == 0) {
+ XFREE_CLEAR(*utf8);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ (*utf8)[bufsize] = '\0';
return 0;
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 12da48347e..9bea9f5c4a 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -582,9 +582,25 @@ static bool emsg_multiline(const char *s, bool multiline)
}
redir_write(s, strlen(s));
}
+
+ // Log (silent) errors as debug messages.
+ if (sourcing_name != NULL && sourcing_lnum != 0) {
+ DLOG("(:silent) %s (%s (line %ld))",
+ s, sourcing_name, (long)sourcing_lnum);
+ } else {
+ DLOG("(:silent) %s", s);
+ }
+
return true;
}
+ // Log editor errors as INFO.
+ if (sourcing_name != NULL && sourcing_lnum != 0) {
+ ILOG("%s (%s (line %ld))", s, sourcing_name, (long)sourcing_lnum);
+ } else {
+ ILOG("%s", s);
+ }
+
ex_exitval = 1;
// Reset msg_silent, an error causes messages to be switched back on.
@@ -2305,18 +2321,19 @@ int msg_use_printf(void)
static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
{
const char *s = str;
- char buf[4];
+ char buf[7];
char *p;
while ((maxlen < 0 || s - str < maxlen) && *s != NUL) {
+ int len = utf_ptr2len((const char_u *)s);
if (!(silent_mode && p_verbose == 0)) {
// NL --> CR NL translation (for Unix, not for "--version")
p = &buf[0];
if (*s == '\n' && !info_message) {
*p++ = '\r';
}
- *p++ = *s;
- *p = '\0';
+ memcpy(p, s, len);
+ *(p + len) = '\0';
if (info_message) {
mch_msg(buf);
} else {
@@ -2324,21 +2341,22 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
}
}
+ int cw = utf_char2cells(utf_ptr2char((const char_u *)s));
// primitive way to compute the current column
if (cmdmsg_rl) {
if (*s == '\r' || *s == '\n') {
msg_col = Columns - 1;
} else {
- msg_col--;
+ msg_col -= cw;
}
} else {
if (*s == '\r' || *s == '\n') {
msg_col = 0;
} else {
- msg_col++;
+ msg_col += cw;
}
}
- s++;
+ s += len;
}
msg_didout = true; // assume that line is not empty
}
@@ -2554,81 +2572,34 @@ static int do_more_prompt(int typed_char)
return retval;
}
-#if defined(USE_MCH_ERRMSG)
-
-#ifdef mch_errmsg
-# undef mch_errmsg
-#endif
-#ifdef mch_msg
-# undef mch_msg
-#endif
-
-/*
- * Give an error message. To be used when the screen hasn't been initialized
- * yet. When stderr can't be used, collect error messages until the GUI has
- * started and they can be displayed in a message box.
- */
-void mch_errmsg(const char *const str)
- FUNC_ATTR_NONNULL_ALL
+#if defined(WIN32)
+void mch_errmsg(char *str)
{
-#ifdef UNIX
- /* On Unix use stderr if it's a tty.
- * When not going to start the GUI also use stderr.
- * On Mac, when started from Finder, stderr is the console. */
- if (os_isatty(2)) {
- fprintf(stderr, "%s", str);
- return;
- }
-#endif
-
- /* avoid a delay for a message that isn't there */
- emsg_on_display = FALSE;
-
- const size_t len = strlen(str) + 1;
- if (error_ga.ga_data == NULL) {
- ga_set_growsize(&error_ga, 80);
- error_ga.ga_itemsize = 1;
- }
- ga_grow(&error_ga, len);
- memmove(error_ga.ga_data + error_ga.ga_len, str, len);
-#ifdef UNIX
- /* remove CR characters, they are displayed */
- {
- char_u *p;
-
- p = (char_u *)error_ga.ga_data + error_ga.ga_len;
- for (;; ) {
- p = vim_strchr(p, '\r');
- if (p == NULL)
- break;
- *p = ' ';
- }
+ assert(str != NULL);
+ wchar_t *utf16str;
+ int r = utf8_to_utf16(str, -1, &utf16str);
+ if (r != 0) {
+ fprintf(stderr, "utf8_to_utf16 failed: %d", r);
+ } else {
+ fwprintf(stderr, L"%ls", utf16str);
+ xfree(utf16str);
}
-#endif
- --len; /* don't count the NUL at the end */
- error_ga.ga_len += len;
}
-/*
- * Give a message. To be used when the screen hasn't been initialized yet.
- * When there is no tty, collect messages until the GUI has started and they
- * can be displayed in a message box.
- */
+// Give a message. To be used when the UI is not initialized yet.
void mch_msg(char *str)
{
-#ifdef UNIX
- /* On Unix use stdout if we have a tty. This allows "vim -h | more" and
- * uses mch_errmsg() when started from the desktop.
- * When not going to start the GUI also use stdout.
- * On Mac, when started from Finder, stderr is the console. */
- if (os_isatty(2)) {
- printf("%s", str);
- return;
+ assert(str != NULL);
+ wchar_t *utf16str;
+ int r = utf8_to_utf16(str, -1, &utf16str);
+ if (r != 0) {
+ fprintf(stderr, "utf8_to_utf16 failed: %d", r);
+ } else {
+ wprintf(L"%ls", utf16str);
+ xfree(utf16str);
}
-# endif
- mch_errmsg(str);
}
-#endif /* USE_MCH_ERRMSG */
+#endif // WIN32
/*
* Put a character on the screen at the current message position and advance
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 44e2c7df5f..bb95cd5737 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -61,7 +61,7 @@
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "misc1.c.generated.h"
#endif
-/* All user names (for ~user completion as done by shell). */
+// All user names (for ~user completion as done by shell).
static garray_T ga_users = GA_EMPTY_INIT_VALUE;
/*
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 73841cf449..bfd91e688e 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -7827,13 +7827,15 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
// 'virtualedit' and past the end of the line, we use the 'c' operator in
// do_put(), which requires the visual selection to still be active.
if (!VIsual_active || VIsual_mode == 'V' || regname != '.') {
- // Now delete the selected text.
+ // Now delete the selected text. Avoid messages here.
cap->cmdchar = 'd';
cap->nchar = NUL;
cap->oap->regname = NUL;
+ msg_silent++;
nv_operator(cap);
do_pending_operator(cap, 0, false);
empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
+ msg_silent--;
// delete PUT_LINE_BACKWARD;
cap->oap->regname = regname;
@@ -7882,6 +7884,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
* line that needs to be deleted now. */
if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) {
ml_delete(curbuf->b_ml.ml_line_count, true);
+ deleted_lines(curbuf->b_ml.ml_line_count + 1, 1);
/* If the cursor was in that line, move it to the end of the last
* line. */
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 40c1358fa5..699f17acc5 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1001,45 +1001,35 @@ void set_init_2(bool headless)
p_window = Rows - 1;
}
set_number_default("window", Rows - 1);
- parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
(void)parse_printoptions(); // parse 'printoptions' default value
}
-/*
- * Initialize the options, part three: After reading the .vimrc
- */
+/// Initialize the options, part three: After reading the .vimrc
void set_init_3(void)
{
+ parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
+
// Set 'shellpipe' and 'shellredir', depending on the 'shell' option.
// This is done after other initializations, where 'shell' might have been
// set, but only if they have not been set before.
- int idx_srr;
- int do_srr;
- int idx_sp;
- int do_sp;
-
- idx_srr = findoption("srr");
- if (idx_srr < 0) {
- do_srr = false;
- } else {
- do_srr = !(options[idx_srr].flags & P_WAS_SET);
- }
- idx_sp = findoption("sp");
- if (idx_sp < 0) {
- do_sp = false;
- } else {
- do_sp = !(options[idx_sp].flags & P_WAS_SET);
- }
+ int idx_srr = findoption("srr");
+ int do_srr = (idx_srr < 0)
+ ? false
+ : !(options[idx_srr].flags & P_WAS_SET);
+ int idx_sp = findoption("sp");
+ int do_sp = (idx_sp < 0)
+ ? false
+ : !(options[idx_sp].flags & P_WAS_SET);
size_t len = 0;
char_u *p = (char_u *)invocation_path_tail(p_sh, &len);
p = vim_strnsave(p, len);
{
- /*
- * Default for p_sp is "| tee", for p_srr is ">".
- * For known shells it is changed here to include stderr.
- */
+ //
+ // Default for p_sp is "| tee", for p_srr is ">".
+ // For known shells it is changed here to include stderr.
+ //
if ( fnamecmp(p, "csh") == 0
|| fnamecmp(p, "tcsh") == 0
) {
@@ -1081,7 +1071,7 @@ void set_init_3(void)
}
}
- set_title_defaults();
+ set_title_defaults(); // 'title', 'icon'
}
/*
@@ -2609,11 +2599,11 @@ did_set_string_option(
} else if (varp == &p_hf) { // 'helpfile'
// May compute new values for $VIM and $VIMRUNTIME
if (didset_vim) {
- vim_setenv("VIM", "");
+ os_setenv("VIM", "", 1);
didset_vim = false;
}
if (didset_vimruntime) {
- vim_setenv("VIMRUNTIME", "");
+ os_setenv("VIMRUNTIME", "", 1);
didset_vimruntime = false;
}
} else if (varp == &curwin->w_p_cc) { // 'colorcolumn'
@@ -6778,7 +6768,7 @@ void vimrc_found(char_u *fname, char_u *envname)
// Set $MYVIMRC to the first vimrc file found.
p = FullName_save((char *)fname, false);
if (p != NULL) {
- vim_setenv((char *)envname, p);
+ os_setenv((char *)envname, p, 1);
xfree(p);
}
} else {
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 33b67a8116..f5dbf0694e 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -178,7 +178,7 @@ char *os_getenvname_at_index(size_t index)
for (wchar_t *it = env; *it != L'\0' || *(it + 1) != L'\0'; it++) {
if (index == current_index) {
char *utf8_str;
- int conversion_result = utf16_to_utf8(it, &utf8_str);
+ int conversion_result = utf16_to_utf8(it, -1, &utf8_str);
if (conversion_result != 0) {
EMSG2("utf16_to_utf8 failed: %d", conversion_result);
break;
@@ -258,7 +258,7 @@ void os_get_hostname(char *hostname, size_t size)
host_utf16[host_wsize] = '\0';
char *host_utf8;
- int conversion_result = utf16_to_utf8(host_utf16, &host_utf8);
+ int conversion_result = utf16_to_utf8(host_utf16, -1, &host_utf8);
if (conversion_result != 0) {
EMSG2("utf16_to_utf8 failed: %d", conversion_result);
return;
@@ -412,6 +412,7 @@ void expand_env_esc(char_u *restrict srcp,
bool esc,
bool one,
char_u *prefix)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
char_u *tail;
char_u *var;
@@ -845,10 +846,10 @@ char *vim_getenv(const char *name)
// next time, and others can also use it (e.g. Perl).
if (vim_path != NULL) {
if (vimruntime) {
- vim_setenv("VIMRUNTIME", vim_path);
+ os_setenv("VIMRUNTIME", vim_path, 1);
didset_vimruntime = true;
} else {
- vim_setenv("VIM", vim_path);
+ os_setenv("VIM", vim_path, 1);
didset_vim = true;
}
}
@@ -995,22 +996,6 @@ char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
return dst;
}
-/// Vim setenv() wrapper with special handling for $VIMRUNTIME to keep the
-/// localization machinery sane.
-void vim_setenv(const char *name, const char *val)
-{
- os_setenv(name, val, 1);
-#ifndef LOCALE_INSTALL_DIR
- // When setting $VIMRUNTIME adjust the directory to find message
- // translations to $VIMRUNTIME/lang.
- if (*val != NUL && STRICMP(name, "VIMRUNTIME") == 0) {
- char *buf = (char *)concat_str((char_u *)val, (char_u *)"/lang");
- bindtextdomain(PROJECT_NAME, buf);
- xfree(buf);
- }
-#endif
-}
-
/// Function given to ExpandGeneric() to obtain an environment variable name.
char_u *get_env_name(expand_T *xp, int idx)
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index dcb3ef7c4a..ae922e4040 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -293,7 +293,7 @@ static bool is_executable(const char *name, char **abspath)
/// Checks if file `name` is executable under any of these conditions:
/// - extension is in $PATHEXT and `name` is executable
/// - result of any $PATHEXT extension appended to `name` is executable
-static bool is_executable_ext(char *name, char **abspath)
+static bool is_executable_ext(const char *name, char **abspath)
FUNC_ATTR_NONNULL_ARG(1)
{
const bool is_unix_shell = strstr((char *)path_tail(p_sh), "sh") != NULL;
@@ -1180,12 +1180,10 @@ char *os_resolve_shortcut(const char *fname)
&IID_IShellLinkW, (void **)&pslw);
if (hr == S_OK) {
wchar_t *p;
- const int conversion_result = utf8_to_utf16(fname, &p);
- if (conversion_result != 0) {
- EMSG2("utf8_to_utf16 failed: %d", conversion_result);
- }
-
- if (p != NULL) {
+ const int r = utf8_to_utf16(fname, -1, &p);
+ if (r != 0) {
+ EMSG2("utf8_to_utf16 failed: %d", r);
+ } else if (p != NULL) {
// Get a pointer to the IPersistFile interface.
hr = pslw->lpVtbl->QueryInterface(
pslw, &IID_IPersistFile, (void **)&ppf);
@@ -1210,9 +1208,9 @@ char *os_resolve_shortcut(const char *fname)
ZeroMemory(wsz, MAX_PATH * sizeof(wchar_t));
hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0);
if (hr == S_OK && wsz[0] != NUL) {
- const int conversion_result = utf16_to_utf8(wsz, &rfname);
- if (conversion_result != 0) {
- EMSG2("utf16_to_utf8 failed: %d", conversion_result);
+ const int r2 = utf16_to_utf8(wsz, -1, &rfname);
+ if (r2 != 0) {
+ EMSG2("utf16_to_utf8 failed: %d", r2);
}
}
diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h
index 68e5c74ee1..f4929b12b1 100644
--- a/src/nvim/os/fs_defs.h
+++ b/src/nvim/os/fs_defs.h
@@ -21,12 +21,6 @@ typedef struct {
uv_dirent_t ent; ///< @private The entry information.
} Directory;
-/// Converts libuv error (negative int) to error description string.
-#define os_strerror uv_strerror
-
-/// Converts system error code to libuv error code.
-#define os_translate_sys_error uv_translate_sys_error
-
// Values returned by os_nodetype()
#define NODE_NORMAL 0 // file or directory, check with os_isdir()
#define NODE_WRITABLE 1 // something we can write to (character
diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h
index c29af5c160..c8ac4218f6 100644
--- a/src/nvim/os/os_defs.h
+++ b/src/nvim/os/os_defs.h
@@ -32,11 +32,12 @@
# include <strings.h>
#endif
-/// Function to convert libuv error to char * error description
-///
-/// negative libuv error codes are returned by a number of os functions.
+/// Converts libuv error (negative int) to error description string.
#define os_strerror uv_strerror
+/// Converts system error code to libuv error code.
+#define os_translate_sys_error uv_translate_sys_error
+
#ifdef WIN32
# define os_strtok strtok_s
#else
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 290668bca3..183219bd3e 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -51,26 +51,26 @@ int pty_process_spawn(PtyProcess *ptyproc)
cfg = winpty_config_new(WINPTY_FLAG_ALLOW_CURPROC_DESKTOP_CREATION, &err);
if (cfg == NULL) {
- emsg = "Failed, winpty_config_new.";
+ emsg = "winpty_config_new failed";
goto cleanup;
}
winpty_config_set_initial_size(cfg, ptyproc->width, ptyproc->height);
winpty_object = winpty_open(cfg, &err);
if (winpty_object == NULL) {
- emsg = "Failed, winpty_open.";
+ emsg = "winpty_open failed";
goto cleanup;
}
- status = utf16_to_utf8(winpty_conin_name(winpty_object), &in_name);
+ status = utf16_to_utf8(winpty_conin_name(winpty_object), -1, &in_name);
if (status != 0) {
- emsg = "Failed to convert in_name from utf16 to utf8.";
+ emsg = "utf16_to_utf8(winpty_conin_name) failed";
goto cleanup;
}
- status = utf16_to_utf8(winpty_conout_name(winpty_object), &out_name);
+ status = utf16_to_utf8(winpty_conout_name(winpty_object), -1, &out_name);
if (status != 0) {
- emsg = "Failed to convert out_name from utf16 to utf8.";
+ emsg = "utf16_to_utf8(winpty_conout_name) failed";
goto cleanup;
}
@@ -93,9 +93,9 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
if (proc->cwd != NULL) {
- status = utf8_to_utf16(proc->cwd, &cwd);
+ status = utf8_to_utf16(proc->cwd, -1, &cwd);
if (status != 0) {
- emsg = "Failed to convert pwd form utf8 to utf16.";
+ emsg = "utf8_to_utf16(proc->cwd) failed";
goto cleanup;
}
}
@@ -103,7 +103,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
status = build_cmd_line(proc->argv, &cmd_line,
os_shell_is_cmdexe(proc->argv[0]));
if (status != 0) {
- emsg = "Failed to convert cmd line form utf8 to utf16.";
+ emsg = "build_cmd_line failed";
goto cleanup;
}
@@ -115,7 +115,7 @@ int pty_process_spawn(PtyProcess *ptyproc)
NULL, // Optional environment variables
&err);
if (spawncfg == NULL) {
- emsg = "Failed winpty_spawn_config_new.";
+ emsg = "winpty_spawn_config_new failed";
goto cleanup;
}
@@ -128,9 +128,9 @@ int pty_process_spawn(PtyProcess *ptyproc)
&err)) {
if (win_err) {
status = (int)win_err;
- emsg = "Failed spawn process.";
+ emsg = "failed to spawn process";
} else {
- emsg = "Failed winpty_spawn.";
+ emsg = "winpty_spawn failed";
}
goto cleanup;
}
@@ -160,11 +160,11 @@ int pty_process_spawn(PtyProcess *ptyproc)
cleanup:
if (status) {
// In the case of an error of MultiByteToWideChar or CreateProcessW.
- ELOG("%s error code: %d", emsg, status);
+ ELOG("pty_process_spawn: %s: error code: %d", emsg, status);
status = os_translate_sys_error(status);
} else if (err != NULL) {
status = (int)winpty_error_code(err);
- ELOG("%s error code: %d", emsg, status);
+ ELOG("pty_process_spawn: %s: error code: %d", emsg, status);
status = translate_winpty_error(status);
}
winpty_error_free(err);
@@ -308,7 +308,7 @@ static int build_cmd_line(char **argv, wchar_t **cmd_line, bool is_cmdexe)
}
}
- int result = utf8_to_utf16(utf8_cmd_line, cmd_line);
+ int result = utf8_to_utf16(utf8_cmd_line, -1, cmd_line);
xfree(utf8_cmd_line);
return result;
}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 75a26d88c1..1c787e3a1d 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -852,8 +852,13 @@ static char_u *get_path_cutoff(char_u *fname, garray_T *gap)
int j = 0;
while ((fname[j] == path_part[i][j]
- ) && fname[j] != NUL && path_part[i][j] != NUL)
+#ifdef WIN32
+ || (vim_ispathsep(fname[j]) && vim_ispathsep(path_part[i][j]))
+#endif
+ ) // NOLINT(whitespace/parens)
+ && fname[j] != NUL && path_part[i][j] != NUL) {
j++;
+ }
if (j > maxlen) {
maxlen = j;
cutoff = &fname[j];
@@ -1257,7 +1262,10 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
} else {
addfile(&ga, t, flags);
}
- xfree(t);
+
+ if (t != p) {
+ xfree(t);
+ }
}
if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH))
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 99ccce1793..1b2143c419 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -4375,7 +4375,7 @@ static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol,
screen_adjust_grid(&grid, &row, &coloff);
// Safety check. Avoids clang warnings down the call stack.
- if (grid->chars == NULL || row >= grid->Rows || col >= grid->Columns) {
+ if (grid->chars == NULL || row >= grid->Rows || coloff >= grid->Columns) {
DLOG("invalid state, skipped");
return;
}
diff --git a/src/nvim/search.c b/src/nvim/search.c
index fe4fdf57ba..26549208a8 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -4683,8 +4683,7 @@ search_line:
}
if (matched) {
if (action == ACTION_EXPAND) {
- int reuse = 0;
- int add_r;
+ bool cont_s_ipos = false;
char_u *aux;
if (depth == -1 && lnum == curwin->w_cursor.lnum)
@@ -4738,7 +4737,7 @@ search_line:
p = aux + IOSIZE - i - 1;
STRNCPY(IObuff + i, aux, p - aux);
i += (int)(p - aux);
- reuse |= CONT_S_IPOS;
+ cont_s_ipos = true;
}
IObuff[i] = NUL;
aux = IObuff;
@@ -4747,14 +4746,15 @@ search_line:
goto exit_matched;
}
- add_r = ins_compl_add_infercase(aux, i, p_ic,
- curr_fname == curbuf->b_fname ? NULL : curr_fname,
- dir, reuse);
- if (add_r == OK)
- /* if dir was BACKWARD then honor it just once */
+ const int add_r = ins_compl_add_infercase(
+ aux, i, p_ic, curr_fname == curbuf->b_fname ? NULL : curr_fname,
+ dir, cont_s_ipos);
+ if (add_r == OK) {
+ // if dir was BACKWARD then honor it just once
dir = FORWARD;
- else if (add_r == FAIL)
+ } else if (add_r == FAIL) {
break;
+ }
} else if (action == ACTION_SHOW_ALL) {
found = TRUE;
if (!did_show)
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 8d800843f8..40bb882948 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -7332,7 +7332,7 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int d
? mb_strnicmp(p, pat, STRLEN(pat)) == 0
: STRNCMP(p, pat, STRLEN(pat)) == 0)
&& ins_compl_add_infercase(p, (int)STRLEN(p),
- p_ic, NULL, *dir, 0) == OK) {
+ p_ic, NULL, *dir, false) == OK) {
// if dir was BACKWARD then honor it just once
*dir = FORWARD;
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 5aeea3223b..3faf6dd5bb 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -662,6 +662,7 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
.rgb_fg_color = vt_fg,
.rgb_bg_color = vt_bg,
.rgb_sp_color = -1,
+ .hl_blend = -1,
});
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 8b43d91e25..03b1bae28f 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -16,7 +16,6 @@ export TMPDIR := $(abspath ../../../Xtest-tmpdir)
SCRIPTS_DEFAULT = \
test42.out \
test48.out \
- test52.out \
test64.out \
ifneq ($(OS),Windows_NT)
@@ -25,6 +24,12 @@ ifneq ($(OS),Windows_NT)
endif
+ifeq ($(OS),Windows_NT)
+ FIXFF = fixff
+else
+ FIXFF =
+endif
+
SCRIPTS ?= $(SCRIPTS_DEFAULT)
# Tests using runtest.vim.
@@ -74,27 +79,39 @@ ifdef TESTNUM
SCRIPTS := test$(TESTNUM).out
endif
-nongui: nolog $(SCRIPTS) newtests report
+nongui: nolog $(FIXFF) $(SCRIPTS) newtests report
.gdbinit:
@echo "[OLDTEST-PREP] Setting up .gdbinit"
@echo 'set $$_exitcode = -1\nrun\nif $$_exitcode != -1\n quit\nend' > .gdbinit
report:
+ $(RUN_VIMTEST) $(NO_INITS) -u NONE -S summarize.vim messages
@echo
@echo 'Test results:'
- @/bin/sh -c "if test -f test.log; then \
- cat test.log; \
- echo TEST FAILURE; \
- exit 1; \
- else \
- echo ALL DONE; \
- fi"
+ @cat test_result.log
+ @/bin/sh -c "if test -f test.log; \
+ then echo TEST FAILURE; exit 1; \
+ else echo ALL DONE; \
+ fi"
test1.out: $(NVIM_PRG)
$(SCRIPTS): $(NVIM_PRG) test1.out
+NO_PLUGINS = --noplugin --headless
+# In vim, if the -u command line option is specified, compatible is turned on
+# and viminfo is not read. Unlike vim, neovim reads viminfo and requires the
+# -i command line option.
+NO_INITS = -U NONE -i NONE $(NO_PLUGINS)
+
+# TODO: find a way to avoid changing the distributed files.
+fixff:
+ -$(NVIM_PRG) $(NO_INITS) -u unix.vim "+argdo set ff=dos|upd" +q \
+ *.in *.ok
+ -$(NVIM_PRG) $(NO_INITS) -u unix.vim "+argdo set ff=dos|upd" +q \
+ dotest.in
+
RM_ON_RUN := test.out X* viminfo
RM_ON_START := test.ok
RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in
@@ -106,6 +123,7 @@ CLEAN_FILES := *.out \
*.orig \
*.tlog \
test.log \
+ test_result.log \
messages \
$(RM_ON_RUN) \
$(RM_ON_START) \
@@ -145,7 +163,7 @@ nolog:
# New style of tests uses Vim script with assert calls. These are easier
# to write and a lot easier to read and debug.
# Limitation: Only works with the +eval feature.
-RUN_VIMTEST = $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin
+RUN_VIMTEST = $(TOOL) $(NVIM_PRG) -u unix.vim
newtests: newtestssilent
@/bin/sh -c "if test -f messages && grep -q 'FAILED' messages; then \
@@ -158,4 +176,4 @@ newtestssilent: $(NEW_TESTS)
@echo "[OLDTEST] Running" $*
@rm -rf $*.failed test.ok $(RM_ON_RUN)
@mkdir -p $(TMPDIR)
- @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIMTEST) -u NONE -S runtest.vim $*.vim
+ @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIMTEST) $(NO_INITS) -u NONE -S runtest.vim $*.vim
diff --git a/src/nvim/testdir/load.vim b/src/nvim/testdir/load.vim
index 6369b8f45e..5697ee7304 100644
--- a/src/nvim/testdir/load.vim
+++ b/src/nvim/testdir/load.vim
@@ -6,8 +6,8 @@ function! s:load_factor() abort
for _ in range(5)
let g:val = 0
- call timer_start(timeout, {-> nvim_set_var('val', 1)})
let start = reltime()
+ call timer_start(timeout, {-> nvim_set_var('val', 1)})
while 1
sleep 10m
if g:val == 1
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
index 43556f3ad3..249b89d04e 100755
--- a/src/nvim/testdir/runnvim.sh
+++ b/src/nvim/testdir/runnvim.sh
@@ -64,7 +64,7 @@ main() {(
fi
valgrind_check .
if test -n "$LOG_DIR" ; then
- asan_check "$LOG_DIR"
+ check_sanitizer "$LOG_DIR"
fi
check_core_dumps
if test "$FAILED" = 1 ; then
diff --git a/src/nvim/testdir/runnvim.vim b/src/nvim/testdir/runnvim.vim
index 52e05cfbeb..a46e2d3fc0 100644
--- a/src/nvim/testdir/runnvim.vim
+++ b/src/nvim/testdir/runnvim.vim
@@ -7,6 +7,13 @@ function s:logger.on_exit(id, data, event)
call add(self.d_events, [a:event, ['']])
endfunction
+" Replace non-printable chars by special sequence, or "<%x>".
+let s:escaped_char = {"\n": '\n', "\r": '\r', "\t": '\t'}
+function! s:escape_non_printable(char) abort
+ let r = get(s:escaped_char, a:char)
+ return r is 0 ? printf('<%x>', char2nr(a:char)) : r
+endfunction
+
function Main()
let argc = +$NVIM_TEST_ARGC
let args = []
@@ -26,9 +33,8 @@ function Main()
\'join(map(v:val[1], '.
\ '''substitute(v:val, '.
\ '"\\v\\C(\\p@!.|\\<)", '.
- \ '"\\=printf(\"<%x>\", '.
- \ 'char2nr(submatch(0)))", '.
- \ '"")''), '.
+ \ '"\\=s:escape_non_printable(submatch(0))", '.
+ \ '"g")''), '.
\ '''\n'')')
call setline(1, [
\ 'Job exited with code ' . results[0],
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index c8161b1f9b..fa25740994 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -31,12 +31,14 @@
" Check that the screen size is at least 24 x 80 characters.
if &lines < 24 || &columns < 80
- let error = 'Screen size too small! Tests require at least 24 lines with 80 characters'
+ let error = 'Screen size too small! Tests require at least 24 lines with 80 characters, got ' .. &lines .. ' lines with ' .. &columns .. ' characters'
echoerr error
split test.log
$put =error
write
split messages
+ call append(line('$'), '')
+ call append(line('$'), 'From ' . expand('%') . ':')
call append(line('$'), error)
write
qa!
@@ -49,13 +51,22 @@ source setup.vim
" This also enables use of line continuation.
set nocp viminfo+=nviminfo
-" Use utf-8 or latin1 by default, instead of whatever the system default
-" happens to be. Individual tests can overrule this at the top of the file.
-if has('multi_byte')
- set encoding=utf-8
-else
- set encoding=latin1
-endif
+" Use utf-8 by default, instead of whatever the system default happens to be.
+" Individual tests can overrule this at the top of the file.
+set encoding=utf-8
+
+" REDIR_TEST_TO_NULL has a very permissive SwapExists autocommand which is for
+" the test_name.vim file itself. Replace it here with a more restrictive one,
+" so we still catch mistakes.
+let s:test_script_fname = expand('%')
+au! SwapExists * call HandleSwapExists()
+func HandleSwapExists()
+ " Only ignore finding a swap file for the test script (the user might be
+ " editing it and do ":make test_name") and the output file.
+ if expand('<afile>') == 'messages' || expand('<afile>') =~ s:test_script_fname
+ let v:swapchoice = 'e'
+ endif
+endfunc
" Avoid stopping at the "hit enter" prompt
set nomore
@@ -64,7 +75,7 @@ set nomore
lang mess C
" Always use forward slashes.
-" set shellslash
+set shellslash
" Prepare for calling test_garbagecollect_now().
let v:testing = 1
@@ -148,8 +159,9 @@ func RunTheTest(test)
endtry
endif
- " Clear any autocommands
+ " Clear any autocommands and put back the catch-all for SwapExists.
au!
+ au SwapExists * call HandleSwapExists()
" Close any extra tab pages and windows and make the current one not modified.
while tabpagenr('$') > 1
@@ -256,6 +268,9 @@ if expand('%') =~ 'test_vimscript.vim'
else
try
source %
+ catch /^\cskipped/
+ call add(s:messages, ' Skipped')
+ call add(s:skipped, 'SKIPPED ' . expand('%') . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
catch
let s:fail += 1
call add(s:errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
@@ -266,14 +281,16 @@ endif
let s:flaky_tests = [
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
+ \ 'Test_map_timeout_with_timer_interrupt()',
\ 'Test_oneshot()',
\ 'Test_out_cb()',
\ 'Test_paused()',
- \ 'Test_popup_and_window_resize()',
\ 'Test_quoteplus()',
\ 'Test_quotestar()',
\ 'Test_reltime()',
+ \ 'Test_repeat_many()',
\ 'Test_repeat_three()',
+ \ 'Test_stop_all_in_callback()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()',
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index 6cc2d06a36..bcd6d021a0 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -196,16 +196,30 @@ func s:feedkeys(timer)
call feedkeys('x', 'nt')
endfunc
+" Get $VIMPROG to run Vim executable.
+" The Makefile writes it as the first line in the "vimcmd" file.
+" Nvim: uses $NVIM_TEST_ARG0.
+func GetVimProg()
+ if empty($NVIM_TEST_ARG0)
+ " Assume the script was sourced instead of running "make".
+ return v:progpath
+ endif
+ if has('win32')
+ return substitute($NVIM_TEST_ARG0, '/', '\\', 'g')
+ else
+ return $NVIM_TEST_ARG0
+ endif
+endfunc
+
" Get the command to run Vim, with -u NONE and --headless arguments.
" If there is an argument use it instead of "NONE".
-" Returns an empty string on error.
func GetVimCommand(...)
if a:0 == 0
let name = 'NONE'
else
let name = a:1
endif
- let cmd = v:progpath
+ let cmd = GetVimProg()
let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '')
if cmd !~ '-u '. name
let cmd = cmd . ' -u ' . name
@@ -215,6 +229,14 @@ func GetVimCommand(...)
return cmd
endfunc
+" Get the command to run Vim, with --clean.
+func GetVimCommandClean()
+ let cmd = GetVimCommand()
+ let cmd = substitute(cmd, '-u NONE', '--clean', '')
+ let cmd = substitute(cmd, '--headless', '', '')
+ return cmd
+endfunc
+
" Run Vim, using the "vimcmd" file and "-u NORC".
" "before" is a list of Vim commands to be executed before loading plugins.
" "after" is a list of Vim commands to be executed after loading plugins.
diff --git a/src/nvim/testdir/summarize.vim b/src/nvim/testdir/summarize.vim
new file mode 100644
index 0000000000..4a88935a40
--- /dev/null
+++ b/src/nvim/testdir/summarize.vim
@@ -0,0 +1,56 @@
+if 1
+ " This is executed only with the eval feature
+ set nocompatible
+ func Count(match, type)
+ if a:type ==# 'executed'
+ let g:executed += (a:match+0)
+ elseif a:type ==# 'failed'
+ let g:failed += a:match+0
+ elseif a:type ==# 'skipped'
+ let g:skipped += 1
+ call extend(g:skipped_output, ["\t".a:match])
+ endif
+ endfunc
+
+ let g:executed = 0
+ let g:skipped = 0
+ let g:failed = 0
+ let g:skipped_output = []
+ let g:failed_output = []
+ let output = [""]
+
+ try
+ " This uses the :s command to just fetch and process the output of the
+ " tests, it doesn't acutally replace anything.
+ " And it uses "silent" to avoid reporting the number of matches.
+ silent %s/^Executed\s\+\zs\d\+\ze\s\+tests/\=Count(submatch(0),'executed')/egn
+ silent %s/^SKIPPED \zs.*/\=Count(submatch(0), 'skipped')/egn
+ silent %s/^\(\d\+\)\s\+FAILED:/\=Count(submatch(1), 'failed')/egn
+
+ call extend(output, ["Skipped:"])
+ call extend(output, skipped_output)
+
+ call extend(output, [
+ \ "",
+ \ "-------------------------------",
+ \ printf("Executed: %5d Tests", g:executed),
+ \ printf(" Skipped: %5d Tests", g:skipped),
+ \ printf(" %s: %5d Tests", g:failed == 0 ? 'Failed' : 'FAILED', g:failed),
+ \ "",
+ \ ])
+ if filereadable('test.log')
+ " outputs and indents the failed test result
+ call extend(output, ["", "Failures: "])
+ let failed_output = filter(readfile('test.log'), { v,k -> !empty(k)})
+ call extend(output, map(failed_output, { v,k -> "\t".k}))
+ " Add a final newline
+ call extend(output, [""])
+ endif
+
+ catch " Catch-all
+ finally
+ call writefile(output, 'test_result.log') " overwrites an existing file
+ endtry
+endif
+
+q!
diff --git a/src/nvim/testdir/test42.in b/src/nvim/testdir/test42.in
index 0ea0198d12..baa6e67d26 100644
--- a/src/nvim/testdir/test42.in
+++ b/src/nvim/testdir/test42.in
Binary files differ
diff --git a/src/nvim/testdir/test52.in b/src/nvim/testdir/test52.in
deleted file mode 100644
index fa75129193..0000000000
--- a/src/nvim/testdir/test52.in
+++ /dev/null
@@ -1,64 +0,0 @@
-Tests for reading and writing files with conversion for Win32.
-
-STARTTEST
-:" make this a dummy test for non-Win32 systems
-:if !has("win32") | e! test.ok | wq! test.out | endif
-:"
-:" write tests:
-:" combine three values for 'encoding' with three values for 'fileencoding'
-:" also write files for read tests
-/^1
-:set encoding=utf-8
-:.w! ++enc=utf-8 test.out
-:.w ++enc=cp1251 >>test.out
-:.w ++enc=cp866 >>test.out
-:.w! ++enc=utf-8 Xutf8
-/^2
-:set encoding=cp1251
-:.w ++enc=utf-8 >>test.out
-:.w ++enc=cp1251 >>test.out
-:.w ++enc=cp866 >>test.out
-:.w! ++enc=cp1251 Xcp1251
-/^3
-:set encoding=cp866
-:.w ++enc=utf-8 >>test.out
-:.w ++enc=cp1251 >>test.out
-:.w ++enc=cp866 >>test.out
-:.w! ++enc=cp866 Xcp866
-:"
-:" read three 'fileencoding's with utf-8 'encoding'
-:set encoding=utf-8 fencs=utf-8,cp1251
-:e Xutf8
-:.w ++enc=utf-8 >>test.out
-:e Xcp1251
-:.w ++enc=utf-8 >>test.out
-:set fencs=utf-8,cp866
-:e Xcp866
-:.w ++enc=utf-8 >>test.out
-:"
-:" read three 'fileencoding's with cp1251 'encoding'
-:set encoding=utf-8 fencs=utf-8,cp1251
-:e Xutf8
-:.w ++enc=cp1251 >>test.out
-:e Xcp1251
-:.w ++enc=cp1251 >>test.out
-:set fencs=utf-8,cp866
-:e Xcp866
-:.w ++enc=cp1251 >>test.out
-:"
-:" read three 'fileencoding's with cp866 'encoding'
-:set encoding=cp866 fencs=utf-8,cp1251
-:e Xutf8
-:.w ++enc=cp866 >>test.out
-:e Xcp1251
-:.w ++enc=cp866 >>test.out
-:set fencs=utf-8,cp866
-:e Xcp866
-:.w ++enc=cp866 >>test.out
-:"
-:qa!
-ENDTEST
-
-1 utf-8 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-2 cp1251 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-3 cp866 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
diff --git a/src/nvim/testdir/test52.ok b/src/nvim/testdir/test52.ok
deleted file mode 100644
index 90b516508d..0000000000
--- a/src/nvim/testdir/test52.ok
+++ /dev/null
@@ -1,18 +0,0 @@
-1 utf-8 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-1 utf-8 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-1 utf-8 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
-2 cp1251 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-2 cp1251 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-2 cp1251 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
-3 cp866 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-3 cp866 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-3 cp866 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
-1 utf-8 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-2 cp1251 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-3 cp866 text: Для Vim version 6.2. ПослСднСС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅: 1970 Jan 01
-1 utf-8 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-2 cp1251 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-3 cp866 text: Δλ Vim version 6.2. Οξρλεδνεε θημενενθε: 1970 Jan 01
-1 utf-8 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
-2 cp1251 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
-3 cp866 text: „«ο Vim version 6.2. α«₯€­₯₯ ¨§¬₯­₯­¨₯: 1970 Jan 01
diff --git a/src/nvim/testdir/test_alot_utf8.vim b/src/nvim/testdir/test_alot_utf8.vim
index 648d806a94..be0bd01413 100644
--- a/src/nvim/testdir/test_alot_utf8.vim
+++ b/src/nvim/testdir/test_alot_utf8.vim
@@ -2,8 +2,7 @@
" This makes testing go faster, since Vim doesn't need to restart.
" These tests use utf8 'encoding'. Setting 'encoding' is already done in
-" runtest.vim. Checking for the multi_byte feature is in the individual
-" files, so that they can be run by themselves.
+" runtest.vim.
source test_charsearch_utf8.vim
source test_expr_utf8.vim
diff --git a/src/nvim/testdir/test_arabic.vim b/src/nvim/testdir/test_arabic.vim
index d67f875f97..450c6f98f5 100644
--- a/src/nvim/testdir/test_arabic.vim
+++ b/src/nvim/testdir/test_arabic.vim
@@ -2,8 +2,8 @@
" NOTE: This just checks if the code works. If you know Arabic please add
" functional tests that check the shaping works with real text.
-if !has('arabic') || !has('multi_byte')
- finish
+if !has('arabic')
+ throw 'Skipped: arabic feature missing'
endif
source view_util.vim
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 05d69631c4..67c537b407 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -1,7 +1,7 @@
" Test 'autochdir' behavior
if !exists("+autochdir")
- finish
+ throw 'Skipped: autochdir feature missing'
endif
func Test_set_filename()
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index 7deffbe452..4b34420cab 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -5,7 +5,7 @@
" It helps to change the tabstop setting and force a redraw (e.g. see
" Test_breakindent08())
if !exists('+breakindent')
- finish
+ throw 'Skipped: breakindent option not supported'
endif
source view_util.vim
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index 4436ebbf31..770ed55b8d 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -24,10 +24,7 @@ func Test_cd_no_arg()
call assert_equal(path, getcwd())
else
" Test that cd without argument echoes cwd on non-Unix systems.
- let shellslash = &shellslash
- set shellslash
call assert_match(getcwd(), execute('cd'))
- let &shellslash = shellslash
endif
endfunc
diff --git a/src/nvim/testdir/test_charsearch_utf8.vim b/src/nvim/testdir/test_charsearch_utf8.vim
index ade7dd408c..eac5d46ad8 100644
--- a/src/nvim/testdir/test_charsearch_utf8.vim
+++ b/src/nvim/testdir/test_charsearch_utf8.vim
@@ -1,7 +1,4 @@
" Tests for related f{char} and t{char} using utf-8.
-if !has('multi_byte')
- finish
-endif
" Test for t,f,F,T movement commands
function! Test_search_cmds()
diff --git a/src/nvim/testdir/test_checkpath.vim b/src/nvim/testdir/test_checkpath.vim
index a7557a107d..eff30cf205 100644
--- a/src/nvim/testdir/test_checkpath.vim
+++ b/src/nvim/testdir/test_checkpath.vim
@@ -2,8 +2,6 @@
" Test for 'include' without \zs or \ze
func Test_checkpath1()
- let save_shellslash = &shellslash
- set shellslash
call mkdir("Xdir1/dir2", "p")
call writefile(['#include "bar.a"'], 'Xdir1/dir2/foo.a')
call writefile(['#include "baz.a"'], 'Xdir1/dir2/bar.a')
@@ -27,7 +25,6 @@ func Test_checkpath1()
call delete("./Xbase.a")
call delete("Xdir1", "rf")
set path&
- let &shellslash = save_shellslash
endfunc
func DotsToSlashes()
@@ -36,8 +33,6 @@ endfunc
" Test for 'include' with \zs and \ze
func Test_checkpath2()
- let save_shellslash = &shellslash
- set shellslash
call mkdir("Xdir1/dir2", "p")
call writefile(['%inc /bar/'], 'Xdir1/dir2/foo.b')
call writefile(['%inc /baz/'], 'Xdir1/dir2/bar.b')
@@ -66,7 +61,6 @@ func Test_checkpath2()
set path&
set include&
set includeexpr&
- let &shellslash = save_shellslash
endfunc
func StripNewlineChar()
@@ -78,8 +72,6 @@ endfunc
" Test for 'include' with \zs and no \ze
func Test_checkpath3()
- let save_shellslash = &shellslash
- set shellslash
call mkdir("Xdir1/dir2", "p")
call writefile(['%inc bar.c'], 'Xdir1/dir2/foo.c')
call writefile(['%inc baz.c'], 'Xdir1/dir2/bar.c')
@@ -109,5 +101,4 @@ func Test_checkpath3()
set path&
set include&
set includeexpr&
- let &shellslash = save_shellslash
endfunc
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index 02840de743..46ac59b3b1 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -1,7 +1,7 @@
" Tests for the +clientserver feature.
if !has('job') || !has('clientserver')
- finish
+ throw 'Skipped: job and/or clientserver feature missing'
endif
source shared.vim
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 4b333e444a..b8b018d5f7 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -568,7 +568,8 @@ func Test_setcmdpos()
endfunc
func Test_cmdline_overstrike()
- let encodings = has('multi_byte') ? [ 'utf8' ] : [ 'latin1' ]
+ " Nvim: only utf8 is supported.
+ let encodings = ['utf8']
let encoding_save = &encoding
for e in encodings
@@ -587,11 +588,9 @@ func Test_cmdline_overstrike()
call assert_equal('"ab0cd3ef4', @:)
endfor
- if has('multi_byte')
- " Test overstrike with multi-byte characters.
- call feedkeys(":\"γƒ†γ‚­γ‚Ήγƒˆγ‚¨γƒ‡γ‚£γ‚Ώ\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
- call assert_equal('"テabγ‚­cdエディタ', @:)
- endif
+ " Test overstrike with multi-byte characters.
+ call feedkeys(":\"γƒ†γ‚­γ‚Ήγƒˆγ‚¨γƒ‡γ‚£γ‚Ώ\<home>\<right>\<right>ab\<right>\<insert>cd\<enter>", 'xt')
+ call assert_equal('"テabγ‚­cdエディタ', @:)
let &encoding = encoding_save
endfunc
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index bb87ef9c58..3ef460b4fe 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -22,7 +22,7 @@ endfunc
" Debugger tests
func Test_Debugger()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
" Create a Vim script with some functions
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 1ba36ca8e9..57b19aa817 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -723,7 +723,7 @@ endfunc
func Test_diff_with_cursorline()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
call writefile([
@@ -750,7 +750,7 @@ endfunc
func Test_diff_of_diff()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
if !has("rightleft")
throw 'Skipped: rightleft not supported'
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index 271066df41..62a5da33df 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -1,6 +1,6 @@
" Tests for digraphs
-if !has("digraphs") || !has("multi_byte")
+if !has("digraphs")
finish
endif
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 0ed672d577..5feb59eef1 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -41,7 +41,7 @@ func! Test_display_foldcolumn()
endfunc
func! Test_display_foldtext_mbyte()
- if !has("folding") || !has("multi_byte")
+ if !has("folding")
return
endif
call NewWindow(10, 40)
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 48376d7922..827c54e704 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -37,12 +37,10 @@ func! Test_edit_01()
call assert_equal([''], getline(1,'$'))
%d
" 4) delete a multibyte character
- if has("multi_byte")
- call setline(1, "\u0401")
- call feedkeys("i\<del>\<esc>", 'tnix')
- call assert_equal([''], getline(1,'$'))
- %d
- endif
+ call setline(1, "\u0401")
+ call feedkeys("i\<del>\<esc>", 'tnix')
+ call assert_equal([''], getline(1,'$'))
+ %d
" 5.1) delete linebreak with 'bs' option containing eol
let _bs=&bs
set bs=eol
@@ -452,7 +450,7 @@ endfunc
func! Test_edit_CTRL_()
" disabled for Windows builds, why?
- if !has("multi_byte") || !has("rightleft") || has("win32")
+ if !has("rightleft") || has("win32")
return
endif
let _encoding=&encoding
@@ -620,7 +618,7 @@ func! Test_edit_CTRL_K()
endtry
call delete('Xdictionary.txt')
- if has("multi_byte") && !has("nvim")
+ if exists('*test_override')
call test_override("char_avail", 1)
set showcmd
%d
diff --git a/src/nvim/testdir/test_erasebackword.vim b/src/nvim/testdir/test_erasebackword.vim
index 098d6edfcb..9522ec2cd6 100644
--- a/src/nvim/testdir/test_erasebackword.vim
+++ b/src/nvim/testdir/test_erasebackword.vim
@@ -1,10 +1,5 @@
func Test_erasebackword()
- if !has('multi_byte')
- return
- endif
-
- set encoding=utf-8
enew
exe "normal o wwwγ“γ‚“γ«γ‘γ‚δΈ–η•Œγƒ―γƒΌγƒ«γƒ‰vim \<C-W>"
@@ -21,5 +16,4 @@ func Test_erasebackword()
call assert_equal('', getline('.'))
enew!
- set encoding&
endfunc
diff --git a/src/nvim/testdir/test_expr_utf8.vim b/src/nvim/testdir/test_expr_utf8.vim
index 1737a9f745..fad725d2e5 100644
--- a/src/nvim/testdir/test_expr_utf8.vim
+++ b/src/nvim/testdir/test_expr_utf8.vim
@@ -1,7 +1,4 @@
" Tests for expressions using utf-8.
-if !has('multi_byte')
- finish
-endif
func Test_strgetchar()
call assert_equal(char2nr('Γ‘'), strgetchar('Γ‘xb', 0))
diff --git a/src/nvim/testdir/test_find_complete.vim b/src/nvim/testdir/test_find_complete.vim
index 7592b16192..a7bc135d47 100644
--- a/src/nvim/testdir/test_find_complete.vim
+++ b/src/nvim/testdir/test_find_complete.vim
@@ -3,8 +3,6 @@
" Do all the tests in a separate window to avoid E211 when we recursively
" delete the Xfind directory during cleanup
func Test_find_complete()
- let shellslash = &shellslash
- set shellslash
set belloff=all
" On windows a stale "Xfind" directory may exist, remove it so that
@@ -162,5 +160,4 @@ func Test_find_complete()
exe 'cd ' . cwd
call delete('Xfind', 'rf')
set path&
- let &shellslash = shellslash
endfunc
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index df3d691d85..3cb42579be 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -706,7 +706,7 @@ endfunc
func Test_folds_with_rnu()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot make screendumps'
endif
call writefile([
@@ -740,3 +740,19 @@ func Test_folds_marker_in_comment2()
set foldmethod&
bwipe!
endfunc
+
+func Test_fold_delete_with_marker()
+ new
+ call setline(1, ['func Func() {{{1', 'endfunc'])
+ 1,2yank
+ new
+ set fdm=marker
+ call setline(1, 'x')
+ normal! Vp
+ normal! zd
+ call assert_equal(['func Func() ', 'endfunc'], getline(1, '$'))
+
+ set fdm&
+ bwipe!
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index fab1d7790d..fe3b8bef6e 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -106,11 +106,9 @@ func Test_strwidth()
call assert_equal(4, strwidth(1234))
call assert_equal(5, strwidth(-1234))
- if has('multi_byte')
- call assert_equal(2, strwidth('πŸ˜‰'))
- call assert_equal(17, strwidth('EΔ₯oŝanĝo Δ‰iuΔ΅aΕ­de'))
- call assert_equal((aw == 'single') ? 6 : 7, strwidth('Straße'))
- endif
+ call assert_equal(2, strwidth('πŸ˜‰'))
+ call assert_equal(17, strwidth('EΔ₯oŝanĝo Δ‰iuΔ΅aΕ­de'))
+ call assert_equal((aw == 'single') ? 6 : 7, strwidth('Straße'))
call assert_fails('call strwidth({->0})', 'E729:')
call assert_fails('call strwidth([])', 'E730:')
@@ -308,10 +306,8 @@ func Test_strpart()
call assert_equal('fg', strpart('abcdefg', 5, 4))
call assert_equal('defg', strpart('abcdefg', 3))
- if has('multi_byte')
- call assert_equal('lΓ©p', strpart('Γ©lΓ©phant', 2, 4))
- call assert_equal('lΓ©phant', strpart('Γ©lΓ©phant', 2))
- endif
+ call assert_equal('lΓ©p', strpart('Γ©lΓ©phant', 2, 4))
+ call assert_equal('lΓ©phant', strpart('Γ©lΓ©phant', 2))
endfunc
func Test_tolower()
@@ -321,10 +317,6 @@ func Test_tolower()
call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~',
\ tolower(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'))
- if !has('multi_byte')
- return
- endif
-
" Test with a few uppercase diacritics.
call assert_equal("aàÑÒãÀΓ₯ΔΔƒΔ…ΗŽΗŸΗ‘αΊ£", tolower("AΓ€ΓΓ‚ΓƒΓ„Γ…Δ€Δ‚Δ„ΗΗžΗ αΊ’"))
call assert_equal("bαΈƒαΈ‡", tolower("BαΈ‚αΈ†"))
@@ -399,10 +391,6 @@ func Test_toupper()
call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~',
\ toupper(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'))
- if !has('multi_byte')
- return
- endif
-
" Test with a few lowercase diacritics.
call assert_equal("AΓ€ΓΓ‚ΓƒΓ„Γ…Δ€Δ‚Δ„ΗΗžΗ αΊ’", toupper("aàÑÒãÀΓ₯ΔΔƒΔ…ΗŽΗŸΗ‘αΊ£"))
call assert_equal("BαΈ‚αΈ†", toupper("bαΈƒαΈ‡"))
@@ -976,8 +964,8 @@ func Test_balloon_show()
endfunc
func Test_shellescape()
- let [save_shell, save_shellslash] = [&shell, &shellslash]
- set shell=bash shellslash
+ let save_shell = &shell
+ set shell=bash
call assert_equal("'text'", shellescape('text'))
call assert_equal("'te\"xt'", shellescape('te"xt'))
call assert_equal("'te'\\''xt'", shellescape("te'xt"))
@@ -991,13 +979,13 @@ func Test_shellescape()
call assert_equal("'te\nxt'", shellescape("te\nxt"))
call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1))
- set shell=tcsh shellslash
+ set shell=tcsh
call assert_equal("'te\\!xt'", shellescape("te!xt"))
call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1))
call assert_equal("'te\\\nxt'", shellescape("te\nxt"))
call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1))
- let [&shell, &shellslash] = [save_shell, save_shellslash]
+ let &shell = save_shell
endfunc
func Test_redo_in_nested_functions()
@@ -1170,6 +1158,8 @@ func Test_libcall_libcallnr()
else
let libc = '/usr/lib/libc.so'
endif
+ elseif system('uname -s') =~ 'OpenBSD'
+ let libc = 'libc.so'
else
" On Unix, libc.so can be in various places.
" Interestingly, using an empty string for the 1st argument of libcall
diff --git a/src/nvim/testdir/test_ga.vim b/src/nvim/testdir/test_ga.vim
index 6a7cba28f0..ea3d211aeb 100644
--- a/src/nvim/testdir/test_ga.vim
+++ b/src/nvim/testdir/test_ga.vim
@@ -21,10 +21,6 @@ func Test_ga_command()
call assert_equal("\n<e> 101, Hex 65, Octal 145", Do_ga('e'))
- if !has('multi_byte')
- return
- endif
-
" Test a few multi-bytes characters.
call assert_equal("\n<Γ©> 233, Hex 00e9, Oct 351, Digr e'", Do_ga('Γ©'))
call assert_equal("\n<αΊ»> 7867, Hex 1ebb, Oct 17273, Digr e2", Do_ga('αΊ»'))
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index e751fb5d16..78ec26fd05 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -532,7 +532,7 @@ endfunc
func Test_cursorline_after_yank()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot make screendumps'
endif
call writefile([
@@ -554,7 +554,7 @@ endfunc
func Test_cursorline_with_visualmode()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot make screendumps'
endif
call writefile([
diff --git a/src/nvim/testdir/test_increment_dbcs.vim b/src/nvim/testdir/test_increment_dbcs.vim
index 474a16feeb..e5d5ccffb3 100644
--- a/src/nvim/testdir/test_increment_dbcs.vim
+++ b/src/nvim/testdir/test_increment_dbcs.vim
@@ -1,5 +1,7 @@
" Tests for using Ctrl-A/Ctrl-X using DBCS.
-if !has('multi_byte')
+" neovim needs an iconv to handle cp932. Please do not remove the following
+" conditions.
+if !has('iconv')
finish
endif
scriptencoding cp932
diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim
index 24c6ef5e01..8a6f1bc320 100644
--- a/src/nvim/testdir/test_let.vim
+++ b/src/nvim/testdir/test_let.vim
@@ -25,3 +25,118 @@ func Test_let()
let s = "\na #1\nb #2"
call assert_equal(s, out)
endfunc
+
+func s:set_arg1(a) abort
+ let a:a = 1
+endfunction
+
+func s:set_arg2(a) abort
+ let a:b = 1
+endfunction
+
+func s:set_arg3(a) abort
+ let b = a:
+ let b['a'] = 1
+endfunction
+
+func s:set_arg4(a) abort
+ let b = a:
+ let b['a'] = 1
+endfunction
+
+func s:set_arg5(a) abort
+ let b = a:
+ let b['a'][0] = 1
+endfunction
+
+func s:set_arg6(a) abort
+ let a:a[0] = 1
+endfunction
+
+func s:set_arg7(a) abort
+ call extend(a:, {'a': 1})
+endfunction
+
+func s:set_arg8(a) abort
+ call extend(a:, {'b': 1})
+endfunction
+
+func s:set_arg9(a) abort
+ let a:['b'] = 1
+endfunction
+
+func s:set_arg10(a) abort
+ let b = a:
+ call extend(b, {'a': 1})
+endfunction
+
+func s:set_arg11(a) abort
+ let b = a:
+ call extend(b, {'b': 1})
+endfunction
+
+func s:set_arg12(a) abort
+ let b = a:
+ let b['b'] = 1
+endfunction
+
+func Test_let_arg_fail()
+ call assert_fails('call s:set_arg1(1)', 'E46:')
+ call assert_fails('call s:set_arg2(1)', 'E461:')
+ call assert_fails('call s:set_arg3(1)', 'E46:')
+ call assert_fails('call s:set_arg4(1)', 'E46:')
+ call assert_fails('call s:set_arg5(1)', 'E46:')
+ call s:set_arg6([0])
+ call assert_fails('call s:set_arg7(1)', 'E742:')
+ call assert_fails('call s:set_arg8(1)', 'E742:')
+ call assert_fails('call s:set_arg9(1)', 'E461:')
+ call assert_fails('call s:set_arg10(1)', 'E742:')
+ call assert_fails('call s:set_arg11(1)', 'E742:')
+ call assert_fails('call s:set_arg12(1)', 'E461:')
+endfunction
+
+func s:set_varg1(...) abort
+ let a:000 = []
+endfunction
+
+func s:set_varg2(...) abort
+ let a:000[0] = 1
+endfunction
+
+func s:set_varg3(...) abort
+ let a:000 += [1]
+endfunction
+
+func s:set_varg4(...) abort
+ call add(a:000, 1)
+endfunction
+
+func s:set_varg5(...) abort
+ let a:000[0][0] = 1
+endfunction
+
+func s:set_varg6(...) abort
+ let b = a:000
+ let b[0] = 1
+endfunction
+
+func s:set_varg7(...) abort
+ let b = a:000
+ call add(b, 1)
+endfunction
+
+func s:set_varg8(...) abort
+ let b = a:000
+ let b[0][0] = 1
+endfunction
+
+func Test_let_varg_fail()
+ call assert_fails('call s:set_varg1(1)', 'E46:')
+ call assert_fails('call s:set_varg2(1)', 'E742:')
+ call assert_fails('call s:set_varg3(1)', 'E46:')
+ call assert_fails('call s:set_varg4(1)', 'E742:')
+ call s:set_varg5([0])
+ call assert_fails('call s:set_varg6(1)', 'E742:')
+ call assert_fails('call s:set_varg7(1)', 'E742:')
+ call s:set_varg8([0])
+endfunction
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index 9e060cdff6..bea62cb0ad 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -500,17 +500,20 @@ endfunc
" No remove() of write-protected scope-level variable
func! Tfunc(this_is_a_long_parameter_name)
- call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E795')
+ call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
endfun
func Test_dict_scope_var_remove()
call Tfunc('testval')
endfunc
" No extend() of write-protected scope-level variable
+func Test_dict_scope_var_extend()
+ call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
+endfunc
func! Tfunc(this_is_a_long_parameter_name)
call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
endfunc
-func Test_dict_scope_var_extend()
+func Test_dict_scope_var_extend_overwrite()
call Tfunc('testval')
endfunc
@@ -699,3 +702,75 @@ func Test_listdict_extend()
call assert_fails("call extend([1, 2], 1)", 'E712:')
call assert_fails("call extend([1, 2], {})", 'E712:')
endfunc
+
+func s:check_scope_dict(x, fixed)
+ func s:gen_cmd(cmd, x)
+ return substitute(a:cmd, '\<x\ze:', a:x, 'g')
+ endfunc
+
+ let cmd = s:gen_cmd('let x:foo = 1', a:x)
+ if a:fixed
+ call assert_fails(cmd, 'E461')
+ else
+ exe cmd
+ exe s:gen_cmd('call assert_equal(1, x:foo)', a:x)
+ endif
+
+ let cmd = s:gen_cmd('let x:["bar"] = 2', a:x)
+ if a:fixed
+ call assert_fails(cmd, 'E461')
+ else
+ exe cmd
+ exe s:gen_cmd('call assert_equal(2, x:bar)', a:x)
+ endif
+
+ let cmd = s:gen_cmd('call extend(x:, {"baz": 3})', a:x)
+ if a:fixed
+ call assert_fails(cmd, 'E742')
+ else
+ exe cmd
+ exe s:gen_cmd('call assert_equal(3, x:baz)', a:x)
+ endif
+
+ if a:fixed
+ if a:x ==# 'a'
+ call assert_fails('unlet a:x', 'E795')
+ call assert_fails('call remove(a:, "x")', 'E742')
+ elseif a:x ==# 'v'
+ call assert_fails('unlet v:count', 'E795')
+ call assert_fails('call remove(v:, "count")', 'E742')
+ endif
+ else
+ exe s:gen_cmd('unlet x:foo', a:x)
+ exe s:gen_cmd('unlet x:bar', a:x)
+ exe s:gen_cmd('call remove(x:, "baz")', a:x)
+ endif
+
+ delfunc s:gen_cmd
+endfunc
+
+func Test_scope_dict()
+ " Test for g:
+ call s:check_scope_dict('g', v:false)
+
+ " Test for s:
+ call s:check_scope_dict('s', v:false)
+
+ " Test for l:
+ call s:check_scope_dict('l', v:false)
+
+ " Test for a:
+ call s:check_scope_dict('a', v:true)
+
+ " Test for b:
+ call s:check_scope_dict('b', v:false)
+
+ " Test for w:
+ call s:check_scope_dict('w', v:false)
+
+ " Test for t:
+ call s:check_scope_dict('t', v:false)
+
+ " Test for v:
+ call s:check_scope_dict('v', v:true)
+endfunc
diff --git a/src/nvim/testdir/test_makeencoding.vim b/src/nvim/testdir/test_makeencoding.vim
index 6e4c7af821..2b346e0720 100644
--- a/src/nvim/testdir/test_makeencoding.vim
+++ b/src/nvim/testdir/test_makeencoding.vim
@@ -1,7 +1,4 @@
" Tests for 'makeencoding'.
-if !has('multi_byte')
- finish
-endif
source shared.vim
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index ee16a22398..6324e39eec 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -1,8 +1,5 @@
" Tests for maparg().
" Also test utf8 map with a 0x80 byte.
-if !has("multi_byte")
- finish
-endif
function s:SID()
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 9f253604ed..34e62e80e8 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -1,9 +1,5 @@
" Tests for mappings and abbreviations
-if !has('multi_byte')
- finish
-endif
-
source shared.vim
func Test_abbreviation()
@@ -229,6 +225,12 @@ func Test_map_meta_quotes()
iunmap <M-">
endfunc
+func Test_map_meta_multibyte()
+ imap <M-Γ‘> foo
+ call assert_match('i <M-Γ‘>\s*foo', execute('imap'))
+ iunmap <M-Γ‘>
+endfunc
+
func Test_abbr_after_line_join()
new
abbr foo bar
@@ -282,7 +284,7 @@ func Test_map_timeout_with_timer_interrupt()
let g:val = 0
nnoremap \12 :let g:val = 1<CR>
nnoremap \123 :let g:val = 2<CR>
- set timeout timeoutlen=1000
+ set timeout timeoutlen=200
func ExitCb(job, status)
let g:timer = timer_start(1, {_ -> feedkeys("3\<Esc>", 't')})
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index 7fd115fd68..272553c29f 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -122,9 +122,6 @@ func Test_marks_cmd()
endfunc
func Test_marks_cmd_multibyte()
- if !has('multi_byte')
- return
- endif
new Xone
call setline(1, [repeat('Γ‘', &columns)])
norm! ma
diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim
index e926b946a9..90dfcf952d 100644
--- a/src/nvim/testdir/test_match.vim
+++ b/src/nvim/testdir/test_match.vim
@@ -114,36 +114,33 @@ function Test_match()
call assert_equal([{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}], getmatches())
call clearmatches()
- "
- if has('multi_byte')
- call setline(1, 'abcdΞ£abcdef')
- call matchaddpos("MyGroup1", [[1, 4, 2], [1, 9, 2]])
- 1
- redraw!
- let v1 = screenattr(1, 1)
- let v4 = screenattr(1, 4)
- let v5 = screenattr(1, 5)
- let v6 = screenattr(1, 6)
- let v7 = screenattr(1, 7)
- let v8 = screenattr(1, 8)
- let v9 = screenattr(1, 9)
- let v10 = screenattr(1, 10)
- call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
- call assert_notequal(v1, v4)
- call assert_equal(v5, v4)
- call assert_equal(v6, v1)
- call assert_equal(v7, v1)
- call assert_equal(v8, v4)
- call assert_equal(v9, v4)
- call assert_equal(v10, v1)
-
- " Check, that setmatches() can correctly restore the matches from matchaddpos()
- call matchadd('MyGroup1', '\%2lmatchadd')
- let m=getmatches()
- call clearmatches()
- call setmatches(m)
- call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches())
- endif
+ call setline(1, 'abcdΞ£abcdef')
+ call matchaddpos("MyGroup1", [[1, 4, 2], [1, 9, 2]])
+ 1
+ redraw!
+ let v1 = screenattr(1, 1)
+ let v4 = screenattr(1, 4)
+ let v5 = screenattr(1, 5)
+ let v6 = screenattr(1, 6)
+ let v7 = screenattr(1, 7)
+ let v8 = screenattr(1, 8)
+ let v9 = screenattr(1, 9)
+ let v10 = screenattr(1, 10)
+ call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
+ call assert_notequal(v1, v4)
+ call assert_equal(v5, v4)
+ call assert_equal(v6, v1)
+ call assert_equal(v7, v1)
+ call assert_equal(v8, v4)
+ call assert_equal(v9, v4)
+ call assert_equal(v10, v1)
+
+ " Check, that setmatches() can correctly restore the matches from matchaddpos()
+ call matchadd('MyGroup1', '\%2lmatchadd')
+ let m=getmatches()
+ call clearmatches()
+ call setmatches(m)
+ call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches())
highlight MyGroup1 NONE
highlight MyGroup2 NONE
diff --git a/src/nvim/testdir/test_matchadd_conceal_utf8.vim b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
index 24c848a99c..160d0598a1 100644
--- a/src/nvim/testdir/test_matchadd_conceal_utf8.vim
+++ b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
@@ -1,5 +1,5 @@
" Test for matchadd() and conceal feature using utf-8.
-if !has('conceal') || !has('multi_byte')
+if !has('conceal')
finish
endif
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index d77dac69c7..4e6d96ee48 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -206,11 +206,10 @@ func Test_mkview_loadview_with_viewdir()
" The directory Xviewdir/ should have been created and the view
" should be stored in that directory.
- let pathsep = has('win32') ? '\' : '/'
- call assert_equal('Xviewdir' . pathsep .
+ call assert_equal('Xviewdir/' .
\ substitute(
\ substitute(
- \ expand('%:p'), pathsep, '=+', 'g'), ':', '=-', 'g') . '=1.vim',
+ \ expand('%:p'), '/', '=+', 'g'), ':', '=-', 'g') . '=1.vim',
\ glob('Xviewdir/*'))
call assert_equal(1, &number)
call assert_match('\*:mkview\*$', getline('.'))
diff --git a/src/nvim/testdir/test_mksession_utf8.vim b/src/nvim/testdir/test_mksession_utf8.vim
index 8ffbba2a1c..67af3a9ca2 100644
--- a/src/nvim/testdir/test_mksession_utf8.vim
+++ b/src/nvim/testdir/test_mksession_utf8.vim
@@ -3,7 +3,7 @@
set encoding=utf-8
scriptencoding utf-8
-if !has('multi_byte') || !has('mksession')
+if !has('mksession')
finish
endif
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 945cd5a617..532beb9c39 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1374,10 +1374,6 @@ func! Test_normal23_K()
endfunc
func! Test_normal24_rot13()
- " This test uses multi byte characters
- if !has("multi_byte")
- return
- endif
" Testing for g?? g?g?
new
call append(0, 'abcdefghijklmnopqrstuvwxyzÀüâ')
@@ -1628,10 +1624,6 @@ fun! Test_normal29_brace()
endfunc
fun! Test_normal30_changecase()
- " This test uses multi byte characters
- if !has("multi_byte")
- return
- endif
new
call append(0, 'This is a simple test: Àüâß')
norm! 1ggVu
@@ -1901,42 +1893,36 @@ func! Test_g_ctrl_g()
call assert_equal("\nCol 1 of 10; Line 1 of 2; Word 1 of 4; Char 1 of 23; Byte 1 of 22", a)
set bin & eol&
- if has('multi_byte')
- call setline(1, ['FranΓ§ais', 'ζ—₯本θͺž'])
+ call setline(1, ['FranΓ§ais', 'ζ—₯本θͺž'])
- let a = execute(":norm! \<Esc>gojlg\<c-g>")
- call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20", a)
+ let a = execute(":norm! \<Esc>gojlg\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20", a)
- let a = execute(":norm! \<Esc>gojvlg\<c-g>")
- call assert_equal("\nSelected 1 of 2 Lines; 1 of 2 Words; 2 of 13 Chars; 6 of 20 Bytes", a)
+ let a = execute(":norm! \<Esc>gojvlg\<c-g>")
+ call assert_equal("\nSelected 1 of 2 Lines; 1 of 2 Words; 2 of 13 Chars; 6 of 20 Bytes", a)
- let a = execute(":norm! \<Esc>goll\<c-v>jlg\<c-g>")
- call assert_equal("\nSelected 4 Cols; 2 of 2 Lines; 2 of 2 Words; 6 of 13 Chars; 11 of 20 Bytes", a)
+ let a = execute(":norm! \<Esc>goll\<c-v>jlg\<c-g>")
+ call assert_equal("\nSelected 4 Cols; 2 of 2 Lines; 2 of 2 Words; 6 of 13 Chars; 11 of 20 Bytes", a)
- set fenc=utf8 bomb
- let a = execute(":norm! \<Esc>gojlg\<c-g>")
- call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+3 for BOM)", a)
+ set fenc=utf8 bomb
+ let a = execute(":norm! \<Esc>gojlg\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+3 for BOM)", a)
- set fenc=utf16 bomb
- let a = execute(":norm! g\<c-g>")
- call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+2 for BOM)", a)
+ set fenc=utf16 bomb
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+2 for BOM)", a)
- set fenc=utf32 bomb
- let a = execute(":norm! g\<c-g>")
- call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+4 for BOM)", a)
+ set fenc=utf32 bomb
+ let a = execute(":norm! g\<c-g>")
+ call assert_equal("\nCol 4-3 of 9-6; Line 2 of 2; Word 2 of 2; Char 11 of 13; Byte 16 of 20(+4 for BOM)", a)
- set fenc& bomb&
- endif
+ set fenc& bomb&
set ff&
bwipe!
endfunc
fun! Test_normal34_g_cmd3()
- if !has("multi_byte")
- return
- endif
-
" Test for g8
new
let a=execute(':norm! 1G0g8')
@@ -1955,9 +1941,6 @@ fun! Test_normal34_g_cmd3()
endfunc
func Test_normal_8g8()
- if !has("multi_byte")
- return
- endif
new
" Test 8g8 which finds invalid utf8 at or after the cursor.
@@ -2298,11 +2281,6 @@ func! Test_normal45_drop()
endfunc
func! Test_normal46_ignore()
- " This test uses multi byte characters
- if !has("multi_byte")
- return
- endif
-
new
" How to test this?
" let's just for now test, that the buffer
@@ -2475,9 +2453,7 @@ func Test_normal54_Ctrl_bsl()
call assert_equal(['abcdefghijklmn'], getline(1,'$'))
exe "norm! df\<c-\>m"
call assert_equal(['abcdefghijklmn'], getline(1,'$'))
- if !has("multi_byte")
- return
- endif
+
call setline(2, 'abcdefghijklmnāf')
norm! 2gg0
exe "norm! df\<Char-0x101>"
@@ -2541,9 +2517,6 @@ func Test_changelist()
endfunc
func Test_delete_until_paragraph()
- if !has('multi_byte')
- return
- endif
new
normal grΓ‘dv}
call assert_equal('Γ‘', getline(1))
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index a6ebd7b023..ffd344200b 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -210,8 +210,6 @@ func Test_set_completion()
call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:)
" Expand directories.
- let shellslash = &shellslash
- set shellslash
call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('./samples/ ', @:)
call assert_notmatch('./small.vim ', @:)
@@ -223,7 +221,6 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
set tags&
- let &shellslash = shellslash
endfunc
func Test_set_errors()
diff --git a/src/nvim/testdir/test_plus_arg_edit.vim b/src/nvim/testdir/test_plus_arg_edit.vim
index 71dbea1991..f6d31e7626 100644
--- a/src/nvim/testdir/test_plus_arg_edit.vim
+++ b/src/nvim/testdir/test_plus_arg_edit.vim
@@ -1,7 +1,7 @@
" Tests for complicated + argument to :edit command
function Test_edit()
- call writefile(["foo|bar"], "Xfile1")
- call writefile(["foo/bar"], "Xfile2")
+ call writefile(["foo|bar"], "Xfile1")
+ call writefile(["foo/bar"], "Xfile2")
edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w
call assert_equal(["fooPIPEbar"], readfile("Xfile1"))
call assert_equal(["fooSLASHbar"], readfile("Xfile2"))
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 98e9de9ffb..0027a0a52e 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -14,7 +14,7 @@ func ListMonths()
if !empty(entered)
let mth = filter(mth, 'v:val=~"^".entered')
endif
- call complete(1, mth)
+ call complete(1, mth)
return ''
endfunc
@@ -72,7 +72,7 @@ func Test_popup_complete()
call feedkeys("aJu\<f5>\<c-p>l\<c-y>", 'tx')
call assert_equal(["Jul"], getline(1,2))
%d
-
+
" any-non printable, non-white character: Add this character and
" reduce number of matches
call feedkeys("aJu\<f5>\<c-p>l\<c-n>\<c-y>", 'tx')
@@ -94,7 +94,7 @@ func Test_popup_complete()
call feedkeys("aJ\<f5>".repeat("\<c-n>",3)."\<c-l>\<esc>", 'tx')
call assert_equal(["J "], getline(1,2))
%d
-
+
" <c-l> - Insert one character from the current match
call feedkeys("aJ\<f5>".repeat("\<c-n>",4)."\<c-l>\<esc>", 'tx')
call assert_equal(["January "], getline(1,2))
@@ -516,6 +516,35 @@ func Test_completion_ctrl_e_without_autowrap()
q!
endfunc
+func DummyCompleteSix()
+ call complete(1, ['Hello', 'World'])
+ return ''
+endfunction
+
+" complete() correctly clears the list of autocomplete candidates
+" See #1411
+func Test_completion_clear_candidate_list()
+ new
+ %d
+ " select first entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
+ call assert_equal('Hello', getline(1))
+ %d
+ " select second entry from the completion popup
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
+ call assert_equal('World', getline(1))
+ %d
+ " select original text
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
+ call assert_equal(' xxx', getline(1))
+ %d
+ " back at first entry from completion list
+ call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
+ call assert_equal('Hello', getline(1))
+
+ bw!
+endfunc
+
func Test_completion_respect_bs_option()
new
let li = ["aaa", "aaa12345", "aaaabcdef", "aaaABC"]
@@ -575,82 +604,6 @@ func Test_completion_comment_formatting()
bwipe!
endfunc
-func DummyCompleteSix()
- call complete(1, ['Hello', 'World'])
- return ''
-endfunction
-
-" complete() correctly clears the list of autocomplete candidates
-func Test_completion_clear_candidate_list()
- new
- %d
- " select first entry from the completion popup
- call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>", "tx")
- call assert_equal('Hello', getline(1))
- %d
- " select second entry from the completion popup
- call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>", "tx")
- call assert_equal('World', getline(1))
- %d
- " select original text
- call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>", "tx")
- call assert_equal(' xxx', getline(1))
- %d
- " back at first entry from completion list
- call feedkeys("a xxx\<C-N>\<C-R>=DummyCompleteSix()\<CR>\<C-N>\<C-N>\<C-N>", "tx")
- call assert_equal('Hello', getline(1))
-
- bw!
-endfunc
-
-func Test_popup_complete_backwards()
- new
- call setline(1, ['Post', 'Port', 'Po'])
- let expected=['Post', 'Port', 'Port']
- call cursor(3,2)
- call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
- call assert_equal(expected, getline(1,'$'))
- bwipe!
-endfunc
-
-func Test_popup_and_preview_autocommand()
- " This used to crash Vim
- if !has('python')
- return
- endif
- let h = winheight(0)
- if h < 15
- return
- endif
- new
- augroup MyBufAdd
- au!
- au BufAdd * nested tab sball
- augroup END
- set omnifunc=pythoncomplete#Complete
- call setline(1, 'import os')
- " make the line long
- call setline(2, ' os.')
- $
- call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
- call assert_equal("import os", getline(1))
- call assert_match(' os.\(EX_IOERR\|O_CREAT\)$', getline(2))
- call assert_equal(1, winnr('$'))
- " previewwindow option is not set
- call assert_equal(0, &previewwindow)
- norm! gt
- call assert_equal(0, &previewwindow)
- norm! gT
- call assert_equal(10, tabpagenr('$'))
- tabonly
- pclose
- augroup MyBufAdd
- au!
- augroup END
- augroup! MyBufAdd
- bw!
-endfunc
-
func MessCompleteMonths()
for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep")
call complete_add(m)
@@ -716,10 +669,10 @@ func Test_popup_and_window_resize()
if h < 15
return
endif
- let g:buf = term_start([$NVIM_PRG, '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3})
- call term_sendkeys(g:buf, (h / 3 - 1)."o\<esc>G")
- call term_sendkeys(g:buf, "i\<c-x>")
+ let g:buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile'], {'term_rows': h / 3})
+ call term_sendkeys(g:buf, (h / 3 - 1)."o\<esc>")
call term_wait(g:buf, 200)
+ call term_sendkeys(g:buf, "Gi\<c-x>")
call term_sendkeys(g:buf, "\<c-v>")
call term_wait(g:buf, 100)
" popup first entry "!" must be at the top
@@ -740,6 +693,55 @@ func Test_popup_and_window_resize()
bwipe!
endfunc
+func Test_popup_and_preview_autocommand()
+ " This used to crash Vim
+ if !has('python')
+ return
+ endif
+ let h = winheight(0)
+ if h < 15
+ return
+ endif
+ new
+ augroup MyBufAdd
+ au!
+ au BufAdd * nested tab sball
+ augroup END
+ set omnifunc=pythoncomplete#Complete
+ call setline(1, 'import os')
+ " make the line long
+ call setline(2, ' os.')
+ $
+ call feedkeys("A\<C-X>\<C-O>\<C-N>\<C-N>\<C-N>\<enter>\<esc>", 'tx')
+ call assert_equal("import os", getline(1))
+ call assert_match(' os.\(EX_IOERR\|O_CREAT\)$', getline(2))
+ call assert_equal(1, winnr('$'))
+ " previewwindow option is not set
+ call assert_equal(0, &previewwindow)
+ norm! gt
+ call assert_equal(0, &previewwindow)
+ norm! gT
+ call assert_equal(10, tabpagenr('$'))
+ tabonly
+ pclose
+ augroup MyBufAdd
+ au!
+ augroup END
+ augroup! MyBufAdd
+ bw!
+endfunc
+
+
+func Test_popup_complete_backwards()
+ new
+ call setline(1, ['Post', 'Port', 'Po'])
+ let expected=['Post', 'Port', 'Port']
+ call cursor(3,2)
+ call feedkeys("A\<C-X>". repeat("\<C-P>", 3). "rt\<cr>", 'tx')
+ call assert_equal(expected, getline(1,'$'))
+ bwipe!
+endfunc
+
func Test_popup_complete_info_01()
new
inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
index 1aa4d5eaf8..9b78d90b0b 100644
--- a/src/nvim/testdir/test_profile.vim
+++ b/src/nvim/testdir/test_profile.vim
@@ -183,7 +183,7 @@ func Test_profile_errors()
endfunc
func Test_profile_truncate_mbyte()
- if !has('multi_byte') || &enc !=# 'utf-8'
+ if &enc !=# 'utf-8'
return
endif
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index d8a231c52e..884ada7e88 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -1,9 +1,6 @@
" Tests for put commands, e.g. ":put", "p", "gp", "P", "gP", etc.
func Test_put_block()
- if !has('multi_byte')
- return
- endif
new
call feedkeys("i\<C-V>u2500\<CR>x\<ESC>", 'x')
call feedkeys("\<C-V>y", 'x')
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index ce0b8f1be8..1072c51aa2 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -139,8 +139,6 @@ func XlistTests(cchar)
\ ' 5:50 col 25 55: one'], l)
" Test for module names, one needs to explicitly set `'valid':v:true` so
- let save_shellslash = &shellslash
- set shellslash
call g:Xsetlist([
\ {'lnum':10,'col':5,'type':'W','module':'Data.Text','text':'ModuleWarning','nr':11,'valid':v:true},
\ {'lnum':20,'col':10,'type':'W','module':'Data.Text','filename':'Data/Text.hs','text':'ModuleWarning','nr':22,'valid':v:true},
@@ -149,7 +147,6 @@ func XlistTests(cchar)
call assert_equal([' 1 Data.Text:10 col 5 warning 11: ModuleWarning',
\ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
\ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
- let &shellslash = save_shellslash
" Error cases
call assert_fails('Xlist abc', 'E488:')
diff --git a/src/nvim/testdir/test_regex_char_classes.vim b/src/nvim/testdir/test_regex_char_classes.vim
index 7873502943..c1a4202c2b 100644
--- a/src/nvim/testdir/test_regex_char_classes.vim
+++ b/src/nvim/testdir/test_regex_char_classes.vim
@@ -1,9 +1,6 @@
" Tests for regexp with backslash and other special characters inside []
" Also test backslash for hex/octal numbered character.
"
-if !has('multi_byte')
- finish
-endif
scriptencoding utf-8
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 8e284ba042..5d4c2a015f 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -480,9 +480,6 @@ endfunc
" Test for search('multi-byte char', 'bce')
func Test_search_multibyte()
- if !has('multi_byte')
- return
- endif
let save_enc = &encoding
set encoding=utf8
enew!
@@ -499,7 +496,7 @@ func Test_incsearch_substitute_dump()
return
endif
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot make screendumps'
endif
call writefile([
\ 'set incsearch hlsearch scrolloff=0',
@@ -530,7 +527,7 @@ endfunc
func Test_incsearch_with_change()
if !has('timers') || !exists('+incsearch') || !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot make screendumps and/or timers feature and/or incsearch option missing'
endif
call writefile([
diff --git a/src/nvim/testdir/test_source_utf8.vim b/src/nvim/testdir/test_source_utf8.vim
index c29c2ec1f3..e93ea29dff 100644
--- a/src/nvim/testdir/test_source_utf8.vim
+++ b/src/nvim/testdir/test_source_utf8.vim
@@ -1,7 +1,4 @@
" Test the :source! command
-if !has('multi_byte')
- finish
-endif
func Test_source_utf8()
" check that sourcing a script with 0x80 as second byte works
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 230cb72335..e49b5542fa 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -137,10 +137,8 @@ func Test_spellinfo()
set enc=cp1250 spell spelllang=en
call assert_match("^\nfile: .*/runtime/spell/en.ascii.spl\n$", execute('spellinfo'))
- if has('multi_byte')
- set enc=utf-8 spell spelllang=en
- call assert_match("^\nfile: .*/runtime/spell/en.utf-8.spl\n$", execute('spellinfo'))
- endif
+ set enc=utf-8 spell spelllang=en
+ call assert_match("^\nfile: .*/runtime/spell/en.utf-8.spl\n$", execute('spellinfo'))
set enc=latin1 spell spelllang=en_us,en_nz
call assert_match("^\n" .
diff --git a/src/nvim/testdir/test_startup_utf8.vim b/src/nvim/testdir/test_startup_utf8.vim
index f824925450..b24b0eb5cf 100644
--- a/src/nvim/testdir/test_startup_utf8.vim
+++ b/src/nvim/testdir/test_startup_utf8.vim
@@ -1,7 +1,4 @@
" Tests for startup using utf-8.
-if !has('multi_byte')
- finish
-endif
source shared.vim
" source screendump.vim
@@ -66,7 +63,7 @@ endfunc
func Test_detect_ambiwidth()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
" Use the title termcap entries to output the escape sequence.
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index ea29da0262..b86340a23a 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -86,11 +86,8 @@ func Test_statusline()
call assert_match('^Xstatusline\s*$', s:get_statusline())
" %F: Full path to the file in the buffer.
- let shellslash = &shellslash
- set shellslash
set statusline=%F
call assert_match('/testdir/Xstatusline\s*$', s:get_statusline())
- let &shellslash = shellslash
" %h: Help buffer flag, text is "[help]".
" %H: Help buffer flag, text is ",HLP".
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index a3de879b2a..fc0dc6693c 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -470,7 +470,7 @@ func Test_bg_detection()
hi Normal ctermbg=NONE
endfunc
-fun Test_synstack_synIDtrans()
+func Test_synstack_synIDtrans()
new
setfiletype c
syntax on
@@ -494,6 +494,39 @@ fun Test_synstack_synIDtrans()
bw!
endfunc
+" Check highlighting for a small piece of C code with a screen dump.
+func Test_syntax_c()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot make screendumps'
+ endif
+ call writefile([
+ \ '/* comment line at the top */',
+ \ ' int',
+ \ 'main(int argc, char **argv)// another comment',
+ \ '{',
+ \ '#if 0',
+ \ ' int not_used;',
+ \ '#else',
+ \ ' int used;',
+ \ '#endif',
+ \ ' printf("Just an example piece of C code\n");',
+ \ ' return 0x0ff;',
+ \ '}',
+ \ ' static void',
+ \ 'myFunction(const double count, struct nothing, long there) {',
+ \ ' // 123: nothing to read here',
+ \ ' for (int i = 0; i < count; ++i) {',
+ \ ' break;',
+ \ ' }',
+ \ '}',
+ \ ], 'Xtest.c')
+ let buf = RunVimInTerminal('Xtest.c', {})
+ call VerifyScreenDump(buf, 'Test_syntax_c_01')
+ call StopVimInTerminal(buf)
+
+ call delete('Xtest.c')
+endfun
+
" Using \z() in a region with NFA failing should not crash.
func Test_syn_wrong_z_one()
new
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 8043d13433..c35ddc4473 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -558,7 +558,7 @@ endfunc
func Test_tabpage_cmdheight()
if !CanRunVimInTerminal()
- throw 'Skipped: only works with terminal'
+ throw 'Skipped: cannot make screendumps'
endif
call writefile([
\ 'set laststatus=2',
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 9384989a35..24c735865c 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -48,7 +48,7 @@ func Test_repeat_many()
endif
sleep 200m
call timer_stop(timer)
- call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(4), g:val)
+ call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(5), g:val)
endfunc
func Test_with_partial_callback()
diff --git a/src/nvim/testdir/test_true_false.vim b/src/nvim/testdir/test_true_false.vim
index ad865bb113..84aca737ac 100644
--- a/src/nvim/testdir/test_true_false.vim
+++ b/src/nvim/testdir/test_true_false.vim
@@ -57,9 +57,6 @@ endfunc
" Test using TRUE or FALSE values for an argument.
func Test_true_false_arg()
- let shellslash = &shellslash
- let wildignore = &wildignore
- set shellslash
call Try_arg_true_false('count(["a", "A"], "a", %v%)', 1, 2)
set wildignore=*.swp
@@ -113,8 +110,6 @@ func Test_true_false_arg()
let here_id = synID(1, 3, 0)
call Try_arg_true_false('synID(1, 3, %v%)', here_id, brackets_id)
bwipe!
- let &wildignore = wildignore
- let &shellslash = shellslash
endfunc
function Try_arg_non_zero(expr, false_val, true_val)
@@ -134,8 +129,6 @@ func Test_non_zero_arg()
" call test_settime(93784)
" call Try_arg_non_zero("mode(%v%)", 'x', 'x!')
" call test_settime(0)
- let shellslash = &shellslash
- set shellslash
call Try_arg_non_zero("shellescape('foo%', %v%)", "'foo%'", "'foo\\%'")
@@ -154,6 +147,4 @@ func Test_non_zero_arg()
let r = visualmode(v)
call assert_equal('', r, 'result for ' . v . ' is not "" but ' . r)
endfor
-
- let &shellslash = shellslash
endfunc
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 0cb5dc4033..86674889ef 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -376,10 +376,9 @@ funct Test_undofile()
" Replace windows drive such as C:... into C%...
let cwd = substitute(cwd, '^\([a-zA-Z]\):', '\1%', 'g')
endif
- let pathsep = has('win32') ? '\' : '/'
- let cwd = substitute(cwd . pathsep . 'Xundofoo', pathsep, '%', 'g')
+ let cwd = substitute(cwd . '/Xundofoo', '/', '%', 'g')
if has('persistent_undo')
- call assert_equal('Xundodir' . pathsep . cwd, undofile('Xundofoo'))
+ call assert_equal('Xundodir/' . cwd, undofile('Xundofoo'))
else
call assert_equal('', undofile('Xundofoo'))
endif
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index b23a4aa62f..2c7cb7bab7 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -201,7 +201,6 @@ func Test_CmdErrors()
call assert_fails('com! docmd :', 'E183:')
call assert_fails('com! \<Tab> :', 'E182:')
call assert_fails('com! _ :', 'E182:')
- call assert_fails('com! X :', 'E841:')
call assert_fails('com! - DoCmd :', 'E175:')
call assert_fails('com! -xxx DoCmd :', 'E181:')
call assert_fails('com! -addr DoCmd :', 'E179:')
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index 24e3db86fb..b1f33f56dd 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -1,7 +1,4 @@
" Tests for Unicode manipulations
-if !has('multi_byte')
- finish
-endif
" Visual block Insert adjusts for multi-byte char
diff --git a/src/nvim/testdir/test_utf8_comparisons.vim b/src/nvim/testdir/test_utf8_comparisons.vim
index 576e86142f..1fc670aafd 100644
--- a/src/nvim/testdir/test_utf8_comparisons.vim
+++ b/src/nvim/testdir/test_utf8_comparisons.vim
@@ -1,10 +1,6 @@
" Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c)
" Also test "g~ap".
-if !has("multi_byte")
- finish
-endif
-
function! Ch(a, op, b, expected)
call assert_equal(eval(printf('"%s" %s "%s"', a:a, a:op, a:b)), a:expected,
\ printf('"%s" %s "%s" should return %d', a:a, a:op, a:b, a:expected))
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index abe79f6a4a..67adede8d7 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -48,11 +48,9 @@ func Test_replace_end_of_line()
call setline(1, range(20))
exe "normal! gg2jv10lr-"
call assert_equal(["1", "-----------", "3"], getline(2,4))
- if has('multi_byte')
- call setline(1, range(20))
- exe "normal! gg2jv10lr\<c-k>hh"
- call assert_equal(["1", "───────────", "3"], getline(2,4))
- endif
+ call setline(1, range(20))
+ exe "normal! gg2jv10lr\<c-k>hh"
+ call assert_equal(["1", "───────────", "3"], getline(2,4))
bwipe!
set virtualedit=
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index f69273635c..7fc8cdd7f4 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -2,9 +2,6 @@
func Test_block_shift_multibyte()
" Uses double-wide character.
- if !has('multi_byte')
- return
- endif
split
call setline(1, ['xヹxxx', 'ヹxxx'])
exe "normal 1G0l\<C-V>jl>"
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 2a07a04401..c87c0a0af4 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -42,6 +42,8 @@ function Test_window_cmd_wincmd_gf()
function s:swap_exists()
let v:swapchoice = s:swap_choice
endfunc
+ " Remove the catch-all that runtest.vim adds
+ au! SwapExists
augroup test_window_cmd_wincmd_gf
autocmd!
exec "autocmd SwapExists " . fname . " call s:swap_exists()"
@@ -144,6 +146,21 @@ func Test_window_preview()
call assert_fails('wincmd P', 'E441:')
endfunc
+func Test_window_preview_from_help()
+ filetype on
+ call writefile(['/* some C code */'], 'Xpreview.c')
+ help
+ pedit Xpreview.c
+ wincmd P
+ call assert_equal(1, &previewwindow)
+ call assert_equal('c', &filetype)
+ wincmd z
+
+ filetype off
+ close
+ call delete('Xpreview.c')
+endfunc
+
func Test_window_exchange()
e Xa
@@ -519,6 +536,7 @@ func Test_winrestcmd()
endfunc
function! Fun_RenewFile()
+ " Need to wait a bit for the timestamp to be older.
sleep 2
silent execute '!echo "1" > tmp.txt'
sp
@@ -536,7 +554,6 @@ func Test_window_prevwin()
call writefile(['2'], 'tmp.txt')
new tmp.txt
q
- " Need to wait a bit for the timestamp to be older.
call Fun_RenewFile()
call assert_equal(2, winnr())
wincmd p
diff --git a/src/nvim/testdir/test_wordcount.vim b/src/nvim/testdir/test_wordcount.vim
index 75c4e4bffa..6a3d4109a8 100644
--- a/src/nvim/testdir/test_wordcount.vim
+++ b/src/nvim/testdir/test_wordcount.vim
@@ -1,9 +1,5 @@
" Test for wordcount() function
-if !has('multi_byte')
- finish
-endif
-
func Test_wordcount()
let save_enc = &enc
set encoding=utf-8
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index 6d88c0d8cd..6066d61af4 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -33,7 +33,7 @@ func Test_writefile_fails_gently()
endfunc
func Test_writefile_fails_conversion()
- if !has('multi_byte') || !has('iconv') || system('uname -s') =~ 'SunOS'
+ if !has('iconv') || system('uname -s') =~ 'SunOS'
return
endif
" Without a backup file the write won't happen if there is a conversion
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 519ef1cccd..9fdc6eceba 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -103,6 +103,7 @@ typedef struct {
bool busy, is_invisible;
bool cork, overflow;
bool cursor_color_changed;
+ bool is_starting;
cursorentry_T cursor_shapes[SHAPE_IDX_COUNT];
HlAttrs clear_attrs;
kvec_t(HlAttrs) attrs;
@@ -122,8 +123,9 @@ typedef struct {
int reset_scroll_region;
int set_cursor_style, reset_cursor_style;
int save_title, restore_title;
- int enter_undercurl_mode, exit_undercurl_mode, set_underline_color;
int get_bg;
+ int set_underline_style;
+ int set_underline_color;
} unibi_ext;
char *space_buf;
} TUIData;
@@ -215,6 +217,7 @@ static void terminfo_start(UI *ui)
data->unibi_ext.set_cursor_style = -1;
data->unibi_ext.reset_cursor_style = -1;
data->unibi_ext.get_bg = -1;
+ data->unibi_ext.set_underline_color = -1;
data->out_fd = 1;
data->out_isatty = os_isatty(data->out_fd);
@@ -396,6 +399,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
ui->data = data;
data->bridge = bridge;
data->loop = &tui_loop;
+ data->is_starting = true;
kv_init(data->invalid_regions);
signal_watcher_init(data->loop, &data->winch_handle, ui);
signal_watcher_init(data->loop, &data->cont_handle, data);
@@ -532,7 +536,7 @@ static void update_attrs(UI *ui, int attr_id)
bool underline;
bool undercurl;
- if (data->unibi_ext.enter_undercurl_mode) {
+ if (data->unibi_ext.set_underline_style != -1) {
underline = attr & HL_UNDERLINE;
undercurl = attr & HL_UNDERCURL;
} else {
@@ -575,10 +579,11 @@ static void update_attrs(UI *ui, int attr_id)
if (italic) {
unibi_out(ui, unibi_enter_italics_mode);
}
- if (undercurl && data->unibi_ext.enter_undercurl_mode) {
- unibi_out_ext(ui, data->unibi_ext.enter_undercurl_mode);
+ if (undercurl && data->unibi_ext.set_underline_style != -1) {
+ UNIBI_SET_NUM_VAR(data->params[0], 3);
+ unibi_out_ext(ui, data->unibi_ext.set_underline_style);
}
- if ((undercurl || underline) && data->unibi_ext.set_underline_color) {
+ if ((undercurl || underline) && data->unibi_ext.set_underline_color != -1) {
int color = attrs.rgb_sp_color;
if (color != -1) {
UNIBI_SET_NUM_VAR(data->params[0], (color >> 16) & 0xff); // red
@@ -888,7 +893,7 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
r->right = MIN(r->right, grid->width);
}
- if (!got_winch && (!starting || did_user_set_dimensions)) {
+ if (!got_winch && (!data->is_starting || did_user_set_dimensions)) {
// Resize the _host_ terminal.
UNIBI_SET_NUM_VAR(data->params[0], (int)height);
UNIBI_SET_NUM_VAR(data->params[1], (int)width);
@@ -1051,6 +1056,7 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
{
TUIData *data = ui->data;
tui_set_mode(ui, (ModeShape)mode_idx);
+ data->is_starting = false; // mode entered, no longer starting
data->showing_mode = (ModeShape)mode_idx;
}
@@ -1355,7 +1361,7 @@ static void tui_guess_size(UI *ui)
int width = 0, height = 0;
// 1 - look for non-default 'columns' and 'lines' options during startup
- if (starting && (Columns != DFLT_COLS || Rows != DFLT_ROWS)) {
+ if (data->is_starting && (Columns != DFLT_COLS || Rows != DFLT_ROWS)) {
did_user_set_dimensions = true;
assert(Columns >= INT_MIN && Columns <= INT_MAX);
assert(Rows >= INT_MIN && Rows <= INT_MAX);
@@ -1908,13 +1914,19 @@ static void augment_terminfo(TUIData *data, const char *term,
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(
ut, "ext.disable_mouse", "\x1b[?1002l\x1b[?1006l");
- int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
- if (vte_version >= 5102
- || (ext_bool_Su != -1 && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
- data->unibi_ext.enter_undercurl_mode = (int)unibi_add_ext_str(
- ut, "ext.enter_undercurl_mode", "\x1b[4:3m");
- data->unibi_ext.exit_undercurl_mode = (int)unibi_add_ext_str(
- ut, "ext.exit_undercurl_mode", "\x1b[4:0m");
+ // Extended underline.
+ // terminfo will have Smulx for this (but no support for colors yet).
+ data->unibi_ext.set_underline_style = unibi_find_ext_str(ut, "Smulx");
+ if (data->unibi_ext.set_underline_style == -1) {
+ int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
+ if (vte_version >= 5102
+ || (ext_bool_Su != -1
+ && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
+ data->unibi_ext.set_underline_style = (int)unibi_add_ext_str(
+ ut, "ext.set_underline_style", "\x1b[4:%p1%dm");
+ }
+ }
+ if (data->unibi_ext.set_underline_style != -1) {
// Only support colon syntax. #9270
data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(
ut, "ext.set_underline_color", "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 2cb3cf7ee7..9517b362af 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -480,8 +480,26 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
if (curgrid != &default_grid) {
flags = flags & ~kLineFlagWrap;
}
- assert(row < default_grid.Rows);
- assert(clearcol <= default_grid.Columns);
+
+ assert(endcol <= clearcol);
+
+ // TODO(bfredl): this should not really be necessary. But on some condition
+ // when resizing nvim, a window will be attempted to be drawn on the older
+ // and possibly larger global screen size.
+ if (row >= default_grid.Rows) {
+ DLOG("compositor: invalid row %"PRId64" on grid %"PRId64, row, grid);
+ return;
+ }
+ if (clearcol > default_grid.Columns) {
+ DLOG("compositor: invalid last column %"PRId64" on grid %"PRId64,
+ clearcol, grid);
+ if (startcol >= default_grid.Columns) {
+ return;
+ }
+ clearcol = default_grid.Columns;
+ endcol = MIN(endcol, clearcol);
+ }
+
if (flags & kLineFlagInvalid
|| kv_size(layers) > curgrid->comp_index+1
|| curgrid->blending) {
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 3e0a5907be..60737014b3 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -287,9 +287,10 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
// functions of these names. The declarations would break if the defines had
// been seen at that stage. But it must be before globals.h, where error_ga
// is declared.
-#define mch_errmsg(str) fprintf(stderr, "%s", (str))
-#define display_errors() fflush(stderr)
-#define mch_msg(str) printf("%s", (str))
+#ifndef WIN32
+# define mch_errmsg(str) fprintf(stderr, "%s", (str))
+# define mch_msg(str) printf("%s", (str))
+#endif
#include "nvim/globals.h" // global variables and messages
#include "nvim/buffer_defs.h" // buffer and windows
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 22a8969b88..4173245439 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -598,6 +598,7 @@ void win_set_minimal_style(win_T *wp)
wp->w_p_cuc = false;
wp->w_p_spell = false;
wp->w_p_list = false;
+ wp->w_p_fdc = 0;
// Hide EOB region: use " " fillchar and cleared highlighting
if (wp->w_p_fcs_chars.eob != ' ') {
@@ -615,6 +616,7 @@ void win_set_minimal_style(win_T *wp)
xfree(old);
}
+ // signcolumn: use 'auto'
if (wp->w_p_scl[0] != 'a') {
xfree(wp->w_p_scl);
wp->w_p_scl = (char_u *)xstrdup("auto");
diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua
index e11e03203f..063d382790 100644
--- a/test/functional/api/proc_spec.lua
+++ b/test/functional/api/proc_spec.lua
@@ -4,8 +4,8 @@ local clear = helpers.clear
local eq = helpers.eq
local funcs = helpers.funcs
local iswin = helpers.iswin
+local neq = helpers.neq
local nvim_argv = helpers.nvim_argv
-local ok = helpers.ok
local request = helpers.request
local retry = helpers.retry
local NIL = helpers.NIL
@@ -63,8 +63,9 @@ describe('api', function()
local pid = funcs.getpid()
local pinfo = request('nvim_get_proc', pid)
eq((iswin() and 'nvim.exe' or 'nvim'), pinfo.name)
- ok(pinfo.pid == pid)
- ok(type(pinfo.ppid) == 'number' and pinfo.ppid ~= pid)
+ eq(pinfo.pid, pid)
+ eq(type(pinfo.ppid), 'number')
+ neq(pinfo.ppid, pid)
end)
it('validates input', function()
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index dbe9f20412..ddd044a10f 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -169,8 +169,7 @@ describe('server -> client', function()
if method == "notification" then
eq('done!', eval('rpcrequest('..cid..', "nested")'))
elseif method == "nested_done" then
- -- this should never have been sent
- ok(false)
+ ok(false, 'this should never have been sent')
end
end
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 110b3a4b16..cd45914552 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -178,6 +178,11 @@ describe('API', function()
-- Verify NO hit-enter prompt.
eq({mode='n', blocking=false}, nvim("get_mode"))
end)
+
+ it('Does not cause heap buffer overflow with large output', function()
+ eq(eval('string(range(1000000))'),
+ nvim('command_output', 'echo range(1000000)'))
+ end)
end)
describe('nvim_eval', function()
@@ -1148,6 +1153,13 @@ describe('API', function()
before_each(function()
meths.set_option('isident', '')
end)
+
+ local it_maybe_pending = it
+ if (helpers.isCI('appveyor') and os.getenv('CONFIGURATION') == 'MSVC_32') then
+ -- For "works with &opt" (flaky on MSVC_32), but not easy to skip alone. #10241
+ it_maybe_pending = pending
+ end
+
local function simplify_east_api_node(line, east_api_node)
if east_api_node == NIL then
return nil
@@ -1345,7 +1357,7 @@ describe('API', function()
end
assert:set_parameter('TableFormatLevel', 1000000)
require('test.unit.viml.expressions.parser_tests')(
- it, _check_parsing, hl, fmtn)
+ it_maybe_pending, _check_parsing, hl, fmtn)
end)
describe('nvim_list_uis', function()
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 180ed9aa02..2531b45521 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -707,11 +707,10 @@ describe('jobs', function()
it('will return -1 if the wait timed out', function()
source([[
call rpcnotify(g:channel, 'wait', jobwait([
- \ jobstart('exit 4'),
\ jobstart((has('win32') ? 'Start-Sleep 10' : 'sleep 10').'; exit 5'),
- \ ], has('win32') ? 6000 : 100))
+ \ ], 100))
]])
- eq({'notification', 'wait', {{4, -1}}}, next_msg())
+ eq({'notification', 'wait', {{-1}}}, next_msg())
end)
it('can pass 0 to check if a job exists', function()
@@ -769,16 +768,79 @@ describe('jobs', function()
-- ..c.."', '-c', '"..c.."'])")
-- Create child with several descendants.
+ if iswin() then
+ source([[
+ function! s:formatprocs(pid, prefix)
+ let result = ''
+ let result .= a:prefix . printf("%-24.24s%6s %12.12s %s\n",
+ \ s:procs[a:pid]['name'],
+ \ a:pid,
+ \ s:procs[a:pid]['Session Name'],
+ \ s:procs[a:pid]['Session'])
+ if has_key(s:procs[a:pid], 'children')
+ for pid in s:procs[a:pid]['children']
+ let result .= s:formatprocs(pid, a:prefix . ' ')
+ endfor
+ endif
+ return result
+ endfunction
+
+ function! PsTree() abort
+ let s:procs = {}
+ for proc in map(
+ \ map(
+ \ systemlist('tasklist /NH'),
+ \ 'substitute(v:val, "\r", "", "")'),
+ \ 'split(v:val, "\\s\\+")')
+ if len(proc) == 6
+ let s:procs[proc[1]] ..']]'..[[= {'name': proc[0],
+ \ 'Session Name': proc[2],
+ \ 'Session': proc[3]}
+ endif
+ endfor
+ for pid in keys(s:procs)
+ let children = nvim_get_proc_children(str2nr(pid))
+ if !empty(children)
+ let s:procs[pid]['children'] = children
+ for cpid in children
+ let s:procs[printf('%d', cpid)]['parent'] = str2nr(pid)
+ endfor
+ endif
+ endfor
+ let result = ''
+ for pid in sort(keys(s:procs), {i1, i2 -> i1 - i2})
+ if !has_key(s:procs[pid], 'parent')
+ let result .= s:formatprocs(pid, '')
+ endif
+ endfor
+ return result
+ endfunction
+ ]])
+ end
local sleep_cmd = (iswin()
and 'ping -n 31 127.0.0.1'
or 'sleep 30')
local j = eval("jobstart('"..sleep_cmd..' | '..sleep_cmd..' | '..sleep_cmd.."')")
local ppid = funcs.jobpid(j)
local children
- retry(nil, nil, function()
- children = meths.get_proc_children(ppid)
- eq((iswin() and 4 or 3), #children)
- end)
+ if iswin() then
+ local status, result = pcall(retry, nil, nil, function()
+ children = meths.get_proc_children(ppid)
+ -- On Windows conhost.exe may exist, and
+ -- e.g. vctip.exe might appear. #10783
+ ok(#children >= 3 and #children <= 5)
+ end)
+ if not status then
+ print('')
+ print(eval('PsTree()'))
+ error(result)
+ end
+ else
+ retry(nil, nil, function()
+ children = meths.get_proc_children(ppid)
+ eq(3, #children)
+ end)
+ end
-- Assert that nvim_get_proc() sees the children.
for _, child_pid in ipairs(children) do
local info = meths.get_proc(child_pid)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 62a45fdf88..3b32c42ec0 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -226,6 +226,31 @@ describe('startup', function()
clear{env={CDPATH='~doesnotexist'}}
eq(',~doesnotexist', eval('&cdpath'))
end)
+
+ it('ENTER dismisses early message #7967', function()
+ local screen
+ screen = Screen.new(60, 6)
+ screen:attach()
+ command([[let g:id = termopen('"]]..nvim_prog..
+ [[" -u NONE -i NONE --cmd "set noruler" --cmd "let g:foo = g:bar"')]])
+ screen:expect([[
+ ^ |
+ Error detected while processing pre-vimrc command line: |
+ E121: Undefined variable: g:bar |
+ E15: Invalid expression: g:bar |
+ Press ENTER or type command to continue |
+ |
+ ]])
+ command([[call chansend(g:id, "\n")]])
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ [No Name] |
+ |
+ |
+ ]])
+ end)
end)
describe('sysinit', function()
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua
index cd099e30ed..5c5b1b42cb 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/eval/timer_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local feed, eq, eval = helpers.feed, helpers.eq, helpers.eval
+local feed, eq, eval, ok = helpers.feed, helpers.eq, helpers.eval, helpers.ok
local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs
local curbufmeths = helpers.curbufmeths
@@ -19,59 +19,71 @@ describe('timers', function()
end)
it('works one-shot', function()
- command("call timer_start(50, 'MyHandler')")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(200))
+ eq(0, eval("[timer_start(10, 'MyHandler'), g:val][1]"))
+ run(nil, nil, nil, load_adjust(100))
eq(1,eval("g:val"))
end)
it('works one-shot when repeat=0', function()
- command("call timer_start(50, 'MyHandler', {'repeat': 0})")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(200))
- eq(1,eval("g:val"))
+ eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 0}), g:val][1]"))
+ run(nil, nil, nil, load_adjust(100))
+ eq(1, eval("g:val"))
end)
-
it('works with repeat two', function()
- command("call timer_start(50, 'MyHandler', {'repeat': 2})")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(300))
- eq(2,eval("g:val"))
+ eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
+ run(nil, nil, nil, load_adjust(20))
+ retry(nil, load_adjust(300), function()
+ eq(2, eval("g:val"))
+ end)
end)
it('are triggered during sleep', function()
- command("call timer_start(50, 'MyHandler', {'repeat': 2})")
+ source([[
+ let g:val = -1
+ func! MyHandler(timer)
+ if g:val >= 0
+ let g:val += 1
+ if g:val == 2
+ call timer_stop(a:timer)
+ endif
+ endif
+ endfunc
+ ]])
+ eval("timer_start(10, 'MyHandler', {'repeat': -1})")
nvim_async("command", "sleep 10")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(300))
- eq(2,eval("g:val"))
+ eq(-1, eval("g:val")) -- timer did nothing yet.
+ nvim_async("command", "let g:val = 0")
+ run(nil, nil, nil, load_adjust(20))
+ retry(nil, nil, function()
+ eq(2, eval("g:val"))
+ end)
end)
it('works with zero timeout', function()
-- timer_start does still not invoke the callback immediately
- eq(0,eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
- run(nil, nil, nil, load_adjust(400))
- eq(1000,eval("g:val"))
+ eq(0, eval("[timer_start(0, 'MyHandler', {'repeat': 1000}), g:val][1]"))
+ retry(nil, nil, function()
+ eq(1000, eval("g:val"))
+ end)
end)
it('can be started during sleep', function()
nvim_async("command", "sleep 10")
-- this also tests that remote requests works during sleep
- eval("timer_start(50, 'MyHandler', {'repeat': 2})")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(300))
- eq(2,eval("g:val"))
+ eq(0, eval("[timer_start(10, 'MyHandler', {'repeat': 2}), g:val][1]"))
+ run(nil, nil, nil, load_adjust(20))
+ retry(nil, load_adjust(300), function() eq(2,eval("g:val")) end)
end)
it('are paused when event processing is disabled', function()
- command("call timer_start(50, 'MyHandler', {'repeat': -1})")
- run(nil, nil, nil, load_adjust(100))
+ command("call timer_start(5, 'MyHandler', {'repeat': -1})")
+ run(nil, nil, nil, load_adjust(10))
local count = eval("g:val")
-- shows two line error message and thus invokes the return prompt.
-- if we start to allow event processing here, we need to change this test.
feed(':throw "fatal error"<CR>')
- run(nil, nil, nil, load_adjust(300))
+ run(nil, nil, nil, load_adjust(30))
feed("<cr>")
local diff = eval("g:val") - count
assert(0 <= diff and diff <= 4,
@@ -79,12 +91,14 @@ describe('timers', function()
end)
it('are triggered in blocking getchar() call', function()
- command("call timer_start(50, 'MyHandler', {'repeat': -1})")
- nvim_async("command", "let g:c = getchar()")
- run(nil, nil, nil, load_adjust(300))
+ command("call timer_start(5, 'MyHandler', {'repeat': -1})")
+ nvim_async("command", "let g:val = 0 | let g:c = getchar()")
+ retry(nil, nil, function()
+ local val = eval("g:val")
+ ok(val >= 2, "expected >= 2, got: "..tostring(val))
+ eq(0, eval("getchar(1)"))
+ end)
feed("c")
- local count = eval("g:val")
- assert(count >= 3, 'expected count >= 3, got: '..tostring(count))
eq(99, eval("g:c"))
end)
@@ -99,12 +113,15 @@ describe('timers', function()
source([[
func! AddItem(timer)
call nvim_buf_set_lines(0, 2, 2, v:true, ['ITEM 3'])
+
+ " Meant to test for what Vim tests in Test_peek_and_get_char.
call getchar(1)
+
redraw
endfunc
- call timer_start(200, 'AddItem')
]])
nvim_async("command", "let g:c2 = getchar()")
+ nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem')")
screen:expect([[
ITEM 1 |
@@ -137,18 +154,15 @@ describe('timers', function()
end)
it('can be stopped', function()
- local t = eval("timer_start(50, 'MyHandler', {'repeat': -1})")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(300))
- funcs.timer_stop(t)
+ local t_init_val = eval("[timer_start(5, 'MyHandler', {'repeat': -1}), g:val]")
+ eq(0, t_init_val[2])
+ run(nil, nil, nil, load_adjust(30))
+ funcs.timer_stop(t_init_val[1])
local count = eval("g:val")
- run(nil, nil, nil, load_adjust(300))
+ run(nil, load_adjust(300), nil, load_adjust(30))
local count2 = eval("g:val")
-- when count is eval:ed after timer_stop this should be non-racy
eq(count, count2)
- assert((3 <= count and count <= load_adjust(7)),
- string.format('expected (3 <= count <= %s), got: %s',
- load_adjust(7), tostring(count)))
end)
it('can be stopped from the handler', function()
@@ -162,10 +176,9 @@ describe('timers', function()
endif
endfunc
]])
+ eq(0, eval("g:val"))
command("call timer_start(10, 'MyHandler', {'repeat': -1})")
- eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(50))
- retry(nil, 5000, function()
+ retry(nil, nil, function()
eq(3, eval("g:val"))
end)
end)
@@ -177,9 +190,9 @@ describe('timers', function()
let g:val2 += 1
endfunc
]])
- command("call timer_start(20, 'MyHandler', {'repeat': 3})")
- command("call timer_start(40, 'MyHandler2', {'repeat': 2})")
- run(nil, nil, nil, load_adjust(300))
+ command("call timer_start(2, 'MyHandler', {'repeat': 3})")
+ command("call timer_start(4, 'MyHandler2', {'repeat': 2})")
+ run(nil, nil, nil, load_adjust(30))
eq(3,eval("g:val"))
eq(2,eval("g:val2"))
end)
@@ -189,13 +202,15 @@ describe('timers', function()
let g:val = 0
func! MyHandler(timer)
call timer_stop(a:timer)
- sleep 100m
+ sleep 10m
let g:val += 1
endfunc
]])
command("call timer_start(5, 'MyHandler', {'repeat': 1})")
- run(nil, nil, nil, load_adjust(300))
- eq(1,eval("g:val"))
+ run(nil, nil, nil, load_adjust(10))
+ retry(nil, load_adjust(100), function()
+ eq(1, eval("g:val"))
+ end)
end)
@@ -232,5 +247,4 @@ describe('timers', function()
eq(1, eval('g:val'))
end)
-
end)
diff --git a/test/functional/fixtures/tty-test.c b/test/functional/fixtures/tty-test.c
index e2a78a594b..4438b73a22 100644
--- a/test/functional/fixtures/tty-test.c
+++ b/test/functional/fixtures/tty-test.c
@@ -38,6 +38,9 @@ bool owns_tty(void)
static void walk_cb(uv_handle_t *handle, void *arg)
{
if (!uv_is_closing(handle)) {
+#ifdef WIN32
+ uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL);
+#endif
uv_close(handle, NULL);
}
}
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index d4ace3030c..d040ff5f8c 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -445,6 +445,8 @@ function module.new_argv(...)
for _, k in ipairs({
'HOME',
'ASAN_OPTIONS',
+ 'TSAN_OPTIONS',
+ 'MSAN_OPTIONS',
'LD_LIBRARY_PATH',
'PATH',
'NVIM_LOG_FILE',
diff --git a/test/functional/legacy/055_list_and_dict_types_spec.lua b/test/functional/legacy/055_list_and_dict_types_spec.lua
index dcbd8b7dff..91ba8bb106 100644
--- a/test/functional/legacy/055_list_and_dict_types_spec.lua
+++ b/test/functional/legacy/055_list_and_dict_types_spec.lua
@@ -666,7 +666,7 @@ describe('list and dictionary types', function()
Vim(put):E741:
{'a': 99, 'b': 100}
No remove() of write-protected scope-level variable:
- Vim(put):E795:
+ Vim(put):E742:
No extend() of write-protected scope-level variable:
Vim(put):E742:
No :unlet of variable in locked scope:
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index 68d4d1e2a1..a3c6c57a73 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -90,6 +90,12 @@ describe('python3 provider', function()
eq({1, 2, {['key'] = 'val'}}, eval([[py3eval('[1, 2, {"key": "val"}]')]]))
end)
+ it('pyxeval #10758', function()
+ eq(0, eval([[&pyxversion]]))
+ eq(3, eval([[pyxeval('sys.version_info[:3][0]')]]))
+ eq(3, eval([[&pyxversion]]))
+ end)
+
it('RPC call to expand("<afile>") during BufDelete #5245 #5617', function()
source([=[
python3 << EOF
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index e598c325a8..1763574bf9 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -158,14 +158,15 @@ describe(':terminal buffer', function()
end)
it('handles loss of focus gracefully', function()
- if helpers.pending_win32(pending) then return end
-- Change the statusline to avoid printing the file name, which varies.
nvim('set_option', 'statusline', '==========')
feed_command('set laststatus=0')
-- Save the buffer number of the terminal for later testing.
local tbuf = eval('bufnr("%")')
-
+ local exitcmd = helpers.iswin()
+ and "['cmd', '/c', 'exit']"
+ or "['sh', '-c', 'exit']"
source([[
function! SplitWindow(id, data, event)
new
@@ -173,7 +174,7 @@ describe(':terminal buffer', function()
endfunction
startinsert
- call jobstart(['sh', '-c', 'exit'], {'on_exit': function("SplitWindow")})
+ call jobstart(]]..exitcmd..[[, {'on_exit': function("SplitWindow")})
call feedkeys("\<C-\>", 't') " vim will expect <C-n>, but be exited out of
" the terminal before it can be entered.
]])
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index ad70b3d14f..7b49a38e77 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -37,7 +37,6 @@ describe(':terminal', function()
end)
it('does not change size on WinEnter', function()
- if helpers.pending_win32(pending) then return end
feed('<c-\\><c-n>')
feed('k')
feed_command('2split')
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 8a1758c4a0..8dfe36c799 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -383,6 +383,7 @@ describe('floating windows', function()
command('set number')
command('set signcolumn=yes')
command('set cursorline')
+ command('set foldcolumn=1')
command('hi NormalFloat guibg=#333333')
feed('ix<cr>y<cr><esc>gg')
local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
@@ -397,9 +398,9 @@ describe('floating windows', function()
[2:----------------------------------------]|
|
## grid 2
- {19: }{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } |
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -410,15 +411,15 @@ describe('floating windows', function()
{15: }|
]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
- screen:expect([[
- {19: }{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } {15:x } |
+ screen:expect{grid=[[
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15:x } |
{0:~ }{15:y }{0: }|
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
|
- ]])
+ ]]}
end
-- signcolumn=yes still works if there actually are signs
@@ -435,9 +436,9 @@ describe('floating windows', function()
[2:----------------------------------------]|
|
## grid 2
- {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } |
+ {19: }{17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -450,9 +451,9 @@ describe('floating windows', function()
else
screen:expect([[
- {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{15:x } |
+ {19: }{17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {17:πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„πŒ’Μ€ΜΜ‚ΜƒΜ…Μ„}{15:x } |
{0:~ }{19: }{15:y }{0: }|
{0:~ }{19: }{15: }{0: }|
{0:~ }{15: }{0: }|
@@ -474,9 +475,9 @@ describe('floating windows', function()
[2:----------------------------------------]|
|
## grid 2
- {19: }{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } |
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
{0:~ }|
{0:~ }|
{0:~ }|
@@ -488,9 +489,9 @@ describe('floating windows', function()
]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
- {19: }{20: 1 }{21:^x }|
- {19: }{14: 2 }y |
- {19: }{14: 3 } {15: } |
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15: } |
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
{0:~ }{15: }{0: }|
@@ -4143,14 +4144,14 @@ describe('floating windows', function()
[4:----------------------------------------]|
[4:----------------------------------------]|
:tabnew |
- ## grid 2
+ ## grid 2 (hidden)
x |
{0:~ }|
{0:~ }|
{0:~ }|
{0:~ }|
{0:~ }|
- ## grid 3
+ ## grid 3 (hidden)
{1:y }|
{2:~ }|
## grid 4
@@ -4192,7 +4193,7 @@ describe('floating windows', function()
## grid 3
{1:y }|
{2:~ }|
- ## grid 4
+ ## grid 4 (hidden)
|
{0:~ }|
{0:~ }|
@@ -4222,13 +4223,13 @@ describe('floating windows', function()
[4:----------------------------------------]|
[4:----------------------------------------]|
:tabnext |
- ## grid 2
+ ## grid 2 (hidden)
x |
{0:~ }|
{0:~ }|
{0:~ }|
{0:~ }|
- ## grid 3
+ ## grid 3 (hidden)
{1:y }|
{2:~ }|
## grid 4
@@ -4266,7 +4267,7 @@ describe('floating windows', function()
[4:----------------------------------------]|
[4:----------------------------------------]|
:tabnew |
- ## grid 2
+ ## grid 2 (hidden)
x |
{0:~ }|
{0:~ }|
@@ -4312,7 +4313,7 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
{0:~ }|
- ## grid 4
+ ## grid 4 (hidden)
|
{0:~ }|
{0:~ }|
@@ -4332,7 +4333,7 @@ describe('floating windows', function()
[4:----------------------------------------]|
[4:----------------------------------------]|
:tabnext |
- ## grid 2
+ ## grid 2 (hidden)
x |
{0:~ }|
{0:~ }|
@@ -4364,7 +4365,11 @@ describe('floating windows', function()
[5] = {foreground = tonumber('0x990000'), background = tonumber('0xfff1ff')},
[6] = {foreground = tonumber('0x332533'), background = tonumber('0xfff1ff')},
[7] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0x0000d8')},
- [8] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}
+ [8] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
+ [9] = {background = Screen.colors.LightMagenta, blend=30},
+ [10] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=0},
+ [11] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=80},
+ [12] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1, blend=30},
})
insert([[
Lorem ipsum dolor sit amet, consectetur
@@ -4444,9 +4449,9 @@ describe('floating windows', function()
qui officia deserunt mollit anim id est |
laborum^. |
## grid 4
- {1:test }|
- {1: }|
- {1:popup text }|
+ {9:test }|
+ {9: }|
+ {9:popup text }|
]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true}
else
screen:expect([[
@@ -4486,9 +4491,9 @@ describe('floating windows', function()
qui officia deserunt mollit anim id est |
laborum^. |
## grid 4
- {1:test }|
- {1: }|
- {4:popup text}{1: }|
+ {9:test }|
+ {9: }|
+ {10:popup text}{9: }|
]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}}
else
screen:expect([[
@@ -4496,7 +4501,7 @@ describe('floating windows', function()
exercitation ullamco laboris nisi ut aliquip ex |
ea co{2:test}{3:o consequat}. Duis aute irure dolor in |
repre{3:henderit in vol}uptate velit esse cillum |
- dolor{4:popup text}{3:ul}la pariatur. Excepteur sint |
+ dolor{10:popup text}{3:ul}la pariatur. Excepteur sint |
occaecat cupidatat non proident, sunt in culpa |
qui officia deserunt mollit anim id est |
laborum^. |
@@ -4527,9 +4532,9 @@ describe('floating windows', function()
qui officia deserunt mollit anim id est |
laborum^. |
## grid 4
- {1:test }|
- {1: }|
- {4:popup text}{1: }|
+ {9:test }|
+ {9: }|
+ {11:popup text}{9: }|
]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true}
else
screen:expect([[
@@ -4569,9 +4574,9 @@ describe('floating windows', function()
qui officia deserunt mollit anim id est |
laborum^. |
## grid 4
- {4:popup text}{1: }|
- {8:~ }|
- {8:~ }|
+ {11:popup text}{9: }|
+ {12:~ }|
+ {12:~ }|
]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}}
else
meths.input_mouse('wheel', 'down', '', 0, 4, 7)
@@ -4671,7 +4676,7 @@ describe('floating windows', function()
[2] = {foreground = Screen.colors.Grey0, background = tonumber('0xffcfff')},
[3] = {bold = true, foreground = Screen.colors.Blue1},
[4] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0xb282ff')},
- [5] = {background = Screen.colors.LightMagenta},
+ [5] = {background = Screen.colors.LightMagenta, blend=30},
})
if multigrid then
screen:expect{grid=[[
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 4f243e6413..238cc368da 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -2634,3 +2634,19 @@ it(':substitute with inccommand, timer-induced :redraw #9777', function()
:%s/foo/ZZZ^ |
]])
end)
+
+it('long :%s/ with inccommand does not collapse cmdline', function()
+ local screen = Screen.new(10,5)
+ clear()
+ common_setup(screen)
+ command('set inccommand=nosplit')
+ feed(':%s/AAAAAAA', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
+ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A')
+ screen:expect([[
+ {15:~ }|
+ {15:~ }|
+ :%s/AAAAAAAA|
+ AAAAAAAAAAAA|
+ AAAAAAA^ |
+ ]])
+end)
diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua
index 121cbe47d6..0009f2c31b 100644
--- a/test/functional/ui/input_spec.lua
+++ b/test/functional/ui/input_spec.lua
@@ -103,6 +103,11 @@ describe('mappings', function()
check_mapping('<kequal>','<kequal>')
check_mapping('<KPEquals>','<kequal>')
end)
+
+ it('support meta + multibyte char mapping', function()
+ add_mapping('<m-Γ€>', '<m-Γ€>')
+ check_mapping('<m-Γ€>', '<m-Γ€>')
+ end)
end)
describe('feeding large chunks of input with <Paste>', function()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 9a1a0f66a2..ed65c4526f 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -6,7 +6,10 @@ local eq = helpers.eq
local command = helpers.command
local set_method_error = helpers.set_method_error
local meths = helpers.meths
-
+local test_build_dir = helpers.test_build_dir
+local nvim_prog = helpers.nvim_prog
+local iswin = helpers.iswin
+local exc_exec = helpers.exc_exec
describe('ui/ext_messages', function()
local screen
@@ -1004,3 +1007,48 @@ describe('ui/ext_messages', function()
}}
end)
end)
+
+describe('ui/msg_puts_printf', function()
+ it('output multibyte characters correctly', function()
+ local screen
+ local cmd = ''
+ local locale_dir = test_build_dir..'/share/locale/ja/LC_MESSAGES'
+
+ clear({env={LANG='ja_JP.UTF-8'}})
+ screen = Screen.new(25, 5)
+ screen:attach()
+
+ if iswin() then
+ if os.execute('chcp 932 > NUL 2>&1') ~= 0 then
+ pending('missing japanese language features', function() end)
+ return
+ else
+ cmd = 'chcp 932 > NULL & '
+ end
+ else
+ if (exc_exec('lang ja_JP.UTF-8') ~= 0) then
+ pending('Locale ja_JP.UTF-8 not supported', function() end)
+ return
+ elseif helpers.isCI() then
+ -- Fails non--Windows CI. Message catalog direcotry issue?
+ pending('fails on unix CI', function() end)
+ return
+ end
+ end
+
+ os.execute('cmake -E make_directory '..locale_dir)
+ os.execute('cmake -E copy '..test_build_dir..'/src/nvim/po/ja.mo '..locale_dir..'/nvim.mo')
+
+ cmd = cmd..'"'..nvim_prog..'" -u NONE -i NONE -Es -V1'
+ command([[call termopen(']]..cmd..[[')]])
+ screen:expect([[
+ ^Exヒードにε…₯γ‚ŠγΎγ™. γƒŽγƒΌ |
+ γƒžγƒ«γƒ’γƒΌγƒ‰γ«ζˆ»γ‚‹γ«γ―"visu|
+ al"とε…₯εŠ›γ—γ¦γγ γ•γ„. |
+ : |
+ |
+ ]])
+
+ os.execute('cmake -E remove_directory '..test_build_dir..'/share')
+ end)
+end)
diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua
index f6b3c1c3c9..a09df075aa 100644
--- a/test/functional/ui/mode_spec.lua
+++ b/test/functional/ui/mode_spec.lua
@@ -2,8 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command, eval = helpers.command, helpers.eval
-local eq = helpers.eq
+local command = helpers.command
describe('ui mode_change event', function()
local screen
@@ -63,7 +62,7 @@ describe('ui mode_change event', function()
]], mode="normal"}
command("set showmatch")
- eq(eval('&matchtime'), 5) -- tenths of seconds
+ command("set matchtime=1") -- tenths of seconds
feed('a(stuff')
screen:expect{grid=[[
word(stuff^ |
@@ -80,7 +79,6 @@ describe('ui mode_change event', function()
{2:-- INSERT --} |
]], mode="showmatch"}
- screen:sleep(400)
screen:expect{grid=[[
word(stuff)^ |
{0:~ }|
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index c5a23e4661..a910f5e2ea 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -76,7 +76,7 @@ describe('ext_multigrid', function()
it('positions windows correctly', function()
command('vsplit')
- screen:expect([[
+ screen:expect{grid=[[
## grid 1
[3:--------------------------]{12:β”‚}[2:--------------------------]|
[3:--------------------------]{12:β”‚}[2:--------------------------]|
@@ -118,15 +118,15 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], nil, nil, function()
+ ]], condition=function()
eq({
- [2] = { win = 1000, startrow = 0, startcol = 27, width = 26, height = 12 },
- [3] = { win = 1001, startrow = 0, startcol = 0, width = 26, height = 12 }
+ [2] = { win = {id=1000}, startrow = 0, startcol = 27, width = 26, height = 12 },
+ [3] = { win = {id=1001}, startrow = 0, startcol = 0, width = 26, height = 12 }
}, screen.win_position)
- end)
+ end}
command('wincmd l')
command('split')
- screen:expect([[
+ screen:expect{grid=[[
## grid 1
[3:--------------------------]{12:β”‚}[4:--------------------------]|
[3:--------------------------]{12:β”‚}[4:--------------------------]|
@@ -168,16 +168,16 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], nil, nil, function()
+ ]], condition=function()
eq({
- [2] = { win = 1000, startrow = 7, startcol = 27, width = 26, height = 5 },
- [3] = { win = 1001, startrow = 0, startcol = 0, width = 26, height = 12 },
- [4] = { win = 1002, startrow = 0, startcol = 27, width = 26, height = 6 }
+ [2] = { win = {id=1000}, startrow = 7, startcol = 27, width = 26, height = 5 },
+ [3] = { win = {id=1001}, startrow = 0, startcol = 0, width = 26, height = 12 },
+ [4] = { win = {id=1002}, startrow = 0, startcol = 27, width = 26, height = 6 }
}, screen.win_position)
- end)
+ end}
command('wincmd h')
command('q')
- screen:expect([[
+ screen:expect{grid=[[
## grid 1
[4:-----------------------------------------------------]|
[4:-----------------------------------------------------]|
@@ -206,12 +206,12 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ]], nil, nil, function()
+ ]], condition=function()
eq({
- [2] = { win = 1000, startrow = 7, startcol = 0, width = 53, height = 5 },
- [4] = { win = 1002, startrow = 0, startcol = 0, width = 53, height = 6 }
+ [2] = { win = {id=1000}, startrow = 7, startcol = 0, width = 53, height = 5 },
+ [4] = { win = {id=1002}, startrow = 0, startcol = 0, width = 53, height = 6 }
}, screen.win_position)
- end)
+ end}
end)
describe('split', function ()
@@ -1206,7 +1206,7 @@ describe('ext_multigrid', function()
]])
end)
- it('handles switich tabs', function()
+ it('handles switch tabs', function()
command('vsp')
screen:expect([[
## grid 1
@@ -1271,7 +1271,7 @@ describe('ext_multigrid', function()
[4:-----------------------------------------------------]|
{11:[No Name] }|
|
- ## grid 2
+ ## grid 2 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1284,7 +1284,7 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ## grid 3
+ ## grid 3 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1328,7 +1328,7 @@ describe('ext_multigrid', function()
[4:-----------------------------------------------------]|
{12:[No Name] }|
|
- ## grid 2
+ ## grid 2 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1341,7 +1341,7 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ## grid 3
+ ## grid 3 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1409,13 +1409,13 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ## grid 4
+ ## grid 4 (hidden)
|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
- ## grid 5
+ ## grid 5 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1440,7 +1440,7 @@ describe('ext_multigrid', function()
[4:-----------------------------------------------------]|
{12:[No Name] }|
|
- ## grid 2
+ ## grid 2 (hidden)
|
{1:~ }|
{1:~ }|
@@ -1452,7 +1452,7 @@ describe('ext_multigrid', function()
{1:~ }|
{1:~ }|
{1:~ }|
- ## grid 3
+ ## grid 3 (hidden)
|
{1:~ }|
{1:~ }|
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 24bf66e2d8..4a0e7ccad0 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -12,8 +12,6 @@ local command = helpers.command
local nvim_dir = helpers.nvim_dir
describe("shell command :!", function()
- if helpers.pending_win32(pending) then return end
-
local screen
before_each(function()
clear()
@@ -36,6 +34,7 @@ describe("shell command :!", function()
end)
it("displays output without LF/EOF. #4646 #4569 #3772", function()
+ if helpers.pending_win32(pending) then return end
-- NOTE: We use a child nvim (within a :term buffer)
-- to avoid triggering a UI flush.
child_session.feed_data(":!printf foo; sleep 200\n")
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 9bfea28ed7..c4cfc9d8d3 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1644,6 +1644,7 @@ describe('builtin popupmenu', function()
[42] = {foreground = tonumber('0x0c0c0c'), background = tonumber('0xe5a8e5')},
[43] = {background = tonumber('0x7f5d7f'), bold = true, foreground = tonumber('0x3f3f3f')},
[44] = {foreground = tonumber('0x3f3f3f'), background = tonumber('0x7f5d7f')},
+ [45] = {background = Screen.colors.WebGray, blend=0},
})
command('syntax on')
command('set mouse=a')
@@ -1761,7 +1762,7 @@ describe('builtin popupmenu', function()
Lorem ipsum d{1:ol}or sit amet, consectetur |
adipisicing elit, sed do eiusmod tempor |
bla bla incididunt^ |
- incidid{22: incididunt }{27: }d{1:ol}ore magna aliqua. |
+ incidid{45: incididunt }{27: }d{1:ol}ore magna aliqua. |
Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud |
exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex |
{2:[No Nam}{30:e}{43:et}{30:[+] }{32: }{2: }|
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 81a15cada2..3b39794465 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -316,9 +316,10 @@ local ext_keys = {
-- cmdline_block: Expected ext_cmdline block (for function definitions)
-- wildmenu_items: Expected items for ext_wildmenu
-- wildmenu_pos: Expected position for ext_wildmenu
-function Screen:expect(expected, attr_ids, attr_ignore)
+function Screen:expect(expected, attr_ids, attr_ignore, ...)
local grid, condition = nil, nil
local expected_rows = {}
+ assert(next({...}) == nil, "invalid args to expect()")
if type(expected) == "table" then
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
@@ -499,7 +500,8 @@ function Screen:_wait(check, flags)
local did_miminal_timeout = false
local function notification_cb(method, args)
- assert(method == 'redraw')
+ assert(method == 'redraw', string.format(
+ 'notification_cb: unexpected method (%s, args=%s)', method, inspect(args)))
did_flush = self:_redraw(args)
if not did_flush then
return
@@ -1211,7 +1213,11 @@ function Screen:render(headers, attr_state, preview)
local rv = {}
for igrid,grid in pairs(self._grids) do
if headers then
- table.insert(rv, "## grid "..igrid)
+ local suffix = ""
+ if igrid > 1 and self.win_position[igrid] == nil and self.float_pos[igrid] == nil then
+ suffix = " (hidden)"
+ end
+ table.insert(rv, "## grid "..igrid..suffix)
end
for i = 1, grid.height do
local cursor = self._cursor.grid == igrid and self._cursor.row == i
@@ -1491,7 +1497,7 @@ function Screen:_equal_attrs(a, b)
a.underline == b.underline and a.undercurl == b.undercurl and
a.italic == b.italic and a.reverse == b.reverse and
a.foreground == b.foreground and a.background == b.background and
- a.special == b.special
+ a.special == b.special and a.blend == b.blend
end
function Screen:_equal_info(a, b)
diff --git a/test/helpers.lua b/test/helpers.lua
index e14bcff2c8..ce5e8b9c04 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -59,8 +59,8 @@ end
function module.neq(expected, actual, context)
return assert.are_not.same(expected, actual, context)
end
-function module.ok(res)
- return assert.is_true(res)
+function module.ok(res, msg)
+ return assert.is_true(res, msg)
end
function module.near(actual, expected, tolerance)
return assert.is.near(actual, expected, tolerance)