aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitattributes1
-rw-r--r--.gitignore3
-rw-r--r--.luacheckrc1
-rw-r--r--.travis.yml139
-rw-r--r--CMakeLists.txt7
-rw-r--r--Makefile2
-rw-r--r--appveyor.yml2
-rw-r--r--busted/outputHandlers/TAP.lua94
-rwxr-xr-xci/before_install.sh13
-rw-r--r--ci/build.ps12
-rwxr-xr-xci/common/submit_coverage.sh3
-rw-r--r--ci/common/test.sh2
-rwxr-xr-xci/script.sh6
-rw-r--r--cmake/GetCompileFlags.cmake8
-rw-r--r--cmake/RunTests.cmake2
-rw-r--r--runtime/autoload/health/provider.vim8
-rw-r--r--runtime/autoload/remote/host.vim2
-rw-r--r--runtime/doc/api.txt8
-rw-r--r--runtime/doc/autocmd.txt6
-rw-r--r--runtime/doc/deprecated.txt5
-rw-r--r--runtime/doc/eval.txt24
-rw-r--r--runtime/doc/options.txt19
-rw-r--r--runtime/doc/ui.txt8
-rw-r--r--runtime/doc/various.txt15
-rwxr-xr-xscripts/pvscheck.sh1
-rwxr-xr-xscripts/stripdecls.py2
-rw-r--r--src/nvim/CMakeLists.txt4
-rw-r--r--src/nvim/api/ui.c1
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/buffer_defs.h14
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/eval.c66
-rw-r--r--src/nvim/eval.lua2
-rw-r--r--src/nvim/eval/typval_encode.c.h2
-rw-r--r--src/nvim/event/process.c10
-rw-r--r--src/nvim/ex_cmds2.c15
-rw-r--r--src/nvim/ex_docmd.c75
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua3
-rw-r--r--src/nvim/getchar.c29
-rw-r--r--src/nvim/globals.h9
-rw-r--r--src/nvim/highlight.c41
-rw-r--r--src/nvim/highlight_defs.h2
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/mark.c73
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/misc1.c20
-rw-r--r--src/nvim/move.c1
-rw-r--r--src/nvim/msgpack_rpc/helpers.c5
-rw-r--r--src/nvim/normal.c23
-rw-r--r--src/nvim/ops.c48
-rw-r--r--src/nvim/option.c13
-rw-r--r--src/nvim/option_defs.h7
-rw-r--r--src/nvim/options.lua7
-rw-r--r--src/nvim/os/fs.c2
-rw-r--r--src/nvim/os/pty_process_unix.c10
-rw-r--r--src/nvim/os/time.c21
-rw-r--r--src/nvim/profile.c48
-rw-r--r--src/nvim/regexp_nfa.c29
-rw-r--r--src/nvim/screen.c27
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/sign.c47
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/syntax.c47
-rw-r--r--src/nvim/testdir/Makefile33
-rw-r--r--src/nvim/testdir/runtest.vim9
-rw-r--r--src/nvim/testdir/test_assert.vim6
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim58
-rw-r--r--src/nvim/testdir/test_functions.vim42
-rw-r--r--src/nvim/testdir/test_source.vim37
-rw-r--r--src/nvim/testdir/test_suspend.vim29
-rw-r--r--src/nvim/testdir/test_window_cmd.vim37
-rw-r--r--src/nvim/ugrid.c4
-rw-r--r--src/nvim/ui.c20
-rw-r--r--src/nvim/ui_compositor.c91
-rw-r--r--src/nvim/window.c232
-rw-r--r--test/busted/outputHandlers/TAP.lua14
-rw-r--r--test/busted/outputHandlers/nvim.lua (renamed from busted/outputHandlers/nvim.lua)19
-rw-r--r--test/functional/autocmd/cursorhold_spec.lua31
-rw-r--r--test/functional/eval/executable_spec.lua9
-rw-r--r--test/functional/eval/reltime_spec.lua14
-rw-r--r--test/functional/eval/system_spec.lua7
-rw-r--r--test/functional/ex_cmds/menu_spec.lua2
-rw-r--r--test/functional/fixtures/shell-test.c17
-rw-r--r--test/functional/terminal/edit_spec.lua7
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua10
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/float_spec.lua769
-rw-r--r--test/functional/ui/highlight_spec.lua32
-rw-r--r--test/functional/ui/messages_spec.lua41
-rw-r--r--test/functional/ui/screen.lua42
-rw-r--r--third-party/CMakeLists.txt11
-rw-r--r--third-party/cmake/BuildGperf.cmake1
-rw-r--r--third-party/cmake/BuildLuarocks.cmake14
-rw-r--r--third-party/cmake/BuildLuv.cmake13
98 files changed, 2119 insertions, 665 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100755
index 0000000000..15a5c58091
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.h linguist-language=C
diff --git a/.gitignore b/.gitignore
index d0315edafa..453211a30e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,3 +55,6 @@ local.mk
/runtime/doc/*.html
/runtime/doc/tags.ref
/runtime/doc/errors.log
+
+# CLion
+/.idea/
diff --git a/.luacheckrc b/.luacheckrc
index f350ff014a..b945835bba 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -11,6 +11,7 @@ cache = true
ignore = {
"631", -- max_line_length
+ "212/_.*", -- unused argument, for vars with "_" prefix
}
-- Global objects defined by the C code
diff --git a/.travis.yml b/.travis.yml
index c7c824afc0..94d691b5f5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,7 +34,6 @@ env:
- ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:log_path=$LOG_DIR/asan"
- TSAN_OPTIONS="log_path=$LOG_DIR/tsan"
- UBSAN_OPTIONS="print_stacktrace=1 log_path=$LOG_DIR/ubsan"
- - ASAN_SYMBOLIZE=asan_symbolize
# Environment variables for Valgrind.
- VALGRIND_LOG="$LOG_DIR/valgrind-%p.log"
# If this file exists, the cache is valid (compile was successful).
@@ -46,48 +45,117 @@ env:
- CCACHE_COMPRESS=1
- CCACHE_SLOPPINESS=time_macros,file_macro
- CCACHE_BASEDIR="$TRAVIS_BUILD_DIR"
+ # Default since 3.3, but Travis (Xenial) has 3.2.4; required with newer gcc/clang.
+ - CCACHE_CPP2=1
+
+anchors:
+ envs: &common-job-env
+ # Do not fall back to cache for "master" for PR on "release" branch:
+ # adds the target branch to the cache key.
+ FOR_TRAVIS_CACHE=$TRAVIS_BRANCH
+
+addons:
+ apt:
+ packages: &common-apt-packages
+ - apport
+ - autoconf
+ - automake
+ - build-essential
+ - clang
+ - cmake
+ - cscope
+ - gcc-multilib
+ - gdb
+ - gperf
+ - language-pack-tr
+ - libc6-dev-i386
+ - libtool-bin
+ - locales
+ - ninja-build
+ - pkg-config
+ - unzip
+ - valgrind
+ - xclip
+ homebrew:
+ update: true
+ packages:
+ - ccache
+ - ninja
jobs:
include:
- stage: baseline
+ name: clang-asan
os: linux
- compiler: clang-4.0
+ compiler: clang
# Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6
- env: >
- CLANG_SANITIZER=ASAN_UBSAN
- CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- ASAN_SYMBOLIZE=asan_symbolize-4.0
- - os: linux
+ env:
+ - CLANG_SANITIZER=ASAN_UBSAN
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ - *common-job-env
+ - name: gcc-functionaltest-lua
+ os: linux
compiler: gcc
- env: >
- FUNCTIONALTEST=functionaltest-lua
- CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
- - os: linux
+ env:
+ - FUNCTIONALTEST=functionaltest-lua
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
+ - *common-job-env
+ - name: gcc-32bit
+ os: linux
# Travis creates a cache per compiler. Set a different value here to
# store 32-bit dependencies in a separate cache.
compiler: gcc
- env: BUILD_32BIT=ON
+ env:
+ - BUILD_32BIT=ON
+ # Minimum required CMake.
+ - CMAKE_URL=https://cmake.org/files/v2.8/cmake-2.8.12-Linux-i386.sh
+ - *common-job-env
- if: branch = master AND commit_message !~ /\[skip.lint\]/
+ name: lint
os: linux
- env: CI_TARGET=lint
+ env:
+ - CI_TARGET=lint
+ - *common-job-env
- stage: second stage
+ name: "macOS: clang"
os: osx
compiler: clang
osx_image: xcode10.2 # macOS 10.14
- - os: osx
+ env:
+ - *common-job-env
+ - name: "macOS: gcc"
+ os: osx
compiler: gcc
osx_image: xcode10.2 # macOS 10.14
+ env:
+ - *common-job-env
- - os: linux
- compiler: gcc
- env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
- - os: linux
+ - name: gcc-coverage (gcc 9)
+ os: linux
+ compiler: gcc-9
+ env:
+ - GCOV=gcov
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
+ - GCOV_ERROR_FILE="/tmp/libgcov-errors.log"
+ - *common-job-env
+ addons:
+ apt:
+ sources:
+ - sourceline: 'ppa:ubuntu-toolchain-r/test'
+ packages:
+ - *common-apt-packages
+ - gcc-9
+
+ - name: clang-tsan
+ os: linux
compiler: clang
- env: CLANG_SANITIZER=TSAN
+ env:
+ - CLANG_SANITIZER=TSAN
+ - *common-job-env
allow_failures:
- - env: CLANG_SANITIZER=TSAN
+ - name: clang-tsan
fast_finish: true
before_install: ci/before_install.sh
@@ -96,35 +164,6 @@ before_script: ci/before_script.sh
script: ci/script.sh
before_cache: ci/before_cache.sh
-addons:
- apt:
- packages:
- - apport
- - autoconf
- - automake
- - build-essential
- - clang-4.0
- - cmake
- - cscope
- - g++-multilib
- - gcc-multilib
- - gdb
- - gperf
- - language-pack-tr
- - libc6-dev-i386
- - libtool-bin
- - locales
- - ninja-build
- - pkg-config
- - unzip
- - valgrind
- - xclip
- homebrew:
- update: true
- packages:
- - ccache
- - ninja
-
branches:
only:
- master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index af526ed72d..ecb5c3cea0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,6 +2,7 @@
# intro: https://codingnest.com/basic-cmake/
# best practices (3.0+): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
+# Version should match the tested CMAKE_URL in .travis.yml.
cmake_minimum_required(VERSION 2.8.12)
project(nvim C)
@@ -328,8 +329,8 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
# 2. But _Pragma("...ignored") is broken (unresolved) in GCC 5+:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099
# So we must disable -Warray-bounds globally for GCC (for kbtree.h, #7083).
- check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG)
- if(HAS_NO_ARRAY_BOUNDS_FLAG)
+ check_c_compiler_flag(-Warray-bounds HAS_WARRAY_BOUNDS)
+ if(HAS_WARRAY_BOUNDS)
add_compile_options(-Wno-array-bounds)
endif()
endif()
@@ -377,7 +378,7 @@ endif()
include_directories("${PROJECT_BINARY_DIR}/config")
include_directories("${PROJECT_SOURCE_DIR}/src")
-find_package(LibUV REQUIRED) # minimum version: v1.12
+find_package(LibUV 1.28.0 REQUIRED)
include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS})
find_package(Msgpack 1.0.0 REQUIRED)
diff --git a/Makefile b/Makefile
index 94db1c853a..6d8f6cb07d 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,7 @@ CMAKE_INSTALL_PREFIX := $(shell echo $(CMAKE_EXTRA_FLAGS) | 2>/dev/null \
grep -o 'CMAKE_INSTALL_PREFIX=[^ ]\+' | cut -d '=' -f2)
endif
ifneq (,$(CMAKE_INSTALL_PREFIX))
-CMAKE_EXTRA_FLAGS += -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX)
+override CMAKE_EXTRA_FLAGS += -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX)
checkprefix:
@if [ -f build/.ran-cmake ]; then \
diff --git a/appveyor.yml b/appveyor.yml
index b41f0ee7a8..bb7bb1c4e9 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -32,6 +32,8 @@ after_build:
if (Test-Path $env:GCOV_ERROR_FILE) {
Get-Content $env:GCOV_ERROR_FILE -Head 10
Get-Content $env:GCOV_ERROR_FILE -Tail 10
+ } else {
+ write-host "no GCOV_ERROR_FILE"
}
cache:
- C:\projects\nvim-deps -> third-party\**
diff --git a/busted/outputHandlers/TAP.lua b/busted/outputHandlers/TAP.lua
deleted file mode 100644
index 612e633576..0000000000
--- a/busted/outputHandlers/TAP.lua
+++ /dev/null
@@ -1,94 +0,0 @@
--- TODO(jkeyes): Use the upstream version when busted releases it. (But how to
--- inject our call to global_helpers.read_nvim_log() ?)
-
-local pretty = require 'pl.pretty'
-local global_helpers = require('test.helpers')
-
-return function(options)
- local busted = require 'busted'
- local handler = require 'busted.outputHandlers.base'()
-
- local success = 'ok %u - %s'
- local failure = 'not ' .. success
- local skip = 'ok %u - # SKIP %s'
- local counter = 0
-
- handler.suiteReset = function()
- counter = 0
- return nil, true
- end
-
- handler.suiteEnd = function()
- io.write(global_helpers.read_nvim_log())
- print('1..' .. counter)
- io.flush()
- return nil, true
- end
-
- local function showFailure(t)
- local message = t.message
- local trace = t.trace or {}
-
- if message == nil then
- message = 'Nil error'
- elseif type(message) ~= 'string' then
- message = pretty.write(message)
- end
-
- print(failure:format(counter, t.name))
- print('# ' .. t.element.trace.short_src .. ' @ ' .. t.element.trace.currentline)
- if t.randomseed then print('# Random seed: ' .. t.randomseed) end
- print('# Failure message: ' .. message:gsub('\n', '\n# '))
- if options.verbose and trace.traceback then
- print('# ' .. trace.traceback:gsub('^\n', '', 1):gsub('\n', '\n# '))
- end
- end
-
- handler.testStart = function(element, parent)
- local trace = element.trace
- if options.verbose and trace and trace.short_src then
- local fileline = trace.short_src .. ' @ ' .. trace.currentline .. ': '
- local testName = fileline .. handler.getFullName(element)
- print('# ' .. testName)
- end
- io.flush()
-
- return nil, true
- end
-
- handler.testEnd = function(element, parent, status, trace)
- counter = counter + 1
- if status == 'success' then
- local t = handler.successes[#handler.successes]
- print(success:format(counter, t.name))
- elseif status == 'pending' then
- local t = handler.pendings[#handler.pendings]
- print(skip:format(counter, (t.message or t.name)))
- elseif status == 'failure' then
- showFailure(handler.failures[#handler.failures])
- elseif status == 'error' then
- showFailure(handler.errors[#handler.errors])
- end
- io.flush()
-
- return nil, true
- end
-
- handler.error = function(element, parent, message, debug)
- if element.descriptor ~= 'it' then
- counter = counter + 1
- showFailure(handler.errors[#handler.errors])
- end
- io.flush()
-
- return nil, true
- end
-
- busted.subscribe({ 'suite', 'reset' }, handler.suiteReset)
- busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
- busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending })
- busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
- busted.subscribe({ 'error' }, handler.error)
-
- return handler
-end
diff --git a/ci/before_install.sh b/ci/before_install.sh
index ff2abc0e12..774c66d38f 100755
--- a/ci/before_install.sh
+++ b/ci/before_install.sh
@@ -46,3 +46,16 @@ fi
source ~/.nvm/nvm.sh
nvm install --lts
nvm use --lts
+
+if [[ -n "$CMAKE_URL" ]]; then
+ echo "Installing custom CMake: $CMAKE_URL"
+ curl --retry 5 --silent --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
+ mkdir -p "$HOME/.local/bin" /opt/cmake-custom
+ bash /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
+ ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
+ cmake_version="$(cmake --version)"
+ echo "$cmake_version" | grep -qF '2.8.12' || {
+ echo "Unexpected CMake version: $cmake_version"
+ exit 1
+ }
+fi
diff --git a/ci/build.ps1 b/ci/build.ps1
index c68b3fccb4..5f0f0de218 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -50,7 +50,7 @@ if ($compiler -eq 'MINGW') {
# in MSYS2, but we cannot build inside the MSYS2 shell.
$cmakeGenerator = 'Ninja'
$cmakeGeneratorArgs = '-v'
- $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils', 'unibilium').ForEach({
+ $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils').ForEach({
"mingw-w64-$arch-$_"
})
diff --git a/ci/common/submit_coverage.sh b/ci/common/submit_coverage.sh
index 7c343268d1..218b90d6f4 100755
--- a/ci/common/submit_coverage.sh
+++ b/ci/common/submit_coverage.sh
@@ -25,6 +25,7 @@ python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2
# Upload to codecov.
# -X gcov: disable gcov, done manually above.
+# -X fix: disable fixing of reports (not necessary, rather slow)
# -Z: exit non-zero on failure
# -F: flag(s)
# NOTE: ignoring flags for now, since this causes timeouts on codecov.io then,
@@ -32,7 +33,7 @@ python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2
# Flags must match pattern ^[\w\,]+$ ("," as separator).
codecov_flags="$(uname -s),${1}"
codecov_flags=$(echo "$codecov_flags" | sed 's/[^,_a-zA-Z0-9]/_/g')
-if ! "$codecov_sh" -f coverage.xml -X gcov -Z -F "${codecov_flags}"; then
+if ! "$codecov_sh" -f coverage.xml -X gcov -X fix -Z -F "${codecov_flags}"; then
echo "codecov upload failed."
fi
diff --git a/ci/common/test.sh b/ci/common/test.sh
index e25af4d56c..c184064236 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -81,7 +81,7 @@ valgrind_check() {
asan_check() {
if test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
- check_logs "${1}" "*san.*" | $ASAN_SYMBOLIZE
+ check_logs "${1}" "*san.*" | asan_symbolize
fi
}
diff --git a/ci/script.sh b/ci/script.sh
index a59c40cd2d..c8025ce34d 100755
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -11,3 +11,9 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
else
ci/run_${CI_TARGET}.sh
fi
+
+if [[ -s "${GCOV_ERROR_FILE}" ]]; then
+ echo '=== Unexpected gcov errors: ==='
+ cat "${GCOV_ERROR_FILE}"
+ exit 1
+fi
diff --git a/cmake/GetCompileFlags.cmake b/cmake/GetCompileFlags.cmake
index 77a5260780..482eacca16 100644
--- a/cmake/GetCompileFlags.cmake
+++ b/cmake/GetCompileFlags.cmake
@@ -1,6 +1,6 @@
function(get_compile_flags _compile_flags)
# Create template akin to CMAKE_C_COMPILE_OBJECT.
- set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS> <COMPILE_DEFINITIONS> <INCLUDES>")
+ set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS><COMPILE_DEFINITIONS> <INCLUDES>")
# Get C compiler.
string(REPLACE
@@ -13,9 +13,11 @@ function(get_compile_flags _compile_flags)
get_directory_property(compile_definitions
DIRECTORY "src/nvim"
COMPILE_DEFINITIONS)
- # NOTE: list(JOIN) requires CMake 3.12.
+ # NOTE: list(JOIN) requires CMake 3.12, string(CONCAT) requires CMake 3.
string(REPLACE ";" " -D" compile_definitions "${compile_definitions}")
- string(CONCAT compile_definitions "-D" "${compile_definitions}")
+ if(compile_definitions)
+ set(compile_definitions " -D${compile_definitions}")
+ endif()
string(REPLACE
"<COMPILE_DEFINITIONS>"
"${compile_definitions}"
diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake
index f5b3f01778..5406a07fc8 100644
--- a/cmake/RunTests.cmake
+++ b/cmake/RunTests.cmake
@@ -43,7 +43,7 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory $ENV{TMPDIR})
set(ENV{SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_NAME}) # used by test/helpers.lua.
execute_process(
- COMMAND ${BUSTED_PRG} -v -o ${BUSTED_OUTPUT_TYPE}
+ COMMAND ${BUSTED_PRG} -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE}
--lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
--lpath=${BUILD_DIR}/?.lua
--lpath=${WORKING_DIR}/runtime/lua/?.lua
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 29bbee4888..87d82150b6 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -564,7 +564,10 @@ function! s:check_node() abort
endif
call health#report_info('Neovim node.js host: '. host)
- let latest_npm_cmd = has('win32') ? 'cmd /c npm info neovim --json' : 'npm info neovim --json'
+ let manager = executable('npm') ? 'npm' : 'yarn'
+ let latest_npm_cmd = has('win32') ?
+ \ 'cmd /c '. manager .' info neovim --json' :
+ \ manager .' info neovim --json'
let latest_npm = s:system(split(latest_npm_cmd))
if s:shell_error || empty(latest_npm)
call health#report_error('Failed to run: '. latest_npm_cmd,
@@ -593,7 +596,8 @@ function! s:check_node() abort
call health#report_warn(
\ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s',
\ current_npm, latest_npm),
- \ ['Run in shell: npm install -g neovim'])
+ \ ['Run in shell: npm install -g neovim',
+ \ 'Run in shell (if you use yarn): yarn global add neovim'])
else
call health#report_ok('Latest "neovim" npm/yarn package is installed: '. current_npm)
endif
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index 6266b312bd..1cf328e08d 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -147,7 +147,7 @@ function! s:RegistrationCommands(host) abort
\ a:host, string(map(registered, "fnamemodify(v:val, ':t')")))
" Delete the temporary host clone
- call rpcstop(s:hosts[host_id].channel)
+ call jobstop(s:hosts[host_id].channel)
call remove(s:hosts, host_id)
call remove(s:plugins_for_host, host_id)
return lines
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 065a052175..709e5885e4 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -284,14 +284,18 @@ highlighting, or |api-highlights|.
By default, floats will use |hl-NormalFloat| as normal highlight, which
links to |hl-Pmenu| in the builtin color scheme. The 'winhighlight' option can
be used to override it. Currently, floating windows don't support any visual
-decorations like a border or additional widgets like scrollbar.
+decorations like a border or additional widgets like scrollbar. By default,
+floats will inherit options from the current window. This is not always
+useful for some options, like 'number'. Use `style='minimal'` flag to
+|nvim_open_win()| to disable many UI features that are unwanted for a simple
+float, like end-of-buffer region or special columns.
Here is an example for creating a float with scratch buffer: >
let buf = nvim_create_buf(v:false, v:true)
call nvim_buf_set_lines(buf, 0, -1, v:true, ["test", "text"])
let opts = {'relative': 'cursor', 'width': 10, 'height': 2, 'col': 0,
- \ 'row': 1, 'anchor': 'NW'}
+ \ 'row': 1, 'anchor': 'NW', 'style': 'minimal'}
let win = nvim_open_win(buf, 0, opts)
" optional: change highlight, otherwise Pmenu is used
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 4cc1f53cca..461167015d 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -955,6 +955,12 @@ ShellFilterPost After executing a shell command with
*SourcePre*
SourcePre Before sourcing a Vim script. |:source|
<afile> is the name of the file being sourced.
+ *SourcePost*
+SourcePost After sourcing a Vim script. |:source|
+ <afile> is the name of the file being sourced.
+ Not triggered when sourcing was interrupted.
+ Also triggered after a SourceCmd autocommand
+ was triggered.
*SourceCmd*
SourceCmd When sourcing a Vim script. |:source|
<afile> is the name of the file being sourced.
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index c58215dce6..27e60be368 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -44,6 +44,11 @@ Functions ~
*jobclose()* Obsolete name for |chanclose()|
*jobsend()* Obsolete name for |chansend()|
*last_buffer_nr()* Obsolete name for bufnr("$").
+*rpcstop()* Deprecated. Instead use |jobstop()| to stop any job,
+ or chanclose(id, "rpc") to close RPC communication
+ without stopping the job. Use chanclose(id) to close
+ any socket.
+
Modifiers ~
*cpo-<*
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 2fb61e3092..06af04bf63 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2006,8 +2006,10 @@ atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2}
browse({save}, {title}, {initdir}, {default})
String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester
+bufadd({name}) Number add a buffer to the buffer list
bufexists({expr}) Number |TRUE| if buffer {expr} exists
buflisted({expr}) Number |TRUE| if buffer {expr} is listed
+bufload({expr}) Number load buffer {expr} if not loaded yet
bufloaded({expr}) Number |TRUE| if buffer {expr} is loaded
bufname({expr}) String Name of the buffer {expr}
bufnr({expr} [, {create}]) Number Number of the buffer {expr}
@@ -2679,6 +2681,14 @@ browsedir({title}, {initdir})
When the "Cancel" button is hit, something went wrong, or
browsing is not possible, an empty string is returned.
+bufadd({name}) *bufadd()*
+ Add a buffer to the buffer list with {name}.
+ If a buffer for file {name} already exists, return that buffer
+ number. Otherwise return the buffer number of the newly
+ created buffer. When {name} is an empty string then a new
+ buffer is always created.
+ The buffer will not have' 'buflisted' set.
+
bufexists({expr}) *bufexists()*
The result is a Number, which is |TRUE| if a buffer called
{expr} exists.
@@ -2706,6 +2716,15 @@ buflisted({expr}) *buflisted()*
{expr} exists and is listed (has the 'buflisted' option set).
The {expr} argument is used like with |bufexists()|.
+bufload({expr}) *bufload()*
+ Ensure the buffer {expr} is loaded. When the buffer name
+ refers to an existing file then the file is read. Otherwise
+ the buffer will be empty. If the buffer was already loaded
+ then there is no change.
+ If there is an existing swap file for the file of the buffer,
+ there will be no dialog, the buffer will be loaded anyway.
+ The {expr} argument is used like with |bufexists()|.
+
bufloaded({expr}) *bufloaded()*
The result is a Number, which is |TRUE| if a buffer called
{expr} exists and is loaded (shown in a window or hidden).
@@ -6689,11 +6708,6 @@ rpcstart({prog}[, {argv}]) *rpcstart()*
< with >
:let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true})
-rpcstop({channel}) *rpcstop()*
- Deprecated. Instead use |jobstop()| to stop any job, and
- chanclose(id, "rpc") to close RPC communication without
- stopping the job. Use chanclose(id) to close any socket.
-
screenattr({row}, {col}) *screenattr()*
Like |screenchar()|, but return the attribute. This is a rather
arbitrary number that can only be used to compare to the
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index a421f6b5e7..8fc8a04df3 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4552,6 +4552,25 @@ A jump table for the options with a short description can be found at |Q_op|.
set for the newly edited buffer.
See 'modifiable' for disallowing changes to the buffer.
+ *'redrawdebug'* *'rdb'*
+'redrawdebug' 'rdb' string (default '')
+ global
+ Flags to change the way redrawing works, for debugging purposes.
+ Most useful with 'writedelay' set to some reasonable value.
+ Supports the following flags:
+ compositor Indicate what redraws come from the compositor
+ by briefly flashing the redrawn regions in colors
+ indicating the redraw type. These are the highlight
+ groups used (and their default colors):
+ RedrawDebugNormal gui=reverse normal redraw passed through
+ RedrawDebugClear guibg=Yellow clear event passed through
+ RedrawDebugComposed guibg=Green redraw event modified by the
+ compositor (due to
+ overlapping grids, etc)
+ RedrawDebugRecompose guibg=Red redraw generated by the
+ compositor itself, due to a
+ grid being moved or deleted.
+
*'redrawtime'* *'rdt'*
'redrawtime' 'rdt' number (default 2000)
global
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index c56f9467a3..1440e2ac78 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -316,6 +316,14 @@ numerical highlight ids to the actual attributes.
`info` is an empty array by default, and will be used by the
|ui-hlstate| extension explained below.
+["hl_group_set", name, hl_id]
+ The bulitin highlight group `name` was set to use the attributes `hl_id`
+ defined by a previous `hl_attr_define` call. This event is not needed
+ to render the grids which use attribute ids directly, but is useful
+ for an UI who want to render its own elements with consistent
+ highlighting. For instance an UI using |ui-popupmenu| events, might
+ use the |hl-Pmenu| family of builtin highlights.
+
*ui-event-grid_line*
["grid_line", grid, row, col_start, cells]
Redraw a continuous part of a `row` on a `grid`, starting at the column
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index c7fcd698db..bfb00f74c4 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -358,7 +358,20 @@ g8 Print the hex values of the bytes used in the
The pattern is matched against the relevant part of
the output, not necessarily the whole line. Only some
commands support filtering, try it out to check if it
- works.
+ works. Some of the commands that support filtering:
+ |:#| - filter whole line
+ |:clist| - filter by file name or module name
+ |:command| - filter by command name
+ |:files| - filter by file name
+ |:highlight| - filter by highlight group
+ |:jumps| - filter by file name
+ |:let| - filter by variable name
+ |:list| - filter whole line
+ |:llist| - filter by file name or module name
+ |:marks| - filter by text in the current file,
+ or file name for other files
+ |:oldfiles| - filter by file name
+ |:set| - filter by variable name
Only normal messages are filtered, error messages are
not.
diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh
index fed50dde53..c09e8c4555 100755
--- a/scripts/pvscheck.sh
+++ b/scripts/pvscheck.sh
@@ -369,7 +369,6 @@ run_analysis() {(
analyze \
--threads "$(get_jobs_num)" \
--output-file PVS-studio.log \
- --verbose \
--file build/compile_commands.json \
--sourcetree-root . || true
diff --git a/scripts/stripdecls.py b/scripts/stripdecls.py
index 34be2a1578..a73b1980cb 100755
--- a/scripts/stripdecls.py
+++ b/scripts/stripdecls.py
@@ -18,8 +18,6 @@ Strip = namedtuple('Strip', 'start_line start_column end_line end_column')
def main(progname, cfname, only_static, move_all):
- only_static = False
-
cfname = os.path.abspath(os.path.normpath(cfname))
hfname1 = os.path.splitext(cfname)[0] + os.extsep + 'h'
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 7807125b92..95ca1052af 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -164,8 +164,8 @@ if(NOT MSVC)
set_source_files_properties(
${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
# gperf generates ANSI-C with incorrect linkage, ignore it.
- check_c_compiler_flag(-Wno-static-in-inline HAS_WNO_STATIC_IN_INLINE_FLAG)
- if(HAS_WNO_STATIC_IN_INLINE_FLAG)
+ check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE)
+ if(HAS_WSTATIC_IN_INLINE)
set_source_files_properties(
eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion")
else()
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 4f28ea5af3..20ed77afad 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -123,6 +123,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->mode_change = remote_ui_mode_change;
ui->grid_scroll = remote_ui_grid_scroll;
ui->hl_attr_define = remote_ui_hl_attr_define;
+ ui->hl_group_set = remote_ui_hl_group_set;
ui->raw_line = remote_ui_raw_line;
ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index a1d25766fe..41bf0af65b 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -73,6 +73,8 @@ void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
Array info)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
+void hl_group_set(String name, Integer id)
+ FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL;
void grid_resize(Integer grid, Integer width, Integer height)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_clear(Integer grid)
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 8e5650633a..dbe3b66fd5 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1064,6 +1064,19 @@ fail:
/// - `external`: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
+/// - `style`: Configure the apparance of the window. Currently only takes
+/// one non-empty value:
+/// - "minimal" Nvim will display the window with many UI options
+/// 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'.
+///
+/// top-level window. Currently accepts no other positioning
+/// configuration together with this.
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
@@ -1085,6 +1098,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
if (buffer > 0) {
nvim_win_set_buf(wp->handle, buffer, err);
}
+
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(wp);
+ didset_window_options(wp);
+ }
return wp->handle;
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9fd1818a5c..4922dd7efc 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -13,6 +13,7 @@
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/option.h"
#include "nvim/window.h"
#include "nvim/screen.h"
#include "nvim/move.h"
@@ -475,6 +476,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(win);
+ didset_window_options(win);
+ }
}
/// Return window configuration.
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index ef528f72b8..12fc8fd02a 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -77,6 +77,7 @@ return {
'Signal', -- after nvim process received a signal
'SourceCmd', -- sourcing a Vim script using command
'SourcePre', -- before sourcing a Vim script
+ 'SourcePost', -- after sourcing a Vim script
'SpellFileMissing', -- spell file missing
'StdinReadPost', -- after reading from stdin
'StdinReadPre', -- before reading from stdin
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index d9ed9c6861..34fe52c10e 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -2543,6 +2543,11 @@ void get_winopts(buf_T *buf)
} else
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+ if (curwin->w_float_config.style == kWinStyleMinimal) {
+ didset_window_options(curwin);
+ win_set_minimal_style(curwin);
+ }
+
// Set 'foldlevel' to 'foldlevelstart' if it's not negative.
if (p_fdls >= 0) {
curwin->w_p_fdl = p_fdls;
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ad10f6baa2..a27672488e 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -972,7 +972,6 @@ struct matchitem {
};
typedef int FloatAnchor;
-typedef int FloatRelative;
enum {
kFloatAnchorEast = 1,
@@ -985,15 +984,20 @@ enum {
// SE -> kFloatAnchorSouth | kFloatAnchorEast
EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" });
-enum {
+typedef enum {
kFloatRelativeEditor = 0,
kFloatRelativeWindow = 1,
kFloatRelativeCursor = 2,
-};
+} FloatRelative;
EXTERN const char *const float_relative_str[] INIT(= { "editor", "window",
"cursor" });
+typedef enum {
+ kWinStyleUnused = 0,
+ kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
+} WinStyle;
+
typedef struct {
Window window;
int height, width;
@@ -1002,12 +1006,14 @@ typedef struct {
FloatRelative relative;
bool external;
bool focusable;
+ WinStyle style;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
- .focusable = true })
+ .focusable = true, \
+ .style = kWinStyleUnused })
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 57c4a5395c..6a37c52e3f 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -649,7 +649,9 @@ static int insert_execute(VimState *state, int key)
s->c = key;
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
- did_cursorhold = true;
+ if (key != K_EVENT) {
+ did_cursorhold = true;
+ }
if (p_hkmap && KeyTyped) {
s->c = hkmap(s->c); // Hebrew mode mapping
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index becd4eaca1..7a8402a6bb 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1782,6 +1782,15 @@ static void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty,
if (!HASHITEM_EMPTY(hi)) {
todo--;
di = TV_DICT_HI2DI(hi);
+ char buf[IOSIZE];
+
+ // apply :filter /pat/ to variable name
+ xstrlcpy(buf, prefix, IOSIZE - 1);
+ xstrlcat(buf, (char *)di->di_key, IOSIZE);
+ if (message_filtered((char_u *)buf)) {
+ continue;
+ }
+
if (empty || di->di_tv.v_type != VAR_STRING
|| di->di_tv.vval.v_string != NULL) {
list_one_var(di, prefix, first);
@@ -2360,6 +2369,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
/* Can't add "v:" variable. */
if (lp->ll_dict == &vimvardict) {
EMSG2(_(e_illvar), name);
+ tv_clear(&var1);
return NULL;
}
@@ -4326,7 +4336,7 @@ static int eval7(
// Dictionary: {key: val, key: val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = get_dict_tv(arg, rettv, evaluate);
+ ret = dict_get_tv(arg, rettv, evaluate);
}
break;
@@ -5710,7 +5720,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
* Allocate a variable for a Dictionary and fill it from "*arg".
* Return OK or FAIL. Returns NOTDONE for {expr}.
*/
-static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -7097,10 +7107,14 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga;
+ int save_trylevel = trylevel;
+ // trylevel must be zero for a ":throw" command to be considered failed
+ trylevel = 0;
called_emsg = false;
suppress_errthrow = true;
emsg_silent = true;
+
do_cmdline_cmd(cmd);
if (!called_emsg) {
prepare_assert_error(&ga);
@@ -7122,6 +7136,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+ trylevel = save_trylevel;
called_emsg = false;
suppress_errthrow = false;
emsg_silent = false;
@@ -7289,6 +7304,14 @@ static buf_T *find_buffer(typval_T *avar)
return buf;
}
+// "bufadd(expr)" function
+static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *name = (char_u *)tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
+}
+
/*
* "bufexists(expr)" function
*/
@@ -7308,6 +7331,21 @@ static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
}
+// "bufload(expr)" function
+static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
+{
+ buf_T *buf = get_buf_arg(&argvars[0]);
+
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
+ aco_save_T aco;
+
+ aucmd_prepbuf(&aco, buf);
+ swap_exists_action = SEA_NONE;
+ open_buffer(false, NULL, 0);
+ aucmd_restbuf(&aco);
+ }
+}
+
/*
* "bufloaded(expr)" function
*/
@@ -12189,8 +12227,16 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
+ const char *error = NULL;
+ if (data->is_rpc) {
+ // Ignore return code, but show error later.
+ (void)channel_close(data->id, kChannelPartRpc, &error);
+ }
process_stop((Process *)&data->stream.proc);
rettv->vval.v_number = 1;
+ if (error) {
+ EMSG(error);
+ }
}
// "jobwait(ids[, timeout])" function
@@ -13802,7 +13848,7 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_string = (char_u *) xstrdup(profile_msg(tm));
+ rettv->vval.v_string = (char_u *)xstrdup(profile_msg(tm));
}
}
@@ -15850,11 +15896,10 @@ static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) {
// get signs placed at this line
- lnum = (linenr_T)tv_get_number_chk(&di->di_tv, &notanum);
- if (notanum) {
+ lnum = tv_get_lnum(&di->di_tv);
+ if (lnum <= 0) {
return;
}
- lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "id", -1)) != NULL) {
// get sign placed with this identifier
@@ -16536,7 +16581,7 @@ static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = 0;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_float = ((float_T)tm) / 1000000;
+ rettv->vval.v_float = ((float_T)tm) / 1000000000;
}
}
@@ -20682,11 +20727,11 @@ void ex_echohl(exarg_T *eap)
*/
void ex_execute(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
int ret = OK;
garray_T ga;
- int save_did_emsg = did_emsg;
+ int save_did_emsg;
ga_init(&ga, 1, 80);
@@ -20824,6 +20869,9 @@ void ex_function(exarg_T *eap)
if (!HASHITEM_EMPTY(hi)) {
--todo;
fp = HI2UF(hi);
+ if (message_filtered(fp->uf_name)) {
+ continue;
+ }
if (!func_name_refcount(fp->uf_name)) {
list_func_head(fp, false);
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 9deee69f32..089b08d5d1 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -40,11 +40,13 @@ return {
atan2={args=2},
browse={args=4},
browsedir={args=2},
+ bufadd={args=1},
bufexists={args=1},
buffer_exists={args=1, func='f_bufexists'}, -- obsolete
buffer_name={args=1, func='f_bufname'}, -- obsolete
buffer_number={args=1, func='f_bufnr'}, -- obsolete
buflisted={args=1},
+ bufload={args=1},
bufloaded={args=1},
bufname={args=1},
bufnr={args={1, 2}},
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 623bdfc93b..289c3ee99c 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -382,7 +382,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_SPECIAL: {
switch (tv->vval.v_special) {
case kSpecialVarNull: {
- TYPVAL_ENCODE_CONV_NIL(tv);
+ TYPVAL_ENCODE_CONV_NIL(tv); // -V1037
break;
}
case kSpecialVarTrue:
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 7a8a39dbcf..990dee0c7f 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -26,6 +26,11 @@
// For PTY processes SIGTERM is sent first (in case SIGHUP was not enough).
#define KILL_TIMEOUT_MS 2000
+/// Externally defined with gcov.
+#ifdef USE_GCOV
+void __gcov_flush(void);
+#endif
+
static bool process_is_tearing_down = false;
/// @returns zero on success, or negative error code
@@ -50,6 +55,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
proc->err.closed = true;
}
+#ifdef USE_GCOV
+ // Flush coverage data before forking, to avoid "Merge mismatch" errors.
+ __gcov_flush();
+#endif
+
int status;
switch (proc->type) {
case kProcessTypeUv:
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 2fb818760a..c092036ce9 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -3039,6 +3039,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL;
proftime_T wait_start;
+ bool trigger_source_post = false;
p = expand_env_save(fname);
if (p == NULL) {
@@ -3059,6 +3060,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
false, curbuf)) {
retval = aborting() ? FAIL : OK;
+ if (retval == OK) {
+ // Apply SourcePost autocommands.
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
goto theend;
}
@@ -3181,7 +3186,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
}
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
- fname_exp = NULL;
+ fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (file_id_ok) {
si->file_id_valid = true;
si->file_id = file_id;
@@ -3261,6 +3266,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
time_pop(rel_time);
}
+ if (!got_int) {
+ trigger_source_post = true;
+ }
+
// After a "finish" in debug mode, need to break at first command of next
// sourced file.
if (save_debug_break_level > ex_nesting_level
@@ -3278,6 +3287,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
xfree(firstline);
convert_setup(&cookie.conv, NULL, NULL);
+ if (trigger_source_post) {
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
+
theend:
xfree(fname_exp);
return retval;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index a494463f89..59e6f227e4 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1108,9 +1108,8 @@ static int current_tab_nr(tabpage_T *tab)
#define CURRENT_TAB_NR current_tab_nr(curtab)
#define LAST_TAB_NR current_tab_nr(NULL)
-/*
-* Figure out the address type for ":wincmd".
-*/
+
+/// Figure out the address type for ":wincmd".
static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
{
switch (*arg) {
@@ -1156,13 +1155,13 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_I:
case 'd':
case Ctrl_D:
- /* window size or any count */
- eap->addr_type = ADDR_LINES;
+ // window size or any count
+ eap->addr_type = ADDR_LINES; // -V1037
break;
case Ctrl_HAT:
case '^':
- /* buffer number */
+ // buffer number
eap->addr_type = ADDR_BUFFERS;
break;
@@ -1177,7 +1176,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case 'W':
case 'x':
case Ctrl_X:
- /* window number */
+ // window number
eap->addr_type = ADDR_WINDOWS;
break;
@@ -1192,7 +1191,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_P:
case '=':
case CAR:
- /* no count */
+ // no count
eap->addr_type = 0;
break;
}
@@ -6922,16 +6921,17 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
- if (*eap->arg == '-' || *eap->arg == '+')
+ if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_width;
- else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */
- n = 9999;
+ } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
+ n = Columns;
+ }
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
- n = 9999;
+ n = Rows-1;
}
win_setheight_win(n, wp);
}
@@ -8452,24 +8452,23 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
int cmd;
switch (name[1]) {
- case 'j': cmd = DT_JUMP; /* ":tjump" */
+ case 'j': cmd = DT_JUMP; // ":tjump"
break;
- case 's': cmd = DT_SELECT; /* ":tselect" */
+ case 's': cmd = DT_SELECT; // ":tselect"
break;
- case 'p': cmd = DT_PREV; /* ":tprevious" */
+ case 'p': // ":tprevious"
+ case 'N': cmd = DT_PREV; // ":tNext"
break;
- case 'N': cmd = DT_PREV; /* ":tNext" */
+ case 'n': cmd = DT_NEXT; // ":tnext"
break;
- case 'n': cmd = DT_NEXT; /* ":tnext" */
+ case 'o': cmd = DT_POP; // ":pop"
break;
- case 'o': cmd = DT_POP; /* ":pop" */
+ case 'f': // ":tfirst"
+ case 'r': cmd = DT_FIRST; // ":trewind"
break;
- case 'f': /* ":tfirst" */
- case 'r': cmd = DT_FIRST; /* ":trewind" */
+ case 'l': cmd = DT_LAST; // ":tlast"
break;
- case 'l': cmd = DT_LAST; /* ":tlast" */
- break;
- default: /* ":tag" */
+ default: // ":tag"
if (p_cst && *eap->arg != NUL) {
ex_cstag(eap);
return;
@@ -9322,26 +9321,30 @@ static frame_T *ses_skipframe(frame_T *fr)
{
frame_T *frc;
- for (frc = fr; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
+ FOR_ALL_FRAMES(frc, fr) {
+ if (ses_do_frame(frc)) {
break;
+ }
+ }
return frc;
}
-/*
- * Return TRUE if frame "fr" has a window somewhere that we want to save in
- * the Session.
- */
-static int ses_do_frame(frame_T *fr)
+// Return true if frame "fr" has a window somewhere that we want to save in
+// the Session.
+static bool ses_do_frame(const frame_T *fr)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- frame_T *frc;
+ const frame_T *frc;
- if (fr->fr_layout == FR_LEAF)
+ if (fr->fr_layout == FR_LEAF) {
return ses_do_win(fr->fr_win);
- for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
- return TRUE;
- return FALSE;
+ }
+ FOR_ALL_FRAMES(frc, fr->fr_child) {
+ if (ses_do_frame(frc)) {
+ return true;
+ }
+ }
+ return false;
}
/// Return non-zero if window "wp" is to be stored in the Session.
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 95dcbc732e..76dcf849d1 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -198,7 +198,8 @@ for i = 1, #functions do
output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Error *error)')
output:write('\n{')
output:write('\n#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL')
- output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "invoke '..fn.name..'");')
+ output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke '
+ ..fn.name..'", channel_id);')
output:write('\n#endif')
output:write('\n Object ret = NIL;')
-- Declare/initialize variables that will hold converted arguments
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 7efae1e637..64722ef35d 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -15,6 +15,7 @@
#include <string.h>
#include <inttypes.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/getchar.h"
@@ -905,18 +906,19 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
s2 = xmalloc((size_t)newlen);
typebuf.tb_buflen = newlen;
- /* copy the old chars, before the insertion point */
- memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off,
- (size_t)offset);
- /* copy the new chars */
+ // copy the old chars, before the insertion point
+ memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
+ // copy the new chars
memmove(s1 + newoff + offset, str, (size_t)addlen);
- /* copy the old chars, after the insertion point, including the NUL at
- * the end */
+ // copy the old chars, after the insertion point, including the NUL at
+ // the end
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(s1 + newoff + offset + addlen,
- typebuf.tb_buf + typebuf.tb_off + offset,
- (size_t)(typebuf.tb_len - offset + 1));
- if (typebuf.tb_buf != typebuf_init)
+ typebuf.tb_buf + typebuf.tb_off + offset, (size_t)bytes);
+ if (typebuf.tb_buf != typebuf_init) {
xfree(typebuf.tb_buf);
+ }
typebuf.tb_buf = s1;
memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
@@ -1062,11 +1064,12 @@ void del_typebuf(int len, int offset)
typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
typebuf.tb_off = MAXMAPLEN;
}
- /* adjust typebuf.tb_buf (include the NUL at the end) */
+ // adjust typebuf.tb_buf (include the NUL at the end)
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(typebuf.tb_buf + typebuf.tb_off + offset,
- typebuf.tb_buf + i + len,
- (size_t)(typebuf.tb_len - offset + 1));
- /* adjust typebuf.tb_noremap[] */
+ typebuf.tb_buf + i + len, (size_t)bytes);
+ // adjust typebuf.tb_noremap[]
memmove(typebuf.tb_noremap + typebuf.tb_off + offset,
typebuf.tb_noremap + i + len,
(size_t)(typebuf.tb_len - offset));
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 139ffe2144..1cb2f4592a 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -435,10 +435,11 @@ EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */
EXTERN win_T *prevwin INIT(= NULL); /* previous window */
# define ONE_WINDOW (firstwin == lastwin)
-/*
- * When using this macro "break" only breaks out of the inner loop. Use "goto"
- * to break out of the tabpage loop.
- */
+# define FOR_ALL_FRAMES(frp, first_frame) \
+ for (frp = first_frame; frp != NULL; frp = frp->fr_next) // NOLINT
+
+// When using this macro "break" only breaks out of the inner loop. Use "goto"
+// to break out of the tabpage loop.
# define FOR_ALL_TAB_WINDOWS(tp, wp) \
FOR_ALL_TABS(tp) \
FOR_ALL_WINDOWS_IN_TAB(wp, tp)
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 15c3d0eb7b..f11880cb2b 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -106,14 +106,19 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
- if (!ui->hl_attr_define) {
- return;
+ if (ui->hl_attr_define) {
+ for (size_t i = 1; i < kv_size(attr_entries); i++) {
+ Array inspect = hl_inspect((int)i);
+ ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
+ kv_A(attr_entries, i).attr, inspect);
+ api_free_array(inspect);
+ }
}
- for (size_t i = 1; i < kv_size(attr_entries); i++) {
- Array inspect = hl_inspect((int)i);
- ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
- kv_A(attr_entries, i).attr, inspect);
- api_free_array(inspect);
+ if (ui->hl_group_set) {
+ for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
+ ui->hl_group_set(ui, cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ }
}
}
@@ -141,10 +146,12 @@ int hl_get_ui_attr(int idx, int final_id, bool optional)
HlAttrs attrs = HLATTRS_INIT;
bool available = false;
- int syn_attr = syn_id2attr(final_id);
- if (syn_attr != 0) {
- attrs = syn_attr2entry(syn_attr);
- available = true;
+ if (final_id > 0) {
+ int syn_attr = syn_id2attr(final_id);
+ if (syn_attr != 0) {
+ attrs = syn_attr2entry(syn_attr);
+ available = true;
+ }
}
if (HLF_PNI <= idx && idx <= HLF_PST) {
@@ -176,15 +183,14 @@ void update_window_hl(win_T *wp, bool invalid)
// determine window specific background set in 'winhighlight'
bool float_win = wp->w_floating && !wp->w_float_config.external;
- if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE,
wp->w_hl_ids[HLF_INACTIVE],
!has_blend);
- } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) {
+ } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT,
- // 'cursorline'
wp->w_hl_ids[HLF_NFLOAT], !has_blend);
- } else if (wp->w_hl_id_normal > 0) {
+ } else if (wp->w_hl_id_normal != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend);
} else {
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
@@ -199,14 +205,14 @@ void update_window_hl(win_T *wp, bool invalid)
}
}
- if (wp != curwin) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) {
wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE),
wp->w_hl_attr_normal);
}
for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
int attr;
- if (wp->w_hl_ids[hlf] > 0) {
+ if (wp->w_hl_ids[hlf] != 0) {
attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false);
} else {
attr = HL_ATTR(hlf);
@@ -250,6 +256,7 @@ void clear_hl_tables(bool reinit)
map_clear(int, int)(combine_attr_entries);
map_clear(int, int)(blend_attr_entries);
map_clear(int, int)(blendthrough_attr_entries);
+ memset(highlight_attr_last, -1, sizeof(highlight_attr_last));
highlight_attr_set_all();
highlight_changed();
screen_invalidate_highlights();
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 60f571ff0f..afccf9e6f6 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -36,6 +36,7 @@ typedef struct attr_entry {
.rgb_sp_color = -1, \
.cterm_fg_color = 0, \
.cterm_bg_color = 0, \
+ .hl_blend = -1, \
}
/// Values for index in highlight_attr[].
@@ -149,6 +150,7 @@ EXTERN const char *hlf_names[] INIT(= {
EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
+EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
EXTERN int cterm_normal_fg_color INIT(= 0);
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 306d2f7bf5..b3654a0690 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -54,6 +54,7 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/shada.h"
@@ -220,6 +221,7 @@ void early_init(void)
set_lang_var(); // set v:lang and v:ctype
init_signs();
+ ui_comp_syn_init();
}
#ifdef MAKE_LIB
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 2f2f2a7d74..3736004527 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -656,48 +656,51 @@ show_one_mark(
int c,
char_u *arg,
pos_T *p,
- char_u *name,
- int current /* in current file */
+ char_u *name_arg,
+ int current // in current file
)
{
- static int did_title = FALSE;
- int mustfree = FALSE;
-
- if (c == -1) { /* finish up */
- if (did_title)
- did_title = FALSE;
- else {
- if (arg == NULL)
+ static bool did_title = false;
+ bool mustfree = false;
+ char_u *name = name_arg;
+
+ if (c == -1) { // finish up
+ if (did_title) {
+ did_title = false;
+ } else {
+ if (arg == NULL) {
MSG(_("No marks set"));
- else
+ } else {
EMSG2(_("E283: No marks matching \"%s\""), arg);
+ }
}
- }
- /* don't output anything if 'q' typed at --more-- prompt */
- else if (!got_int
- && (arg == NULL || vim_strchr(arg, c) != NULL)
- && p->lnum != 0) {
- if (!did_title) {
- /* Highlight title */
- MSG_PUTS_TITLE(_("\nmark line col file/text"));
- did_title = TRUE;
+ } else if (!got_int
+ && (arg == NULL || vim_strchr(arg, c) != NULL)
+ && p->lnum != 0) {
+ // don't output anything if 'q' typed at --more-- prompt
+ if (name == NULL && current) {
+ name = mark_line(p, 15);
+ mustfree = true;
}
- msg_putchar('\n');
- if (!got_int) {
- sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
- msg_outtrans(IObuff);
- if (name == NULL && current) {
- name = mark_line(p, 15);
- mustfree = TRUE;
+ if (!message_filtered(name)) {
+ if (!did_title) {
+ // Highlight title
+ msg_puts_title(_("\nmark line col file/text"));
+ did_title = true;
}
- if (name != NULL) {
- msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
- if (mustfree) {
- xfree(name);
+ msg_putchar('\n');
+ if (!got_int) {
+ snprintf((char *)IObuff, IOSIZE, " %c %6ld %4d ", c, p->lnum, p->col);
+ msg_outtrans(IObuff);
+ if (name != NULL) {
+ msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
}
}
+ ui_flush(); // show one line at a time
+ }
+ if (mustfree) {
+ xfree(name);
}
- ui_flush(); /* show one line at a time */
}
}
@@ -786,8 +789,12 @@ void ex_jumps(exarg_T *eap)
for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i) {
if (curwin->w_jumplist[i].fmark.mark.lnum != 0) {
name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
- if (name == NULL) /* file name not available */
+
+ // apply :filter /pat/ or file name not available
+ if (name == NULL || message_filtered(name)) {
+ xfree(name);
continue;
+ }
msg_putchar('\n');
if (got_int) {
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 86c185dbc2..df130565e0 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1878,8 +1878,8 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
msg_ext_last_attr = attr;
}
// Concat pieces with the same highlight
- size_t len = strnlen((char *)str, maxlen);
- ga_concat_len(&msg_ext_last_chunk, (char *)str, len); // -V781
+ size_t len = strnlen((char *)str, maxlen); // -V781
+ ga_concat_len(&msg_ext_last_chunk, (char *)str, len);
msg_ext_cur_len += len;
return;
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 6738e59bb2..5a5bd16b98 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -495,9 +495,14 @@ open_line (
}
if (lead_len > 0) {
// allocate buffer (may concatenate p_extra later)
- leader = xmalloc((size_t)(lead_len + lead_repl_len + extra_space
- + extra_len + (second_line_indent > 0
- ? second_line_indent : 0) + 1));
+ int bytes = lead_len
+ + lead_repl_len
+ + extra_space
+ + extra_len
+ + (second_line_indent > 0 ? second_line_indent : 0)
+ + 1;
+ assert(bytes >= 0);
+ leader = xmalloc((size_t)bytes);
allocated = leader; // remember to free it later
STRLCPY(leader, saved_line, lead_len + 1);
@@ -1556,11 +1561,14 @@ void ins_str(char_u *s)
oldp = ml_get(lnum);
oldlen = (int)STRLEN(oldp);
- newp = (char_u *) xmalloc((size_t)(oldlen + newlen + 1));
- if (col > 0)
+ newp = (char_u *)xmalloc((size_t)oldlen + (size_t)newlen + 1);
+ if (col > 0) {
memmove(newp, oldp, (size_t)col);
+ }
memmove(newp + col, s, (size_t)newlen);
- memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
+ int bytes = oldlen - col + 1;
+ assert(bytes >= 0);
+ memmove(newp + col + newlen, oldp + col, (size_t)bytes);
ml_replace(lnum, newp, false);
changed_bytes(lnum, col);
curwin->w_cursor.col += newlen;
diff --git a/src/nvim/move.c b/src/nvim/move.c
index e076543614..05db39b981 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -119,7 +119,6 @@ static void redraw_for_cursorline(win_T *wp)
// the current window.
redrawWinline(wp, wp->w_last_cursorline);
redrawWinline(wp, wp->w_cursor.lnum);
- redraw_win_later(wp, VALID);
} else {
redraw_win_later(wp, SOME_VALID);
}
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 3f768dcc0c..18b0bf3c16 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -384,10 +384,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
- case kObjectTypeNil: {
- msgpack_pack_nil(res);
- break;
- }
+ case kObjectTypeNil:
case kObjectTypeLuaRef: {
// TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
// should only appear when the caller has opted in to handle references,
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index de8ff52fe1..4ef4b69def 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1376,9 +1376,8 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount)
*set_prevcount = false; /* only set v:prevcount once */
}
-/*
- * Handle an operator after visual mode or when the movement is finished
- */
+// Handle an operator after Visual mode or when the movement is finished.
+// "gui_yank" is true when yanking text for the clipboard.
void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
{
oparg_T *oap = cap->oap;
@@ -1402,8 +1401,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* If an operation is pending, handle it...
*/
if ((finish_op
- || VIsual_active
- ) && oap->op_type != OP_NOP) {
+ || VIsual_active)
+ && oap->op_type != OP_NOP) {
+ // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
+ // for the clipboard.
+ const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
+
// Avoid a problem with unwanted linebreaks in block mode
if (curwin->w_p_lbr) {
curwin->w_valid &= ~VALID_VIRTCOL;
@@ -1433,9 +1436,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
VIsual_reselect = false;
}
- /* Only redo yank when 'y' flag is in 'cpoptions'. */
- /* Never redo "zf" (define fold). */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // Only redo yank when 'y' flag is in 'cpoptions'.
+ // Never redo "zf" (define fold).
+ if ((redo_yank || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
// Also redo Operator-pending Visual mode mappings.
|| (cap->cmdchar == ':' && oap->op_type != OP_COLON))
@@ -1608,8 +1611,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
resel_VIsual_line_count = oap->line_count;
}
- /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // can't redo yank (unless 'y' is in 'cpoptions') and ":"
+ if ((redo_yank || oap->op_type != OP_YANK)
&& oap->op_type != OP_COLON
&& oap->op_type != OP_FOLD
&& oap->op_type != OP_FOLDOPEN
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index b96e075f66..0f26d83597 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -379,8 +379,10 @@ static void shift_block(oparg_T *oap, int amount)
/* if we're splitting a TAB, allow for it */
bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
const int len = (int)STRLEN(bd.textstart) + 1;
- newp = (char_u *)xmalloc((size_t)(bd.textcol + i + j + len));
- memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
+ int col = bd.textcol + i +j + len;
+ assert(col >= 0);
+ newp = (char_u *)xmalloc((size_t)col);
+ memset(newp, NUL, (size_t)col);
memmove(newp, oldp, (size_t)bd.textcol);
memset(newp + bd.textcol, TAB, (size_t)i);
memset(newp + bd.textcol + i, ' ', (size_t)j);
@@ -1471,7 +1473,8 @@ int op_delete(oparg_T *oap)
// copy up to deleted part
memmove(newp, oldp, (size_t)bd.textcol);
// insert spaces
- memset(newp + bd.textcol, ' ', (size_t)(bd.startspaces + bd.endspaces));
+ memset(newp + bd.textcol, ' ', (size_t)bd.startspaces +
+ (size_t)bd.endspaces);
// copy the part after the deleted part
oldp += bd.textcol + bd.textlen;
STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
@@ -1743,7 +1746,7 @@ int op_replace(oparg_T *oap, int c)
oldp = get_cursor_line_ptr();
oldlen = (int)STRLEN(oldp);
- size_t newp_size = (size_t)(bd.textcol + bd.startspaces);
+ size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
newp_size += (size_t)numc;
if (!bd.is_short) {
@@ -1760,6 +1763,8 @@ int op_replace(oparg_T *oap, int c)
// insert replacement chars CHECK FOR ALLOCATED SPACE
// REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR literally.
size_t after_p_len = 0;
+ int col = oldlen - bd.textcol - bd.textlen + 1;
+ assert(col >= 0);
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
// strlen(newp) at this point
int newp_len = bd.textcol + bd.startspaces;
@@ -1771,12 +1776,11 @@ int op_replace(oparg_T *oap, int c)
memset(newp + newp_len, ' ', (size_t)bd.endspaces);
newp_len += bd.endspaces;
// copy the part after the changed part
- memmove(newp + newp_len, oldp,
- (size_t)(oldlen - bd.textcol - bd.textlen + 1));
+ memmove(newp + newp_len, oldp, (size_t)col);
}
} else {
// Replacing with \r or \n means splitting the line.
- after_p_len = (size_t)(oldlen - bd.textcol - bd.textlen + 1);
+ after_p_len = (size_t)col;
after_p = (char_u *)xmalloc(after_p_len);
memmove(after_p, oldp, after_p_len);
}
@@ -2602,8 +2606,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx)
{
- char_u *pnew = xmallocz((size_t)(bd->startspaces + bd->endspaces
- + bd->textlen));
+ int size = bd->startspaces + bd->endspaces + bd->textlen;
+ assert(size >= 0);
+ char_u *pnew = xmallocz((size_t)size);
reg->y_array[y_idx] = pnew;
memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces;
@@ -3085,8 +3090,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
memset(ptr, ' ', (size_t)bd.endspaces);
ptr += bd.endspaces;
// move the text after the cursor to the end of the line.
- memmove(ptr, oldp + bd.textcol + delcount,
- (size_t)((int)oldlen - bd.textcol - delcount + 1));
+ int columns = (int)oldlen - bd.textcol - delcount + 1;
+ assert(columns >= 0);
+ memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
ml_replace(curwin->w_cursor.lnum, newp, false);
++curwin->w_cursor.lnum;
@@ -3209,11 +3215,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
xfree(newp);
oldp = ml_get(lnum);
- newp = (char_u *) xmalloc((size_t)(col + yanklen + 1));
- /* copy first part of line */
+ newp = (char_u *)xmalloc((size_t)col + (size_t)yanklen + 1);
+ // copy first part of line
memmove(newp, oldp, (size_t)col);
- /* append to first line */
- memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
+ // append to first line
+ memmove(newp + col, y_array[0], (size_t)yanklen + 1);
ml_replace(lnum, newp, false);
curwin->w_cursor.lnum = lnum;
@@ -3705,11 +3711,11 @@ int do_join(size_t count,
}
}
- /* store the column position before last line */
+ // store the column position before last line
col = sumsize - currsize - spaces[count - 1];
- /* allocate the space for the new line */
- newp = (char_u *) xmalloc((size_t)(sumsize + 1));
+ // allocate the space for the new line
+ newp = (char_u *)xmalloc((size_t)sumsize + 1);
cend = newp + sumsize;
*cend = 0;
@@ -5472,7 +5478,7 @@ void cursor_pos_info(dict_T *dict)
byte_count_cursor = byte_count
+ line_count_info(ml_get(lnum), &word_count_cursor,
&char_count_cursor,
- (varnumber_T)(curwin->w_cursor.col + 1),
+ (varnumber_T)curwin->w_cursor.col + 1,
eol_size);
}
}
@@ -5490,8 +5496,10 @@ void cursor_pos_info(dict_T *dict)
if (l_VIsual_active) {
if (l_VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) {
getvcols(curwin, &min_pos, &max_pos, &min_pos.col, &max_pos.col);
+ int64_t cols;
+ STRICT_SUB(oparg.end_vcol + 1, oparg.start_vcol, &cols, int64_t);
vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "),
- (int64_t)(oparg.end_vcol - oparg.start_vcol + 1));
+ cols);
} else {
buf1[0] = NUL;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 62f736ea31..8483c02bbe 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2191,6 +2191,7 @@ static void didset_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
(void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
@@ -2650,6 +2651,10 @@ did_set_string_option(
if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (varp == &p_rdb) { // 'redrawdebug'
+ if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_sbo) { // 'scrollopt'
if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) {
errmsg = e_invarg;
@@ -3762,7 +3767,8 @@ static bool parse_winhl_opt(win_T *wp)
size_t nlen = (size_t)(colon-p);
char *hi = colon+1;
char *commap = xstrchrnul(hi, ',');
- int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi));
+ int len = (int)(commap-hi);
+ int hl_id = len ? syn_check_group((char_u *)hi, len) : -1;
if (strncmp("Normal", p, nlen) == 0) {
w_hl_id_normal = hl_id;
@@ -5041,6 +5047,11 @@ showoptions(
// collect the items in items[]
item_count = 0;
for (p = &options[0]; p->fullname != NULL; p++) {
+ // apply :filter /pat/
+ if (message_filtered((char_u *)p->fullname)) {
+ continue;
+ }
+
varp = NULL;
if (opt_flags != 0) {
if (p->indir != PV_NONE) {
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 35fe3b5b00..a480de735d 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -511,6 +511,13 @@ EXTERN char_u *p_pm; // 'patchmode'
EXTERN char_u *p_path; // 'path'
EXTERN char_u *p_cdpath; // 'cdpath'
EXTERN long p_pyx; // 'pyxversion'
+EXTERN char_u *p_rdb; // 'redrawdebug'
+EXTERN unsigned rdb_flags;
+# ifdef IN_OPTION_C
+static char *(p_rdb_values[]) = { "compositor", NULL };
+# endif
+# define RDB_COMPOSITOR 0x001
+
EXTERN long p_rdt; // 'redrawtime'
EXTERN int p_remap; // 'remap'
EXTERN long p_re; // 'regexpengine'
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 27f72f6441..c48366e205 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1848,6 +1848,13 @@ return {
defaults={if_true={vi=false}}
},
{
+ full_name='redrawdebug', abbreviation='rdb',
+ type='string', list='onecomma', scope={'global'},
+ vi_def=true,
+ varname='p_rdb',
+ defaults={if_true={vi=''}}
+ },
+ {
full_name='redrawtime', abbreviation='rdt',
type='number', scope={'global'},
vi_def=true,
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 65362b545f..4a10b5199c 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -364,7 +364,7 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
#ifdef WIN32
// Prepend ".;" to $PATH.
size_t pathlen = strlen(path_env);
- char *path = memcpy(xmallocz(pathlen + 3), "." ENV_SEPSTR, 2);
+ char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2);
memcpy(path + 2, path_env, pathlen);
#else
char *path = xstrdup(path_env);
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 97545a6cb1..5fdf0e6181 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -36,11 +36,6 @@
# include "os/pty_process_unix.c.generated.h"
#endif
-/// Externally defined with gcov.
-#ifdef USE_GCOV
-void __gcov_flush(void);
-#endif
-
/// termios saved at startup (for TUI) or initialized by pty_process_spawn().
static struct termios termios_default;
@@ -64,11 +59,6 @@ int pty_process_spawn(PtyProcess *ptyproc)
init_termios(&termios_default);
}
-#ifdef USE_GCOV
- // Flush coverage data before forking, to avoid "Merge mismatch" errors.
- __gcov_flush();
-#endif
-
int status = 0; // zero or negative error code (libuv convention)
Process *proc = (Process *)ptyproc;
assert(proc->err.closed);
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 18239c5566..4dd0614fe2 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -31,27 +31,6 @@ void time_init(void)
uv_cond_init(&delay_cond);
}
-/// Gets the current time with microsecond (μs) precision.
-///
-/// Subject to system-clock quirks (drift, going backwards, skipping).
-/// But it is much faster than os_hrtime() on some systems. #10328
-///
-/// @see gettimeofday(2)
-///
-/// @return Current time in microseconds.
-uint64_t os_utime(void)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- uv_timeval64_t tm;
- int e = uv_gettimeofday(&tm);
- if (e != 0 || tm.tv_sec < 0 || tm.tv_usec < 0) {
- return 0;
- }
- uint64_t rv = (uint64_t)tm.tv_sec * 1000 * 1000; // s => μs
- STRICT_ADD(rv, tm.tv_usec, &rv, uint64_t);
- return rv;
-}
-
/// Gets a high-resolution (nanosecond), monotonically-increasing time relative
/// to an arbitrary time in the past.
///
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index cc12e00396..a6314e7b9d 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -5,6 +5,7 @@
#include <math.h>
#include <assert.h>
+#include "nvim/assert.h"
#include "nvim/profile.h"
#include "nvim/os/time.h"
#include "nvim/func_attr.h"
@@ -23,7 +24,7 @@ static proftime_T prof_wait_time;
/// @return the current time
proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
{
- return os_utime();
+ return os_hrtime();
}
/// Computes the time elapsed.
@@ -31,7 +32,7 @@ proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
/// @return Elapsed time from `tm` until now.
proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
- return profile_sub(os_utime(), tm);
+ return profile_sub(os_hrtime(), tm);
}
/// Gets a string representing time `tm`.
@@ -43,7 +44,8 @@ proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
const char *profile_msg(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
static char buf[50];
- snprintf(buf, sizeof(buf), "%10.6lf", (double)tm / 1000000.0);
+ snprintf(buf, sizeof(buf), "%10.6lf",
+ (double)profile_signed(tm) / 1000000000.0);
return buf;
}
@@ -59,10 +61,9 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT
// no limit
return profile_zero();
}
- assert(msec <= (INT64_MAX / 1000LL) - 1);
-
- proftime_T usec = (proftime_T)msec * 1000ULL;
- return os_utime() + usec;
+ assert(msec <= (INT64_MAX / 1000000LL) - 1);
+ proftime_T nsec = (proftime_T)msec * 1000000ULL;
+ return os_hrtime() + nsec;
}
/// Checks if current time has passed `tm`.
@@ -75,7 +76,8 @@ bool profile_passed_limit(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
// timer was not set
return false;
}
- return profile_cmp(os_utime(), tm) < 0;
+
+ return profile_cmp(os_hrtime(), tm) < 0;
}
/// Gets the zero time.
@@ -108,10 +110,15 @@ proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
/// Subtracts time `tm2` from `tm1`.
///
+/// Unsigned overflow (wraparound) occurs if `tm2` is greater than `tm1`.
+/// Use `profile_signed()` to get the signed integer value.
+///
+/// @see profile_signed
+///
/// @return `tm1` - `tm2`
proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
{
- return tm1 > tm2 ? tm1 - tm2 : 0; // os_utime() may go backwards.
+ return tm1 - tm2;
}
/// Adds the `self` time from the total time and the `children` time.
@@ -162,22 +169,31 @@ bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
return tm1 == tm2;
}
-/// Calculates the sign of a 64-bit integer.
+/// Converts a proftime_T value `tm` to a signed integer.
///
-/// @return -1, 0, or +1
-static inline int sgn64(int64_t x) FUNC_ATTR_CONST
+/// @return signed representation of the given time value
+int64_t profile_signed(proftime_T tm)
+ FUNC_ATTR_CONST
{
- return (int) ((x > 0) - (x < 0));
+ // (tm > INT64_MAX) is >=150 years, so we can assume it was produced by
+ // arithmetic of two proftime_T values. For human-readable representation
+ // (and Vim-compat) we want the difference after unsigned wraparound. #10452
+ return (tm <= INT64_MAX) ? (int64_t)tm : -(int64_t)(UINT64_MAX - tm);
}
/// Compares profiling times.
///
/// Times `tm1` and `tm2` must be less than 150 years apart.
///
-/// @return <0, 0 or >0 if `tm2` < `tm1`, `tm2` == `tm1` or `tm2` > `tm1`
+/// @return <0: `tm2` < `tm1`
+/// 0: `tm2` == `tm1`
+/// >0: `tm2` > `tm1`
int profile_cmp(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
{
- return sgn64((int64_t)(tm2 - tm1));
+ if (tm1 == tm2) {
+ return 0;
+ }
+ return profile_signed(tm2 - tm1) < 0 ? -1 : 1;
}
/// globals for use in the startuptime related functionality (time_*).
@@ -219,7 +235,7 @@ void time_pop(proftime_T tp)
static void time_diff(proftime_T then, proftime_T now)
{
proftime_T diff = profile_sub(now, then);
- fprintf(time_fd, "%07.3lf", (double)diff / 1.0E3);
+ fprintf(time_fd, "%07.3lf", (double)diff / 1.0E6);
}
/// Initializes the startuptime code.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index dc1ab971ab..a8919560a0 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1263,8 +1263,8 @@ static int nfa_regatom(void)
IEMSGN("INTERNAL: Unknown character class char: %" PRId64, c);
return FAIL;
}
- /* When '.' is followed by a composing char ignore the dot, so that
- * the composing char is matched here. */
+ // When '.' is followed by a composing char ignore the dot, so that
+ // the composing char is matched here.
if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr())) {
old_regparse = regparse;
c = getchr();
@@ -1279,25 +1279,26 @@ static int nfa_regatom(void)
break;
case Magic('n'):
- if (reg_string)
- /* In a string "\n" matches a newline character. */
+ if (reg_string) {
+ // In a string "\n" matches a newline character.
EMIT(NL);
- else {
- /* In buffer text "\n" matches the end of a line. */
+ } else {
+ // In buffer text "\n" matches the end of a line.
EMIT(NFA_NEWL);
regflags |= RF_HASNL;
}
break;
case Magic('('):
- if (nfa_reg(REG_PAREN) == FAIL)
- return FAIL; /* cascaded error */
+ if (nfa_reg(REG_PAREN) == FAIL) {
+ return FAIL; // cascaded error
+ }
break;
case Magic('|'):
case Magic('&'):
case Magic(')'):
- EMSGN(_(e_misplaced), no_Magic(c));
+ EMSGN(_(e_misplaced), no_Magic(c)); // -V1037
return FAIL;
case Magic('='):
@@ -1306,7 +1307,7 @@ static int nfa_regatom(void)
case Magic('@'):
case Magic('*'):
case Magic('{'):
- /* these should follow an atom, not form an atom */
+ // these should follow an atom, not form an atom
EMSGN(_(e_misplaced), no_Magic(c));
return FAIL;
@@ -1314,8 +1315,8 @@ static int nfa_regatom(void)
{
char_u *lp;
- /* Previous substitute pattern.
- * Generated as "\%(pattern\)". */
+ // Previous substitute pattern.
+ // Generated as "\%(pattern\)".
if (reg_prev_sub == NULL) {
EMSG(_(e_nopresub));
return FAIL;
@@ -3002,8 +3003,8 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size)
return NULL; \
}
- if (nfa_calc_size == FALSE) {
- /* Allocate space for the stack. Max states on the stack : nstate */
+ if (nfa_calc_size == false) {
+ // Allocate space for the stack. Max states on the stack: "nstate".
stack = xmalloc((nstate + 1) * sizeof(Frag_T));
stackp = stack;
stack_end = stack + (nstate + 1);
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 846ffeb442..2f8b1b6b02 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1612,7 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row,
}
}
- int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl));
+ int attr = hl_combine_attr(wp->w_hl_attr_normal,
+ hl ? win_hl_attr(wp, hl) : 0);
if (wp->w_p_rl) {
grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n,
@@ -3777,7 +3778,7 @@ win_line (
* At end of the text line or just after the last character.
*/
if (c == NUL) {
- long prevcol = (long)(ptr - line) - (c == NUL);
+ long prevcol = (long)(ptr - line) - 1;
/* we're not really at that column when skipping some text */
if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol)
@@ -4570,17 +4571,21 @@ void redraw_statuslines(void)
/*
* Redraw all status lines at the bottom of frame "frp".
*/
-void win_redraw_last_status(frame_T *frp)
+void win_redraw_last_status(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- if (frp->fr_layout == FR_LEAF)
- frp->fr_win->w_redr_status = TRUE;
- else if (frp->fr_layout == FR_ROW) {
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ if (frp->fr_layout == FR_LEAF) {
+ frp->fr_win->w_redr_status = true;
+ } else if (frp->fr_layout == FR_ROW) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
win_redraw_last_status(frp);
- } else { /* frp->fr_layout == FR_COL */
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
frp = frp->fr_child;
- while (frp->fr_next != NULL)
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
+ }
win_redraw_last_status(frp);
}
}
@@ -6078,8 +6083,8 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
{
int new_row;
ScreenGrid new = *grid;
-
- size_t ncells = (size_t)((rows+1) * columns);
+ assert(rows >= 0 && columns >= 0);
+ size_t ncells = (size_t)rows * columns;
new.chars = xmalloc(ncells * sizeof(schar_T));
new.attrs = xmalloc(ncells * sizeof(sattr_T));
new.line_offset = xmalloc((size_t)(rows * sizeof(unsigned)));
diff --git a/src/nvim/search.c b/src/nvim/search.c
index ed18df3877..ed5934cec2 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1217,7 +1217,7 @@ int do_search(
xfree(msgbuf);
msgbuf = r;
// move reversed text to beginning of buffer
- while (*r != NUL && *r == ' ') {
+ while (*r == ' ') {
r++;
}
size_t pat_len = msgbuf + STRLEN(msgbuf) - r;
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 8c85fbdaa7..9c391428ca 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -83,11 +83,8 @@ static signgroup_T * sign_group_ref(const char_u *groupname)
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
if (HASHITEM_EMPTY(hi)) {
// new group
- group = (signgroup_T *)xmalloc(
- (unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
- if (group == NULL) {
- return NULL;
- }
+ group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+
STRCPY(group->sg_name, groupname);
group->refcount = 1;
group->next_sign_id = 1;
@@ -188,10 +185,6 @@ static void insert_sign(
newsign->typenr = typenr;
if (group != NULL) {
newsign->group = sign_group_ref(group);
- if (newsign->group == NULL) {
- xfree(newsign);
- return;
- }
} else {
newsign->group = NULL;
}
@@ -1347,8 +1340,8 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict)
/// Otherwise, return information about the specified sign.
void sign_getlist(const char_u *name, list_T *retlist)
{
- sign_T *sp = first_sign;
- dict_T *dict;
+ sign_T *sp = first_sign;
+ dict_T *dict;
if (name != NULL) {
sp = sign_find(name, NULL);
@@ -1358,9 +1351,7 @@ void sign_getlist(const char_u *name, list_T *retlist)
}
for (; sp != NULL && !got_int; sp = sp->sn_next) {
- if ((dict = tv_dict_alloc()) == NULL) {
- return;
- }
+ dict = tv_dict_alloc();
tv_list_append_dict(retlist, dict);
sign_getinfo(sp, dict);
@@ -1374,14 +1365,13 @@ void sign_getlist(const char_u *name, list_T *retlist)
list_T *get_buffer_signs(buf_T *buf)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- signlist_T *sign;
- dict_T *d;
+ signlist_T *sign;
+ dict_T *d;
list_T *const l = tv_list_alloc(kListLenMayKnow);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if ((d = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, d);
- }
+ d = sign_get_info(sign);
+ tv_list_append_dict(l, d);
}
return l;
}
@@ -1394,21 +1384,16 @@ static void sign_get_placed_in_buf(
const char_u *sign_group,
list_T *retlist)
{
- dict_T *d;
- list_T *l;
- signlist_T *sign;
- dict_T *sdict;
+ dict_T *d;
+ list_T *l;
+ signlist_T *sign;
- if ((d = tv_dict_alloc()) == NULL) {
- return;
- }
+ d = tv_dict_alloc();
tv_list_append_dict(retlist, d);
tv_dict_add_nr(d, S_LEN("bufnr"), (long)buf->b_fnum);
- if ((l = tv_list_alloc(kListLenMayKnow)) == NULL) {
- return;
- }
+ l = tv_list_alloc(kListLenMayKnow);
tv_dict_add_list(d, S_LEN("signs"), l);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
@@ -1419,9 +1404,7 @@ static void sign_get_placed_in_buf(
|| (sign_id == 0 && lnum == sign->lnum)
|| (lnum == 0 && sign_id == sign->id)
|| (lnum == sign->lnum && sign_id == sign->id)) {
- if ((sdict = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, sdict);
- }
+ tv_list_append_dict(l, sign_get_info(sign));
}
}
}
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 6fd22a6537..17306744ad 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -5283,7 +5283,7 @@ add_sound_suggest (
}
// Go over the list of good words that produce this soundfold word
- nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
+ nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false);
orgnr = 0;
while (*nrline != NUL) {
// The wordnr was stored in a minimal nr of bytes as an offset to the
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 0d204b2f43..4fa70c0684 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -14,6 +14,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/syntax.h"
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
@@ -350,7 +351,7 @@ static reg_extmatch_T *next_match_extmatch = NULL;
/*
* A state stack is an array of integers or stateitem_T, stored in a
- * garray_T. A state stack is invalid if it's itemsize entry is zero.
+ * garray_T. A state stack is invalid if its itemsize entry is zero.
*/
#define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0)
#define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0)
@@ -3608,7 +3609,7 @@ syn_list_one(
continue;
}
- (void)syn_list_header(did_header, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
did_header = true;
last_matchgroup = 0;
if (spp->sp_type == SPTYPE_MATCH) {
@@ -3657,7 +3658,7 @@ syn_list_one(
/* list the link, if there is one */
if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int) {
- (void)syn_list_header(did_header, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
msg_puts_attr("links to", attr);
msg_putchar(' ');
msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
@@ -3799,7 +3800,6 @@ static bool syn_list_keywords(
const int attr
)
{
- int outlen;
int prev_contained = 0;
const int16_t *prev_next_list = NULL;
const int16_t *prev_cont_in_list = NULL;
@@ -3817,17 +3817,20 @@ static bool syn_list_keywords(
todo--;
for (keyentry_T *kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next) {
if (kp->k_syn.id == id) {
+ int outlen = 0;
+ bool force_newline = false;
if (prev_contained != (kp->flags & HL_CONTAINED)
|| prev_skipnl != (kp->flags & HL_SKIPNL)
|| prev_skipwhite != (kp->flags & HL_SKIPWHITE)
|| prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
- || prev_next_list != kp->next_list)
- outlen = 9999;
- else
+ || prev_next_list != kp->next_list) {
+ force_newline = true;
+ } else {
outlen = (int)STRLEN(kp->keyword);
- /* output "contained" and "nextgroup" on each line */
- if (syn_list_header(did_header, outlen, id)) {
+ }
+ // output "contained" and "nextgroup" on each line
+ if (syn_list_header(did_header, outlen, id, force_newline)) {
prev_contained = 0;
prev_next_list = NULL;
prev_cont_in_list = NULL;
@@ -5970,6 +5973,10 @@ static const char *highlight_init_both[] = {
"default link Whitespace NonText",
"default link MsgSeparator StatusLine",
"default link NormalFloat Pmenu",
+ "RedrawDebugNormal cterm=reverse gui=reverse",
+ "RedrawDebugClear ctermbg=Yellow guibg=Yellow",
+ "RedrawDebugComposed ctermbg=Green guibg=Green",
+ "RedrawDebugRecompose ctermbg=Red guibg=Red",
NULL
};
@@ -7044,6 +7051,10 @@ static void highlight_list_one(const int id)
struct hl_group *const sgp = &HL_TABLE()[id - 1]; // index is ID minus one
bool didh = false;
+ if (message_filtered(sgp->sg_name)) {
+ return;
+ }
+
didh = highlight_list_arg(id, didh, LIST_ATTR,
sgp->sg_cterm, NULL, "cterm");
didh = highlight_list_arg(id, didh, LIST_INT,
@@ -7064,7 +7075,7 @@ static void highlight_list_one(const int id)
sgp->sg_blend+1, NULL, "blend");
if (sgp->sg_link && !got_int) {
- (void)syn_list_header(didh, 9999, id);
+ (void)syn_list_header(didh, 0, id, true);
didh = true;
msg_puts_attr("links to", HL_ATTR(HLF_D));
msg_putchar(' ');
@@ -7109,7 +7120,8 @@ static bool highlight_list_arg(
}
}
- (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
+ (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id,
+ false);
didh = true;
if (!got_int) {
if (*name != NUL) {
@@ -7227,9 +7239,10 @@ const char *highlight_color(const int id, const char *const what,
/// @param did_header did header already
/// @param outlen length of string that comes
/// @param id highlight group id
+/// @param force_newline always start a new line
/// @return true when started a new line.
static bool syn_list_header(const bool did_header, const int outlen,
- const int id)
+ const int id, bool force_newline)
{
int endcol = 19;
bool newline = true;
@@ -7242,10 +7255,10 @@ static bool syn_list_header(const bool did_header, const int outlen,
}
msg_outtrans(HL_TABLE()[id - 1].sg_name);
endcol = 15;
- } else if (ui_has(kUIMessages) || msg_silent) {
+ } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
msg_putchar(' ');
adjust = false;
- } else if (msg_col + outlen + 1 >= Columns) {
+ } else if (msg_col + outlen + 1 >= Columns || force_newline) {
msg_putchar('\n');
if (got_int) {
return true;
@@ -7518,6 +7531,12 @@ void highlight_changed(void)
highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
hlf == (int)HLF_INACTIVE);
+
+ if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
+ ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ highlight_attr_last[hlf] = highlight_attr[hlf];
+ }
}
/* Setup the user highlights
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index fe9e0bc9c8..8b43d91e25 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -99,23 +99,24 @@ 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
+CLEAN_FILES := *.out \
+ *.failed \
+ *.res \
+ *.rej \
+ *.orig \
+ *.tlog \
+ test.log \
+ messages \
+ $(RM_ON_RUN) \
+ $(RM_ON_START) \
+ valgrind.* \
+ .*.swp \
+ .*.swo \
+ .gdbinit \
+ $(TMPDIR) \
+ del
clean:
- -rm -rf *.out \
- *.failed \
- *.res \
- *.rej \
- *.orig \
- *.tlog \
- test.log \
- messages \
- $(RM_ON_RUN) \
- $(RM_ON_START) \
- valgrind.* \
- .*.swp \
- .*.swo \
- .gdbinit \
- $(TMPDIR) \
- del
+ $(RM) -rf $(CLEAN_FILES)
test1.out: .gdbinit test1.in
@echo "[OLDTEST-PREP] Running test1"
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 605e7c73eb..009908ec09 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -263,7 +263,7 @@ else
endif
" Names of flaky tests.
-let s:flaky = [
+let s:flaky_tests = [
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_oneshot()',
@@ -281,6 +281,9 @@ let s:flaky = [
\ 'Test_lambda_with_timer()',
\ ]
+" Pattern indicating a common flaky test failure.
+let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
+
" Locate Test_ functions and execute them.
redir @q
silent function /^Test_
@@ -305,7 +308,9 @@ for s:test in sort(s:tests)
" Repeat a flaky test. Give up when:
" - it fails again with the same message
" - it fails five times (with a different mesage)
- if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
+ if len(v:errors) > 0
+ \ && (index(s:flaky_tests, s:test) >= 0
+ \ || v:errors[0] =~ s:flaky_errors_re)
while 1
call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors)
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index fe87bd6ef5..a4c8ce7e43 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -1,5 +1,11 @@
" Test that the methods used for testing work.
+func Test_assert_fails_in_try_block()
+ try
+ call assert_equal(0, assert_fails('throw "error"'))
+ endtry
+endfunc
+
" Must be last.
func Test_zz_quit_detected()
" Verify that if a test function ends Vim the test script detects this.
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 86347ab77f..0c45db049b 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -87,3 +87,61 @@ func Test_filter_cmd_with_filter()
call assert_equal('a|b', out)
set shelltemp&
endfunction
+
+func Test_filter_commands()
+ let g:test_filter_a = 1
+ let b:test_filter_b = 2
+ let test_filter_c = 3
+
+ " Test filtering :let command
+ let res = split(execute("filter /^test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1"], res)
+
+ let res = split(execute("filter /\\v^(b:)?test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1", "b:test_filter_b #2"], res)
+
+ unlet g:test_filter_a
+ unlet b:test_filter_b
+ unlet test_filter_c
+
+ " Test filtering :set command
+ let helplang=&helplang
+ set helplang=en
+ let res = join(split(execute("filter /^help/ set"), "\n")[1:], " ")
+ call assert_match('^\s*helplang=\w*$', res)
+ let &helplang=helplang
+
+ " Test filtering :llist command
+ call setloclist(0, [{"filename": "/path/vim.c"}, {"filename": "/path/vim.h"}, {"module": "Main.Test"}])
+ let res = split(execute("filter /\\.c$/ llist"), "\n")
+ call assert_equal([" 1 /path/vim.c: "], res)
+
+ let res = split(execute("filter /\\.Test$/ llist"), "\n")
+ call assert_equal([" 3 Main.Test: "], res)
+
+ " Test filtering :jump command
+ e file.c
+ e file.h
+ e file.hs
+ let res = split(execute("filter /\.c$/ jumps"), "\n")[1:]
+ call assert_equal([" 2 1 0 file.c", ">"], res)
+
+ " Test filtering :marks command
+ b file.c
+ mark A
+ b file.h
+ mark B
+ let res = split(execute("filter /\.c$/ marks"), "\n")[1:]
+ call assert_equal([" A 1 0 file.c"], res)
+
+ call setline(1, ['one', 'two', 'three'])
+ 1mark a
+ 2mark b
+ 3mark c
+ let res = split(execute("filter /two/ marks abc"), "\n")[1:]
+ call assert_equal([" b 2 0 two"], res)
+
+ bwipe! file.c
+ bwipe! file.h
+ bwipe! file.hs
+endfunc
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 0c3c356622..615536baef 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1188,3 +1188,45 @@ func Test_libcall_libcallnr()
call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
endfunc
+
+func Test_bufadd_bufload()
+ call assert_equal(0, bufexists('someName'))
+ let buf = bufadd('someName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('someName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal([''], getbufline(buf, 1, '$'))
+
+ let curbuf = bufnr('')
+ call writefile(['some', 'text'], 'otherName')
+ let buf = bufadd('otherName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('otherName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
+ call assert_equal(curbuf, bufnr(''))
+
+ let buf1 = bufadd('')
+ let buf2 = bufadd('')
+ call assert_notequal(0, buf1)
+ call assert_notequal(0, buf2)
+ call assert_notequal(buf1, buf2)
+ call assert_equal(1, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ call assert_equal(0, bufloaded(buf1))
+ exe 'bwipe ' .. buf1
+ call assert_equal(0, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ exe 'bwipe ' .. buf2
+ call assert_equal(0, bufexists(buf2))
+
+ bwipe someName
+ bwipe otherName
+ call assert_equal(0, bufexists('someName'))
+endfunc
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
index 42ac0c4d0f..697b552df4 100644
--- a/src/nvim/testdir/test_source.vim
+++ b/src/nvim/testdir/test_source.vim
@@ -8,3 +8,40 @@ func Test_source_sandbox()
call assert_fails('sandbox source! Xsourcehello', 'E48:')
bwipe!
endfunc
+
+func Test_source_autocmd()
+ call writefile([
+ \ 'let did_source = 1',
+ \ ], 'Xsourced')
+ au SourcePre *source* let did_source_pre = 1
+ au SourcePost *source* let did_source_post = 1
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 1)
+ call assert_equal(g:did_source_pre, 1)
+ call assert_equal(g:did_source_post, 1)
+
+ call delete('Xsourced')
+ au! SourcePre
+ au! SourcePost
+ unlet g:did_source
+ unlet g:did_source_pre
+ unlet g:did_source_post
+endfunc
+
+func Test_source_cmd()
+ au SourceCmd *source* let did_source = expand('<afile>')
+ au SourcePre *source* let did_source_pre = 2
+ au SourcePost *source* let did_source_post = 2
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 'Xsourced')
+ call assert_false(exists('g:did_source_pre'))
+ call assert_equal(g:did_source_post, 2)
+
+ au! SourceCmd
+ au! SourcePre
+ au! SourcePost
+endfunc
diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim
index e569e49055..ef5a96bd72 100644
--- a/src/nvim/testdir/test_suspend.vim
+++ b/src/nvim/testdir/test_suspend.vim
@@ -2,6 +2,20 @@
source shared.vim
+func CheckSuspended(buf, fileExists)
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(a:buf, '.'))})
+
+ if a:fileExists
+ call assert_equal(['foo'], readfile('Xfoo'))
+ else
+ " Without 'autowrite', buffer should not be written.
+ call assert_equal(0, filereadable('Xfoo'))
+ endif
+
+ call term_sendkeys(a:buf, "fg\<CR>\<C-L>")
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(a:buf, '.'))})
+endfunc
+
func Test_suspend()
if !has('terminal') || !executable('/bin/sh')
return
@@ -26,13 +40,7 @@ func Test_suspend()
\ "\<C-Z>"]
" Suspend and wait for shell prompt.
call term_sendkeys(buf, suspend_cmd)
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
-
- " Without 'autowrite', buffer should not be written.
- call assert_equal(0, filereadable('Xfoo'))
-
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 0)
endfor
" Test that :suspend! with 'autowrite' writes content of buffers if modified.
@@ -40,14 +48,13 @@ func Test_suspend()
call assert_equal(0, filereadable('Xfoo'))
call term_sendkeys(buf, ":suspend\<CR>")
" Wait for shell prompt.
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
- call assert_equal(['foo'], readfile('Xfoo'))
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 1)
" Quit gracefully to dump coverage information.
call term_sendkeys(buf, ":qall!\<CR>")
call term_wait(buf)
+ " Wait until Vim actually exited and shell shows a prompt
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
call Stop_shell_in_terminal(buf)
exe buf . 'bwipe!'
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 003a23ea7b..2a07a04401 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -518,6 +518,43 @@ func Test_winrestcmd()
only
endfunc
+function! Fun_RenewFile()
+ sleep 2
+ silent execute '!echo "1" > tmp.txt'
+ sp
+ wincmd p
+ edit! tmp.txt
+endfunction
+
+func Test_window_prevwin()
+ " Can we make this work on MS-Windows?
+ if !has('unix')
+ return
+ endif
+
+ set hidden autoread
+ 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
+ call assert_equal(1, winnr())
+ wincmd p
+ q
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ " reset
+ q
+ call delete('tmp.txt')
+ set hidden&vim autoread&vim
+ delfunc Fun_RenewFile
+endfunc
+
func Test_relative_cursor_position_in_one_line_window()
new
only
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index 8adb421ee1..9e4aaff878 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <limits.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
#include "nvim/ugrid.h"
@@ -72,8 +73,9 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)
for (i = start; i != stop; i += step) {
UCell *target_row = grid->cells[i] + left;
UCell *source_row = grid->cells[i + count] + left;
+ assert(right >= left && left >= 0);
memcpy(target_row, source_row,
- sizeof(UCell) * (size_t)(right - left + 1));
+ sizeof(UCell) * ((size_t)right - (size_t)left + 1));
}
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 7dbb8ec790..fc4a3a403d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -341,15 +341,15 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
flags, (const schar_T *)grid->chars + off,
(const sattr_T *)grid->attrs + off);
- if (p_wd) { // 'writedelay': flush & delay each time.
- int old_row = cursor_row, old_col = cursor_col;
- handle_T old_grid = cursor_grid_handle;
+ // 'writedelay': flush & delay each time.
+ if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) {
// If 'writedelay' is active, set the cursor to indicate what was drawn.
- ui_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)Columns-1));
- ui_flush();
+ ui_call_grid_cursor_goto(grid->handle, row,
+ MIN(clearcol, (int)grid->Columns-1));
+ ui_call_flush();
uint64_t wd = (uint64_t)labs(p_wd);
os_microdelay(wd * 1000u, true);
- ui_grid_cursor_goto(old_grid, old_row, old_col);
+ pending_cursor_update = true; // restore the cursor later
}
}
@@ -372,6 +372,14 @@ void ui_grid_cursor_goto(handle_T grid_handle, int new_row, int new_col)
pending_cursor_update = true;
}
+/// moving the cursor grid will implicitly move the cursor
+void ui_check_cursor_grid(handle_T grid_handle)
+{
+ if (cursor_grid_handle == grid_handle) {
+ pending_cursor_update = true;
+ }
+}
+
void ui_mode_info_set(void)
{
pending_mode_info_update = true;
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index d12a411019..d0b21ae591 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -49,6 +49,8 @@ static bool valid_screen = true;
static bool msg_scroll_mode = false;
static int msg_first_invalid = 0;
+static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose;
+
void ui_comp_init(void)
{
if (compositor != NULL) {
@@ -81,6 +83,13 @@ void ui_comp_init(void)
ui_attach_impl(compositor);
}
+void ui_comp_syn_init(void)
+{
+ dbghl_normal = syn_check_group((char_u *)S_LEN("RedrawDebugNormal"));
+ dbghl_clear = syn_check_group((char_u *)S_LEN("RedrawDebugClear"));
+ dbghl_composed = syn_check_group((char_u *)S_LEN("RedrawDebugComposed"));
+ dbghl_recompose = syn_check_group((char_u *)S_LEN("RedrawDebugRecompose"));
+}
void ui_comp_attach(UI *ui)
{
@@ -290,10 +299,14 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
{
// in case we start on the right half of a double-width char, we need to
// check the left half. But skip it in output if it wasn't doublewidth.
- int skip = 0;
+ int skipstart = 0, skipend = 0;
if (startcol > 0 && (flags & kLineFlagInvalid)) {
startcol--;
- skip = 1;
+ skipstart = 1;
+ }
+ if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) {
+ endcol++;
+ skipend = 1;
}
int col = (int)startcol;
@@ -331,11 +344,22 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
// 'pumblend' and 'winblend'
if (grid->blending) {
- for (int i = col-(int)startcol; i < until-startcol; i++) {
- bool thru = strequal((char *)linebuf[i], " "); // negative space
+ int width;
+ for (int i = col-(int)startcol; i < until-startcol; i += width) {
+ width = 1;
+ // negative space
+ bool thru = strequal((char *)linebuf[i], " ") && bg_line[i][0] != NUL;
+ if (i+1 < endcol-startcol && bg_line[i+1][0] == NUL) {
+ width = 2;
+ thru &= strequal((char *)linebuf[i+1], " ");
+ }
attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], &thru);
+ if (width == 2) {
+ attrbuf[i+1] = (sattr_T)hl_blend_attrs(bg_attrs[i+1],
+ attrbuf[i+1], &thru);
+ }
if (thru) {
- memcpy(linebuf[i], bg_line[i], sizeof(linebuf[i]));
+ memcpy(linebuf[i], bg_line[i], (size_t)width * sizeof(linebuf[i]));
}
}
}
@@ -345,20 +369,27 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
if (linebuf[col-startcol][0] == NUL) {
linebuf[col-startcol][0] = ' ';
linebuf[col-startcol][1] = NUL;
+ if (col == endcol-1) {
+ skipend = 0;
+ }
} else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
- skip = 0;
+ skipstart = 0;
}
if (grid->comp_col+grid->Columns > until
&& grid->chars[off+n][0] == NUL) {
linebuf[until-1-startcol][0] = ' ';
linebuf[until-1-startcol][1] = '\0';
if (col == startcol && n == 1) {
- skip = 0;
+ skipstart = 0;
}
}
col = until;
}
+ if (linebuf[endcol-startcol-1][0] == NUL) {
+ skipend = 0;
+ }
+
assert(endcol <= chk_width);
assert(row < chk_height);
@@ -368,14 +399,48 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
flags = flags & ~kLineFlagWrap;
}
- ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags,
- (const schar_T *)linebuf+skip,
- (const sattr_T *)attrbuf+skip);
+ ui_composed_call_raw_line(1, row, startcol+skipstart,
+ endcol-skipend, endcol-skipend, 0, flags,
+ (const schar_T *)linebuf+skipstart,
+ (const sattr_T *)attrbuf+skipstart);
}
+static void compose_debug(Integer startrow, Integer endrow, Integer startcol,
+ Integer endcol, int syn_id, bool delay)
+{
+ if (!(rdb_flags & RDB_COMPOSITOR)) {
+ return;
+ }
+
+ endrow = MIN(endrow, default_grid.Rows);
+ endcol = MIN(endcol, default_grid.Columns);
+ int attr = syn_id2attr(syn_id);
+
+ for (int row = (int)startrow; row < endrow; row++) {
+ ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false,
+ (const schar_T *)linebuf,
+ (const sattr_T *)attrbuf);
+ }
+
+
+ if (delay) {
+ debug_delay(endrow-startrow);
+ }
+}
+
+static void debug_delay(Integer lines)
+{
+ ui_call_flush();
+ uint64_t wd = (uint64_t)labs(p_wd);
+ uint64_t factor = (uint64_t)MAX(MIN(lines, 5), 1);
+ os_microdelay(factor * wd * 1000u, true);
+}
+
+
static void compose_area(Integer startrow, Integer endrow,
Integer startcol, Integer endcol)
{
+ compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns);
if (endcol <= startcol) {
@@ -420,8 +485,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
if (flags & kLineFlagInvalid
|| kv_size(layers) > curgrid->comp_index+1
|| curgrid->blending) {
+ compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true);
compose_line(row, startcol, clearcol, flags);
} else {
+ compose_debug(row, row+1, startcol, endcol, dbghl_normal, false);
+ compose_debug(row, row+1, endcol, clearcol, dbghl_clear, true);
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
flags, chunk, attrs);
}
@@ -481,6 +549,9 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
} else {
msg_first_invalid = MIN(msg_first_invalid, (int)top);
ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols);
+ if (rdb_flags & RDB_COMPOSITOR) {
+ debug_delay(2);
+ }
}
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a3b1efeaaa..38246bfe2a 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -375,7 +375,7 @@ newwindow:
/* set current window height */
case Ctrl__:
case '_':
- win_setheight(Prenum ? (int)Prenum : 9999);
+ win_setheight(Prenum ? (int)Prenum : Rows-1);
break;
/* increase current window width */
@@ -390,7 +390,7 @@ newwindow:
/* set current window width */
case '|':
- win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
+ win_setwidth(Prenum != 0 ? (int)Prenum : Columns);
break;
/* jump to tag and split window if tag exists (in preview window) */
@@ -584,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
wp->w_status_height = 0;
wp->w_vsep_width = 0;
- // TODO(bfredl): use set_option_to() after merging #9110 ?
- wp->w_p_nu = false;
- wp->w_allbuf_opt.wo_nu = false;
win_config_float(wp, fconfig);
wp->w_pos_changed = true;
redraw_win_later(wp, VALID);
return wp;
}
+void win_set_minimal_style(win_T *wp)
+{
+ wp->w_p_nu = false;
+ wp->w_p_rnu = false;
+ wp->w_p_cul = false;
+ wp->w_p_cuc = false;
+ wp->w_p_spell = false;
+ wp->w_p_list = false;
+
+ // Hide EOB region: use " " fillchar and cleared highlighting
+ if (wp->w_p_fcs_chars.eob != ' ') {
+ char_u *old = wp->w_p_fcs;
+ wp->w_p_fcs = ((*old == NUL)
+ ? (char_u *)xstrdup("eob: ")
+ : concat_str(old, (char_u *)",eob: "));
+ xfree(old);
+ }
+ if (wp->w_hl_ids[HLF_EOB] != -1) {
+ char_u *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? (char_u *)xstrdup("EndOfBuffer:")
+ : concat_str(old, (char_u *)",EndOfBuffer:"));
+ xfree(old);
+ }
+
+ if (wp->w_p_scl[0] != 'a') {
+ xfree(wp->w_p_scl);
+ wp->w_p_scl = (char_u *)xstrdup("auto");
+ }
+}
+
void win_config_float(win_T *wp, FloatConfig fconfig)
{
wp->w_width = MAX(fconfig.width, 1);
@@ -666,6 +694,7 @@ static void ui_ext_win_position(win_T *wp)
bool on_top = (curwin == wp) || !curwin->w_floating;
ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height,
wp->w_width, valid, on_top);
+ ui_check_cursor_grid(wp->w_grid.handle);
if (!valid) {
wp->w_grid.valid = false;
redraw_win_later(wp, NOT_VALID);
@@ -821,6 +850,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
"'focusable' key must be Boolean");
return false;
}
+ } else if (!strcmp(key, "style")) {
+ if (val.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "'style' key must be String");
+ return false;
+ }
+ if (val.data.string.data[0] == NUL) {
+ fconfig->style = kWinStyleUnused;
+ } else if (striequal(val.data.string.data, "minimal")) {
+ fconfig->style = kWinStyleMinimal;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'style' key");
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
@@ -981,7 +1024,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_ROW) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minwidth += frame_minwidth(frp2, NOWIN);
}
@@ -1059,7 +1102,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minheight += frame_minheight(frp2, NOWIN);
}
@@ -1204,11 +1247,13 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
curfrp->fr_child = frp;
curfrp->fr_win = NULL;
curfrp = frp;
- if (frp->fr_win != NULL)
+ if (frp->fr_win != NULL) {
oldwin->w_frame = frp;
- else
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ } else {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frp->fr_parent = curfrp;
+ }
+ }
}
if (new_wp == NULL)
@@ -1674,13 +1719,13 @@ static void win_rotate(bool upwards, int count)
return;
}
- /* Check if all frames in this row/col have one window. */
- for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next)
+ // Check if all frames in this row/col have one window.
+ FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child) {
if (frp->fr_win == NULL) {
EMSG(_("E443: Cannot rotate when another window is split"));
return;
}
+ }
while (count--) {
if (upwards) { /* first window becomes last window */
@@ -1918,10 +1963,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixwidth' set keep the window width if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixwidth' set keep the window width if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_width(fr)) {
continue;
}
@@ -1964,7 +2009,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2039,10 +2084,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixheight' set keep the window height if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixheight' set keep the window height if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_height(fr)) {
continue;
}
@@ -2085,7 +2130,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2772,8 +2817,9 @@ winframe_remove (
* and remove it. */
frp2->fr_parent->fr_layout = frp2->fr_layout;
frp2->fr_parent->fr_child = frp2->fr_child;
- for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, frp2->fr_child) {
frp->fr_parent = frp2->fr_parent;
+ }
frp2->fr_parent->fr_win = frp2->fr_win;
if (frp2->fr_win != NULL)
frp2->fr_win->w_frame = frp2->fr_parent;
@@ -2894,13 +2940,14 @@ static win_T *frame2win(frame_T *frp)
///
/// @param frp frame
/// @param wp window
-static bool frame_has_win(frame_T *frp, win_T *wp)
+static bool frame_has_win(const frame_T *frp, const win_T *wp)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
if (frp->fr_layout == FR_LEAF) {
return frp->fr_win == wp;
}
- for (frame_T *p = frp->fr_child; p != NULL; p = p->fr_next) {
+ const frame_T *p;
+ FOR_ALL_FRAMES(p, frp->fr_child) {
if (frame_has_win(p, wp)) {
return true;
}
@@ -2931,8 +2978,8 @@ frame_new_height (
height - topfrp->fr_win->w_status_height);
} else if (topfrp->fr_layout == FR_ROW) {
do {
- /* All frames in this row get the same new height. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this row get the same new height.
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_height(frp, height, topfirst, wfh);
if (frp->fr_height > height) {
/* Could not fit the windows, make the whole row higher. */
@@ -3013,7 +3060,7 @@ static bool frame_fixed_height(frame_T *frp)
if (frp->fr_layout == FR_ROW) {
// The frame is fixed height if one of the frames in the row is fixed
// height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_height(frp)) {
return true;
}
@@ -3023,7 +3070,7 @@ static bool frame_fixed_height(frame_T *frp)
// frp->fr_layout == FR_COL: The frame is fixed height if all of the
// frames in the row are fixed height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_height(frp)) {
return false;
}
@@ -3047,7 +3094,7 @@ static bool frame_fixed_width(frame_T *frp)
if (frp->fr_layout == FR_COL) {
// The frame is fixed width if one of the frames in the row is fixed
// width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_width(frp)) {
return true;
}
@@ -3057,7 +3104,7 @@ static bool frame_fixed_width(frame_T *frp)
// frp->fr_layout == FR_ROW: The frame is fixed width if all of the
// frames in the row are fixed width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_width(frp)) {
return false;
}
@@ -3081,13 +3128,15 @@ static void frame_add_statusline(frame_T *frp)
wp->w_status_height = STATUS_HEIGHT;
}
} else if (frp->fr_layout == FR_ROW) {
- /* Handle all the frames in the row. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the row.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_statusline(frp);
- } else { /* frp->fr_layout == FR_COL */
- /* Only need to handle the last frame in the column. */
- for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
- ;
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
+ // Only need to handle the last frame in the column.
+ for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) {
+ }
frame_add_statusline(frp);
}
}
@@ -3122,8 +3171,8 @@ frame_new_width (
win_new_width(wp, width - wp->w_vsep_width);
} else if (topfrp->fr_layout == FR_COL) {
do {
- /* All frames in this column get the same new width. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this column get the same new width.
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_width(frp, width, leftfirst, wfw);
if (frp->fr_width > width) {
/* Could not fit the windows, make whole column wider. */
@@ -3192,7 +3241,8 @@ frame_new_width (
* Add the vertical separator to windows at the right side of "frp".
* Note: Does not check if there is room!
*/
-static void frame_add_vsep(frame_T *frp)
+static void frame_add_vsep(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
win_T *wp;
@@ -3204,11 +3254,13 @@ static void frame_add_vsep(frame_T *frp)
wp->w_vsep_width = 1;
}
} else if (frp->fr_layout == FR_COL) {
- /* Handle all the frames in the column. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the column.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_vsep(frp);
- } else { /* frp->fr_layout == FR_ROW */
- /* Only need to handle the last frame in the row. */
+ }
+ } else {
+ assert(frp->fr_layout == FR_ROW);
+ // Only need to handle the last frame in the row.
frp = frp->fr_child;
while (frp->fr_next != NULL)
frp = frp->fr_next;
@@ -3258,7 +3310,7 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
} else if (topfrp->fr_layout == FR_ROW) {
/* get the minimal height from each frame in this row */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minheight(frp, next_curwin);
if (n > m)
m = n;
@@ -3266,8 +3318,9 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
} else {
/* Add up the minimal heights for all frames in this column. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minheight(frp, next_curwin);
+ }
}
return m;
@@ -3301,7 +3354,7 @@ frame_minwidth (
} else if (topfrp->fr_layout == FR_COL) {
/* get the minimal width from each frame in this column */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minwidth(frp, next_curwin);
if (n > m)
m = n;
@@ -3309,8 +3362,9 @@ frame_minwidth (
} else {
/* Add up the minimal widths for all frames in this row. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minwidth(frp, next_curwin);
+ }
}
return m;
@@ -4787,11 +4841,12 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
} else {
startrow = *row;
startcol = *col;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
- if (topfrp->fr_layout == FR_ROW)
- *row = startrow; /* all frames are at the same row */
- else
- *col = startcol; /* all frames are at the same col */
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
+ if (topfrp->fr_layout == FR_ROW) {
+ *row = startrow; // all frames are at the same row
+ } else {
+ *col = startcol; // all frames are at the same col
+ }
frame_comp_pos(frp, row, col);
}
}
@@ -4823,13 +4878,9 @@ void win_setheight_win(int height, win_T *win)
}
if (win->w_floating) {
- if (win->w_float_config.external) {
- win->w_float_config.height = height;
- win_config_float(win, win->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ win->w_float_config.height = height;
+ win_config_float(win, win->w_float_config);
+ redraw_win_later(win, NOT_VALID);
} else {
frame_setheight(win->w_frame, height + win->w_status_height);
@@ -4844,9 +4895,9 @@ void win_setheight_win(int height, win_T *win)
cmdline_row = row;
msg_row = row;
msg_col = 0;
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
@@ -4904,15 +4955,16 @@ static void frame_setheight(frame_T *curfrp, int height)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfh)
+ && frp->fr_win->w_p_wfh) {
room_reserved += frp->fr_height;
+ }
room += frp->fr_height;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minheight(frp, NULL);
+ }
}
if (curfrp->fr_width != Columns) {
room_cmdline = 0;
@@ -5029,21 +5081,17 @@ void win_setwidth_win(int width, win_T *wp)
width = 1;
}
if (wp->w_floating) {
- if (wp->w_float_config.external) {
- wp->w_float_config.width = width;
- win_config_float(wp, wp->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ wp->w_float_config.width = width;
+ win_config_float(wp, wp->w_float_config);
+ redraw_win_later(wp, NOT_VALID);
} else {
frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
// recompute the window positions
(void)win_comp_pos();
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
/*
@@ -5089,15 +5137,16 @@ static void frame_setwidth(frame_T *curfrp, int width)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfw)
+ && frp->fr_win->w_p_wfw) {
room_reserved += frp->fr_width;
+ }
room += frp->fr_width;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minwidth(frp, NULL);
+ }
}
if (width <= room)
@@ -5261,10 +5310,11 @@ void win_drag_status_line(win_T *dragwin, int offset)
room -= p_ch;
if (room < 0)
room = 0;
- /* sum up the room of frames below of the current one */
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ // sum up the room of frames below of the current one
+ FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_height - frame_minheight(fr, NULL);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
if (room < offset) /* Not enough room */
@@ -5364,9 +5414,10 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
left = FALSE;
/* sum up the room of frames right of the current one */
room = 0;
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_width - frame_minwidth(fr, NULL);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
assert(fr);
@@ -5898,9 +5949,10 @@ static void last_status_rec(frame_T *fr, int statusline)
redraw_all_later(SOME_VALID);
}
} else if (fr->fr_layout == FR_ROW) {
- /* vertically split windows, set status line for each one */
- for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
+ // vertically split windows, set status line for each one
+ FOR_ALL_FRAMES(fp, fr->fr_child) {
last_status_rec(fp, statusline);
+ }
} else {
/* horizontally split window, set status line for last one */
for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
@@ -6516,14 +6568,15 @@ matchitem_T *get_match(win_T *wp, int id)
///
/// @param topfrp top frame pointer
/// @param height expected height
-static bool frame_check_height(frame_T *topfrp, int height)
+static bool frame_check_height(const frame_T *topfrp, int height)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_height != height) {
return false;
}
if (topfrp->fr_layout == FR_ROW) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_height != height) {
return false;
}
@@ -6536,14 +6589,15 @@ static bool frame_check_height(frame_T *topfrp, int height)
///
/// @param topfrp top frame pointer
/// @param width expected width
-static bool frame_check_width(frame_T *topfrp, int width)
+static bool frame_check_width(const frame_T *topfrp, int width)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_width != width) {
return false;
}
if (topfrp->fr_layout == FR_COL) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_width != width) {
return false;
}
diff --git a/test/busted/outputHandlers/TAP.lua b/test/busted/outputHandlers/TAP.lua
new file mode 100644
index 0000000000..3dd171dc1b
--- /dev/null
+++ b/test/busted/outputHandlers/TAP.lua
@@ -0,0 +1,14 @@
+-- Extends the upstream TAP handler, to display the log with suiteEnd.
+
+local global_helpers = require('test.helpers')
+
+return function(options)
+ local handler = require 'busted.outputHandlers.TAP'(options)
+
+ handler.suiteEnd = function()
+ io.write(global_helpers.read_nvim_log())
+ return handler.suiteEnd()
+ end
+
+ return handler
+end
diff --git a/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index d137300a7e..1b500fc999 100644
--- a/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -1,6 +1,4 @@
-local s = require 'say'
local pretty = require 'pl.pretty'
-local term = require 'term'
local global_helpers = require('test.helpers')
local colors
@@ -65,8 +63,6 @@ return function(options)
},
}
- c = nil
-
local fileCount = 0
local fileTestCount = 0
local testCount = 0
@@ -76,7 +72,6 @@ return function(options)
local errorCount = 0
local pendingDescription = function(pending)
- local name = pending.name
local string = ''
if type(pending.message) == 'string' then
@@ -175,7 +170,7 @@ return function(options)
return nil, true
end
- handler.suiteStart = function(suite, count, total, randomseed)
+ handler.suiteStart = function(_suite, count, total, randomseed)
if total > 1 then
io.write(repeatSuiteString:format(count, total))
end
@@ -196,7 +191,7 @@ return function(options)
end
end
- handler.suiteEnd = function(suite, count, total)
+ handler.suiteEnd = function(suite, _count, _total)
local elapsedTime_ms = getElapsedTime(suite)
local tests = (testCount == 1 and 'test' or 'tests')
local files = (fileCount == 1 and 'file' or 'files')
@@ -225,14 +220,14 @@ return function(options)
return nil, true
end
- handler.testStart = function(element, parent)
+ handler.testStart = function(element, _parent)
io.write(runString:format(handler.getFullName(element)))
io.flush()
return nil, true
end
- handler.testEnd = function(element, parent, status, debug)
+ handler.testEnd = function(element, _parent, status, _debug)
local elapsedTime_ms = getElapsedTime(element)
local string
@@ -263,7 +258,7 @@ return function(options)
return nil, true
end
- handler.testFailure = function(element, parent, message, debug)
+ handler.testFailure = function(_element, _parent, _message, _debug)
io.write(failureString)
io.flush()
@@ -272,7 +267,7 @@ return function(options)
return nil, true
end
- handler.testError = function(element, parent, message, debug)
+ handler.testError = function(_element, _parent, _message, _debug)
io.write(errorString)
io.flush()
@@ -281,7 +276,7 @@ return function(options)
return nil, true
end
- handler.error = function(element, parent, message, debug)
+ handler.error = function(element, _parent, _message, _debug)
if element.descriptor ~= 'it' then
io.write(failureDescription(handler.errors[#handler.errors]))
io.flush()
diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua
new file mode 100644
index 0000000000..506b688853
--- /dev/null
+++ b/test/functional/autocmd/cursorhold_spec.lua
@@ -0,0 +1,31 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local retry = helpers.retry
+local source = helpers.source
+local sleep = helpers.sleep
+
+describe('CursorHoldI', function()
+ before_each(clear)
+
+ -- NOTE: since this test uses RPC it is not necessary to trigger the initial
+ -- issue (#3757) via timer's or RPC callbacks in the first place.
+ it('is triggered after input', function()
+ source([[
+ set updatetime=1
+
+ let g:cursorhold = 0
+ augroup test
+ au CursorHoldI * let g:cursorhold += 1
+ augroup END
+ ]])
+ feed('ifoo')
+ retry(5, nil, function()
+ sleep(1)
+ eq(1, eval('g:cursorhold'))
+ end)
+ end)
+end)
diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua
index ca82c8c9da..1107fe6a0b 100644
--- a/test/functional/eval/executable_spec.lua
+++ b/test/functional/eval/executable_spec.lua
@@ -21,17 +21,10 @@ describe('executable()', function()
-- Windows: siblings are in Nvim's "pseudo-$PATH".
local expected = iswin() and 1 or 0
if iswin() then
- -- $PATH on AppVeyor CI might be oversized, redefine it to a minimal one.
- clear({env={PATH=[[C:\Windows\system32;C:\Windows]]}})
eq('arg1=lemon;arg2=sky;arg3=tree;',
call('system', sibling_exe..' lemon sky tree'))
end
- local is_executable = call('executable', sibling_exe)
- if iswin() and is_executable ~= expected then
- pending('XXX: sometimes fails on AppVeyor')
- else
- eq(expected, is_executable)
- end
+ eq(expected, call('executable', sibling_exe))
end)
describe('exec-bit', function()
diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua
index 0181f09024..d78d858fb7 100644
--- a/test/functional/eval/reltime_spec.lua
+++ b/test/functional/eval/reltime_spec.lua
@@ -33,4 +33,18 @@ describe('reltimestr(), reltimefloat()', function()
ok(reltimefloat(differs) < 1.0)
end)
+
+ it('reltime() allows negative result #10452', function()
+ local older_time = reltime()
+ command('sleep 1m')
+ local newer_time = reltime()
+
+ -- Start/end swapped: should be something like -0.002123.
+ local rv = tonumber(reltimestr(reltime(newer_time, older_time)))
+ ok(rv < 0 and rv > -10)
+
+ -- Not swapped: should be something like 0.002123.
+ rv = tonumber(reltimestr(reltime(older_time, newer_time)))
+ ok(rv > 0 and rv < 10)
+ end)
end)
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index 5cbf34365b..865a890acf 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -203,12 +203,15 @@ describe('system()', function()
end)
it('prints verbose information', function()
+ nvim('set_option', 'shell', 'fake_shell')
+ nvim('set_option', 'shellcmdflag', 'cmdflag')
+
screen:try_resize(72, 14)
feed(':4verbose echo system("echo hi")<cr>')
if iswin() then
- screen:expect{any=[[Executing command: "'cmd.exe' '/s' '/c' '"echo hi"'"]]}
+ screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' '"echo hi"'"]]}
else
- screen:expect{any=[[Executing command: "'/[^']*sh' '%-c' 'echo hi'"]]}
+ screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' 'echo hi'"]]}
end
feed('<cr>')
end)
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index 2309e949c0..0cd32df27c 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -83,7 +83,7 @@ describe('menu_get', function()
it("path='', modes='a'", function()
local m = funcs.menu_get("","a");
-- HINT: To print the expected table and regenerate the tests:
- -- print(require('inspect')(m))
+ -- print(require('vim.inspect')(m))
local expected = {
{
shortcut = "T",
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index 6a1f9226d2..1ff1598e2b 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -33,13 +33,12 @@ static void help(void)
puts(" Prints \"ready $ prog args...\\n\" to stderr.");
puts(" shell-test -t {prompt text} EXE \"prog args...\"");
puts(" Prints \"{prompt text} $ progs args...\" to stderr.");
- puts(" shell-test REP {byte} \"line line line\"");
- puts(" Prints \"{lnr}: line line line\\n\" to stdout {byte} times.");
- puts(" I.e. for `shell-test REP ab \"test\"'");
+ puts(" shell-test REP {count} \"line line line\"");
+ puts(" Prints \"{lnr}: line line line\\n\" to stdout {count} times.");
+ puts(" I.e. for `shell-test REP 97 \"test\"'");
puts(" 0: test");
puts(" ...");
puts(" 96: test");
- puts(" will be printed because byte `a' is equal to 97.");
puts(" shell-test INTERACT");
puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input.");
}
@@ -71,8 +70,12 @@ int main(int argc, char **argv)
fprintf(stderr, "Not enough REP arguments\n");
return 4;
}
- uint8_t number = (uint8_t) *argv[2];
- for (uint8_t i = 0; i < number; i++) {
+ int count = 0;
+ if (sscanf(argv[2], "%d", &count) != 1) {
+ fprintf(stderr, "Invalid count: %s\n", argv[2]);
+ return 4;
+ }
+ for (uint8_t i = 0; i < count; i++) {
printf("%d: %s\n", (int) i, argv[3]);
}
} else if (strcmp(argv[1], "UTF-8") == 0) {
@@ -104,7 +107,7 @@ int main(int argc, char **argv)
break; // EOF
}
- input_argc = sscanf(input, "%s %d", cmd, &arg);
+ input_argc = sscanf(input, "%99s %d", cmd, &arg);
if(1 == input_argc) {
arg = 0;
}
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index 84d7ae6e9c..d213bae7b3 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -34,10 +34,9 @@ describe(':edit term://*', function()
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
- local rep = 'a'
+ local rep = 97
meths.set_option('shellcmdflag', 'REP ' .. rep)
command('set shellxquote=') -- win: avoid extra quotes
- local rep_size = rep:byte() -- 'a' => 97
local sb = 10
command('autocmd TermOpen * :setlocal scrollback='..tostring(sb)
..'|call feedkeys("G", "n")')
@@ -45,8 +44,8 @@ describe(':edit term://*', function()
local bufcontents = {}
local winheight = curwinmeths.get_height()
- local buf_cont_start = rep_size - sb - winheight + 2
- for i = buf_cont_start,(rep_size - 1) do
+ local buf_cont_start = rep - sb - winheight + 2
+ for i = buf_cont_start,(rep - 1) do
bufcontents[#bufcontents + 1] = ('%d: foobar'):format(i)
end
bufcontents[#bufcontents + 1] = ''
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 2c731066bd..591e6340cf 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -261,4 +261,14 @@ describe(':terminal (with fake shell)', function()
eq('scripts/shadacat.py', eval('bufname("%")'))
end)
+ it('with bufhidden=delete #3958', function()
+ command('set hidden')
+ eq(1, eval('&hidden'))
+ command('autocmd BufNew * setlocal bufhidden=delete')
+ for _ = 1, 5 do
+ source([[
+ execute 'edit '.reltimestr(reltime())
+ terminal]])
+ end
+ end)
end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 4dc86f1e1f..6475eb2923 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -216,10 +216,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 50
+ m.hl_id = 54
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 51 end
+ if m.id_lm then m.id_lm = 55 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 41ba542899..8a1758c4a0 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -35,6 +35,10 @@ describe('floating windows', function()
[15] = {background = Screen.colors.Grey20},
[16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1},
[17] = {background = Screen.colors.Yellow},
+ [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20},
+ [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [20] = {bold = true, foreground = Screen.colors.Brown},
+ [21] = {background = Screen.colors.Gray90},
}
it('behavior', function()
@@ -168,6 +172,121 @@ describe('floating windows', function()
end
end)
+ it('draws correctly with redrawdebug=compositor', function()
+ -- NB: we do not test that it produces the "correct" debug info
+ -- (as it is intermediate only, and is allowed to change by internal
+ -- refactors). Only check that it doesn't cause permanent glitches,
+ -- or something.
+ command("set redrawdebug=compositor")
+ command("set wd=1")
+ local buf = meths.create_buf(false,false)
+ local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5})
+ local expected_pos = {
+ [3]={{id=1001}, 'NW', 1, 2, 5, true},
+ }
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }{1: }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+
+ meths.win_set_config(win, {relative='editor', row=0, col=10})
+ expected_pos[3][4] = 0
+ expected_pos[3][5] = 10
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ ^ {1: } |
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ meths.win_close(win, false)
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+ end)
+
it('return their configuration', function()
local buf = meths.create_buf(false, false)
local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5})
@@ -182,7 +301,7 @@ describe('floating windows', function()
end
end)
- it('defaults to nonumber and NormalFloat highlight', function()
+ it('defaults to NormalFloat highlight and inherited options', function()
command('set number')
command('hi NormalFloat guibg=#333333')
feed('ix<cr>y<cr><esc>gg')
@@ -205,18 +324,18 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15:x }|
- {15:y }|
- {15: }|
+ {18: 1 }{15:x }|
+ {18: 2 }{15:y }|
+ {18: 3 }{15: }|
{16:~ }|
]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15:x } |
- {0:~ }{15:y }{0: }|
- {0:~ }{15: }{0: }|
+ {14: 3 } {18: 1 }{15:x } |
+ {0:~ }{18: 2 }{15:y }{0: }|
+ {0:~ }{18: 3 }{15: }{0: }|
{0:~ }{16:~ }{0: }|
|
]])
@@ -242,7 +361,7 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15: }|
+ {18: 1 }{15: }|
{16:~ }|
{16:~ }|
{16:~ }|
@@ -251,7 +370,7 @@ describe('floating windows', function()
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15: } |
+ {14: 3 } {18: 1 }{15: } |
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
@@ -260,6 +379,126 @@ describe('floating windows', function()
end
end)
+ it("can use 'minimal' style", function()
+ command('set number')
+ command('set signcolumn=yes')
+ command('set cursorline')
+ 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'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15:x }|
+ {15:y }|
+ {15: }|
+ {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 } |
+ {0:~ }{15:y }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+
+ -- signcolumn=yes still works if there actually are signs
+ command('sign define piet1 text=𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄ texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
+ {19: }{15:y }|
+ {19: }{15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+
+ else
+ screen:expect([[
+ {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: }|
+ |
+ ]])
+ end
+ command('sign unplace 1 buffer=1')
+
+ local buf = meths.create_buf(false, true)
+ meths.win_set_buf(win, buf)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15: }|
+ {15: }|
+ {15: }|
+ {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: } |
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ end)
+
it('can have minimum size', function()
insert("the background text")
local buf = meths.create_buf(false, true)
@@ -2539,6 +2778,356 @@ describe('floating windows', function()
end)
+ it("vertical resize + - _", function()
+ feed('<c-w>w')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>+')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>2-')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>4_')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ |
+ ]])
+ end
+
+ feed('<c-w>_')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x {1:^y } |
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ |
+ ]])
+ end
+ end)
+
+ it("horizontal resize > < |", function()
+ feed('<c-w>w')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>10<lt>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>15|')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>|')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {1:^y }|
+ {2:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+ end)
+
it("s :split (non-float)", function()
feed("<c-w>s")
if multigrid then
@@ -3999,6 +4588,168 @@ describe('floating windows', function()
]])
end
end)
+
+ it('can overlap doublewidth chars', function()
+ insert([[
+ # TODO: 测试字典信息的准确性
+ # FIXME: 测试字典信息的准确性]])
+ local buf = meths.create_buf(false,false)
+ local win = meths.open_win(buf, false, {relative='editor', width=5, height=3, row=0, col=11, style='minimal'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信息的准确性 |
+ # FIXME: 测试字典信息的准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {1: }|
+ {1: }|
+ ]], float_pos={ [3] = { { id = 1001 }, "NW", 1, 0, 11, true } }}
+ else
+ screen:expect([[
+ # TODO: 测 {1: }信息的准确性 |
+ # FIXME: 测{1: } 信息的准确^性 |
+ {0:~ }{1: }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ meths.win_close(win, false)
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信息的准确性 |
+ # FIXME: 测试字典信息的准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ # TODO: 测试字典信息的准确性 |
+ # FIXME: 测试字典信息的准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ -- The interaction between 'winblend' and doublewidth chars in the background
+ -- does not look very good. But check no chars get incorrectly placed
+ -- at least. Also check invisible EndOfBuffer region blends correctly.
+ meths.buf_set_lines(buf, 0, -1, true, {" x x x xx", " x x x x"})
+ win = meths.open_win(buf, false, {relative='editor', width=12, height=3, row=0, col=11, style='minimal'})
+ meths.win_set_option(win, 'winblend', 30)
+ screen:set_default_attr_ids({
+ [1] = {foreground = tonumber('0xb282b2'), background = tonumber('0xffcfff')},
+ [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},
+ })
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信息的准确性 |
+ # FIXME: 测试字典信息的准确^性 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ ## grid 5
+ {5: x x x xx}|
+ {5: x x x x}|
+ {5: }|
+ ]], float_pos={
+ [5] = { {
+ id = 1003
+ }, "NW", 1, 0, 11, true }
+ }}
+ else
+ screen:expect([[
+ # TODO: 测 {2: x x x}{1:息}{2: xx} 确性 |
+ # FIXME: 测{1:试}{2:x x x}{1:息}{2: x}准确^性 |
+ {3:~ }{4: }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='editor', row=0, col=12})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信息的准确性 |
+ # FIXME: 测试字典信息的准确^性 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ ## grid 5
+ {5: x x x xx}|
+ {5: x x x x}|
+ {5: }|
+ ]], float_pos={
+ [5] = { {
+ id = 1003
+ }, "NW", 1, 0, 12, true }
+ }}
+ else
+ screen:expect([[
+ # TODO: 测试{2: x x}{1:信}{2:x }{1:的}{2:xx}确性 |
+ # FIXME: 测 {2: x x}{1:信}{2:x }{1:的}{2:x} 确^性 |
+ {3:~ }{4: }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 85b5aed2f8..08566fe493 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -311,6 +311,38 @@ describe('highlight defaults', function()
[1] = {foreground=Screen.colors.Blue},
})
end)
+
+ it('are sent to UIs', function()
+ screen:try_resize(53, 4)
+ screen:set_default_attr_ids({
+ [0] = {},
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {italic=true}
+ })
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=1, MsgSeparator=2}}
+
+ command('highlight EndOfBuffer gui=italic')
+ screen:expect{grid=[[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=3, MsgSeparator=2}}
+
+ command('highlight clear EndOfBuffer')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ |
+ ]], hl_groups={EndOfBuffer=0, MsgSeparator=2}}
+ end)
end)
describe('highlight', function()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 09e13b1464..2857c2fe1e 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -804,6 +804,7 @@ describe('ui/builtin messages', function()
[3] = {bold = true, reverse = true},
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
[5] = {foreground = Screen.colors.Blue1},
+ [6] = {bold = true, foreground = Screen.colors.Magenta},
})
end)
@@ -856,6 +857,46 @@ describe('ui/builtin messages', function()
eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red',
meths.command_output("hi ErrorMsg"))
end)
+
+ it(':syntax list langGroup output', function()
+ command("syntax on")
+ command("set syntax=vim")
+ screen:try_resize(110,7)
+ feed(':syntax list vimComment<cr>')
+ screen:expect([[
+ {6:--- Syntax items ---} |
+ vimComment {5:xxx} {5:match} /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 {5:excludenl} {5:contains}=@vimCommentGroup,vimCommentString |
+ |
+ {5:match} /\<endif\s\+".*$/ms=s+5,lc=5 {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:match} /\<else\s\+".*$/ms=s+4,lc=4 {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:links to} Comment |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:try_resize(55,7)
+ feed(':syntax list vimComment<cr>')
+ screen:expect([[
+ |
+ {5:match} /\<endif\s\+".*$/ms=s+5,lc=5 |
+ {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:match} /\<else\s\+".*$/ms=s+4,lc=4 {5:c}|
+ {5:ontains}=@vimCommentGroup,vimCommentString |
+ {5:links to} Comment |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+
+ -- ignore final whitespace inside string
+ -- luacheck: push ignore
+ eq([[--- Syntax items ---
+vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vimCommentGroup,vimCommentString
+ match /\<endif\s\+".*$/ms=s+5,lc=5 contains=@vimCommentGroup,vimCommentString
+ match /\<else\s\+".*$/ms=s+4,lc=4 contains=@vimCommentGroup,vimCommentString
+ links to Comment]],
+ meths.command_output('syntax list vimComment'))
+ -- luacheck: pop
+ end)
end)
describe('ui/ext_messages', function()
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index f1254b68f6..eb059c38ee 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -81,7 +81,7 @@ local dedent = helpers.dedent
local get_session = helpers.get_session
local create_callindex = helpers.create_callindex
-local inspect = require('inspect')
+local inspect = require('vim.inspect')
local function isempty(v)
return type(v) == 'table' and next(v) == nil
@@ -165,6 +165,7 @@ function Screen.new(width, height)
showmode = {},
showcmd = {},
ruler = {},
+ hl_groups = {},
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
@@ -322,7 +323,7 @@ function Screen:expect(expected, attr_ids, attr_ignore)
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
any=true, mode=true, unchanged=true, intermediate=true,
- reset=true, timeout=true, request_cb=true}
+ reset=true, timeout=true, request_cb=true, hl_groups=true}
for _, v in ipairs(ext_keys) do
is_key[v] = true
end
@@ -418,9 +419,10 @@ screen:redraw_debug() to show all intermediate screen states. ]])
-- (e.g. no external cmdline visible). Some extensions require
-- preprocessing to represent highlights in a reproducible way.
local extstate = self:_extstate_repr(attr_state)
- if expected['mode'] ~= nil then
- extstate['mode'] = self.mode
+ if expected.mode ~= nil then
+ extstate.mode = self.mode
end
+
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
-- Empty states are considered the default and need not be mentioned.
@@ -431,6 +433,17 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
+
+ if expected.hl_groups ~= nil then
+ for name, id in pairs(expected.hl_groups) do
+ local expected_hl = attr_state.ids[id]
+ local actual_hl = self._attr_table[self.hl_groups[name]][(self._options.rgb and 1) or 2]
+ local status, res = pcall(eq, expected_hl, actual_hl, "highlight "..name)
+ if not status then
+ return tostring(res)
+ end
+ end
+ end
end, expected)
end
@@ -492,7 +505,7 @@ function Screen:_wait(check, flags)
end
elseif success_seen and #args > 0 then
failure_after_success = true
- --print(require('inspect')(args))
+ -- print(inspect(args))
end
return true
@@ -576,8 +589,7 @@ end
function Screen:_redraw(updates)
local did_flush = false
for k, update in ipairs(updates) do
- -- print('--')
- -- print(require('inspect')(update))
+ -- print('--', inspect(update))
local method = update[1]
for i = 2, #update do
local handler_name = '_handle_'..method
@@ -837,6 +849,10 @@ function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
self._new_attrs = true
end
+function Screen:_handle_hl_group_set(name, id)
+ self.hl_groups[name] = id
+end
+
function Screen:get_hl(val)
if self._options.ext_newgrid then
return self._attr_table[val][1]
@@ -1339,7 +1355,7 @@ end
function Screen:_pprint_hlstate(item)
- --print(require('inspect')(item))
+ -- print(inspect(item))
local attrdict = "{"..self:_pprint_attrs(item[1]).."}, "
local attrdict2, hlinfo
if self._hlstate_cterm then
@@ -1412,17 +1428,17 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
end
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
else
- for id, a in pairs(attr_state.ids) do
- if self:_equal_attrs(a, attrs) then
- return id
- end
- end
if self:_equal_attrs(attrs, {}) or
attr_state.ignore == true or
self:_attr_index(attr_state.ignore, attrs) ~= nil then
-- ignore this attrs
return nil
end
+ for id, a in pairs(attr_state.ids) do
+ if self:_equal_attrs(a, attrs) then
+ return id
+ end
+ end
if attr_state.mutable then
table.insert(attr_state.ids, attrs)
attr_state.modified = true
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index b2b05e1175..768c89f922 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -1,6 +1,6 @@
# This is not meant to be included by the top-level.
cmake_minimum_required (VERSION 2.8.12)
-project(NVIM_DEPS)
+project(NVIM_DEPS C)
# Needed for: check_c_compiler_flag()
include(CheckCCompilerFlag)
@@ -101,6 +101,7 @@ set(DEPS_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
if(CMAKE_OSX_SYSROOT)
set(DEPS_C_COMPILER "${DEPS_C_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}")
+ set(DEPS_CXX_COMPILER "${DEPS_CXX_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}")
endif()
# Cross compiling: use these for dependencies built for the
@@ -125,11 +126,11 @@ include(ExternalProject)
if(WIN32)
# "nvim" branch of https://github.com/neovim/libuv
- set(LIBUV_URL https://github.com/neovim/libuv/archive/0ac136359903c70ab1db1838c3ad06da6fa5b912.tar.gz)
- set(LIBUV_SHA256 600badb81e39578ddfc8f3636f78dd308ea0915e5bf1ee56e6cdfa314d3c463f)
+ set(LIBUV_URL https://github.com/neovim/libuv/archive/eeae18d085de25f138c23966f98a179f0fb609e7.tar.gz)
+ set(LIBUV_SHA256 c37d0b7cb1defe69ae8dbb4d712c0d7cf838d6539178e8bcf71c72579ab5b666)
else()
- set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.29.1.tar.gz)
- set(LIBUV_SHA256 bdde1140087ce97080ea323c3598553ece00a24ae63ac568be78bef3e97f3e25)
+ set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.30.0.tar.gz)
+ set(LIBUV_SHA256 44c8fdadf3b3f393006a4ac4ba144020673a3f9cd72bed1fbb2c366ebcf0d199)
endif()
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0/msgpack-3.0.0.tar.gz)
diff --git a/third-party/cmake/BuildGperf.cmake b/third-party/cmake/BuildGperf.cmake
index 71c3cc1eef..e922f71ed5 100644
--- a/third-party/cmake/BuildGperf.cmake
+++ b/third-party/cmake/BuildGperf.cmake
@@ -2,6 +2,7 @@
# cross compiling we still want to build for the HOST system, whenever
# writing a recipe that is meant for cross-compile, use the HOSTDEPS_* variables
# instead of DEPS_* - check the main CMakeLists.txt for a list.
+enable_language(CXX)
# BuildGperf(CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...)
# Reusable function to build Gperf, wraps ExternalProject_Add.
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index 8ab04cf87b..87e2946c96 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -129,20 +129,12 @@ add_custom_command(OUTPUT ${ROCKS_DIR}/lpeg
add_custom_target(lpeg DEPENDS ${ROCKS_DIR}/lpeg)
list(APPEND THIRD_PARTY_DEPS lpeg)
-# inspect
-add_custom_command(OUTPUT ${ROCKS_DIR}/inspect
- COMMAND ${LUAROCKS_BINARY}
- ARGS build inspect 3.1.1-0 ${LUAROCKS_BUILDARGS}
- DEPENDS lpeg)
-add_custom_target(inspect DEPENDS ${ROCKS_DIR}/inspect)
-list(APPEND THIRD_PARTY_DEPS inspect)
-
if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
# luabitop
add_custom_command(OUTPUT ${ROCKS_DIR}/luabitop
COMMAND ${LUAROCKS_BINARY}
ARGS build luabitop 1.0.2-3 ${LUAROCKS_BUILDARGS}
- DEPENDS inspect)
+ DEPENDS lpeg)
add_custom_target(luabitop DEPENDS ${ROCKS_DIR}/luabitop)
list(APPEND THIRD_PARTY_DEPS luabitop)
endif()
@@ -151,7 +143,7 @@ if(USE_BUNDLED_BUSTED)
if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
set(PENLIGHT_DEPENDS luabitop)
else()
- set(PENLIGHT_DEPENDS inspect)
+ set(PENLIGHT_DEPENDS lpeg)
endif()
# penlight
@@ -171,7 +163,7 @@ if(USE_BUNDLED_BUSTED)
endif()
add_custom_command(OUTPUT ${BUSTED_EXE}
COMMAND ${LUAROCKS_BINARY}
- ARGS build busted 2.0.rc13-0 ${LUAROCKS_BUILDARGS}
+ ARGS build busted 2.0.0 ${LUAROCKS_BUILDARGS}
DEPENDS penlight)
add_custom_target(busted DEPENDS ${BUSTED_EXE})
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index 9f8e4bbc4f..967e0a1711 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -71,6 +71,19 @@ set(LUV_CONFIGURE_COMMAND_COMMON
-DBUILD_SHARED_LIBS=OFF
-DBUILD_MODULE=OFF)
+if(USE_BUNDLED_LUAJIT)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit)
+elseif(USE_BUNDLED_LUA)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua)
+else()
+ find_package(LuaJit)
+ if(LUAJIT_FOUND)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit)
+ else()
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua)
+ endif()
+endif()
+
if(USE_BUNDLED_LIBUV)
set(LUV_CONFIGURE_COMMAND_COMMON
${LUV_CONFIGURE_COMMAND_COMMON}