diff options
36 files changed, 1136 insertions, 499 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/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/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 b9b913a969..94683d22cb 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); } } @@ -22146,7 +22199,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 827473e55d..fffae1ecb2 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3144,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 cc08abfa4f..0c95459060 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -25,9 +25,9 @@ SCRIPTS := \ test88.out \ test_listlbr.out \ test_breakindent.out \ - test_charsearch.out \ test_close_count.out \ test_marks.out \ + test_match_conceal.out \ NEW_TESTS = 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_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 07a68549a0..fbace9ec93 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, 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/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/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) |