aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--ISSUE_TEMPLATE.md9
-rw-r--r--runtime/autoload/remote/host.vim22
-rw-r--r--runtime/doc/eval.txt13
-rw-r--r--runtime/doc/options.txt2
-rw-r--r--runtime/doc/vim_diff.txt2
-rw-r--r--runtime/filetype.vim2
-rw-r--r--runtime/plugin/rplugin.vim4
-rwxr-xr-xscripts/legacy2luatest.pl2
-rwxr-xr-xscripts/vim-patch.sh231
-rw-r--r--src/nvim/buffer.c9
-rw-r--r--src/nvim/buffer_defs.h146
-rw-r--r--src/nvim/diff.c86
-rw-r--r--src/nvim/eval.c154
-rw-r--r--src/nvim/ex_cmds.c1
-rw-r--r--src/nvim/ex_docmd.c17
-rw-r--r--src/nvim/file_search.c77
-rw-r--r--src/nvim/move.c12
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/option.c165
-rw-r--r--src/nvim/os/env.c19
-rw-r--r--src/nvim/path.c49
-rw-r--r--src/nvim/regexp_nfa.c1
-rw-r--r--src/nvim/screen.c118
-rw-r--r--src/nvim/search.c40
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/terminal.c9
-rw-r--r--src/nvim/testdir/Makefile7
-rw-r--r--src/nvim/testdir/test11.in84
-rw-r--r--src/nvim/testdir/test11.ok61
-rw-r--r--src/nvim/testdir/test36.in105
-rw-r--r--src/nvim/testdir/test36.ok96
-rw-r--r--src/nvim/testdir/test_charsearch.in25
-rw-r--r--src/nvim/testdir/test_charsearch.ok3
-rw-r--r--src/nvim/testdir/test_command_count.in158
-rw-r--r--src/nvim/testdir/test_command_count.ok38
-rw-r--r--src/nvim/testdir/test_listlbr.in33
-rw-r--r--src/nvim/testdir/test_listlbr.ok14
-rw-r--r--src/nvim/version.c52
-rw-r--r--src/nvim/window.c20
-rw-r--r--test/functional/autocmd/termclose_spec.lua16
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua230
-rw-r--r--test/functional/legacy/036_regexp_character_classes_spec.lua272
-rw-r--r--test/functional/legacy/autocmd_option_spec.lua43
-rw-r--r--test/functional/legacy/charsearch_spec.lua42
-rw-r--r--test/functional/legacy/command_count_spec.lua243
-rw-r--r--test/functional/legacy/comparators_spec.lua14
-rw-r--r--test/functional/legacy/match_conceal_spec.lua228
-rw-r--r--test/functional/legacy/search_mbyte_spec.lua26
49 files changed, 1942 insertions, 1071 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 527a085d3e..73f33292ff 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,12 @@ if(CMAKE_C_FLAGS_RELEASE MATCHES "-O3")
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
endif()
+# Enable link-time optimisations on release builds.
+check_c_compiler_flag(-flto HAS_FLTO_FLAG)
+if(HAS_FLTO_FLAG)
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -flto")
+endif()
+
# Disable logging for release-type builds.
if(NOT CMAKE_C_FLAGS_RELEASE MATCHES DDISABLE_LOG)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DDISABLE_LOG")
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..4abcc4eae1
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,9 @@
+- Neovim version:
+- Operating system:
+- Terminal emulator:
+
+### Actual behaviour
+
+### Expected behaviour
+
+### Steps to reproduce
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index d04dea180c..24497b10c2 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -5,7 +5,7 @@ let s:remote_plugins_manifest = fnamemodify(expand($MYVIMRC, 1), ':h')
" Register a host by associating it with a factory(funcref)
-function! remote#host#Register(name, pattern, factory)
+function! remote#host#Register(name, pattern, factory) abort
let s:hosts[a:name] = {'factory': a:factory, 'channel': 0, 'initialized': 0}
let s:plugin_patterns[a:name] = a:pattern
if type(a:factory) == type(1) && a:factory
@@ -19,7 +19,7 @@ endfunction
" as `source`, but it will run as a different process. This can be used by
" plugins that should run isolated from other plugins created for the same host
" type
-function! remote#host#RegisterClone(name, orig_name)
+function! remote#host#RegisterClone(name, orig_name) abort
if !has_key(s:hosts, a:orig_name)
throw 'No host named "'.a:orig_name.'" is registered'
endif
@@ -34,7 +34,7 @@ endfunction
" Get a host channel, bootstrapping it if necessary
-function! remote#host#Require(name)
+function! remote#host#Require(name) abort
if !has_key(s:hosts, a:name)
throw 'No host named "'.a:name.'" is registered'
endif
@@ -51,7 +51,7 @@ function! remote#host#Require(name)
endfunction
-function! remote#host#IsRunning(name)
+function! remote#host#IsRunning(name) abort
if !has_key(s:hosts, a:name)
throw 'No host named "'.a:name.'" is registered'
endif
@@ -72,7 +72,7 @@ endfunction
"
" The third item in a declaration is a boolean: non zero means the command,
" autocommand or function will be executed synchronously with rpcrequest.
-function! remote#host#RegisterPlugin(host, path, specs)
+function! remote#host#RegisterPlugin(host, path, specs) abort
let plugins = remote#host#PluginsForHost(a:host)
for plugin in plugins
@@ -116,14 +116,14 @@ function! remote#host#RegisterPlugin(host, path, specs)
endfunction
-function! remote#host#LoadRemotePlugins()
+function! remote#host#LoadRemotePlugins() abort
if filereadable(s:remote_plugins_manifest)
exe 'source '.s:remote_plugins_manifest
endif
endfunction
-function! s:RegistrationCommands(host)
+function! s:RegistrationCommands(host) abort
" Register a temporary host clone for discovering specs
let host_id = a:host.'-registration-clone'
call remote#host#RegisterClone(host_id, a:host)
@@ -163,7 +163,7 @@ function! s:RegistrationCommands(host)
endfunction
-function! s:UpdateRemotePlugins()
+function! s:UpdateRemotePlugins() abort
let commands = []
let hosts = keys(s:hosts)
for host in hosts
@@ -180,6 +180,8 @@ function! s:UpdateRemotePlugins()
endif
endfor
call writefile(commands, s:remote_plugins_manifest)
+ echomsg printf('remote/host: generated the manifest file in "%s"',
+ \ s:remote_plugins_manifest)
endfunction
@@ -187,7 +189,7 @@ command! UpdateRemotePlugins call s:UpdateRemotePlugins()
let s:plugins_for_host = {}
-function! remote#host#PluginsForHost(host)
+function! remote#host#PluginsForHost(host) abort
if !has_key(s:plugins_for_host, a:host)
let s:plugins_for_host[a:host] = []
end
@@ -198,7 +200,7 @@ endfunction
" Registration of standard hosts
" Python/Python3 {{{
-function! s:RequirePythonHost(host)
+function! s:RequirePythonHost(host) abort
let ver = (a:host.orig_name ==# 'python') ? 2 : 3
" Python host arguments
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index a5f8660691..45980f5d94 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -4598,9 +4598,18 @@ matchadd({group}, {pattern}[, {priority}[, {id}]])
message will appear and the match will not be added. An ID
is specified as a positive integer (zero excluded). IDs 1, 2
and 3 are reserved for |:match|, |:2match| and |:3match|,
- respectively. If the {id} argument is not specified,
+ respectively. If the {id} argument is not specified or -1,
|matchadd()| automatically chooses a free ID.
+ The optional {dict} argmument allows for further custom
+ values. Currently this is used to specify a match specifc
+ conceal character that will be shown for |hl-Conceal|
+ highlighted matches. The dict can have the following members:
+
+ conceal Special character to show instead of the
+ match (only for |hl-Conceal| highlighed
+ matches, see |:syn-cchar|)
+
The number of matches is not limited, as it is the case with
the |:match| commands.
@@ -4614,7 +4623,7 @@ matchadd({group}, {pattern}[, {priority}[, {id}]])
available from |getmatches()|. All matches can be deleted in
one operation by |clearmatches()|.
-matchaddpos({group}, {pos}[, {priority}[, {id}]]) *matchaddpos()*
+matchaddpos({group}, {pos}[, {priority}[, {id}[, {dict}]]]) *matchaddpos()*
Same as |matchadd()|, but requires a list of positions {pos}
instead of a pattern. This command is faster than |matchadd()|
because it does not require to handle regular expressions and
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e875be6218..ced303947b 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1360,7 +1360,7 @@ A jump table for the options with a short description can be found at |Q_op|.
option, yank and delete operations (but not put)
will additionally copy the text into register
'*'. See |nvim-clipboard|.
-<
+
*clipboard-autoselect*
autoselect Works like the 'a' flag in 'guioptions': If present,
then whenever Visual mode is started, or the Visual
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index ac5efc6a1d..d3768409f5 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -50,7 +50,7 @@ these differences.
- 'listchars' defaults to "tab:> ,trail:-,nbsp:+"
- 'mouse' defaults to "a"
- 'nocompatible' is always set
-- 'nrformats' defaults to "hex"
+- 'nrformats' defaults to "bin,hex"
- 'sessionoptions' doesn't include "options"
- 'smarttab' is set by default
- 'tabpagemax' defaults to 50
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index c5b01f0c40..d60ab65ce7 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -868,7 +868,7 @@ func! s:FThtml()
setf xhtml
return
endif
- if getline(n) =~ '{%\s*\(extends\|block\|load\)\>'
+ if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
setf htmldjango
return
endif
diff --git a/runtime/plugin/rplugin.vim b/runtime/plugin/rplugin.vim
index 2b2d333738..879775ff0e 100644
--- a/runtime/plugin/rplugin.vim
+++ b/runtime/plugin/rplugin.vim
@@ -1,5 +1,5 @@
-if exists('loaded_remote_plugins') || &cp
+if exists('g:loaded_remote_plugins') || &cp
finish
endif
-let loaded_remote_plugins = 1
+let g:loaded_remote_plugins = 1
call remote#host#LoadRemotePlugins()
diff --git a/scripts/legacy2luatest.pl b/scripts/legacy2luatest.pl
index ebd8dad1e1..8155353fc7 100755
--- a/scripts/legacy2luatest.pl
+++ b/scripts/legacy2luatest.pl
@@ -287,7 +287,7 @@ local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
describe('$test_name', function()
- setup(clear)
+ before_each(clear)
it('is working', function()
@{[join "\n", map { /^$/ ? '' : ' ' . $_ } @{$test_body_lines}]}
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index bdd3d6209b..7612a2ada0 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -5,9 +5,12 @@ set -u
set -o pipefail
readonly NEOVIM_SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-readonly VIM_SOURCE_DIR_DEFAULT=${NEOVIM_SOURCE_DIR}/.vim-src
+readonly VIM_SOURCE_DIR_DEFAULT="${NEOVIM_SOURCE_DIR}/.vim-src"
readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}"
readonly BASENAME="$(basename "${0}")"
+readonly BRANCH_PREFIX="vim-"
+
+CREATED_FILES=()
usage() {
echo "Helper script for porting Vim patches. For more information, see"
@@ -21,6 +24,7 @@ usage() {
echo " -p {vim-revision} Download and apply the Vim patch vim-revision."
echo " vim-revision can be a version number of the "
echo " format '7.4.xxx' or a Git commit hash."
+ echo " -s Submit a vim-patch pull request to Neovim."
echo " -r {pr-number} Review a vim-patch pull request to Neovim."
echo
echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored."
@@ -35,6 +39,27 @@ check_executable() {
fi
}
+clean_files() {
+ if [[ ${#CREATED_FILES[@]} -eq 0 ]]; then
+ return
+ fi
+
+ echo
+ echo "Created files:"
+ local file
+ for file in ${CREATED_FILES[@]}; do
+ echo " • ${file}"
+ done
+
+ read -p "Delete these files (Y/n)? " -n 1 -r reply
+ echo
+ if [[ "${reply}" =~ ^[Yy]$ ]]; then
+ rm -- ${CREATED_FILES[@]}
+ else
+ echo "You can use 'git clean' to remove these files when you're done."
+ fi
+}
+
get_vim_sources() {
check_executable git
@@ -66,22 +91,26 @@ assign_commit_details() {
# Interpret parameter as version number (tag).
vim_version="${1}"
vim_tag="v${1}"
- vim_commit=$( cd "${VIM_SOURCE_DIR}" \
- && git log -1 --format="%H" ${vim_tag} )
+ vim_commit=$(cd "${VIM_SOURCE_DIR}" \
+ && git log -1 --format="%H" ${vim_tag})
local strip_commit_line=true
else
# Interpret parameter as commit hash.
vim_version="${1:0:7}"
- vim_commit="${1}"
+ vim_commit=$(cd "${VIM_SOURCE_DIR}" \
+ && git log -1 --format="%H" ${vim_version})
local strip_commit_line=false
fi
vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
- vim_message="$(git log -1 --pretty='format:%B' "${vim_commit}")"
+ vim_message="$(cd "${VIM_SOURCE_DIR}" \
+ && git log -1 --pretty='format:%B' "${vim_commit}" \
+ | sed -e 's/\(#[0-9]*\)/vim\/vim\1/g')"
if [[ ${strip_commit_line} == "true" ]]; then
# Remove first line of commit message.
vim_message="$(echo "${vim_message}" | sed -e '1d')"
fi
+ patch_file="vim-${vim_version}.patch"
}
get_vim_patch() {
@@ -96,66 +125,108 @@ get_vim_patch() {
echo
echo "✔ Found Vim revision '${vim_commit}'."
- # Collect patch details and store into variables.
- vim_full="$(git show -1 --pretty=medium "${vim_commit}")"
# Patch surgery: preprocess the patch.
# - transform src/ paths to src/nvim/
- vim_diff="$(git show -1 "${vim_commit}" \
+ local vim_full="$(git show -1 --pretty=medium "${vim_commit}" \
| LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g')"
- neovim_message="$(commit_message)"
- neovim_pr="
-\`\`\`
-${vim_message}
-\`\`\`
-
-${vim_commit_url}
-
-Original patch:
-
-\`\`\`diff
-${vim_diff}
-\`\`\`"
- neovim_branch="vim-${vim_version}"
+ local neovim_branch="${BRANCH_PREFIX}${vim_version}"
- echo
- echo "Creating Git branch."
cd "${NEOVIM_SOURCE_DIR}"
- output="$(git checkout -b "${neovim_branch}" 2>&1)" &&
- echo "✔ ${output}" ||
- (echo "✘ ${output}"; false)
+ local checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
+ if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then
+ echo "✔ Current branch '${checked_out_branch}' seems to be a vim-patch"
+ echo " branch; not creating a new branch."
+ else
+ echo
+ echo "Fetching 'upstream/master'."
+ output="$(git fetch upstream master 2>&1)" &&
+ echo "✔ ${output}" ||
+ (echo "✘ ${output}"; false)
+
+ echo
+ echo "Creating new branch '${neovim_branch}' based on 'upstream/master'."
+ cd "${NEOVIM_SOURCE_DIR}"
+ output="$(git checkout -b "${neovim_branch}" upstream/master 2>&1)" &&
+ echo "✔ ${output}" ||
+ (echo "✘ ${output}"; false)
+ fi
echo
echo "Creating empty commit with correct commit message."
- output="$(git commit --allow-empty --file 2>&1 - <<< "${neovim_message}")" &&
+ output="$(commit_message | git commit --allow-empty --file 2>&1 -)" &&
echo "✔ ${output}" ||
(echo "✘ ${output}"; false)
echo
echo "Creating files."
- echo "${vim_diff}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff"
- echo "✔ Saved diff to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff'."
- echo "${vim_full}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch"
- echo "✔ Saved full commit details to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch'."
- echo "${neovim_pr}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr"
- echo "✔ Saved suggested PR description to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr'."
- echo "You can use 'git clean' to remove these files when you're done."
+ echo "${vim_full}" > "${NEOVIM_SOURCE_DIR}/${patch_file}"
+ echo "✔ Saved full commit details to '${NEOVIM_SOURCE_DIR}/${patch_file}'."
echo
echo "Instructions:"
echo
echo " Proceed to port the patch."
- echo " You might want to try 'patch -p1 < ${neovim_branch}.diff' first."
+ echo " You might want to try 'patch -p1 < ${patch_file}' first."
+ echo
+ echo " If the patch contains a new test, consider porting it to Lua."
+ echo " You might want to try 'scripts/legacy2luatest.pl'."
echo
echo " Stage your changes ('git add ...') and use 'git commit --amend' to commit."
echo
- echo " Push your changes with 'git push origin ${neovim_branch}' and create a"
- echo " pull request called '[RFC] vim-patch:${vim_version}'. You might want "
- echo " to use the text in '${neovim_branch}.pr' as the description of this pull request."
+ echo " To port additional patches related to ${vim_version} and add them to the current"
+ echo " branch, call '${BASENAME} -p' again. Please use this only if it wouldn't make"
+ echo " sense to send in each patch individually, as it will increase the size of the"
+ echo " pull request and make it harder to review."
+ echo
+ echo " When you are finished, use '${BASENAME} -s' to submit a pull request."
echo
echo " See https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim"
echo " for more information."
}
+submit_pr() {
+ check_executable git
+ check_executable hub
+
+ cd "${NEOVIM_SOURCE_DIR}"
+ local checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
+ if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then
+ echo "✘ Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch."
+ exit 1
+ fi
+
+ local pr_body="$(git log --reverse --format='#### %s%n%n%b%n' upstream/master..HEAD)"
+ local patches=("$(git log --reverse --format='%s' upstream/master..HEAD)")
+ patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
+ local pr_title="${patches[@]}" # Create space-separated string from array.
+ pr_title="${pr_title// /,}" # Replace spaces with commas.
+
+ local pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
+
+ echo "Pushing to 'origin/${checked_out_branch}'."
+ output="$(git push origin "${checked_out_branch}" 2>&1)" &&
+ echo "✔ ${output}" ||
+ (echo "✘ ${output}"; git reset --soft HEAD^1; false)
+
+ echo
+ echo "Creating pull request."
+ output="$(hub pull-request -F - 2>&1 <<< "${pr_message}")" &&
+ echo "✔ ${output}" ||
+ (echo "✘ ${output}"; false)
+
+ echo
+ echo "Cleaning up files."
+ local patch_file
+ for patch_file in ${patches[@]}; do
+ patch_file="vim-${patch_file}.patch"
+ if [[ ! -f "${NEOVIM_SOURCE_DIR}/${patch_file}" ]]; then
+ continue
+ fi
+ rm -- "${NEOVIM_SOURCE_DIR}/${patch_file}"
+ echo "✔ Removed '${NEOVIM_SOURCE_DIR}/${patch_file}'."
+ done
+}
+
list_vim_patches() {
get_vim_sources
@@ -189,7 +260,8 @@ list_vim_patches() {
echo "Instructions:"
echo
echo " To port one of the above patches to Neovim, execute"
- echo " this script with the patch revision as argument."
+ echo " this script with the patch revision as argument and"
+ echo " follow the instructions."
echo
echo " Examples: '${BASENAME} -p 7.4.487'"
echo " '${BASENAME} -p 1e8ebf870720e7b671f98f22d653009826304c4f'"
@@ -198,32 +270,28 @@ list_vim_patches() {
echo " Out-of-order patches increase the possibility of bugs."
}
-review_pr() {
- check_executable curl
- check_executable nvim
-
- get_vim_sources
-
- local pr="${1}"
- echo
- echo "Downloading data for pull request #${pr}."
+review_commit() {
+ local neovim_commit_url="${1}"
+ local neovim_patch_url="${neovim_commit_url}.patch"
local git_patch_prefix='Subject: \[PATCH\] '
- local neovim_patch="$(curl -Ssf "https://patch-diff.githubusercontent.com/raw/neovim/neovim/pull/${pr}.patch")"
- echo "${neovim_patch}" > a
+ local neovim_patch="$(curl -Ssf "${neovim_patch_url}")"
local vim_version="$(head -n 4 <<< "${neovim_patch}" | sed -n "s/${git_patch_prefix}vim-patch:\([a-z0-9.]*\)$/\1/p")"
+ echo
if [[ -n "${vim_version}" ]]; then
echo "✔ Detected Vim patch '${vim_version}'."
else
echo "✘ Could not detect the Vim patch number."
- echo " This script assumes that the PR contains a single commit"
- echo " with 'vim-patch:XXX' as its title."
+ echo " This script assumes that the PR contains only commits"
+ echo " with 'vim-patch:XXX' in their title."
exit 1
fi
assign_commit_details "${vim_version}"
+ local vim_patch_url="${vim_commit_url}.patch"
+
local expected_commit_message="$(commit_message)"
local message_length="$(wc -l <<< "${expected_commit_message}")"
local commit_message="$(tail -n +4 <<< "${neovim_patch}" | head -n "${message_length}")"
@@ -235,26 +303,57 @@ review_pr() {
echo "${expected_commit_message}"
echo " Actual:"
echo "${commit_message#${git_patch_prefix}}"
- exit 1
fi
- local base_name="vim-${vim_version}"
echo
echo "Creating files."
- curl -Ssfo "${NEOVIM_SOURCE_DIR}/n${base_name}.diff" "https://patch-diff.githubusercontent.com/raw/neovim/neovim/pull/${pr}.diff"
- echo "✔ Saved pull request diff to '${NEOVIM_SOURCE_DIR}/n${base_name}.diff'."
- echo "${neovim_patch}" > "${NEOVIM_SOURCE_DIR}/n${base_name}.patch"
- echo "✔ Saved full pull request commit details to '${NEOVIM_SOURCE_DIR}/n${base_name}.patch'."
- git show "${vim_commit}" > "${NEOVIM_SOURCE_DIR}/${base_name}.diff"
- echo "✔ Saved Vim diff to '${NEOVIM_SOURCE_DIR}/${base_name}.diff'."
- echo "You can use 'git clean' to remove these files when you're done."
+ echo "${neovim_patch}" > "${NEOVIM_SOURCE_DIR}/n${patch_file}"
+ echo "✔ Saved pull request diff to '${NEOVIM_SOURCE_DIR}/n${patch_file}'."
+ CREATED_FILES+=("${NEOVIM_SOURCE_DIR}/n${patch_file}")
+
+ curl -Ssfo "${NEOVIM_SOURCE_DIR}/${patch_file}" "${vim_patch_url}"
+ echo "✔ Saved Vim diff to '${NEOVIM_SOURCE_DIR}/${patch_file}'."
+ CREATED_FILES+=("${NEOVIM_SOURCE_DIR}/${patch_file}")
echo
echo "Launching nvim."
- exec nvim -O "${NEOVIM_SOURCE_DIR}/${base_name}.diff" "${NEOVIM_SOURCE_DIR}/n${base_name}.diff"
+ nvim -c "cd ${NEOVIM_SOURCE_DIR}" \
+ -O "${NEOVIM_SOURCE_DIR}/${patch_file}" "${NEOVIM_SOURCE_DIR}/n${patch_file}"
}
-while getopts "hlp:r:" opt; do
+review_pr() {
+ check_executable curl
+ check_executable nvim
+ check_executable jq
+
+ get_vim_sources
+
+ local pr="${1}"
+ echo
+ echo "Downloading data for pull request #${pr}."
+
+ local pr_commit_urls=($(curl -Ssf "https://api.github.com/repos/neovim/neovim/pulls/${pr}/commits" \
+ | jq -r '.[].html_url'))
+
+ echo "Found ${#pr_commit_urls[@]} commit(s)."
+
+ local pr_commit_url
+ local reply
+ for pr_commit_url in ${pr_commit_urls[@]}; do
+ review_commit "${pr_commit_url}"
+ if [[ "${pr_commit_url}" != "${pr_commit_urls[-1]}" ]]; then
+ read -p "Continue with next commit (Y/n)? " -n 1 -r reply
+ echo
+ if [[ ! "${reply}" =~ ^[Yy]$ ]]; then
+ break
+ fi
+ fi
+ done
+
+ clean_files
+}
+
+while getopts "hlp:r:s" opt; do
case ${opt} in
h)
usage
@@ -272,6 +371,10 @@ while getopts "hlp:r:" opt; do
review_pr "${OPTARG}"
exit 0
;;
+ s)
+ submit_pr
+ exit 0
+ ;;
*)
exit 1
;;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 9806623433..c05090bbf6 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1741,12 +1741,15 @@ int buflist_findpat(
int toggledollar;
if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) {
- if (*pattern == '%')
+ if (*pattern == '%') {
match = curbuf->b_fnum;
- else
+ } else {
match = curwin->w_alt_fnum;
- if (diffmode && !diff_mode_buf(buflist_findnr(match)))
+ }
+ buf_T *found_buf = buflist_findnr(match);
+ if (diffmode && !(found_buf && diff_mode_buf(found_buf))) {
match = -1;
+ }
}
/*
* Try four ways of matching a listed buffer:
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 78d9a9484e..bdea609820 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -592,71 +592,72 @@ struct file_buffer {
int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */
- int b_p_ai; /* 'autoindent' */
- int b_p_ai_nopaste; /* b_p_ai saved for paste mode */
- char_u *b_p_bkc; ///< 'backupcopy'
- unsigned int b_bkc_flags; ///< flags for 'backupcopy'
- int b_p_ci; /* 'copyindent' */
- int b_p_bin; /* 'binary' */
- int b_p_bomb; /* 'bomb' */
- char_u *b_p_bh; /* 'bufhidden' */
- char_u *b_p_bt; /* 'buftype' */
- int b_p_bl; /* 'buflisted' */
- int b_p_cin; /* 'cindent' */
- char_u *b_p_cino; /* 'cinoptions' */
- char_u *b_p_cink; /* 'cinkeys' */
- char_u *b_p_cinw; /* 'cinwords' */
- char_u *b_p_com; /* 'comments' */
- char_u *b_p_cms; /* 'commentstring' */
- char_u *b_p_cpt; /* 'complete' */
- char_u *b_p_cfu; /* 'completefunc' */
- char_u *b_p_ofu; /* 'omnifunc' */
- int b_p_eol; /* 'endofline' */
- int b_p_fixeol; /* 'fixendofline' */
- int b_p_et; /* 'expandtab' */
- int b_p_et_nobin; /* b_p_et saved for binary mode */
- char_u *b_p_fenc; /* 'fileencoding' */
- char_u *b_p_ff; /* 'fileformat' */
- char_u *b_p_ft; /* 'filetype' */
- char_u *b_p_fo; /* 'formatoptions' */
- char_u *b_p_flp; /* 'formatlistpat' */
- int b_p_inf; /* 'infercase' */
- char_u *b_p_isk; /* 'iskeyword' */
- char_u *b_p_def; /* 'define' local value */
- char_u *b_p_inc; /* 'include' */
- char_u *b_p_inex; /* 'includeexpr' */
- uint32_t b_p_inex_flags; /* flags for 'includeexpr' */
- char_u *b_p_inde; /* 'indentexpr' */
- uint32_t b_p_inde_flags; /* flags for 'indentexpr' */
- char_u *b_p_indk; /* 'indentkeys' */
- char_u *b_p_fex; /* 'formatexpr' */
- uint32_t b_p_fex_flags; /* flags for 'formatexpr' */
- char_u *b_p_kp; /* 'keywordprg' */
- int b_p_lisp; /* 'lisp' */
- char_u *b_p_mps; /* 'matchpairs' */
- int b_p_ml; /* 'modeline' */
- int b_p_ml_nobin; /* b_p_ml saved for binary mode */
- int b_p_ma; /* 'modifiable' */
- char_u *b_p_nf; /* 'nrformats' */
- int b_p_pi; /* 'preserveindent' */
- char_u *b_p_qe; /* 'quoteescape' */
- int b_p_ro; /* 'readonly' */
- long b_p_sw; /* 'shiftwidth' */
- int b_p_si; /* 'smartindent' */
- long b_p_sts; /* 'softtabstop' */
- long b_p_sts_nopaste; /* b_p_sts saved for paste mode */
- char_u *b_p_sua; /* 'suffixesadd' */
- bool b_p_swf; /* 'swapfile' */
- long b_p_smc; /* 'synmaxcol' */
- char_u *b_p_syn; /* 'syntax' */
- long b_p_ts; /* 'tabstop' */
- long b_p_tw; /* 'textwidth' */
- long b_p_tw_nobin; /* b_p_tw saved for binary mode */
- long b_p_tw_nopaste; /* b_p_tw saved for paste mode */
- long b_p_wm; /* 'wrapmargin' */
- long b_p_wm_nobin; /* b_p_wm saved for binary mode */
- long b_p_wm_nopaste; /* b_p_wm saved for paste mode */
- char_u *b_p_keymap; /* 'keymap' */
+ int b_p_ai; ///< 'autoindent'
+ int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
+ char_u *b_p_bkc; ///< 'backupco
+ unsigned int b_bkc_flags; ///< flags for 'backupco
+ int b_p_ci; ///< 'copyindent'
+ int b_p_bin; ///< 'binary'
+ int b_p_bomb; ///< 'bomb'
+ char_u *b_p_bh; ///< 'bufhidden'
+ char_u *b_p_bt; ///< 'buftype'
+ int b_p_bl; ///< 'buflisted'
+ int b_p_cin; ///< 'cindent'
+ char_u *b_p_cino; ///< 'cinoptions'
+ char_u *b_p_cink; ///< 'cinkeys'
+ char_u *b_p_cinw; ///< 'cinwords'
+ char_u *b_p_com; ///< 'comments'
+ char_u *b_p_cms; ///< 'commentstring'
+ char_u *b_p_cpt; ///< 'complete'
+ char_u *b_p_cfu; ///< 'completefunc'
+ char_u *b_p_ofu; ///< 'omnifunc'
+ int b_p_eol; ///< 'endofline'
+ int b_p_fixeol; ///< 'fixendofline'
+ int b_p_et; ///< 'expandtab'
+ int b_p_et_nobin; ///< b_p_et saved for binary mode
+ int b_p_et_nopaste; ///< b_p_et saved for paste mode
+ char_u *b_p_fenc; ///< 'fileencoding'
+ char_u *b_p_ff; ///< 'fileformat'
+ char_u *b_p_ft; ///< 'filetype'
+ char_u *b_p_fo; ///< 'formatoptions'
+ char_u *b_p_flp; ///< 'formatlistpat'
+ int b_p_inf; ///< 'infercase'
+ char_u *b_p_isk; ///< 'iskeyword'
+ char_u *b_p_def; ///< 'define' local value
+ char_u *b_p_inc; ///< 'include'
+ char_u *b_p_inex; ///< 'includeexpr'
+ uint32_t b_p_inex_flags; ///< flags for 'includeexpr'
+ char_u *b_p_inde; ///< 'indentexpr'
+ uint32_t b_p_inde_flags; ///< flags for 'indentexpr'
+ char_u *b_p_indk; ///< 'indentkeys'
+ char_u *b_p_fex; ///< 'formatexpr'
+ uint32_t b_p_fex_flags; ///< flags for 'formatexpr'
+ char_u *b_p_kp; ///< 'keywordprg'
+ int b_p_lisp; ///< 'lisp'
+ char_u *b_p_mps; ///< 'matchpairs'
+ int b_p_ml; ///< 'modeline'
+ int b_p_ml_nobin; ///< b_p_ml saved for binary mode
+ int b_p_ma; ///< 'modifiable'
+ char_u *b_p_nf; ///< 'nrformats'
+ int b_p_pi; ///< 'preserveindent'
+ char_u *b_p_qe; ///< 'quoteescape'
+ int b_p_ro; ///< 'readonly'
+ long b_p_sw; ///< 'shiftwidth'
+ int b_p_si; ///< 'smartindent'
+ long b_p_sts; ///< 'softtabstop'
+ long b_p_sts_nopaste; ///< b_p_sts saved for paste mode
+ char_u *b_p_sua; ///< 'suffixesadd'
+ bool b_p_swf; ///< 'swapfile'
+ long b_p_smc; ///< 'synmaxcol'
+ char_u *b_p_syn; ///< 'syntax'
+ long b_p_ts; ///< 'tabstop'
+ long b_p_tw; ///< 'textwidth'
+ long b_p_tw_nobin; ///< b_p_tw saved for binary mode
+ long b_p_tw_nopaste; ///< b_p_tw saved for paste mode
+ long b_p_wm; ///< 'wrapmargin'
+ long b_p_wm_nobin; ///< b_p_wm saved for binary mode
+ long b_p_wm_nopaste; ///< b_p_wm saved for paste mode
+ char_u *b_p_keymap; ///< 'keymap'
/* local values for options which are normally global */
char_u *b_p_gp; /* 'grepprg' local value */
@@ -904,13 +905,14 @@ struct posmatch
typedef struct matchitem matchitem_T;
struct matchitem {
matchitem_T *next;
- int id; /* match ID */
- int priority; /* match priority */
- char_u *pattern; /* pattern to highlight */
- int hlg_id; /* highlight group ID */
- regmmatch_T match; /* regexp program for pattern */
- posmatch_T pos; // position matches
- match_T hl; /* struct for doing the actual highlighting */
+ int id; ///< match ID
+ int priority; ///< match priority
+ char_u *pattern; ///< pattern to highlight
+ int hlg_id; ///< highlight group ID
+ regmmatch_T match; ///< regexp program for pattern
+ posmatch_T pos; ///< position matches
+ match_T hl; ///< struct for doing the actual highlighting
+ int conceal_char; ///< cchar for Conceal highlighting
};
/*
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index e06ffd0bbc..0be8b3c514 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1531,37 +1531,37 @@ int diff_check(win_T *wp, linenr_T lnum)
return maxcount - dp->df_count[idx];
}
-/// Compare two entries in diff "*dp" and return TRUE if they are equal.
+/// Compare two entries in diff "dp" and return true if they are equal.
///
-/// @param dp
-/// @param idx1 First entry in diff "*dp"
-/// @param idx2 Second entry in diff "*dp"
+/// @param dp diff
+/// @param idx1 first entry in diff "dp"
+/// @param idx2 second entry in diff "dp"
///
-/// @return return TRUE if two entires are equal.
-static int diff_equal_entry(diff_T *dp, int idx1, int idx2)
+/// @return true if two entires are equal.
+static bool diff_equal_entry(diff_T *dp, int idx1, int idx2)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
if (dp->df_count[idx1] != dp->df_count[idx2]) {
- return FALSE;
+ return false;
}
if (diff_check_sanity(curtab, dp) == FAIL) {
- return FALSE;
+ return false;
}
- int i;
- for (i = 0; i < dp->df_count[idx1]; ++i) {
+ for (int i = 0; i < dp->df_count[idx1]; i++) {
char_u *line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1],
- dp->df_lnum[idx1] + i, FALSE));
+ dp->df_lnum[idx1] + i, false));
int cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2],
- dp->df_lnum[idx2] + i, FALSE));
+ dp->df_lnum[idx2] + i, false));
xfree(line);
if (cmp != 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/// Compare strings "s1" and "s2" according to 'diffopt'.
@@ -1830,28 +1830,30 @@ int diffopt_changed(void)
return OK;
}
-/// Return TRUE if 'diffopt' contains "horizontal".
-///
-/// @return TRUE if 'diffopt' contains "horizontal"
-int diffopt_horizontal(void)
+/// Check that "diffopt" contains "horizontal".
+bool diffopt_horizontal(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return (diff_flags & DIFF_HORIZONTAL) != 0;
}
/// Find the difference within a changed line.
///
-/// @param startp first char of the change
-/// @param endp last char of the change
+/// @param wp window whose current buffer to check
+/// @param lnum line number to check within the buffer
+/// @param startp first char of the change
+/// @param endp last char of the change
///
-/// @returns TRUE if the line was added, no other buffer has it.
-int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
+/// @return true if the line was added, no other buffer has it.
+bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
char_u *line_new;
int si_org;
int si_new;
int ei_org;
int ei_new;
- int added = TRUE;
+ bool added = true;
// Make a copy of the line, the next ml_get() will invalidate it.
char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE));
@@ -1860,7 +1862,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
if (idx == DB_COUNT) {
// cannot happen
xfree(line_org);
- return FALSE;
+ return false;
}
// search for a change that includes "lnum" in the list of diffblocks.
@@ -1873,7 +1875,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
if ((dp == NULL) || (diff_check_sanity(curtab, dp) == FAIL)) {
xfree(line_org);
- return FALSE;
+ return false;
}
int off = lnum - dp->df_lnum[idx];
@@ -1884,7 +1886,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
if (off >= dp->df_count[i]) {
continue;
}
- added = FALSE;
+ added = false;
line_new = ml_get_buf(curtab->tp_diffbuf[i],
dp->df_lnum[i] + off, FALSE);
@@ -1956,21 +1958,22 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
return added;
}
-/// Return TRUE if line "lnum" is not close to a diff block, this line should
+/// Check that line "lnum" is not close to a diff block, this line should
/// be in a fold.
///
-/// @param wp
-/// @param lnum
+/// @param wp window containing the buffer to check
+/// @param lnum line number to check within the buffer
///
-/// @return FALSE if there are no diff blocks at all in this window.
-int diff_infold(win_T *wp, linenr_T lnum)
+/// @return false if there are no diff blocks at all in this window.
+bool diff_infold(win_T *wp, linenr_T lnum)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
- int other = FALSE;
+ bool other = false;
diff_T *dp;
// Return if 'diff' isn't set.
if (!wp->w_p_diff) {
- return FALSE;
+ return false;
}
int idx = -1;
@@ -1979,13 +1982,13 @@ int diff_infold(win_T *wp, linenr_T lnum)
if (curtab->tp_diffbuf[i] == wp->w_buffer) {
idx = i;
} else if (curtab->tp_diffbuf[i] != NULL) {
- other = TRUE;
+ other = true;
}
}
// return here if there are no diffs in the window
if ((idx == -1) || !other) {
- return FALSE;
+ return false;
}
if (curtab->tp_diff_invalid) {
@@ -1995,7 +1998,7 @@ int diff_infold(win_T *wp, linenr_T lnum)
// Return if there are no diff blocks. All lines will be folded.
if (curtab->tp_first_diff == NULL) {
- return TRUE;
+ return true;
}
for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) {
@@ -2006,10 +2009,10 @@ int diff_infold(win_T *wp, linenr_T lnum)
// If this change ends before the line we have a match.
if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
/// "dp" and "do" commands.
@@ -2372,12 +2375,11 @@ static void diff_fold_update(diff_T *dp, int skip_idx)
}
}
-/// Checks if the buffer is in diff-mode.
-///
-/// @param buf The buffer to check.
+/// Checks that the buffer is in diff-mode.
///
-/// @return TRUE if buffer "buf" is in diff-mode.
+/// @param buf buffer to check.
bool diff_mode_buf(buf_T *buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
FOR_ALL_TABS(tp) {
if (diff_buf_idx_tp(buf, tp) != DB_COUNT) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index f1d57c698b..96fc79504f 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -3580,9 +3580,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
type = TYPE_SEQUAL;
break;
case 'i': if (p[1] == 's') {
- if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
+ if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') {
len = 5;
- if (!vim_isIDc(p[len])) {
+ }
+ if (!isalnum(p[len]) && p[len] != '_') {
type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL;
type_is = TRUE;
}
@@ -7270,8 +7271,8 @@ static struct fst {
{ "maparg", 1, 4, f_maparg },
{ "mapcheck", 1, 3, f_mapcheck },
{ "match", 2, 4, f_match },
- { "matchadd", 2, 4, f_matchadd },
- { "matchaddpos", 2, 4, f_matchaddpos },
+ { "matchadd", 2, 5, f_matchadd },
+ { "matchaddpos", 2, 5, f_matchaddpos },
{ "matcharg", 1, 1, f_matcharg },
{ "matchdelete", 1, 1, f_matchdelete },
{ "matchend", 2, 4, f_matchend },
@@ -10422,6 +10423,14 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv)
dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id));
dict_add_nr_str(dict, "priority", (long)cur->priority, NULL);
dict_add_nr_str(dict, "id", (long)cur->id, NULL);
+
+ if (cur->conceal_char) {
+ char_u buf[MB_MAXBYTES + 1];
+
+ buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
+ dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf);
+ }
+
list_append_dict(rettv->vval.v_list, dict);
cur = cur->next;
}
@@ -10689,11 +10698,11 @@ getwinvar (
int off /* 1 for gettabwinvar() */
)
{
- win_T *win, *oldcurwin;
- char_u *varname;
- dictitem_T *v;
- tabpage_T *tp = NULL;
- tabpage_T *oldtabpage = NULL;
+ win_T *win, *oldcurwin;
+ char_u *varname;
+ dictitem_T *v;
+ tabpage_T *tp = NULL;
+ tabpage_T *oldtabpage = NULL;
bool done = false;
if (off == 1)
@@ -10708,12 +10717,16 @@ getwinvar (
rettv->vval.v_string = NULL;
if (win != NULL && varname != NULL) {
- /* Set curwin to be our win, temporarily. Also set the tabpage,
- * otherwise the window is not valid. */
- if (switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) {
- if (*varname == '&') { /* window-local-option */
- if (get_option_tv(&varname, rettv, 1) == OK)
+ // Set curwin to be our win, temporarily. Also set the tabpage,
+ // otherwise the window is not valid. Only do this when needed,
+ // autocommands get blocked.
+ bool need_switch_win = tp != curtab || win != curwin;
+ if (!need_switch_win
+ || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) {
+ if (*varname == '&') { // window-local-option
+ if (get_option_tv(&varname, rettv, 1) == OK) {
done = true;
+ }
} else {
// Look up the variable.
// Let getwinvar({nr}, "") return the "w:" dictionary.
@@ -10725,8 +10738,10 @@ getwinvar (
}
}
- /* restore previous notion of curwin */
- restore_win(oldcurwin, oldtabpage, TRUE);
+ if (need_switch_win) {
+ // restore previous notion of curwin
+ restore_win(oldcurwin, oldtabpage, true);
+ }
}
if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
@@ -12487,7 +12502,8 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv)
char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */
int prio = 10; /* default priority */
int id = -1;
- int error = FALSE;
+ int error = false;
+ char_u *conceal_char = NULL;
rettv->vval.v_number = -1;
@@ -12495,17 +12511,31 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv)
return;
if (argvars[2].v_type != VAR_UNKNOWN) {
prio = get_tv_number_chk(&argvars[2], &error);
- if (argvars[3].v_type != VAR_UNKNOWN)
+ if (argvars[3].v_type != VAR_UNKNOWN) {
id = get_tv_number_chk(&argvars[3], &error);
+ if (argvars[4].v_type != VAR_UNKNOWN) {
+ if (argvars[4].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ if (dict_find(argvars[4].vval.v_dict,
+ (char_u *)"conceal", -1) != NULL) {
+ conceal_char = get_dict_string(argvars[4].vval.v_dict,
+ (char_u *)"conceal", false);
+ }
+ }
+ }
}
- if (error == TRUE)
+ if (error == true) {
return;
+ }
if (id >= 1 && id <= 3) {
EMSGN("E798: ID is reserved for \":match\": %" PRId64, id);
return;
}
- rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL);
+ rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL,
+ conceal_char);
}
static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL
@@ -12533,12 +12563,24 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_
int error = false;
int prio = 10;
int id = -1;
+ char_u *conceal_char = NULL;
if (argvars[2].v_type != VAR_UNKNOWN) {
- prio = get_tv_number_chk(&argvars[2], &error);
- if (argvars[3].v_type != VAR_UNKNOWN) {
- id = get_tv_number_chk(&argvars[3], &error);
+ prio = get_tv_number_chk(&argvars[2], &error);
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ id = get_tv_number_chk(&argvars[3], &error);
+ if (argvars[4].v_type != VAR_UNKNOWN) {
+ if (argvars[4].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ if (dict_find(argvars[4].vval.v_dict,
+ (char_u *)"conceal", -1) != NULL) {
+ conceal_char = get_dict_string(argvars[4].vval.v_dict,
+ (char_u *)"conceal", false);
+ }
}
+ }
}
if (error == true) {
return;
@@ -12550,7 +12592,8 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_
return;
}
- rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l);
+ rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l,
+ conceal_char);
}
/*
@@ -15259,8 +15302,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
int i = 0;
char_u buf[5];
dictitem_T *di;
- d = li->li_tv.vval.v_dict;
+ d = li->li_tv.vval.v_dict;
if (dict_find(d, (char_u *)"pattern", -1) == NULL) {
if (s == NULL) {
s = list_alloc();
@@ -15285,15 +15328,19 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv)
}
}
+ char_u *group = get_dict_string(d, (char_u *)"group", false);
+ int priority = get_dict_number(d, (char_u *)"priority");
+ int id = get_dict_number(d, (char_u *)"id");
+ char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
+ ? get_dict_string(d, (char_u *)"conceal",
+ false)
+ : NULL;
if (i == 0) {
- match_add(curwin, get_dict_string(d, (char_u *)"group", false),
+ match_add(curwin, group,
get_dict_string(d, (char_u *)"pattern", false),
- (int)get_dict_number(d, (char_u *)"priority"),
- (int)get_dict_number(d, (char_u *)"id"), NULL);
+ priority, id, NULL, conceal);
} else {
- match_add(curwin, get_dict_string(d, (char_u *)"group", false),
- NULL, (int)get_dict_number(d, (char_u *)"priority"),
- (int)get_dict_number(d, (char_u *)"id"), s);
+ match_add(curwin, group, NULL, priority, id, s, conceal);
list_unref(s);
s = NULL;
}
@@ -15519,26 +15566,32 @@ static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
varname = get_tv_string_chk(&argvars[off + 1]);
varp = &argvars[off + 2];
- if (win != NULL && varname != NULL && varp != NULL
- && switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) {
- if (*varname == '&') {
- long numval;
- char_u *strval;
- int error = FALSE;
-
- ++varname;
- numval = get_tv_number_chk(varp, &error);
- strval = get_tv_string_buf_chk(varp, nbuf);
- if (!error && strval != NULL)
- set_option_value(varname, numval, strval, OPT_LOCAL);
- } else {
- winvarname = xmalloc(STRLEN(varname) + 3);
- STRCPY(winvarname, "w:");
- STRCPY(winvarname + 2, varname);
- set_var(winvarname, varp, TRUE);
- xfree(winvarname);
+ if (win != NULL && varname != NULL && varp != NULL) {
+ bool need_switch_win = tp != curtab || win != curwin;
+ if (!need_switch_win
+ || switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) {
+ if (*varname == '&') {
+ long numval;
+ char_u *strval;
+ int error = false;
+
+ ++varname;
+ numval = get_tv_number_chk(varp, &error);
+ strval = get_tv_string_buf_chk(varp, nbuf);
+ if (!error && strval != NULL) {
+ set_option_value(varname, numval, strval, OPT_LOCAL);
+ }
+ } else {
+ winvarname = xmalloc(STRLEN(varname) + 3);
+ STRCPY(winvarname, "w:");
+ STRCPY(winvarname + 2, varname);
+ set_var(winvarname, varp, true);
+ xfree(winvarname);
+ }
+ }
+ if (need_switch_win) {
+ restore_win(save_curwin, save_curtab, true);
}
- restore_win(save_curwin, save_curtab, TRUE);
}
}
@@ -22150,7 +22203,6 @@ static void on_process_exit(Process *proc, int status, void *d)
char msg[22];
snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status);
terminal_close(data->term, msg);
- apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, curbuf);
}
if (data->status_ptr) {
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 4d62dd0ff9..4a423269cc 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4779,6 +4779,7 @@ void ex_helptags(exarg_T *eap)
WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
if (dirname == NULL || !os_isdir(dirname)) {
EMSG2(_("E150: Not a directory: %s"), eap->arg);
+ xfree(dirname);
return;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index c785b1c1b9..13a298cc78 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8774,19 +8774,18 @@ static int ses_do_frame(frame_T *fr)
return FALSE;
}
-/*
- * Return non-zero if window "wp" is to be stored in the Session.
- */
+/// Return non-zero if window "wp" is to be stored in the Session.
static int ses_do_win(win_T *wp)
{
if (wp->w_buffer->b_fname == NULL
- /* When 'buftype' is "nofile" can't restore the window contents. */
- || bt_nofile(wp->w_buffer)
- )
+ // When 'buftype' is "nofile" can't restore the window contents.
+ || (!wp->w_buffer->terminal && bt_nofile(wp->w_buffer))) {
return ssop_flags & SSOP_BLANK;
- if (wp->w_buffer->b_help)
+ }
+ if (wp->w_buffer->b_help) {
return ssop_flags & SSOP_HELP;
- return TRUE;
+ }
+ return true;
}
/*
@@ -9404,7 +9403,7 @@ static void ex_match(exarg_T *eap)
c = *end;
*end = NUL;
- match_add(curwin, g, p + 1, 10, id, NULL);
+ match_add(curwin, g, p + 1, 10, id, NULL, NULL);
xfree(g);
*end = c;
}
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index b213a42c52..2929790ebf 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -484,28 +484,21 @@ vim_findfile_init (
len = (int)(p - search_ctx->ffsc_fix_path) - 1;
STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
add_pathsep((char *)ff_expand_buffer);
- } else
+ } else {
len = (int)STRLEN(search_ctx->ffsc_fix_path);
+ }
if (search_ctx->ffsc_wc_path != NULL) {
wc_path = vim_strsave(search_ctx->ffsc_wc_path);
temp = xmalloc(STRLEN(search_ctx->ffsc_wc_path)
+ STRLEN(search_ctx->ffsc_fix_path + len)
+ 1);
- }
-
- if (temp == NULL || wc_path == NULL) {
- xfree(buf);
- xfree(temp);
+ STRCPY(temp, search_ctx->ffsc_fix_path + len);
+ STRCAT(temp, search_ctx->ffsc_wc_path);
+ xfree(search_ctx->ffsc_wc_path);
xfree(wc_path);
- goto error_return;
+ search_ctx->ffsc_wc_path = temp;
}
-
- STRCPY(temp, search_ctx->ffsc_fix_path + len);
- STRCAT(temp, search_ctx->ffsc_wc_path);
- xfree(search_ctx->ffsc_wc_path);
- xfree(wc_path);
- search_ctx->ffsc_wc_path = temp;
}
xfree(buf);
}
@@ -1046,41 +1039,44 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, ff_visited_l
return retptr;
}
-/*
- * check if two wildcard paths are equal. Returns TRUE or FALSE.
- * They are equal if:
- * - both paths are NULL
- * - they have the same length
- * - char by char comparison is OK
- * - the only differences are in the counters behind a '**', so
- * '**\20' is equal to '**\24'
- */
-static int ff_wc_equal(char_u *s1, char_u *s2)
+// Check if two wildcard paths are equal.
+// They are equal if:
+// - both paths are NULL
+// - they have the same length
+// - char by char comparison is OK
+// - the only differences are in the counters behind a '**', so
+// '**\20' is equal to '**\24'
+static bool ff_wc_equal(char_u *s1, char_u *s2)
{
- int i;
+ int i, j;
+ int c1 = NUL;
+ int c2 = NUL;
int prev1 = NUL;
int prev2 = NUL;
- if (s1 == s2)
- return TRUE;
-
- if (s1 == NULL || s2 == NULL)
- return FALSE;
+ if (s1 == s2) {
+ return true;
+ }
- if (STRLEN(s1) != STRLEN(s2))
- return FAIL;
+ if (s1 == NULL || s2 == NULL) {
+ return false;
+ }
- for (i = 0; s1[i] != NUL && s2[i] != NUL; i += MB_PTR2LEN(s1 + i)) {
- int c1 = PTR2CHAR(s1 + i);
- int c2 = PTR2CHAR(s2 + i);
+ for (i = 0, j = 0; s1[i] != NUL && s2[j] != NUL;) {
+ c1 = PTR2CHAR(s1 + i);
+ c2 = PTR2CHAR(s2 + j);
if ((p_fic ? vim_tolower(c1) != vim_tolower(c2) : c1 != c2)
- && (prev1 != '*' || prev2 != '*'))
- return FAIL;
+ && (prev1 != '*' || prev2 != '*')) {
+ return false;
+ }
prev2 = prev1;
prev1 = c1;
+
+ i += MB_PTR2LEN(s1 + i);
+ j += MB_PTR2LEN(s2 + j);
}
- return TRUE;
+ return s1[i] == s2[j];
}
/*
@@ -1111,10 +1107,11 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
|| (!url && vp->file_id_valid
&& os_fileid_equal(&(vp->file_id), &file_id))) {
- /* are the wildcard parts equal */
- if (ff_wc_equal(vp->ffv_wc_path, wc_path) == TRUE)
- /* already visited */
+ // are the wildcard parts equal
+ if (ff_wc_equal(vp->ffv_wc_path, wc_path)) {
+ // already visited
return FAIL;
+ }
}
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index eb55397511..ba79c0411a 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1288,9 +1288,10 @@ void scroll_cursor_top(int min_scroll, int always)
* - at least 'scrolloff' lines above and below the cursor
*/
validate_cheight();
- int used = curwin->w_cline_height;
- if (curwin->w_cursor.lnum < curwin->w_topline)
+ int used = curwin->w_cline_height; // includes filler lines above
+ if (curwin->w_cursor.lnum < curwin->w_topline) {
scrolled = used;
+ }
if (hasFolding(curwin->w_cursor.lnum, &top, &bot)) {
--top;
@@ -1301,9 +1302,10 @@ void scroll_cursor_top(int min_scroll, int always)
}
new_topline = top + 1;
- /* count filler lines of the cursor window as context */
+ // "used" already contains the number of filler lines above, don't add it
+ // again.
+ // Hide filler lines above cursor line by adding them to "extra".
int extra = diff_check_fill(curwin, curwin->w_cursor.lnum);
- used += extra;
/*
* Check if the lines from "top" to "bot" fit in the window. If they do,
@@ -1312,7 +1314,7 @@ void scroll_cursor_top(int min_scroll, int always)
while (top > 0) {
int i = hasFolding(top, &top, NULL)
? 1 // count one logical line for a sequence of folded lines
- : plines(top);
+ : plines_nofill(top);
used += i;
if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) {
if (hasFolding(bot, NULL, &bot))
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index e6c5354941..e064d34e09 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -7783,7 +7783,7 @@ static void nv_open(cmdarg_T *cap)
n_opencmd(cap);
}
-// calculate start/end virtual columns for operating in block mode
+// Calculate start/end virtual columns for operating in block mode.
static void get_op_vcol(
oparg_T *oap,
colnr_T redo_VIsual_vcol,
@@ -7793,7 +7793,8 @@ static void get_op_vcol(
colnr_T start;
colnr_T end;
- if (VIsual_mode != Ctrl_V) {
+ if (VIsual_mode != Ctrl_V
+ || (!initial && oap->end.col < curwin->w_width)) {
return;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index c11e22703e..0f6874e941 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -168,11 +168,12 @@ static int p_ml_nobin;
static long p_tw_nobin;
static long p_wm_nobin;
-/* Saved values for when 'paste' is set */
+// Saved values for when 'paste' is set.
+static int p_ai_nopaste;
+static int p_et_nopaste;
+static long p_sts_nopaste;
static long p_tw_nopaste;
static long p_wm_nopaste;
-static long p_sts_nopaste;
-static int p_ai_nopaste;
typedef struct vimoption {
char *fullname; /* full option name */
@@ -710,15 +711,11 @@ void set_init_1(void)
/* Must be before option_expand(), because that one needs vim_isIDc() */
didset_options();
- /* Use the current chartab for the generic chartab. */
+ // Use the current chartab for the generic chartab. This is not in
+ // didset_options() because it only depends on 'encoding'.
init_spell_chartab();
/*
- * initialize the table for 'breakat'.
- */
- fill_breakat_flags();
-
- /*
* Expand environment variables and things like "~" for the defaults.
* If option_expand() returns non-NULL the variable is expanded. This can
* only happen for non-indirect options.
@@ -750,14 +747,8 @@ void set_init_1(void)
}
}
- /* Initialize the highlight_attr[] table. */
- highlight_changed();
-
save_file_ff(curbuf); /* Buffer is unchanged */
- /* Parse default for 'wildmode' */
- check_opt_wim();
-
/* Detect use of mlterm.
* Mlterm is a terminal emulator akin to xterm that has some special
* abilities (bidi namely).
@@ -767,11 +758,7 @@ void set_init_1(void)
if (os_env_exists("MLTERM"))
set_option_value((char_u *)"tbidi", 1L, NULL, 0);
- /* Parse default for 'fillchars'. */
- (void)set_chars_option(&p_fcs);
-
- /* Parse default for 'listchars'. */
- (void)set_chars_option(&p_lcs);
+ didset_options2();
// enc_locale() will try to find the encoding of the current locale.
// This will be used when 'default' is used as encoding specifier
@@ -1150,9 +1137,12 @@ do_set (
*/
arg += 3;
if (*arg == '&') {
- ++arg;
- /* Only for :set command set global value of local options. */
+ arg++;
+ // Only for :set command set global value of local options.
set_options_default(OPT_FREE | opt_flags);
+ didset_options();
+ didset_options2();
+ redraw_all_later(CLEAR);
} else {
showoptions(1, opt_flags);
did_show = TRUE;
@@ -2072,9 +2062,31 @@ static void didset_options(void)
(void)spell_check_msm();
(void)spell_check_sps();
(void)compile_cap_prog(curwin->w_s);
- /* set cedit_key */
+ (void)did_set_spell_option(true);
+ // set cedit_key
(void)check_cedit();
briopt_check(curwin);
+ // initialize the table for 'breakat'.
+ fill_breakat_flags();
+}
+
+// More side effects of setting options.
+static void didset_options2(void)
+{
+ // Initialize the highlight_attr[] table.
+ (void)highlight_changed();
+
+ // Parse default for 'clipboard'.
+ (void)opt_strings_flags(p_cb, p_cb_values, &cb_flags, true);
+
+ // Parse default for 'fillchars'.
+ (void)set_chars_option(&p_fcs);
+
+ // Parse default for 'listchars'.
+ (void)set_chars_option(&p_lcs);
+
+ // Parse default for 'wildmode'.
+ check_opt_wim();
}
/*
@@ -2853,22 +2865,7 @@ did_set_string_option (
|| varp == &(curwin->w_s->b_p_spf)) {
// When 'spelllang' or 'spellfile' is set and there is a window for this
// buffer in which 'spell' is set load the wordlists.
- if (varp == &(curwin->w_s->b_p_spf)) {
- int l = (int)STRLEN(curwin->w_s->b_p_spf);
- if (l > 0
- && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
- errmsg = e_invarg;
- }
- }
-
- if (errmsg == NULL) {
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == curbuf && wp->w_p_spell) {
- errmsg = did_set_spelllang(wp);
- break;
- }
- }
- }
+ errmsg = did_set_spell_option(varp == &(curwin->w_s->b_p_spf));
}
/* When 'spellcapcheck' is set compile the regexp program. */
else if (varp == &(curwin->w_s->b_p_spc)) {
@@ -3424,6 +3421,30 @@ char_u *check_stl_option(char_u *s)
return NULL;
}
+static char_u *did_set_spell_option(bool is_spellfile)
+{
+ char_u *errmsg = NULL;
+
+ if (is_spellfile) {
+ int l = (int)STRLEN(curwin->w_s->b_p_spf);
+ if (l > 0
+ && (l < 4 || STRCMP(curwin->w_s->b_p_spf + l - 4, ".add") != 0)) {
+ errmsg = e_invarg;
+ }
+ }
+
+ if (errmsg == NULL) {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer == curbuf && wp->w_p_spell) {
+ errmsg = did_set_spelllang(wp);
+ break;
+ }
+ }
+ }
+
+ return errmsg;
+}
+
/*
* Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
* Return error message when failed, NULL when OK.
@@ -5503,6 +5524,7 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_et = p_et;
buf->b_p_fixeol = p_fixeol;
buf->b_p_et_nobin = p_et_nobin;
+ buf->b_p_et_nopaste = p_et_nopaste;
buf->b_p_ml = p_ml;
buf->b_p_ml_nobin = p_ml_nobin;
buf->b_p_inf = p_inf;
@@ -6160,6 +6182,7 @@ static void paste_option_changed(void)
{
static int old_p_paste = FALSE;
static int save_sm = 0;
+ static int save_sta = 0;
static int save_ru = 0;
static int save_ri = 0;
static int save_hkmap = 0;
@@ -6176,40 +6199,44 @@ static void paste_option_changed(void)
buf->b_p_wm_nopaste = buf->b_p_wm;
buf->b_p_sts_nopaste = buf->b_p_sts;
buf->b_p_ai_nopaste = buf->b_p_ai;
+ buf->b_p_et_nopaste = buf->b_p_et;
}
- /* save global options */
+ // save global options
save_sm = p_sm;
+ save_sta = p_sta;
save_ru = p_ru;
save_ri = p_ri;
save_hkmap = p_hkmap;
- /* save global values for local buffer options */
+ // save global values for local buffer options
+ p_ai_nopaste = p_ai;
+ p_et_nopaste = p_et;
+ p_sts_nopaste = p_sts;
p_tw_nopaste = p_tw;
p_wm_nopaste = p_wm;
- p_sts_nopaste = p_sts;
- p_ai_nopaste = p_ai;
}
- /*
- * Always set the option values, also when 'paste' is set when it is
- * already on.
- */
- /* set options for each buffer */
+ // Always set the option values, also when 'paste' is set when it is
+ // already on.
+ // set options for each buffer
FOR_ALL_BUFFERS(buf) {
- buf->b_p_tw = 0; /* textwidth is 0 */
- buf->b_p_wm = 0; /* wrapmargin is 0 */
- buf->b_p_sts = 0; /* softtabstop is 0 */
- buf->b_p_ai = 0; /* no auto-indent */
- }
-
- /* set global options */
- p_sm = 0; /* no showmatch */
- if (p_ru)
- status_redraw_all(); /* redraw to remove the ruler */
- p_ru = 0; /* no ruler */
- p_ri = 0; /* no reverse insert */
- p_hkmap = 0; /* no Hebrew keyboard */
- /* set global values for local buffer options */
+ buf->b_p_tw = 0; // textwidth is 0
+ buf->b_p_wm = 0; // wrapmargin is 0
+ buf->b_p_sts = 0; // softtabstop is 0
+ buf->b_p_ai = 0; // no auto-indent
+ buf->b_p_et = 0; // no expandtab
+ }
+
+ // set global options
+ p_sm = 0; // no showmatch
+ p_sta = 0; // no smarttab
+ if (p_ru) {
+ status_redraw_all(); // redraw to remove the ruler
+ }
+ p_ru = 0; // no ruler
+ p_ri = 0; // no reverse insert
+ p_hkmap = 0; // no Hebrew keyboard
+ // set global values for local buffer options
p_tw = 0;
p_wm = 0;
p_sts = 0;
@@ -6225,20 +6252,24 @@ static void paste_option_changed(void)
buf->b_p_wm = buf->b_p_wm_nopaste;
buf->b_p_sts = buf->b_p_sts_nopaste;
buf->b_p_ai = buf->b_p_ai_nopaste;
+ buf->b_p_et = buf->b_p_et_nopaste;
}
/* restore global options */
p_sm = save_sm;
- if (p_ru != save_ru)
- status_redraw_all(); /* redraw to draw the ruler */
+ p_sta = save_sta;
+ if (p_ru != save_ru) {
+ status_redraw_all(); // redraw to draw the ruler
+ }
p_ru = save_ru;
p_ri = save_ri;
p_hkmap = save_hkmap;
- /* set global values for local buffer options */
+ // set global values for local buffer options
+ p_ai = p_ai_nopaste;
+ p_et = p_et_nopaste;
+ p_sts = p_sts_nopaste;
p_tw = p_tw_nopaste;
p_wm = p_wm_nopaste;
- p_sts = p_sts_nopaste;
- p_ai = p_ai_nopaste;
}
old_p_paste = p_paste;
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index c1804067e9..41ce8ddbc2 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -262,8 +262,25 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
startstr_len = (int)STRLEN(startstr);
src = skipwhite(srcp);
- --dstlen; // leave one char space for "\,"
+ dstlen--; // leave one char space for "\,"
while (*src && dstlen > 0) {
+ // Skip over `=expr`.
+ if (src[0] == '`' && src[1] == '=') {
+ var = src;
+ src += 2;
+ (void)skip_expr(&src);
+ if (*src == '`') {
+ src++;
+ }
+ size_t len = (size_t)(src - var);
+ if (len > (size_t)dstlen) {
+ len = (size_t)dstlen;
+ }
+ memcpy((char *)dst, (char *)var, len);
+ dst += len;
+ dstlen -= (int)len;
+ continue;
+ }
copy_char = true;
if ((*src == '$') || (*src == '~' && at_start)) {
mustfree = false;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 8b9a49dfc0..5cd93ab811 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -556,8 +556,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
return 0;
}
- /* make room for file name */
- buf = xmalloc(STRLEN(path) + BASENAMELEN + 5);
+ // Make room for file name. When doing encoding conversion the actual
+ // length may be quite a bit longer, thus use the maximum possible length.
+ buf = xmalloc(MAXPATHL);
/*
* Find the first part in the path name that contains a wildcard.
@@ -1158,12 +1159,17 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
add_pat = -1;
p = pat[i];
- if (vim_backtick(p))
+ if (vim_backtick(p)) {
add_pat = expand_backtick(&ga, p, flags);
- else {
- /*
- * First expand environment variables, "~/" and "~user/".
- */
+ if (add_pat == -1) {
+ recursive = false;
+ FreeWild(ga.ga_len, (char_u **)ga.ga_data);
+ *num_file = 0;
+ *file = NULL;
+ return FAIL;
+ }
+ } else {
+ // First expand environment variables, "~/" and "~user/".
if (has_env_var(p) || *p == '~') {
p = expand_env_save_opt(p, true);
if (p == NULL)
@@ -1246,13 +1252,10 @@ static int vim_backtick(char_u *p)
return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`';
}
-/*
- * Expand an item in `backticks` by executing it as a command.
- * Currently only works when pat[] starts and ends with a `.
- * Returns number of file names found.
- */
-static int
-expand_backtick (
+// Expand an item in `backticks` by executing it as a command.
+// Currently only works when pat[] starts and ends with a `.
+// Returns number of file names found, -1 if an error is encountered.
+static int expand_backtick(
garray_T *gap,
char_u *pat,
int flags /* EW_* flags */
@@ -1273,8 +1276,9 @@ expand_backtick (
buffer = get_cmd_output(cmd, NULL,
(flags & EW_SILENT) ? kShellOptSilent : 0, NULL);
xfree(cmd);
- if (buffer == NULL)
- return 0;
+ if (buffer == NULL) {
+ return -1;
+ }
cmd = buffer;
while (*cmd != NUL) {
@@ -1775,19 +1779,20 @@ bool same_directory(char_u *f1, char_u *f2)
*/
int pathcmp(const char *p, const char *q, int maxlen)
{
- int i;
+ int i, j;
int c1, c2;
const char *s = NULL;
- for (i = 0; maxlen < 0 || i < maxlen; i += MB_PTR2LEN((char_u *)p + i)) {
+ for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) {
c1 = PTR2CHAR((char_u *)p + i);
- c2 = PTR2CHAR((char_u *)q + i);
+ c2 = PTR2CHAR((char_u *)q + j);
/* End of "p": check if "q" also ends or just has a slash. */
if (c1 == NUL) {
if (c2 == NUL) /* full match */
return 0;
s = q;
+ i = j;
break;
}
@@ -1811,9 +1816,13 @@ int pathcmp(const char *p, const char *q, int maxlen)
return p_fic ? vim_toupper(c1) - vim_toupper(c2)
: c1 - c2; /* no match */
}
+
+ i += MB_PTR2LEN((char_u *)p + i);
+ j += MB_PTR2LEN((char_u *)q + j);
}
- if (s == NULL) /* "i" ran into "maxlen" */
+ if (s == NULL) { // "i" or "j" ran into "maxlen"
return 0;
+ }
c1 = PTR2CHAR((char_u *)s + i);
c2 = PTR2CHAR((char_u *)s + i + MB_PTR2LEN((char_u *)s + i));
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 4020fa6e28..dd41535110 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -4048,6 +4048,7 @@ skip_add:
sub->list.multi[subidx].start_col =
(colnr_T)(reginput - regline + off);
}
+ sub->list.multi[subidx].end_lnum = -1;
} else {
if (subidx < sub->in_use) {
save_ptr = sub->list.line[subidx].start;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index e036c49be4..3b5836f0b5 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2199,11 +2199,13 @@ win_line (
int syntax_seqnr = 0;
int prev_syntax_id = 0;
int conceal_attr = hl_attr(HLF_CONCEAL);
- int is_concealing = FALSE;
- int boguscols = 0; /* nonexistent columns added to force
- wrapping */
- int vcol_off = 0; /* offset for concealed characters */
- int did_wcol = FALSE;
+ int is_concealing = false;
+ int boguscols = 0; ///< nonexistent columns added to
+ ///< force wrapping
+ int vcol_off = 0; ///< offset for concealed characters
+ int did_wcol = false;
+ int match_conc = false; ///< cchar for match functions
+ int has_match_conc = false; ///< match wants to conceal
int old_boguscols = 0;
# define VCOL_HLC (vcol - vcol_off)
# define FIX_FOR_BOGUSCOLS \
@@ -2430,13 +2432,18 @@ win_line (
}
}
- /* find start of trailing whitespace */
- if (wp->w_p_list && lcs_trail) {
- trailcol = (colnr_T)STRLEN(ptr);
- while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1]))
- --trailcol;
- trailcol += (colnr_T) (ptr - line);
- extra_check = TRUE;
+ if (wp->w_p_list) {
+ if (lcs_space || lcs_trail) {
+ extra_check = true;
+ }
+ // find start of trailing whitespace
+ if (lcs_trail) {
+ trailcol = (colnr_T)STRLEN(ptr);
+ while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1])) {
+ trailcol--;
+ }
+ trailcol += (colnr_T) (ptr - line);
+ }
}
/*
@@ -2633,11 +2640,10 @@ win_line (
extra_check = true;
}
- /*
- * Repeat for the whole displayed line.
- */
+ // Repeat for the whole displayed line.
for (;; ) {
- /* Skip this quickly when working on the text. */
+ has_match_conc = false;
+ // Skip this quickly when working on the text.
if (draw_state != WL_LINE) {
if (draw_state == WL_CMDLINE - 1 && n_extra == 0) {
draw_state = WL_CMDLINE;
@@ -2884,8 +2890,16 @@ win_line (
shl->endcol = tmp_col;
}
shl->attr_cur = shl->attr;
+ if (cur != NULL && syn_name2id((char_u *)"Conceal")
+ == cur->hlg_id) {
+ has_match_conc = true;
+ match_conc = cur->conceal_char;
+ } else {
+ has_match_conc = match_conc = false;
+ }
} else if (v == (long)shl->endcol) {
shl->attr_cur = 0;
+ prev_syntax_id = 0;
next_search_hl(wp, shl, lnum, (colnr_T)v, cur);
pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
@@ -3201,27 +3215,7 @@ win_line (
}
}
- ++ptr;
-
- // 'list': change char 160 to lcs_nbsp and space to lcs_space.
- if (wp->w_p_list
- && (((c == 160 || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
- && lcs_nbsp)
- || (c == ' ' && lcs_space && ptr - line <= trailcol))) {
- c = (c == ' ') ? lcs_space : lcs_nbsp;
- if (area_attr == 0 && search_attr == 0) {
- n_attr = 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
- }
- mb_c = c;
- if (enc_utf8 && (*mb_char2len)(c) > 1) {
- mb_utf8 = TRUE;
- u8cc[0] = 0;
- c = 0xc0;
- } else
- mb_utf8 = FALSE;
- }
+ ptr++;
if (extra_check) {
bool can_spell = true;
@@ -3368,6 +3362,28 @@ win_line (
}
}
+ // 'list': change char 160 to lcs_nbsp and space to lcs_space.
+ if (wp->w_p_list
+ && (((c == 160
+ || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
+ && lcs_nbsp)
+ || (c == ' ' && lcs_space && ptr - line <= trailcol))) {
+ c = (c == ' ') ? lcs_space : lcs_nbsp;
+ if (area_attr == 0 && search_attr == 0) {
+ n_attr = 1;
+ extra_attr = hl_attr(HLF_8);
+ saved_attr2 = char_attr; // save current attr
+ }
+ mb_c = c;
+ if (enc_utf8 && (*mb_char2len)(c) > 1) {
+ mb_utf8 = true;
+ u8cc[0] = 0;
+ c = 0xc0;
+ } else {
+ mb_utf8 = false;
+ }
+ }
+
if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') {
c = lcs_trail;
if (!attr_pri) {
@@ -3602,24 +3618,28 @@ win_line (
}
}
- if ( wp->w_p_cole > 0
- && (wp != curwin || lnum != wp->w_cursor.lnum ||
- conceal_cursor_line(wp))
- && (syntax_flags & HL_CONCEAL) != 0
- && !(lnum_in_visual_area
- && vim_strchr(wp->w_p_cocu, 'v') == NULL)) {
+ if (wp->w_p_cole > 0
+ && (wp != curwin || lnum != wp->w_cursor.lnum ||
+ conceal_cursor_line(wp))
+ && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc)
+ && !(lnum_in_visual_area
+ && vim_strchr(wp->w_p_cocu, 'v') == NULL)) {
char_attr = conceal_attr;
if (prev_syntax_id != syntax_seqnr
- && (syn_get_sub_char() != NUL || wp->w_p_cole == 1)
+ && (syn_get_sub_char() != NUL || match_conc
+ || wp->w_p_cole == 1)
&& wp->w_p_cole != 3) {
- /* First time at this concealed item: display one
- * character. */
- if (syn_get_sub_char() != NUL)
+ // First time at this concealed item: display one
+ // character.
+ if (match_conc) {
+ c = match_conc;
+ } else if (syn_get_sub_char() != NUL) {
c = syn_get_sub_char();
- else if (lcs_conceal != NUL)
+ } else if (lcs_conceal != NUL) {
c = lcs_conceal;
- else
+ } else {
c = ' ';
+ }
prev_syntax_id = syntax_seqnr;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 2dd0201259..fffae1ecb2 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -497,6 +497,7 @@ int searchit(
pos_T start_pos;
int at_first_line;
int extra_col;
+ int start_char_len;
int match_ok;
long nmatched;
int submatch = 0;
@@ -519,16 +520,21 @@ int searchit(
// When not accepting a match at the start position set "extra_col" to a
// non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1
// is zero.
- if ((options & SEARCH_START) || pos->col == MAXCOL) {
- extra_col = 0;
- } else if (dir != BACKWARD && has_mbyte
- && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count
- && pos->col < MAXCOL - 2) {
+ if (pos->col == MAXCOL) {
+ start_char_len = 0;
+ } else if (has_mbyte
+ && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count
+ && pos->col < MAXCOL - 2) {
// Watch out for the "col" being MAXCOL - 2, used in a closed fold.
- ptr = ml_get_buf(buf, pos->lnum, FALSE) + pos->col;
- extra_col = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr);
+ ptr = ml_get_buf(buf, pos->lnum, false) + pos->col;
+ start_char_len = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr);
} else {
- extra_col = 1;
+ start_char_len = 1;
+ }
+ if (dir == FORWARD) {
+ extra_col = (options & SEARCH_START) ? 0 : start_char_len;
+ } else {
+ extra_col = (options & SEARCH_START) ? start_char_len : 0;
}
start_pos = *pos; /* remember start pos for detecting no match */
@@ -679,16 +685,14 @@ int searchit(
|| (lnum + regmatch.endpos[0].lnum
== start_pos.lnum
&& (int)regmatch.endpos[0].col - 1
- + extra_col
- <= (int)start_pos.col))
+ < (int)start_pos.col + extra_col))
: (lnum + regmatch.startpos[0].lnum
< start_pos.lnum
|| (lnum + regmatch.startpos[0].lnum
== start_pos.lnum
&& (int)regmatch.startpos[0].col
- + extra_col
- <= (int)start_pos.col)))) {
- match_ok = TRUE;
+ < (int)start_pos.col + extra_col)))) {
+ match_ok = true;
matchpos = regmatch.startpos[0];
endpos = regmatch.endpos[0];
submatch = first_submatch(&regmatch);
@@ -3140,10 +3144,12 @@ current_block (
}
if (VIsual_active) {
- if (*p_sel == 'e')
- ++curwin->w_cursor.col;
- if (sol && gchar_cursor() != NUL)
- inc(&curwin->w_cursor); /* include the line break */
+ if (*p_sel == 'e') {
+ inc(&curwin->w_cursor);
+ }
+ if (sol && gchar_cursor() != NUL) {
+ inc(&curwin->w_cursor); // include the line break
+ }
VIsual = start_pos;
VIsual_mode = 'v';
redraw_curbuf_later(INVERTED); /* update the inversion */
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index b7d8a19de9..478fa973a1 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -3294,7 +3294,7 @@ static void syn_cmd_onoff(exarg_T *eap, char *name)
eap->nextcmd = check_nextcmd(eap->arg);
if (!eap->skip) {
char buf[100];
- strncpy(buf, "so ", 3);
+ strncpy(buf, "so ", 4);
vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name);
do_cmdline_cmd(buf);
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 0a7807d811..fb74569e3b 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -236,7 +236,7 @@ Terminal *terminal_open(TerminalOptions opts)
set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL);
RESET_BINDING(curwin);
// Apply TermOpen autocmds so the user can configure the terminal
- apply_autocmds(EVENT_TERMOPEN, NULL, NULL, true, curbuf);
+ apply_autocmds(EVENT_TERMOPEN, NULL, NULL, false, curbuf);
// Configure the scrollback buffer. Try to get the size from:
//
@@ -288,8 +288,9 @@ void terminal_close(Terminal *term, char *msg)
term->forward_mouse = false;
term->closed = true;
+ buf_T *buf = handle_get_buffer(term->buf_handle);
+
if (!msg || exiting) {
- buf_T *buf = handle_get_buffer(term->buf_handle);
// If no msg was given, this was called by close_buffer(buffer.c). Or if
// exiting, we must inform the buffer the terminal no longer exists so that
// close_buffer() doesn't call this again.
@@ -304,6 +305,10 @@ void terminal_close(Terminal *term, char *msg)
} else {
terminal_receive(term, msg, strlen(msg));
}
+
+ if (buf) {
+ apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
+ }
}
void terminal_resize(Terminal *term, uint16_t width, uint16_t height)
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index d1a7abfbf7..7886835b4d 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -9,12 +9,12 @@ SCRIPTSOURCE := ../../../runtime
SCRIPTS := \
test8.out test10.out \
- test11.out test12.out test13.out test14.out \
+ test12.out test13.out test14.out \
test17.out \
test24.out \
test30.out \
test32.out test34.out \
- test36.out test37.out test40.out \
+ test37.out test40.out \
test42.out \
test47.out test48.out test49.out \
test52.out test53.out test55.out \
@@ -25,10 +25,9 @@ SCRIPTS := \
test88.out \
test_listlbr.out \
test_breakindent.out \
- test_charsearch.out \
test_close_count.out \
- test_command_count.out \
test_marks.out \
+ test_match_conceal.out \
NEW_TESTS =
diff --git a/src/nvim/testdir/test11.in b/src/nvim/testdir/test11.in
deleted file mode 100644
index 9e9e257c1d..0000000000
--- a/src/nvim/testdir/test11.in
+++ /dev/null
@@ -1,84 +0,0 @@
-Tests for autocommands:
-- FileWritePre writing a compressed file
-- FileReadPost reading a compressed file
-- BufNewFile reading a file template
-- BufReadPre decompressing the file to be read
-- FilterReadPre substituting characters in the temp file
-- FilterReadPost substituting characters after filtering
-- FileReadPre set options for decompression
-- FileReadPost decompress the file
-
-Note: This test is skipped if "gzip" is not available.
-$GZIP is made empty, "-v" would cause trouble.
-Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz" being
-modified outside of Vim (noticed on Solaris).
-
-STARTTEST
-:so small.vim
-:" drop out when there is no gzip program
-:if !executable("gzip")
-: e! test.ok
-: w! test.out
-: qa!
-:endif
-:let $GZIP = ""
-:au FileChangedShell * echo "caught FileChangedShell"
-:set bin
-:au FileWritePre *.gz '[,']!gzip
-:au FileWritePost *.gz undo
-:/^start of testfile/,/^end of testfile/w! Xtestfile.gz
-:au FileReadPost *.gz '[,']!gzip -d
-:$r Xtestfile.gz " Read and decompress the testfile
-:?startstart?,$w! test.out " Write contents of this file
-:au BufNewFile *.c read Xtest.c
-:/^start of test.c/+1,/^end of test.c/-1w! Xtest.c
-:e! foo.c " Will load Xtest.c
-:au FileAppendPre *.out '[,']s/new/NEW/
-:au FileAppendPost *.out !cat Xtest.c >>test.out
-:w>>test.out " Append it to the output file
-:au! FileAppendPre
-:" setup autocommands to decompress before reading and re-compress afterwards
-:au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand("<afile>"))
-:au BufReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))
-:au BufReadPost *.gz call rename(expand("<afile>"), expand("<afile>:r"))
-:au BufReadPost *.gz exe '!gzip ' . shellescape(expand("<afile>:r"))
-:e! Xtestfile.gz " Edit compressed file
-:w>>test.out " Append it to the output file
-:set shelltemp " need temp files here
-:au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")
-:au FilterReadPre *.out exe 'silent !sed s/e/E/ ' . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))
-:au FilterReadPre *.out exe 'silent !rm ' . shellescape(expand("<afile>")) . '.t'
-:au FilterReadPost *.out '[,']s/x/X/g
-:e! test.out " Edit the output file
-:23,$!cat
-:23,$s/\r$// " remove CR for when sed adds them
-:au! FileReadPre *.gz exe 'silent !gzip -d ' . shellescape(expand("<afile>"))
-:au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))
-:au! FileReadPost *.gz '[,']s/l/L/
-:$r Xtestfile.gz " Read compressed file
-:w " write it, after filtering
-:au! " remove all autocommands
-:e " Edit test.out again
-:set nobin ff& " use the default fileformat for writing
-:w
-:qa!
-ENDTEST
-
-startstart
-start of testfile
-line 2 Abcdefghijklmnopqrstuvwxyz
-line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 4 Abcdefghijklmnopqrstuvwxyz
-line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 6 Abcdefghijklmnopqrstuvwxyz
-line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 8 Abcdefghijklmnopqrstuvwxyz
-line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 10 Abcdefghijklmnopqrstuvwxyz
-end of testfile
-
-start of test.c
-/*
- * Here is a new .c file
- */
-end of test.c
diff --git a/src/nvim/testdir/test11.ok b/src/nvim/testdir/test11.ok
deleted file mode 100644
index af8c5ce261..0000000000
--- a/src/nvim/testdir/test11.ok
+++ /dev/null
@@ -1,61 +0,0 @@
-startstart
-start of testfile
-line 2 Abcdefghijklmnopqrstuvwxyz
-line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 4 Abcdefghijklmnopqrstuvwxyz
-line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 6 Abcdefghijklmnopqrstuvwxyz
-line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 8 Abcdefghijklmnopqrstuvwxyz
-line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 10 Abcdefghijklmnopqrstuvwxyz
-end of testfile
-
-start of test.c
-/*
- * Here is a new .c file
- */
-end of test.c
-start of testfile
-line 2 Abcdefghijklmnopqrstuvwxyz
-line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-line 4 Abcdefghijklmnopqrstuvwxyz
-linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 6 AbcdefghijklmnopqrstuvwXyz
-linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 8 AbcdefghijklmnopqrstuvwXyz
-linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 10 AbcdefghijklmnopqrstuvwXyz
-End of testfile
-
-/*
- * HEre is a NEW .c file
- */
-/*
- * HEre is a new .c file
- */
-start of tEstfile
-linE 2 AbcdefghijklmnopqrstuvwXyz
-linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 4 AbcdefghijklmnopqrstuvwXyz
-linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 6 AbcdefghijklmnopqrstuvwXyz
-linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 8 AbcdefghijklmnopqrstuvwXyz
-linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-linE 10 AbcdefghijklmnopqrstuvwXyz
-End of testfile
-/*
- * HEre is a new .c file
- */
-start of testfiLe
-Line 2 Abcdefghijklmnopqrstuvwxyz
-Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Line 4 Abcdefghijklmnopqrstuvwxyz
-Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Line 6 Abcdefghijklmnopqrstuvwxyz
-Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Line 8 Abcdefghijklmnopqrstuvwxyz
-Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-Line 10 Abcdefghijklmnopqrstuvwxyz
-end of testfiLe
diff --git a/src/nvim/testdir/test36.in b/src/nvim/testdir/test36.in
deleted file mode 100644
index 8cdb5262bd..0000000000
--- a/src/nvim/testdir/test36.in
+++ /dev/null
@@ -1,105 +0,0 @@
-Test character classes in regexp using regexpengine 0, 1, 2.
-
-STARTTEST
-/^start-here/+1
-Y:s/\%#=0\d//g
-p:s/\%#=1\d//g
-p:s/\%#=2\d//g
-p:s/\%#=0[0-9]//g
-p:s/\%#=1[0-9]//g
-p:s/\%#=2[0-9]//g
-p:s/\%#=0\D//g
-p:s/\%#=1\D//g
-p:s/\%#=2\D//g
-p:s/\%#=0[^0-9]//g
-p:s/\%#=1[^0-9]//g
-p:s/\%#=2[^0-9]//g
-p:s/\%#=0\o//g
-p:s/\%#=1\o//g
-p:s/\%#=2\o//g
-p:s/\%#=0[0-7]//g
-p:s/\%#=1[0-7]//g
-p:s/\%#=2[0-7]//g
-p:s/\%#=0\O//g
-p:s/\%#=1\O//g
-p:s/\%#=2\O//g
-p:s/\%#=0[^0-7]//g
-p:s/\%#=1[^0-7]//g
-p:s/\%#=2[^0-7]//g
-p:s/\%#=0\x//g
-p:s/\%#=1\x//g
-p:s/\%#=2\x//g
-p:s/\%#=0[0-9A-Fa-f]//g
-p:s/\%#=1[0-9A-Fa-f]//g
-p:s/\%#=2[0-9A-Fa-f]//g
-p:s/\%#=0\X//g
-p:s/\%#=1\X//g
-p:s/\%#=2\X//g
-p:s/\%#=0[^0-9A-Fa-f]//g
-p:s/\%#=1[^0-9A-Fa-f]//g
-p:s/\%#=2[^0-9A-Fa-f]//g
-p:s/\%#=0\w//g
-p:s/\%#=1\w//g
-p:s/\%#=2\w//g
-p:s/\%#=0[0-9A-Za-z_]//g
-p:s/\%#=1[0-9A-Za-z_]//g
-p:s/\%#=2[0-9A-Za-z_]//g
-p:s/\%#=0\W//g
-p:s/\%#=1\W//g
-p:s/\%#=2\W//g
-p:s/\%#=0[^0-9A-Za-z_]//g
-p:s/\%#=1[^0-9A-Za-z_]//g
-p:s/\%#=2[^0-9A-Za-z_]//g
-p:s/\%#=0\h//g
-p:s/\%#=1\h//g
-p:s/\%#=2\h//g
-p:s/\%#=0[A-Za-z_]//g
-p:s/\%#=1[A-Za-z_]//g
-p:s/\%#=2[A-Za-z_]//g
-p:s/\%#=0\H//g
-p:s/\%#=1\H//g
-p:s/\%#=2\H//g
-p:s/\%#=0[^A-Za-z_]//g
-p:s/\%#=1[^A-Za-z_]//g
-p:s/\%#=2[^A-Za-z_]//g
-p:s/\%#=0\a//g
-p:s/\%#=1\a//g
-p:s/\%#=2\a//g
-p:s/\%#=0[A-Za-z]//g
-p:s/\%#=1[A-Za-z]//g
-p:s/\%#=2[A-Za-z]//g
-p:s/\%#=0\A//g
-p:s/\%#=1\A//g
-p:s/\%#=2\A//g
-p:s/\%#=0[^A-Za-z]//g
-p:s/\%#=1[^A-Za-z]//g
-p:s/\%#=2[^A-Za-z]//g
-p:s/\%#=0\l//g
-p:s/\%#=1\l//g
-p:s/\%#=2\l//g
-p:s/\%#=0[a-z]//g
-p:s/\%#=1[a-z]//g
-p:s/\%#=2[a-z]//g
-p:s/\%#=0\L//g
-p:s/\%#=1\L//g
-p:s/\%#=2\L//g
-p:s/\%#=0[^a-z]//g
-p:s/\%#=1[^a-z]//g
-p:s/\%#=2[^a-z]//g
-p:s/\%#=0\u//g
-p:s/\%#=1\u//g
-p:s/\%#=2\u//g
-p:s/\%#=0[A-Z]//g
-p:s/\%#=1[A-Z]//g
-p:s/\%#=2[A-Z]//g
-p:s/\%#=0\U//g
-p:s/\%#=1\U//g
-p:s/\%#=2\U//g
-p:s/\%#=0[^A-Z]//g
-p:s/\%#=1[^A-Z]//g
-p:s/\%#=2[^A-Z]//g
-:/^start-here/+1,$wq! test.out
-ENDTEST
-
-start-here
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
diff --git a/src/nvim/testdir/test36.ok b/src/nvim/testdir/test36.ok
deleted file mode 100644
index f72a74b2b7..0000000000
--- a/src/nvim/testdir/test36.ok
+++ /dev/null
@@ -1,96 +0,0 @@
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
-0123456789
-0123456789
-0123456789
-0123456789
-0123456789
-0123456789
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./89:;<=>?@ABCDEFGHIXYZ[\]^_`abcdefghiwxyz{|}~
-01234567
-01234567
-01234567
-01234567
-01234567
-01234567
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
- !"#$%&'()#+'-./:;<=>?@GHIXYZ[\]^_`ghiwxyz{|}~
-0123456789ABCDEFabcdef
-0123456789ABCDEFabcdef
-0123456789ABCDEFabcdef
-0123456789ABCDEFabcdef
-0123456789ABCDEFabcdef
-0123456789ABCDEFabcdef
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./:;<=>?@[\]^`{|}~
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
-0123456789ABCDEFGHIXYZ_abcdefghiwxyz
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^`{|}~
-ABCDEFGHIXYZ_abcdefghiwxyz
-ABCDEFGHIXYZ_abcdefghiwxyz
-ABCDEFGHIXYZ_abcdefghiwxyz
-ABCDEFGHIXYZ_abcdefghiwxyz
-ABCDEFGHIXYZ_abcdefghiwxyz
-ABCDEFGHIXYZ_abcdefghiwxyz
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`{|}~
-ABCDEFGHIXYZabcdefghiwxyz
-ABCDEFGHIXYZabcdefghiwxyz
-ABCDEFGHIXYZabcdefghiwxyz
-ABCDEFGHIXYZabcdefghiwxyz
-ABCDEFGHIXYZabcdefghiwxyz
-ABCDEFGHIXYZabcdefghiwxyz
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@ABCDEFGHIXYZ[\]^_`{|}~
-abcdefghiwxyz
-abcdefghiwxyz
-abcdefghiwxyz
-abcdefghiwxyz
-abcdefghiwxyz
-abcdefghiwxyz
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
- !"#$%&'()#+'-./0123456789:;<=>?@[\]^_`abcdefghiwxyz{|}~
-ABCDEFGHIXYZ
-ABCDEFGHIXYZ
-ABCDEFGHIXYZ
-ABCDEFGHIXYZ
-ABCDEFGHIXYZ
-ABCDEFGHIXYZ
diff --git a/src/nvim/testdir/test_charsearch.in b/src/nvim/testdir/test_charsearch.in
deleted file mode 100644
index 5085cb39bc..0000000000
--- a/src/nvim/testdir/test_charsearch.in
+++ /dev/null
@@ -1,25 +0,0 @@
-Test for character searches
-
-STARTTEST
-:so small.vim
-:" check that "fe" and ";" work
-/^X
-ylfep;;p,,p:
-:" check that save/restore works
-/^Y
-ylfep:let csave = getcharsearch()
-fip:call setcharsearch(csave)
-;p;p:
-:" check that setcharsearch() changes the settins.
-/^Z
-ylfep:call setcharsearch({'char': 'k'})
-;p:call setcharsearch({'forward': 0})
-$;p:call setcharseearch({'until'}: 1})
-;;p:
-:/^X/,$w! test.out
-:qa!
-ENDTEST
-
-Xabcdefghijkemnopqretuvwxyz
-Yabcdefghijkemnopqretuvwxyz
-Zabcdefghijkemnokqretkvwxyz
diff --git a/src/nvim/testdir/test_charsearch.ok b/src/nvim/testdir/test_charsearch.ok
deleted file mode 100644
index a0c90e24f9..0000000000
--- a/src/nvim/testdir/test_charsearch.ok
+++ /dev/null
@@ -1,3 +0,0 @@
-XabcdeXfghijkeXmnopqreXtuvwxyz
-YabcdeYfghiYjkeYmnopqreYtuvwxyz
-ZabcdeZfghijkZemnokZqretkZvwxyz
diff --git a/src/nvim/testdir/test_command_count.in b/src/nvim/testdir/test_command_count.in
deleted file mode 100644
index 170c810923..0000000000
--- a/src/nvim/testdir/test_command_count.in
+++ /dev/null
@@ -1,158 +0,0 @@
-Test for user command counts vim: set ft=vim :
-
-STARTTEST
-:so tiny.vim
-:lang C
-:let g:lines = []
-:com -range=% RangeLines :call add(g:lines, 'RangeLines '.<line1>.' '.<line2>)
-:com -range -addr=arguments RangeArguments :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>)
-:com -range=% -addr=arguments RangeArgumentsAll :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>)
-:com -range -addr=loaded_buffers RangeLoadedBuffers :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>)
-:com -range=% -addr=loaded_buffers RangeLoadedBuffersAll :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>)
-:com -range -addr=buffers RangeBuffers :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>)
-:com -range=% -addr=buffers RangeBuffersAll :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>)
-:com -range -addr=windows RangeWindows :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>)
-:com -range=% -addr=windows RangeWindowsAll :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>)
-:com -range -addr=tabs RangeTabs :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>)
-:com -range=% -addr=tabs RangeTabsAll :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>)
-:set hidden
-:arga a b c d
-:argdo echo "loading buffers"
-:argu 3
-:.-,$-RangeArguments
-:%RangeArguments
-:RangeArgumentsAll
-:N
-:.RangeArguments
-:split|split|split|split
-:3wincmd w
-:.,$RangeWindows
-:%RangeWindows
-:RangeWindowsAll
-:only
-:blast|bd
-:.,$RangeLoadedBuffers
-:%RangeLoadedBuffers
-:RangeLoadedBuffersAll
-:.,$RangeBuffers
-:%RangeBuffers
-:RangeBuffersAll
-:tabe|tabe|tabe|tabe
-:normal 2gt
-:.,$RangeTabs
-:%RangeTabs
-:RangeTabsAll
-:1tabonly
-:s/\n/\r\r\r\r\r/
-:2ma<
-:$-ma>
-:'<,'>RangeLines
-:com -range=% -buffer LocalRangeLines :call add(g:lines, 'LocalRangeLines '.<line1>.' '.<line2>)
-:'<,'>LocalRangeLines
-:b1
-ENDTEST
-
-STARTTEST
-:call add(g:lines, '')
-:%argd
-:arga a b c d
-:let v:errmsg = ''
-:5argu
-:call add(g:lines, '5argu ' . v:errmsg)
-:$argu
-:call add(g:lines, '4argu ' . expand('%:t'))
-:let v:errmsg = ''
-:1argu
-:call add(g:lines, '1argu ' . expand('%:t'))
-:let v:errmsg = ''
-:100b
-:call add(g:lines, '100b ' . v:errmsg)
-:split|split|split|split
-:let v:errmsg = ''
-:0close
-:call add(g:lines, '0close ' . v:errmsg)
-:$wincmd w
-:$close
-:call add(g:lines, '$close ' . winnr())
-:let v:errmsg = ''
-:$+close
-:call add(g:lines, '$+close ' . v:errmsg)
-:$tabe
-:call add(g:lines, '$tabe ' . tabpagenr())
-:let v:errmsg = ''
-:$+tabe
-:call add(g:lines, '$+tabe ' . v:errmsg)
-:only!
-:e x
-:0tabm
-:normal 1gt
-:call add(g:lines, '0tabm ' . expand('%:t'))
-:tabonly!
-:only!
-:e! test.out
-:call append(0, g:lines)
-:unlet g:lines
-:w|bd
-:b1
-ENDTEST
-
-STARTTEST
-:let g:lines = []
-:func BufStatus()
-: call add(g:lines, 'aaa: ' . buflisted(g:buf_aaa) . ' bbb: ' . buflisted(g:buf_bbb) . ' ccc: ' . buflisted(g:buf_ccc))
-:endfunc
-:se nohidden
-:e aaa
-:let buf_aaa = bufnr('%')
-:e bbb
-:let buf_bbb = bufnr('%')
-:e ccc
-:let buf_ccc = bufnr('%')
-:b1
-:call BufStatus()
-:exe buf_bbb . "," . buf_ccc . "bdelete"
-:call BufStatus()
-:exe buf_aaa . "bdelete"
-:call BufStatus()
-:e! test.out
-:call append('$', g:lines)
-:unlet g:lines
-:delfunc BufStatus
-:w|bd
-:b1
-ENDTEST
-
-STARTTEST
-:se hidden
-:only!
-:let g:lines = []
-:%argd
-:arga a b c d e f
-:3argu
-:let args = ''
-:.,$-argdo let args .= ' '.expand('%')
-:call add(g:lines, 'argdo:' . args)
-:split|split|split|split
-:2wincmd w
-:let windows = ''
-:.,$-windo let windows .= ' '.winnr()
-:call add(g:lines, 'windo:'. windows)
-:b2
-:let buffers = ''
-:.,$-bufdo let buffers .= ' '.bufnr('%')
-:call add(g:lines, 'bufdo:' . buffers)
-:3bd
-:let buffers = ''
-:3,7bufdo let buffers .= ' '.bufnr('%')
-:call add(g:lines, 'bufdo:' . buffers)
-:tabe|tabe|tabe|tabe
-:normal! 2gt
-:let tabpages = ''
-:.,$-tabdo let tabpages .= ' '.tabpagenr()
-:call add(g:lines, 'tabdo:' . tabpages)
-:e! test.out
-:call append('$', g:lines)
-:w|qa!
-ENDTEST
-
-
diff --git a/src/nvim/testdir/test_command_count.ok b/src/nvim/testdir/test_command_count.ok
deleted file mode 100644
index e74155ec1b..0000000000
--- a/src/nvim/testdir/test_command_count.ok
+++ /dev/null
@@ -1,38 +0,0 @@
-RangeArguments 2 4
-RangeArguments 1 5
-RangeArgumentsAll 1 5
-RangeArguments 2 2
-RangeWindows 3 5
-RangeWindows 1 5
-RangeWindowsAll 1 5
-RangeLoadedBuffers 2 4
-RangeLoadedBuffers 1 4
-RangeLoadedBuffersAll 1 4
-RangeBuffers 2 5
-RangeBuffers 1 5
-RangeBuffersAll 1 5
-RangeTabs 2 5
-RangeTabs 1 5
-RangeTabsAll 1 5
-RangeLines 2 5
-LocalRangeLines 2 5
-
-5argu E16: Invalid range
-4argu d
-1argu a
-100b E16: Invalid range
-0close
-$close 3
-$+close E16: Invalid range
-$tabe 2
-$+tabe E16: Invalid range
-0tabm x
-
-aaa: 1 bbb: 1 ccc: 1
-aaa: 1 bbb: 0 ccc: 0
-aaa: 0 bbb: 0 ccc: 0
-argdo: c d e
-windo: 2 3 4
-bufdo: 2 3 4 5 6 7 8 9 10 15
-bufdo: 4 5 6 7
-tabdo: 2 3 4
diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in
index f13eee121e..6084711786 100644
--- a/src/nvim/testdir/test_listlbr.in
+++ b/src/nvim/testdir/test_listlbr.in
@@ -24,20 +24,24 @@ STARTTEST
: $put =g:line
: wincmd p
:endfu
+:"
:let g:test="Test 1: set linebreak"
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
+:"
:let g:test="Test 2: set linebreak + set list"
:set linebreak list listchars=
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
+:"
:let g:test ="Test 3: set linebreak nolist"
:set nolist linebreak
:redraw!
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
+:"
:let g:test ="Test 4: set linebreak with tab and 1 line as long as screen: should break!"
:set nolist linebreak ts=8
:let line="1\t".repeat('a', winwidth(0)-2)
@@ -51,6 +55,7 @@ STARTTEST
:$put =line
:$
:norm! zt
+:"
:let g:test ="Test 5: set linebreak with conceal and set list and tab displayed by different char (line may not be truncated)"
:set cpo&vim list linebreak conceallevel=2 concealcursor=nv listchars=tab:ab
:syn match ConcealVar contained /_/ conceal
@@ -58,6 +63,7 @@ STARTTEST
:let line=ScreenChar(winwidth(0))
:call DoRecordScreen()
:set cpo&vim linebreak
+:"
:let g:test ="Test 6: set linebreak with visual block mode"
:let line="REMOVE: this not"
:$put =g:test
@@ -67,20 +73,47 @@ STARTTEST
:1/^REMOVE:
0jf x:$put
:set cpo&vim linebreak
+:"
:let g:test ="Test 7: set linebreak with visual block mode and v_b_A"
:$put =g:test
Golong line: 40afoobar aTARGET at end
:exe "norm! $3B\<C-v>eAx\<Esc>"
:set cpo&vim linebreak sbr=
+:"
:let g:test ="Test 8: set linebreak with visual char mode and changing block"
:$put =g:test
Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj.
+:"
:let g:test ="Test 9: using redo after block visual mode"
:$put =g:test
Go
aaa
aaa
a2k2j~e.
+:"
+:let g:test ="Test 10: using normal commands after block-visual"
+:$put =g:test
+:set linebreak
+Go
+abcd{ef
+ghijklm
+no}pqrs2k0f{c%
+:"
+:let g:test ="Test 11: using block replace mode after wrapping"
+:$put =g:test
+:set linebreak wrap
+Go150aayypk147|jr0
+:"
+:let g:test ="Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$"
+:set list listchars=space:_,trail:-,tab:>-,eol:$
+:$put =g:test
+:let line="a aaaaaaaaaaaaaaaaaaaaaa\ta "
+:$put =line
+:$
+:norm! zt
+:redraw!
+:let line=ScreenChar(winwidth(0))
+:call DoRecordScreen()
:%w! test.out
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok
index 323bcdee08..b32a54969e 100644
--- a/src/nvim/testdir/test_listlbr.ok
+++ b/src/nvim/testdir/test_listlbr.ok
@@ -46,3 +46,17 @@ Test 9: using redo after block visual mode
AaA
AaA
A
+Test 10: using normal commands after block-visual
+
+abcdpqrs
+Test 11: using block replace mode after wrapping
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0aaa
+Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$
+a aaaaaaaaaaaaaaaaaaaaaa a
+
+Test 12: set linebreak list listchars=space:_,tab:>-,tail:-,eol:$
+a_
+aaaaaaaaaaaaaaaaaaaa
+aa>-----a-$
+~
diff --git a/src/nvim/version.c b/src/nvim/version.c
index e63440b26e..3470e1f354 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,6 +69,8 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
+ 1366,
+
// 1219 NA
// 1218 NA
// 1217 NA
@@ -247,7 +249,7 @@ static int included_patches[] = {
// 1044 NA,
// 1043 NA,
// 1042,
- // 1041,
+ 1041,
// 1040 NA,
// 1039,
// 1038 NA,
@@ -311,7 +313,7 @@ static int included_patches[] = {
980,
// 979 NA
978,
- // 977,
+ 977,
// 976 NA
975,
// 974,
@@ -366,7 +368,7 @@ static int included_patches[] = {
// 925,
// 924 NA
// 923 NA
- // 922,
+ 922,
// 921 NA
// 920 NA
// 919 NA
@@ -385,7 +387,7 @@ static int included_patches[] = {
// 906 NA
// 905,
// 904,
- // 903,
+ 903,
// 902 NA
// 901,
// 900 NA
@@ -400,18 +402,18 @@ static int included_patches[] = {
// 891,
// 890 NA
// 889,
- // 888,
- // 887,
+ 888,
+ 887,
// 886 NA
- // 885,
+ 885,
// 884 NA
- // 883,
+ 883,
// 882,
881,
// 880 NA
879,
// 878,
- // 877,
+ 877,
// 876 NA
// 875 NA
// 874 NA
@@ -420,7 +422,7 @@ static int included_patches[] = {
// 871,
// 870,
// 869 NA
- // 868,
+ 868,
// 867 NA
// 866 NA
// 865 NA
@@ -429,23 +431,23 @@ static int included_patches[] = {
// 862 NA
// 861 NA
// 860 NA
- // 859,
+ 859,
858,
// 857,
- // 856,
+ 856,
// 855 NA
// 854 NA
- // 853,
+ 853,
// 852 NA
// 851 NA
// 850 NA
849,
848,
- // 847,
+ 847,
// 846 NA
- // 845,
- // 844,
- // 843,
+ 845,
+ 844,
+ 843,
// 842 NA
// 841 NA
// 840 NA
@@ -453,12 +455,12 @@ static int included_patches[] = {
// 838 NA
// 837 NA
836,
- // 835,
+ 835,
834,
- // 833,
- // 832,
- // 831,
- // 830,
+ 833,
+ 832,
+ 831,
+ 830,
// 829 NA
828,
// 827 NA
@@ -470,7 +472,7 @@ static int included_patches[] = {
// 821 NA
820,
// 819,
- // 818,
+ 818,
817,
816,
815,
@@ -496,7 +498,7 @@ static int included_patches[] = {
795,
// 794 NA
793,
- // 792,
+ 792,
791,
790,
789,
@@ -517,7 +519,7 @@ static int included_patches[] = {
774,
773,
// 772 NA
- // 771,
+ 771,
// 770 NA
769,
768,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index e84d8df36b..36cb48f3a1 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5342,14 +5342,14 @@ void restore_buffer(buf_T *save_curbuf)
}
-/*
- * Add match to the match list of window 'wp'. The pattern 'pat' will be
- * highlighted with the group 'grp' with priority 'prio'.
- * Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
- * If no particular ID is desired, -1 must be specified for 'id'.
- * Return ID of added match, -1 on failure.
- */
-int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list)
+// Add match to the match list of window 'wp'. The pattern 'pat' will be
+// highlighted with the group 'grp' with priority 'prio'.
+// Optionally, a desired ID 'id' can be specified (greater than or equal to 1).
+// If no particular ID is desired, -1 must be specified for 'id'.
+// Return ID of added match, -1 on failure.
+int match_add(win_T *wp, char_u *grp, char_u *pat,
+ int prio, int id, list_T *pos_list,
+ char_u *conceal_char)
{
matchitem_T *cur;
matchitem_T *prev;
@@ -5405,6 +5405,10 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos
m->match.regprog = regprog;
m->match.rmm_ic = FALSE;
m->match.rmm_maxcol = 0;
+ m->conceal_char = 0;
+ if (conceal_char != NULL) {
+ m->conceal_char = (*mb_ptr2char)(conceal_char);
+ }
// Set up position matches
if (pos_list != NULL)
diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua
index 0961340e61..4de3f039c1 100644
--- a/test/functional/autocmd/termclose_spec.lua
+++ b/test/functional/autocmd/termclose_spec.lua
@@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen')
local clear, execute, feed, nvim, nvim_dir = helpers.clear,
helpers.execute, helpers.feed, helpers.nvim, helpers.nvim_dir
+local eval, eq = helpers.eval, helpers.eq
describe('TermClose event', function()
local screen
@@ -25,4 +26,19 @@ describe('TermClose event', function()
TermClose works! |
]])
end)
+
+ it('reports the correct <abuf>', function()
+ execute('set hidden')
+ execute('autocmd TermClose * let g:abuf = expand("<abuf>")')
+ execute('edit foo')
+ execute('edit bar')
+ eq(2, eval('bufnr("%")'))
+ execute('terminal')
+ feed('<c-\\><c-n>')
+ eq(3, eval('bufnr("%")'))
+ execute('buffer 1')
+ eq(1, eval('bufnr("%")'))
+ execute('3bdelete!')
+ eq('3', eval('g:abuf'))
+ end)
end)
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
new file mode 100644
index 0000000000..483e465cee
--- /dev/null
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -0,0 +1,230 @@
+-- Tests for autocommands
+-- - FileWritePre writing a compressed file
+-- - FileReadPost reading a compressed file
+-- - BufNewFile reading a file template
+-- - BufReadPre decompressing the file to be read
+-- - FilterReadPre substituting characters in the temp file
+-- - FilterReadPost substituting characters after filtering
+-- - FileReadPre set options for decompression
+-- - FileReadPost decompress the file
+-- Note: This test is skipped if "gzip" is not available.
+-- $GZIP is made empty, "-v" would cause trouble.
+-- Use a FileChangedShell autocommand to avoid a prompt for "Xtestfile.gz"
+-- being modified outside of Vim (noticed on Solaris).
+
+local helpers, lfs = require('test.functional.helpers'), require('lfs')
+local clear, execute, expect, eq, neq, dedent, write_file, feed =
+ helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.neq,
+ helpers.dedent, helpers.write_file, helpers.feed
+
+local function has_gzip()
+ return os.execute('gzip --help >/dev/null 2>&1') == 0
+end
+
+local function prepare_gz_file(name, text)
+ write_file(name, text..'\n')
+ -- Compress the file with gzip.
+ os.execute('gzip --force '..name)
+ -- This should create the .gz file and delete the original.
+ neq(nil, lfs.attributes(name..'.gz'))
+ eq(nil, lfs.attributes(name))
+end
+
+describe('file reading, writing and bufnew and filter autocommands', function()
+ local text1 = dedent([[
+ start of testfile
+ line 2 Abcdefghijklmnopqrstuvwxyz
+ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 4 Abcdefghijklmnopqrstuvwxyz
+ line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 6 Abcdefghijklmnopqrstuvwxyz
+ line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 8 Abcdefghijklmnopqrstuvwxyz
+ line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 10 Abcdefghijklmnopqrstuvwxyz
+ end of testfile]])
+ setup(function()
+ write_file('Xtest.c', [[
+ /*
+ * Here is a new .c file
+ */
+ ]])
+ end)
+ before_each(clear)
+ teardown(function()
+ os.remove('Xtestfile.gz')
+ os.remove('Xtest.c')
+ os.remove('test.out')
+ end)
+
+ if not has_gzip() then
+ pending('skipped (missing `gzip` utility)', function() end)
+ else
+
+ it('FileReadPost (using gzip)', function()
+ prepare_gz_file('Xtestfile', text1)
+ execute('let $GZIP = ""')
+ --execute('au FileChangedShell * echo "caught FileChangedShell"')
+ execute('set bin')
+ execute("au FileReadPost *.gz '[,']!gzip -d")
+ -- Read and decompress the testfile.
+ execute('$r Xtestfile.gz')
+ expect('\n'..text1)
+ end)
+
+ it('BufReadPre, BufReadPost (using gzip)', function()
+ prepare_gz_file('Xtestfile', text1)
+ local gzip_data = io.open('Xtestfile.gz'):read('*all')
+ execute('let $GZIP = ""')
+ -- Setup autocommands to decompress before reading and re-compress afterwards.
+ execute("au BufReadPre *.gz exe '!gzip -d ' . shellescape(expand('<afile>'))")
+ execute("au BufReadPre *.gz call rename(expand('<afile>:r'), expand('<afile>'))")
+ execute("au BufReadPost *.gz call rename(expand('<afile>'), expand('<afile>:r'))")
+ execute("au BufReadPost *.gz exe '!gzip ' . shellescape(expand('<afile>:r'))")
+ -- Edit compressed file.
+ execute('e! Xtestfile.gz')
+ -- Discard all prompts and messages.
+ feed('<C-L>')
+ -- Expect the decompressed file in the buffer.
+ expect(text1)
+ -- Expect the original file to be unchanged.
+ eq(gzip_data, io.open('Xtestfile.gz'):read('*all'))
+ end)
+
+ it('FileReadPre, FileReadPost', function()
+ prepare_gz_file('Xtestfile', text1)
+ execute('au! FileReadPre *.gz exe "silent !gzip -d " . shellescape(expand("<afile>"))')
+ execute('au FileReadPre *.gz call rename(expand("<afile>:r"), expand("<afile>"))')
+ execute("au! FileReadPost *.gz '[,']s/l/L/")
+ -- Read compressed file.
+ execute('$r Xtestfile.gz')
+ -- Discard all prompts and messages.
+ feed('<C-L>')
+ expect([[
+
+ start of testfiLe
+ Line 2 Abcdefghijklmnopqrstuvwxyz
+ Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ Line 4 Abcdefghijklmnopqrstuvwxyz
+ Line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ Line 6 Abcdefghijklmnopqrstuvwxyz
+ Line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ Line 8 Abcdefghijklmnopqrstuvwxyz
+ Line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ Line 10 Abcdefghijklmnopqrstuvwxyz
+ end of testfiLe]])
+ end)
+
+ end
+
+ it('FileAppendPre, FileAppendPost', function()
+ execute('au BufNewFile *.c read Xtest.c')
+ -- Will load Xtest.c.
+ execute('e! foo.c')
+ execute("au FileAppendPre *.out '[,']s/new/NEW/")
+ execute('au FileAppendPost *.out !cat Xtest.c >>test.out')
+ -- Append it to the output file.
+ execute('w>>test.out')
+ -- Discard all prompts and messages.
+ feed('<C-L>')
+ -- Expect the decompressed file in the buffer.
+ execute('e test.out')
+ expect([[
+
+ /*
+ * Here is a NEW .c file
+ */]])
+ end)
+
+ it('FilterReadPre, FilterReadPost', function()
+ -- Write a special input file for this test block.
+ write_file('test.out', dedent([[
+ startstart
+ ]]) .. text1 .. dedent([[
+
+
+ start of test.c
+ /*
+ * Here is a new .c file
+ */
+ end of test.c
+ ]]) .. text1 .. dedent([[
+
+
+ /*
+ * Here is a NEW .c file
+ */
+ /*
+ * Here is a new .c file
+ */
+ ]]) .. text1 .. dedent([[
+
+ /*
+ * Here is a new .c file
+ */]]))
+ -- Need temp files here.
+ execute('set shelltemp')
+ execute('au FilterReadPre *.out call rename(expand("<afile>"), expand("<afile>") . ".t")')
+ execute('au FilterReadPre *.out exe "silent !sed s/e/E/ " . shellescape(expand("<afile>")) . ".t >" . shellescape(expand("<afile>"))')
+ execute('au FilterReadPre *.out exe "silent !rm " . shellescape(expand("<afile>")) . ".t"')
+ execute("au FilterReadPost *.out '[,']s/x/X/g")
+ -- Edit the output file.
+ execute('e! test.out')
+ execute('23,$!cat')
+ -- Discard all prompts and messages.
+ feed('<C-L>')
+ -- Remove CR for when sed adds them.
+ execute([[23,$s/\r$//]])
+ expect([[
+ startstart
+ start of testfile
+ line 2 Abcdefghijklmnopqrstuvwxyz
+ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 4 Abcdefghijklmnopqrstuvwxyz
+ line 5 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 6 Abcdefghijklmnopqrstuvwxyz
+ line 7 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 8 Abcdefghijklmnopqrstuvwxyz
+ line 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 10 Abcdefghijklmnopqrstuvwxyz
+ end of testfile
+
+ start of test.c
+ /*
+ * Here is a new .c file
+ */
+ end of test.c
+ start of testfile
+ line 2 Abcdefghijklmnopqrstuvwxyz
+ line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ line 4 Abcdefghijklmnopqrstuvwxyz
+ linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 6 AbcdefghijklmnopqrstuvwXyz
+ linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 8 AbcdefghijklmnopqrstuvwXyz
+ linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 10 AbcdefghijklmnopqrstuvwXyz
+ End of testfile
+
+ /*
+ * HEre is a NEW .c file
+ */
+ /*
+ * HEre is a new .c file
+ */
+ start of tEstfile
+ linE 2 AbcdefghijklmnopqrstuvwXyz
+ linE 3 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 4 AbcdefghijklmnopqrstuvwXyz
+ linE 5 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 6 AbcdefghijklmnopqrstuvwXyz
+ linE 7 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 8 AbcdefghijklmnopqrstuvwXyz
+ linE 9 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ linE 10 AbcdefghijklmnopqrstuvwXyz
+ End of testfile
+ /*
+ * HEre is a new .c file
+ */]])
+ end)
+end)
diff --git a/test/functional/legacy/036_regexp_character_classes_spec.lua b/test/functional/legacy/036_regexp_character_classes_spec.lua
new file mode 100644
index 0000000000..205922eac2
--- /dev/null
+++ b/test/functional/legacy/036_regexp_character_classes_spec.lua
@@ -0,0 +1,272 @@
+-- Test character classes in regexp using regexpengine 0, 1, 2.
+
+local helpers = require('test.functional.helpers')
+local ffi = require('ffi')
+local feed, insert, source = helpers.feed, helpers.insert, helpers.source
+local clear, execute, expect, eq, eval = helpers.clear, helpers.execute, helpers.expect, helpers.eq, helpers.eval
+local write_file = helpers.write_file
+
+local function sixlines(text)
+ local result = ''
+ for i = 1, 6 do
+ result = result .. text .. '\n'
+ end
+ return result
+end
+
+local function diff(text, nodedent)
+ local tmpname = os.tmpname()
+ if ffi.os == 'OSX' and string.match(tmpname, '^/tmp') then
+ tmpname = '/private'..tmpname
+ end
+ execute('w! '..tmpname)
+ helpers.wait()
+ local data = io.open(tmpname):read('*all')
+ if nodedent then
+ helpers.eq(text, data)
+ else
+ helpers.eq(helpers.dedent(text), data)
+ end
+ os.remove(tmpname)
+end
+
+describe('character classes in regexp', function()
+ local ctrl1 = '\t\x0c\r'
+ local punct1 = " !\"#$%&'()#+'-./"
+ local digits = '0123456789'
+ local punct2 = ':;<=>?@'
+ local upper = 'ABCDEFGHIXYZ'
+ local punct3 = '[\\]^_`'
+ local lower = 'abcdefghiwxyz'
+ local punct4 = '{|}~'
+ local ctrl2 = '\x7f\x80\x82\x90\x9b'
+ local iso_text = '\xa6\xb1\xbc\xc7\xd3\xe9' -- "¦±¼ÇÓé" in utf-8
+ setup(function()
+ -- The original test32.in file was not in utf-8 encoding and did also
+ -- contain some control characters. We use lua escape sequences to write
+ -- them to the test file.
+ local line = ctrl1..punct1..digits..punct2..upper..punct3..lower..punct4..ctrl2..iso_text
+ write_file('test36.in', sixlines(line))
+ end)
+ before_each(function()
+ clear()
+ execute('e test36.in')
+ end)
+ teardown(function()
+ os.remove('test36.in')
+ end)
+
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\d//g
+ 2 s/\%#=1\d//g
+ 3 s/\%#=2\d//g
+ 4 s/\%#=0[0-9]//g
+ 5 s/\%#=1[0-9]//g
+ 6 s/\%#=2[0-9]//g]])
+ diff(sixlines(ctrl1..punct1..punct2..upper..punct3..lower..punct4..
+ ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\D//g
+ 2 s/\%#=1\D//g
+ 3 s/\%#=2\D//g
+ 4 s/\%#=0[^0-9]//g
+ 5 s/\%#=1[^0-9]//g
+ 6 s/\%#=2[^0-9]//g]])
+ expect([[
+ 0123456789
+ 0123456789
+ 0123456789
+ 0123456789
+ 0123456789
+ 0123456789]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\o//g
+ 2 s/\%#=1\o//g
+ 3 s/\%#=2\o//g
+ 4 s/\%#=0[0-7]//g
+ 5 s/\%#=1[0-7]//g
+ 6 s/\%#=2[0-7]//g]])
+ diff(sixlines(ctrl1..punct1..'89'..punct2..upper..punct3..lower..punct4..ctrl2..
+ iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\O//g
+ 2 s/\%#=1\O//g
+ 3 s/\%#=2\O//g
+ 4 s/\%#=0[^0-7]//g
+ 5 s/\%#=1[^0-7]//g
+ 6 s/\%#=2[^0-7]//g]])
+ expect([[
+ 01234567
+ 01234567
+ 01234567
+ 01234567
+ 01234567
+ 01234567]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\x//g
+ 2 s/\%#=1\x//g
+ 3 s/\%#=2\x//g
+ 4 s/\%#=0[0-9A-Fa-f]//g
+ 5 s/\%#=1[0-9A-Fa-f]//g
+ 6 s/\%#=2[0-9A-Fa-f]//g]])
+ diff(sixlines(ctrl1..punct1..punct2..'GHIXYZ'..punct3..'ghiwxyz'..punct4..ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\X//g
+ 2 s/\%#=1\X//g
+ 3 s/\%#=2\X//g
+ 4 s/\%#=0[^0-9A-Fa-f]//g
+ 5 s/\%#=1[^0-9A-Fa-f]//g
+ 6 s/\%#=2[^0-9A-Fa-f]//g]])
+ expect([[
+ 0123456789ABCDEFabcdef
+ 0123456789ABCDEFabcdef
+ 0123456789ABCDEFabcdef
+ 0123456789ABCDEFabcdef
+ 0123456789ABCDEFabcdef
+ 0123456789ABCDEFabcdef]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\w//g
+ 2 s/\%#=1\w//g
+ 3 s/\%#=2\w//g
+ 4 s/\%#=0[0-9A-Za-z_]//g
+ 5 s/\%#=1[0-9A-Za-z_]//g
+ 6 s/\%#=2[0-9A-Za-z_]//g]])
+ diff(sixlines(ctrl1..punct1..punct2..'[\\]^`'..punct4..ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\W//g
+ 2 s/\%#=1\W//g
+ 3 s/\%#=2\W//g
+ 4 s/\%#=0[^0-9A-Za-z_]//g
+ 5 s/\%#=1[^0-9A-Za-z_]//g
+ 6 s/\%#=2[^0-9A-Za-z_]//g]])
+ expect([[
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz
+ 0123456789ABCDEFGHIXYZ_abcdefghiwxyz]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\h//g
+ 2 s/\%#=1\h//g
+ 3 s/\%#=2\h//g
+ 4 s/\%#=0[A-Za-z_]//g
+ 5 s/\%#=1[A-Za-z_]//g
+ 6 s/\%#=2[A-Za-z_]//g]])
+ diff(sixlines(ctrl1..punct1..digits..punct2..'[\\]^`'..punct4..ctrl2..
+ iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\H//g
+ 2 s/\%#=1\H//g
+ 3 s/\%#=2\H//g
+ 4 s/\%#=0[^A-Za-z_]//g
+ 5 s/\%#=1[^A-Za-z_]//g
+ 6 s/\%#=2[^A-Za-z_]//g]])
+ expect([[
+ ABCDEFGHIXYZ_abcdefghiwxyz
+ ABCDEFGHIXYZ_abcdefghiwxyz
+ ABCDEFGHIXYZ_abcdefghiwxyz
+ ABCDEFGHIXYZ_abcdefghiwxyz
+ ABCDEFGHIXYZ_abcdefghiwxyz
+ ABCDEFGHIXYZ_abcdefghiwxyz]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\a//g
+ 2 s/\%#=1\a//g
+ 3 s/\%#=2\a//g
+ 4 s/\%#=0[A-Za-z]//g
+ 5 s/\%#=1[A-Za-z]//g
+ 6 s/\%#=2[A-Za-z]//g]])
+ diff(sixlines(ctrl1..punct1..digits..punct2..punct3..punct4..ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\A//g
+ 2 s/\%#=1\A//g
+ 3 s/\%#=2\A//g
+ 4 s/\%#=0[^A-Za-z]//g
+ 5 s/\%#=1[^A-Za-z]//g
+ 6 s/\%#=2[^A-Za-z]//g]])
+ expect([[
+ ABCDEFGHIXYZabcdefghiwxyz
+ ABCDEFGHIXYZabcdefghiwxyz
+ ABCDEFGHIXYZabcdefghiwxyz
+ ABCDEFGHIXYZabcdefghiwxyz
+ ABCDEFGHIXYZabcdefghiwxyz
+ ABCDEFGHIXYZabcdefghiwxyz]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\l//g
+ 2 s/\%#=1\l//g
+ 3 s/\%#=2\l//g
+ 4 s/\%#=0[a-z]//g
+ 5 s/\%#=1[a-z]//g
+ 6 s/\%#=2[a-z]//g]])
+ diff(sixlines(ctrl1..punct1..digits..punct2..upper..punct3..punct4..
+ ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\L//g
+ 2 s/\%#=1\L//g
+ 3 s/\%#=2\L//g
+ 4 s/\%#=0[^a-z]//g
+ 5 s/\%#=1[^a-z]//g
+ 6 s/\%#=2[^a-z]//g]])
+ expect([[
+ abcdefghiwxyz
+ abcdefghiwxyz
+ abcdefghiwxyz
+ abcdefghiwxyz
+ abcdefghiwxyz
+ abcdefghiwxyz]])
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\u//g
+ 2 s/\%#=1\u//g
+ 3 s/\%#=2\u//g
+ 4 s/\%#=0[A-Z]//g
+ 5 s/\%#=1[A-Z]//g
+ 6 s/\%#=2[A-Z]//g]])
+ diff(sixlines(ctrl1..punct1..digits..punct2..punct3..lower..punct4..
+ ctrl2..iso_text))
+ end)
+ it('is working', function()
+ source([[
+ 1 s/\%#=0\U//g
+ 2 s/\%#=1\U//g
+ 3 s/\%#=2\U//g
+ 4 s/\%#=0[^A-Z]//g
+ 5 s/\%#=1[^A-Z]//g
+ 6 s/\%#=2[^A-Z]//g]])
+ expect([[
+ ABCDEFGHIXYZ
+ ABCDEFGHIXYZ
+ ABCDEFGHIXYZ
+ ABCDEFGHIXYZ
+ ABCDEFGHIXYZ
+ ABCDEFGHIXYZ]])
+ end)
+end)
diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua
index 855e9c6271..6349371808 100644
--- a/test/functional/legacy/autocmd_option_spec.lua
+++ b/test/functional/legacy/autocmd_option_spec.lua
@@ -2,6 +2,8 @@ local helpers = require('test.functional.helpers')
local nvim = helpers.meths
local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq
local curbuf, buf = helpers.curbuf, helpers.bufmeths
+local curwin = helpers.curwin
+local redir_exec = helpers.redir_exec
local source, execute = helpers.source, helpers.execute
local function declare_hook_function()
@@ -86,7 +88,7 @@ end
local function make_buffer()
local old_buf = curbuf()
- execute('new')
+ execute('botright new')
local new_buf = curbuf()
execute('wincmd p') -- move previous window
@@ -96,6 +98,19 @@ local function make_buffer()
return new_buf
end
+local function get_new_window_number()
+ local old_win = curwin()
+ execute('botright new')
+ local new_win = curwin()
+ local new_winnr = redir_exec('echo winnr()')
+ execute('wincmd p') -- move previous window
+
+ neq(old_win, new_win)
+ eq(old_win, curwin())
+
+ return new_winnr:gsub('\n', '')
+end
+
describe('au OptionSet', function()
describe('with any opton (*)', function()
@@ -248,6 +263,32 @@ describe('au OptionSet', function()
end)
end)
+ describe('being set by setwinvar()', function()
+ it('should not trigger because option name does not match with backup', function()
+ set_hook('backup')
+
+ execute('call setwinvar(1, "&l:bk", 1)')
+ expected_empty()
+ end)
+
+ it('should trigger, use correct option name backup', function()
+ set_hook('backup')
+
+ execute('call setwinvar(1, "&backup", 1)')
+ expected_combination({'backup', 0, 1, 'local'})
+ end)
+
+ it('should not trigger if the current window is different from the targetted window', function()
+ set_hook('cursorcolumn')
+
+ local new_winnr = get_new_window_number()
+
+ execute('call setwinvar(' .. new_winnr .. ', "&cursorcolumn", 1)')
+ -- expected_combination({'cursorcolumn', 0, 1, 'local', {winnr = new_winnr}})
+ expected_empty()
+ end)
+ end)
+
describe('being set by neovim api', function()
it('should trigger if a boolean option be set globally', function()
set_hook('autochdir')
diff --git a/test/functional/legacy/charsearch_spec.lua b/test/functional/legacy/charsearch_spec.lua
new file mode 100644
index 0000000000..4a83801cfc
--- /dev/null
+++ b/test/functional/legacy/charsearch_spec.lua
@@ -0,0 +1,42 @@
+-- Test for character searches
+
+local helpers = require('test.functional.helpers')
+local feed, insert = helpers.feed, helpers.insert
+local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
+
+describe('charsearch', function()
+ setup(clear)
+
+ it('is working', function()
+ insert([[
+ Xabcdefghijkemnopqretuvwxyz
+ Yabcdefghijkemnopqretuvwxyz
+ Zabcdefghijkemnokqretkvwxyz]])
+
+ -- Check that "fe" and ";" work.
+ execute('/^X')
+ feed('ylfep;;p,,p')
+ -- Check that save/restore works.
+ execute('/^Y')
+ feed('ylfep')
+ execute('let csave = getcharsearch()')
+ feed('fip')
+ execute('call setcharsearch(csave)')
+ feed(';p;p')
+ -- Check that setcharsearch() changes the settings.
+ execute('/^Z')
+ feed('ylfep')
+ execute("call setcharsearch({'char': 'k'})")
+ feed(';p')
+ execute("call setcharsearch({'forward': 0})")
+ feed('$;p')
+ execute("call setcharsearch({'until': 1})")
+ feed(';;p')
+
+ -- Assert buffer contents.
+ expect([[
+ XabcdeXfghijkeXmnopqreXtuvwxyz
+ YabcdeYfghiYjkeYmnopqreYtuvwxyz
+ ZabcdeZfghijkZZemnokqretkZvwxyz]])
+ end)
+end)
diff --git a/test/functional/legacy/command_count_spec.lua b/test/functional/legacy/command_count_spec.lua
new file mode 100644
index 0000000000..d9b4f09263
--- /dev/null
+++ b/test/functional/legacy/command_count_spec.lua
@@ -0,0 +1,243 @@
+-- Test for user command counts
+
+local helpers = require('test.functional.helpers')
+local clear, source, expect = helpers.clear, helpers.source, helpers.expect
+local execute, spawn = helpers.execute, helpers.spawn
+local nvim_prog = helpers.nvim_prog
+
+describe('command_count', function()
+ setup(clear)
+ teardown(function()
+ os.remove('test.out')
+ end)
+
+ it('is working', function()
+ -- It is relevant for the test to load a file initially. If this is
+ -- emulated with :arg the buffer count is wrong as nvim creates an empty
+ -- buffer if it was started without a filename.
+ local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed',
+ 'test_command_count.in'})
+ helpers.set_session(nvim2)
+
+ source([[
+ lang C
+ let g:lines = []
+ com -range=% RangeLines
+ \ :call add(g:lines, 'RangeLines '.<line1>.' '.<line2>)
+ com -range -addr=arguments RangeArguments
+ \ :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>)
+ com -range=% -addr=arguments RangeArgumentsAll
+ \ :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>)
+ com -range -addr=loaded_buffers RangeLoadedBuffers
+ \ :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>)
+ com -range=% -addr=loaded_buffers RangeLoadedBuffersAll
+ \ :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>)
+ com -range -addr=buffers RangeBuffers
+ \ :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>)
+ com -range=% -addr=buffers RangeBuffersAll
+ \ :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>)
+ com -range -addr=windows RangeWindows
+ \ :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>)
+ com -range=% -addr=windows RangeWindowsAll
+ \ :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>)
+ com -range -addr=tabs RangeTabs
+ \ :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>)
+ com -range=% -addr=tabs RangeTabsAll
+ \ :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>)
+ set hidden
+ arga a b c d
+ argdo echo "loading buffers"
+ argu 3
+ .-,$-RangeArguments
+ %RangeArguments
+ RangeArgumentsAll
+ N
+ .RangeArguments
+ split
+ split
+ split
+ split
+ 3wincmd w
+ .,$RangeWindows
+ %RangeWindows
+ RangeWindowsAll
+ only
+ blast
+ bd
+ .,$RangeLoadedBuffers
+ %RangeLoadedBuffers
+ RangeLoadedBuffersAll
+ .,$RangeBuffers
+ %RangeBuffers
+ RangeBuffersAll
+ tabe
+ tabe
+ tabe
+ tabe
+ normal 2gt
+ .,$RangeTabs
+ %RangeTabs
+ RangeTabsAll
+ 1tabonly
+ s/\n/\r\r\r\r\r/
+ 2ma<
+ $-ma>
+ '<,'>RangeLines
+ com -range=% -buffer LocalRangeLines
+ \ :call add(g:lines, 'LocalRangeLines '.<line1>.' '.<line2>)
+ '<,'>LocalRangeLines
+ b1
+ call add(g:lines, '')
+ %argd
+ arga a b c d
+ ]])
+ -- This can not be in the source() call as it will produce errors.
+ execute([[let v:errmsg = '']])
+ execute('5argu')
+ execute([[call add(g:lines, '5argu ' . v:errmsg)]])
+ execute('$argu')
+ execute([[call add(g:lines, '4argu ' . expand('%:t'))]])
+ execute([[let v:errmsg = '']])
+ execute('1argu')
+ execute([[call add(g:lines, '1argu ' . expand('%:t'))]])
+ execute([[let v:errmsg = '']])
+ execute('100b')
+ execute([[call add(g:lines, '100b ' . v:errmsg)]])
+ execute('split')
+ execute('split')
+ execute('split')
+ execute('split')
+ execute([[let v:errmsg = '']])
+ execute('0close')
+ execute([[call add(g:lines, '0close ' . v:errmsg)]])
+ execute('$wincmd w')
+ execute('$close')
+ execute([[call add(g:lines, '$close ' . winnr())]])
+ execute([[let v:errmsg = '']])
+ execute('$+close')
+ execute([[call add(g:lines, '$+close ' . v:errmsg)]])
+ execute('$tabe')
+ execute([[call add(g:lines, '$tabe ' . tabpagenr())]])
+ execute([[let v:errmsg = '']])
+ execute('$+tabe')
+ execute([[call add(g:lines, '$+tabe ' . v:errmsg)]])
+ source([[
+ only!
+ e x
+ 0tabm
+ normal 1gt
+ call add(g:lines, '0tabm ' . expand('%:t'))
+ tabonly!
+ only!
+ e! test.out
+ call append(0, g:lines)
+ unlet g:lines
+ w
+ bd
+ b1
+ let g:lines = []
+ func BufStatus()
+ call add(g:lines,
+ \ 'aaa: ' . buflisted(g:buf_aaa) .
+ \ ' bbb: ' . buflisted(g:buf_bbb) .
+ \ ' ccc: ' . buflisted(g:buf_ccc))
+ endfunc
+ se nohidden
+ e aaa
+ let buf_aaa = bufnr('%')
+ e bbb
+ let buf_bbb = bufnr('%')
+ e ccc
+ let buf_ccc = bufnr('%')
+ b1
+ call BufStatus()
+ exe buf_bbb . "," . buf_ccc . "bdelete"
+ call BufStatus()
+ exe buf_aaa . "bdelete"
+ call BufStatus()
+ e! test.out
+ call append('$', g:lines)
+ unlet g:lines
+ delfunc BufStatus
+ w
+ bd
+ b1
+ se hidden
+ only!
+ let g:lines = []
+ %argd
+ arga a b c d e f
+ 3argu
+ let args = ''
+ .,$-argdo let args .= ' '.expand('%')
+ call add(g:lines, 'argdo:' . args)
+ split
+ split
+ split
+ split
+ 2wincmd w
+ let windows = ''
+ .,$-windo let windows .= ' '.winnr()
+ call add(g:lines, 'windo:'. windows)
+ b2
+ let buffers = ''
+ .,$-bufdo let buffers .= ' '.bufnr('%')
+ call add(g:lines, 'bufdo:' . buffers)
+ 3bd
+ let buffers = ''
+ 3,7bufdo let buffers .= ' '.bufnr('%')
+ call add(g:lines, 'bufdo:' . buffers)
+ tabe
+ tabe
+ tabe
+ tabe
+ normal! 2gt
+ let tabpages = ''
+ .,$-tabdo let tabpages .= ' '.tabpagenr()
+ call add(g:lines, 'tabdo:' . tabpages)
+ e! test.out
+ call append('$', g:lines)
+ ]])
+
+ -- Assert buffer contents.
+ expect([[
+ RangeArguments 2 4
+ RangeArguments 1 5
+ RangeArgumentsAll 1 5
+ RangeArguments 2 2
+ RangeWindows 3 5
+ RangeWindows 1 5
+ RangeWindowsAll 1 5
+ RangeLoadedBuffers 2 4
+ RangeLoadedBuffers 1 4
+ RangeLoadedBuffersAll 1 4
+ RangeBuffers 2 5
+ RangeBuffers 1 5
+ RangeBuffersAll 1 5
+ RangeTabs 2 5
+ RangeTabs 1 5
+ RangeTabsAll 1 5
+ RangeLines 2 5
+ LocalRangeLines 2 5
+
+ 5argu E16: Invalid range
+ 4argu d
+ 1argu a
+ 100b E16: Invalid range
+ 0close
+ $close 3
+ $+close E16: Invalid range
+ $tabe 2
+ $+tabe E16: Invalid range
+ 0tabm x
+
+ aaa: 1 bbb: 1 ccc: 1
+ aaa: 1 bbb: 0 ccc: 0
+ aaa: 0 bbb: 0 ccc: 0
+ argdo: c d e
+ windo: 2 3 4
+ bufdo: 2 3 4 5 6 7 8 9 10 15
+ bufdo: 4 5 6 7
+ tabdo: 2 3 4]])
+ end)
+end)
diff --git a/test/functional/legacy/comparators_spec.lua b/test/functional/legacy/comparators_spec.lua
new file mode 100644
index 0000000000..e3fa3eea23
--- /dev/null
+++ b/test/functional/legacy/comparators_spec.lua
@@ -0,0 +1,14 @@
+-- " Test for expression comparators.
+
+local helpers = require('test.functional.helpers')
+local clear, eq = helpers.clear, helpers.eq
+local eval, execute = helpers.eval, helpers.execute
+
+describe('comparators', function()
+ before_each(clear)
+
+ it('is working', function()
+ execute('set isident+=#')
+ eq(1, eval('1 is#1'))
+ end)
+end)
diff --git a/test/functional/legacy/match_conceal_spec.lua b/test/functional/legacy/match_conceal_spec.lua
new file mode 100644
index 0000000000..0ffa3cae7a
--- /dev/null
+++ b/test/functional/legacy/match_conceal_spec.lua
@@ -0,0 +1,228 @@
+-- Test for matchadd() and conceal feature
+
+local helpers = require('test.functional.helpers')
+local clear = helpers.clear
+local expect = helpers.expect
+local source = helpers.source
+
+describe('match_conceal', function()
+ before_each(function()
+ clear()
+
+ source([[
+ set wildchar=^E
+ 10new
+ vsp
+ vert resize 20
+ put =\"\#\ This\ is\ a\ Test\"
+ norm! mazt
+
+ fu! ScreenChar(width, lines)
+ let c=''
+ for j in range(1,a:lines)
+ for i in range(1,a:width)
+ let c.=nr2char(screenchar(j, i))
+ endfor
+ let c.="\n"
+ endfor
+ return c
+ endfu
+
+ fu! ScreenAttr(line, pos, eval)
+ let g:attr=[]
+ for col in a:pos
+ call add(g:attr, screenattr(a:line,col))
+ endfor
+ " In case all values are zero, probably the terminal
+ " isn't set correctly, so catch that case
+ let null = (eval(join(g:attr, '+')) == 0)
+ let str=substitute(a:eval, '\d\+', 'g:attr[&]', 'g')
+ if null || eval(str)
+ let g:attr_test="OK: ". str
+ else
+ let g:attr_test="FAILED: ".str
+ let g:attr_test.="\n". join(g:attr, ' ')
+ let g:attr_test.="\n TERM: ". &term
+ endif
+ endfu
+
+ fu! DoRecordScreen()
+ wincmd l
+ $put =printf(\"\n%s\", g:test)
+ $put =g:line
+ $put =g:attr_test
+ wincmd p
+ endfu
+ ]])
+ end)
+
+ it('is working', function()
+ source([=[
+ let g:test ="Test 1: simple addmatch()"
+ call matchadd('Conceal', '\%2l ')
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+
+ let g:test ="Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)"
+ norm! 'azt
+ call clearmatches()
+ syntax on
+ set concealcursor=n conceallevel=1
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+
+ let g:test ="Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)"
+ norm! 'azt
+ set conceallevel=3
+ call clearmatches()
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'})
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 1==3 && 1==4 && 0!=5")
+ call DoRecordScreen()
+
+ let g:test ="Test 4: more match() (should be: #Thisisa Test)"
+ norm! 'azt
+ call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'})
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 0!=3 && 3==4 && 0!=5 && 3!=5")
+ call DoRecordScreen()
+
+ let g:test ="Test 5/1: default conceal char (should be: # This is a Test)"
+ norm! 'azt
+ call clearmatches()
+ set conceallevel=1
+ call matchadd('Conceal', '\%2l ', 10, -1, {})
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+ let g:test ="Test 5/2: default conceal char (should be: #+This+is+a+Test)"
+ norm! 'azt
+ set listchars=conceal:+
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+ set listchars&vi
+
+ let g:test ="Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)"
+ norm! 'azt
+ call clearmatches()
+ set conceallevel=1
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+ syn match MyConceal /\%2l / conceal containedin=ALL cchar=*
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+ let g:test ="Test 6/2: syn and match conceal (should be: #*This*is*a*Test)"
+ norm! 'azt
+ call clearmatches()
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+
+ let g:test ="Test 7/1: clear matches"
+ norm! 'azt
+ syn on
+ call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'})
+ let a=getmatches()
+ call clearmatches()
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 0==2 && 0==3 && 0==4 && 0==5")
+ call DoRecordScreen()
+ $put =a
+ call setmatches(a)
+ norm! 'azt
+ let g:test ="Test 7/2: reset match using setmatches()"
+ norm! 'azt
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+
+ let g:test ="Test 8: using matchaddpos() (should be #Pis a Test"
+ norm! 'azt
+ call clearmatches()
+ call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'})
+ let a=getmatches()
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1!=2 && 0==2 && 0==3 && 0!=4 && 0!=5 && 4==5")
+ call DoRecordScreen()
+ $put =a
+
+ let g:test ="Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)"
+ norm! 'azt
+ call clearmatches()
+ call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"})
+ redraw!
+ let line=ScreenChar(winwidth(0),1)
+ call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5")
+ call DoRecordScreen()
+ ]=])
+
+ expect([=[
+
+ # This is a Test
+
+ Test 1: simple addmatch()
+ # This is a Test
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)
+ #XThisXisXaXTest
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)
+ #ThisisaTest
+ OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]!=g:attr[5]
+
+ Test 4: more match() (should be: #Thisisa Test)
+ #Thisisa Test
+ OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[0]!=g:attr[3] && g:attr[3]==g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[3]!=g:attr[5]
+
+ Test 5/1: default conceal char (should be: # This is a Test)
+ # This is a Test
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 5/2: default conceal char (should be: #+This+is+a+Test)
+ #+This+is+a+Test
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)
+ #ZThisZisZaZTest
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 6/2: syn and match conceal (should be: #*This*is*a*Test)
+ #*This*is*a*Test
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 7/1: clear matches
+ # This is a Test
+ OK: g:attr[0]==g:attr[1] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]==g:attr[4] && g:attr[0]==g:attr[5]
+ {'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': 10, 'conceal': 'Z'}
+
+ Test 7/2: reset match using setmatches()
+ #ZThisZisZaZTest
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]
+
+ Test 8: using matchaddpos() (should be #Pis a Test
+ #Pis a Test
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]!=g:attr[2] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]!=g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[4]==g:attr[5]
+ {'group': 'Conceal', 'id': 11, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'}
+
+ Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)
+ #ˑThisˑisˑaˑTest
+ OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]]=])
+ end)
+end)
diff --git a/test/functional/legacy/search_mbyte_spec.lua b/test/functional/legacy/search_mbyte_spec.lua
new file mode 100644
index 0000000000..075b24b897
--- /dev/null
+++ b/test/functional/legacy/search_mbyte_spec.lua
@@ -0,0 +1,26 @@
+local helpers = require('test.functional.helpers')
+local insert = helpers.insert
+local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
+
+describe('search_mbyte', function()
+ before_each(clear)
+
+ it("search('multi-byte char', 'bce')", function()
+ insert([=[
+ Results:
+
+ Test bce:
+ A]=])
+
+ execute('/^Test bce:/+1')
+ execute([[$put =search('A', 'bce', line('.'))]])
+
+ -- Assert buffer contents.
+ expect([=[
+ Results:
+
+ Test bce:
+ A
+ 4]=])
+ end)
+end)