diff options
37 files changed, 1162 insertions, 296 deletions
diff --git a/MAINTAIN.md b/MAINTAIN.md index 7df91b7d57..2b390270a9 100644 --- a/MAINTAIN.md +++ b/MAINTAIN.md @@ -76,6 +76,12 @@ These "bundled" dependencies can be updated by bumping their versions in `third- - [lua-compat](https://github.com/keplerproject/lua-compat-5.3) - [tree-sitter](https://github.com/tree-sitter/tree-sitter) +`scripts/bump-dep.sh` is a script that can automate this process for `LuaJIT`, `Luv`, `libuv` & `tree-sitter`. See usage guide: + - Run `./scripts/bump-deps.sh --dep Luv --version 1.43.0-0` to update a dependency. + See `./scripts/bump-deps.sh -h` for more detailed usage + - Run `./scripts/bump-deps.sh --pr` to create a pr + To generate the default PR title and body, the script uses the most recent commit (not in `master`) with prefix `build(deps): ` + These dependencies are "vendored" (inlined), we need to update the sources manually: - [libmpack](https://github.com/libmpack/libmpack) - [xdiff](https://github.com/git/git/tree/master/xdiff) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index d7a3ec182f..bc94ea848c 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1348,9 +1348,10 @@ au BufNewFile,BufRead *.pm au BufNewFile,BufRead *.pod setf pod " Php, php3, php4, etc. -" Also Phtml (was used for PHP 2 in the past) -" Also .ctp for Cake template file -au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp setf php +" Also Phtml (was used for PHP 2 in the past). +" Also .ctp for Cake template file. +" Also .phpt for php tests. +au BufNewFile,BufRead *.php,*.php\d,*.phtml,*.ctp,*.phpt setf php " PHP config au BufNewFile,BufRead php.ini-* setf dosini diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 0466057d72..6d8f734bed 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -457,6 +457,7 @@ local extension = { al = "perl", ctp = "php", php = "php", + phpt = "php", phtml = "php", pike = "pike", pmod = "pike", diff --git a/scripts/bump-deps.sh b/scripts/bump-deps.sh new file mode 100755 index 0000000000..85c7f72700 --- /dev/null +++ b/scripts/bump-deps.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -e +set -u +# Use privileged mode, which e.g. skips using CDPATH. +set -p + +# Ensure that the user has a bash that supports -A +if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then + echo >&2 "error: script requires bash 4+ (you have ${BASH_VERSION})." + exit 1 +fi + +readonly NVIM_SOURCE_DIR="${NVIM_SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" +readonly VIM_SOURCE_DIR_DEFAULT="${NVIM_SOURCE_DIR}/.vim-src" +readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}" +BASENAME="$(basename "${0}")" +readonly BASENAME + +usage() { + echo "Bump Neovim dependencies" + echo + echo "Usage: ${BASENAME} [ -h | --pr | --branch=<dep> | --dep=<dependency> ]" + echo + echo "Options:" + echo " -h show this message and exit." + echo " --pr submit pr for bumping deps." + echo " --branch=<dep> create a branch bump-<dep> from current branch." + echo " --dep=<dependency> bump to a specific release or tag." + echo + echo "Dependency Options:" + echo " --version=<tag> bump to a specific release or tag." + echo " --commit=<hash> bump to a specific commit." + echo " --HEAD bump to a current head." + echo + echo " <dependency> is one of:" + echo " \"LuaJIT\", \"libuv\", \"Luv\", \"tree-sitter\"" +} + +# Checks if a program is in the user's PATH, and is executable. +check_executable() { + test -x "$(command -v "${1}")" +} + +require_executable() { + if ! check_executable "${1}"; then + echo >&2 "${BASENAME}: '${1}' not found in PATH or not executable." + exit 1 + fi +} + +require_executable "nvim" + +if [ $# -eq 0 ]; then + usage + exit 1 +fi + +PARSED_ARGS=$(getopt -a -n "$BASENAME" -o h --long pr,branch:,dep:,version:,commit:,HEAD -- "$@") + +DEPENDENCY="" +eval set -- "$PARSED_ARGS" +while :; do + case "$1" in + -h) + usage + exit 0 + ;; + --pr) + nvim -es +"lua require('scripts.bump_deps').submit_pr()" + exit 0 + ;; + --branch) + DEP=$2 + nvim -es +"lua require('scripts.bump_deps').create_branch('$DEP')" + exit 0 + ;; + --dep) + DEPENDENCY=$2 + shift 2 + ;; + --version) + VERSION=$2 + nvim -es +"lua require('scripts.bump_deps').version('$DEPENDENCY', '$VERSION')" + exit 0 + ;; + --commit) + COMMIT=$2 + nvim -es +"lua require('scripts.bump_deps').commit('$DEPENDENCY', '$COMMIT')" + exit 0 + ;; + --HEAD) + nvim -es +"lua require('scripts.bump_deps').head('$DEPENDENCY')" + exit 0 + ;; + *) + break + ;; + esac +done + +usage +exit 1 + +# vim: et sw=2 diff --git a/scripts/bump_deps.lua b/scripts/bump_deps.lua new file mode 100644 index 0000000000..2ecbb2e658 --- /dev/null +++ b/scripts/bump_deps.lua @@ -0,0 +1,343 @@ +-- Usage: +-- # bump to version +-- nvim -es +"lua require('scripts.bump_deps').version(dependency, version_tag)" +-- +-- # bump to commit +-- nvim -es +"lua require('scripts.bump_deps').commit(dependency, commit_hash)" +-- +-- # bump to HEAD +-- nvim -es +"lua require('scripts.bump_deps').head(dependency)" +-- +-- # submit PR +-- nvim -es +"lua require('scripts.bump_deps').submit_pr()" +-- +-- # create branch +-- nvim -es +"lua require('scripts.bump_deps').create_branch()" + +local M = {} + +local _trace = false +local required_branch_prefix = "bump-" +local commit_prefix = "build(deps): " + +-- Print message +local function p(s) + vim.cmd("set verbose=1") + vim.api.nvim_echo({ { s, "" } }, false, {}) + vim.cmd("set verbose=0") +end + +local function die() + p("") + vim.cmd("cquit 1") +end + +-- Executes and returns the output of `cmd`, or nil on failure. +-- if die_on_fail is true, process dies with die_msg on failure +-- +-- Prints `cmd` if `trace` is enabled. +local function _run(cmd, die_on_fail, die_msg) + if _trace then + p("run: " .. vim.inspect(cmd)) + end + local rv = vim.trim(vim.fn.system(cmd)) or "" + if vim.v.shell_error ~= 0 then + if die_on_fail then + if _trace then + p(rv) + end + p(die_msg) + die() + end + return nil + end + return rv +end + +-- Run a command, return nil on failure +local function run(cmd) + return _run(cmd, false, "") +end + +-- Run a command, die on failure with err_msg +local function run_die(cmd, err_msg) + return _run(cmd, true, err_msg) +end + +local function require_executable(cmd) + local cmd_path = run_die({ "command", "-v", cmd }, cmd .. " not found!") + run_die({ "test", "-x", cmd_path }, cmd .. " is not executable") +end + +local function rm_file_if_present(path_to_file) + run({ "rm", "-f", path_to_file }) +end + +local nvim_src_dir = vim.fn.getcwd() +local temp_dir = nvim_src_dir .. "/tmp" +run({ "mkdir", "-p", temp_dir }) + +local function get_dependency(dependency_name) + local dependency_table = { + ["LuaJIT"] = { + repo = "LuaJIT/LuaJIT", + symbol = "LUAJIT", + }, + ["libuv"] = { + repo = "libuv/libuv", + symbol = "LIBUV", + }, + ["Luv"] = { + repo = "luvit/luv", + symbol = "LUV", + }, + ["tree-sitter"] = { + repo = "tree-sitter/tree-sitter", + symbol = "TREESITTER", + }, + } + local dependency = dependency_table[dependency_name] + if dependency == nil then + p("Not a dependency: " .. dependency_name) + die() + end + dependency.name = dependency_name + return dependency +end + +local function get_gh_commit_sha(repo, ref) + require_executable("gh") + + local sha = run_die( + { "gh", "api", "repos/" .. repo .. "/commits/" .. ref, "--jq", ".sha" }, + "Failed to get commit hash from GitHub. Not a valid ref?" + ) + return sha +end + +local function get_archive_info(repo, ref) + require_executable("curl") + + local archive_name = ref .. ".tar.gz" + local archive_path = temp_dir .. "/" .. archive_name + local archive_url = "https://github.com/" .. repo .. "/archive/" .. archive_name + + rm_file_if_present(archive_path) + run_die({ "curl", "-sL", archive_url, "-o", archive_path }, "Failed to download archive from GitHub") + + local archive_sha = run({ "sha256sum", archive_path }):gmatch("%w+")() + return { url = archive_url, sha = archive_sha } +end + +local function write_cmakelists_line(symbol, kind, value) + require_executable("sed") + + local cmakelists_path = nvim_src_dir .. "/" .. "third-party/CMakeLists.txt" + run_die({ + "sed", + "-i", + "-e", + "s/set(" .. symbol .. "_" .. kind .. ".*$" .. "/set(" .. symbol .. "_" .. kind .. " " .. value .. ")" .. "/", + cmakelists_path, + }, "Failed to write " .. cmakelists_path) +end + +local function explicit_create_branch(dep) + require_executable("git") + + local checked_out_branch = run({ "git", "rev-parse", "--abbrev-ref", "HEAD" }) + if checked_out_branch ~= "master" then + p("Not on master!") + die() + end + run_die({ "git", "checkout", "-b", "bump-" .. dep }, "git failed to create branch") +end + +local function verify_branch(new_branch_suffix) + require_executable("git") + + local checked_out_branch = run({ "git", "rev-parse", "--abbrev-ref", "HEAD" }) + if not checked_out_branch:match("^" .. required_branch_prefix) then + p("Current branch '" .. checked_out_branch .. "' doesn't seem to start with " .. required_branch_prefix) + p("Checking out to bump-" .. new_branch_suffix) + explicit_create_branch(new_branch_suffix) + end +end + +local function update_cmakelists(dependency, archive, comment) + require_executable("git") + + verify_branch(dependency.name) + + local changed_file = nvim_src_dir .. "/" .. "third-party/CMakeLists.txt" + + p("Updating " .. dependency.name .. " to " .. archive.url .. "\n") + write_cmakelists_line(dependency.symbol, "URL", archive.url:gsub("/", "\\/")) + write_cmakelists_line(dependency.symbol, "SHA256", archive.sha) + run_die( + { "git", "commit", changed_file, "-m", commit_prefix .. "bump " .. dependency.name .. " to " .. comment }, + "git failed to commit" + ) +end + +local function verify_cmakelists_committed() + require_executable("git") + + local cmakelists_path = nvim_src_dir .. "/" .. "third-party/CMakeLists.txt" + run_die({ "git", "diff", "--quiet", "HEAD", "--", cmakelists_path }, cmakelists_path .. " has uncommitted changes") +end + +local function warn_luv_symbol() + p("warning: " .. get_dependency("Luv").symbol .. "_VERSION will not be updated") +end + +-- return first 9 chars of commit +local function short_commit(commit) + return string.sub(commit, 1, 9) +end + +-- TODO: remove hardcoded fork +local function gh_pr(pr_title, pr_body) + require_executable("gh") + + local pr_url = run_die({ + "gh", + "pr", + "create", + "--title", + pr_title, + "--body", + pr_body, + }, "Failed to create PR") + return pr_url +end + +local function find_git_remote(fork) + require_executable("git") + + local remotes = run({ "git", "remote", "-v" }) + local git_remote = "" + for remote in remotes:gmatch("[^\r\n]+") do + local words = {} + for word in remote:gmatch("%w+") do + table.insert(words, word) + end + local match = words[1]:match("/github.com[:/]neovim/neovim/") + if fork == "fork" then + match = not match + end + if match and words[3] == "(fetch)" then + git_remote = words[0] + break + end + end + if git_remote == "" then + git_remote = "origin" + end + return git_remote +end + +local function create_pr(pr_title, pr_body) + require_executable("git") + + local push_first = true + + local checked_out_branch = run({ "git", "rev-parse", "--abbrev-ref", "HEAD" }) + if push_first then + local push_remote = run({ "git", "config", "--get", "branch." .. checked_out_branch .. ".pushRemote" }) + if push_remote == nil then + push_remote = run({ "git", "config", "--get", "remote.pushDefault" }) + if push_remote == nil then + push_remote = run({ "git", "config", "--get", "branch." .. checked_out_branch .. ".remote" }) + if push_remote == nil or push_remote == find_git_remote(nil) then + push_remote = find_git_remote("fork") + end + end + end + + p("Pushing to " .. push_remote .. "/" .. checked_out_branch) + run_die({ "git", "push", push_remote, checked_out_branch }, "Git failed to push") + end + + local pr_url = gh_pr(pr_title, pr_body) + p("\nCreated PR: " .. pr_url .. "\n") +end + +function M.commit(dependency_name, commit) + local dependency = get_dependency(dependency_name) + verify_cmakelists_committed() + local commit_sha = get_gh_commit_sha(dependency.repo, commit) + if commit_sha ~= commit then + p("Not a commit: " .. commit .. ". Did you mean version?") + die() + end + local archive = get_archive_info(dependency.repo, commit) + if dependency_name == "Luv" then + warn_luv_symbol() + end + update_cmakelists(dependency, archive, short_commit(commit)) +end + +function M.version(dependency_name, version) + local dependency = get_dependency(dependency_name) + verify_cmakelists_committed() + local commit_sha = get_gh_commit_sha(dependency.repo, version) + if commit_sha == version then + p("Not a version: " .. version .. ". Did you mean commit?") + die() + end + local archive = get_archive_info(dependency.repo, version) + if dependency_name == "Luv" then + write_cmakelists_line(dependency.symbol, "VERSION", version) + end + update_cmakelists(dependency, archive, version) +end + +function M.head(dependency_name) + local dependency = get_dependency(dependency_name) + verify_cmakelists_committed() + local commit_sha = get_gh_commit_sha(dependency.repo, "HEAD") + local archive = get_archive_info(dependency.repo, commit_sha) + if dependency_name == "Luv" then + warn_luv_symbol() + end + update_cmakelists(dependency, archive, "HEAD - " .. short_commit(commit_sha)) +end + +function M.create_branch(dep) + explicit_create_branch(dep) +end + +function M.submit_pr() + require_executable("git") + + verify_branch("deps") + + local nvim_remote = find_git_remote(nil) + local relevant_commit = run_die({ + "git", + "log", + "--grep=" .. commit_prefix, + "--reverse", + "--format='%s'", + nvim_remote .. "/master..HEAD", + "-1", + }, "Failed to fetch commits") + + local pr_title + local pr_body + + if relevant_commit == "" then + pr_title = commit_prefix .. "bump some dependencies" + pr_body = "bump some dependencies" + else + relevant_commit = relevant_commit:gsub("'", "") + pr_title = relevant_commit + pr_body = relevant_commit:gsub(commit_prefix:gsub("%(", "%%("):gsub("%)", "%%)"), "") + end + pr_body = pr_body .. "\n\n(add explanations if needed)" + p(pr_title .. "\n" .. pr_body .. "\n") + create_pr(pr_title, pr_body) +end + +return M diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index bf592a626d..4ec23244cd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -174,7 +174,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags) if (ml_open(curbuf) == FAIL) { // There MUST be a memfile, otherwise we can't do anything // If we can't create one for the current buffer, take another buffer - close_buffer(NULL, curbuf, 0, false); + close_buffer(NULL, curbuf, 0, false, false); curbuf = NULL; FOR_ALL_BUFFERS(buf) { @@ -402,8 +402,10 @@ bool buf_valid(buf_T *buf) /// there to be only one window with this buffer. e.g. when /// ":quit" is supposed to close the window but autocommands /// close all other windows. +/// @param ignore_abort +/// If true, don't abort even when aborting() returns true. /// @return true when we got to the end and b_nwindows was decremented. -bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) +bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool ignore_abort) { bool unload_buf = (action != 0); bool del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE); @@ -494,7 +496,8 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) return false; } } - if (aborting()) { // autocmds may abort script processing + // autocmds may abort script processing + if (!ignore_abort && aborting()) { return false; } } @@ -552,14 +555,16 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) buf->b_nwindows = nwindows; - buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0)); + buf_freeall(buf, ((del_buf ? BFA_DEL : 0) + + (wipe_buf ? BFA_WIPE : 0) + + (ignore_abort ? BFA_IGNORE_ABORT : 0))); if (!bufref_valid(&bufref)) { // Autocommands may have deleted the buffer. return false; } - if (aborting()) { - // Autocmds may abort script processing. + // autocmds may abort script processing. + if (!ignore_abort && aborting()) { return false; } @@ -660,9 +665,10 @@ void buf_clear(void) /// buf_freeall() - free all things allocated for a buffer that are related to /// the file. Careful: get here with "curwin" NULL when exiting. /// -/// @param flags BFA_DEL buffer is going to be deleted -/// BFA_WIPE buffer is going to be wiped out -/// BFA_KEEP_UNDO do not free undo information +/// @param flags BFA_DEL buffer is going to be deleted +/// BFA_WIPE buffer is going to be wiped out +/// BFA_KEEP_UNDO do not free undo information +/// BFA_IGNORE_ABORT don't abort even when aborting() returns true void buf_freeall(buf_T *buf, int flags) { bool is_curbuf = (buf == curbuf); @@ -706,7 +712,8 @@ void buf_freeall(buf_T *buf, int flags) goto_tabpage_win(the_curtab, the_curwin); unblock_autocmds(); } - if (aborting()) { // autocmds may abort script processing + // autocmds may abort script processing + if ((flags & BFA_IGNORE_ABORT) == 0 && aborting()) { return; } @@ -877,7 +884,7 @@ void handle_swap_exists(bufref_T *old_curbuf) // open a new, empty buffer. swap_exists_action = SEA_NONE; // don't want it again swap_exists_did_quit = true; - close_buffer(curwin, curbuf, DOBUF_UNLOAD, false); + close_buffer(curwin, curbuf, DOBUF_UNLOAD, false, false); if (old_curbuf == NULL || !bufref_valid(old_curbuf) || old_curbuf->br_buf == curbuf) { @@ -1074,7 +1081,7 @@ static int empty_curbuf(int close_others, int forceit, int action) // the old one. But do_ecmd() may have done that already, check // if the buffer still exists. if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0) { - close_buffer(NULL, buf, action, false); + close_buffer(NULL, buf, action, false, false); } if (!close_others) { @@ -1259,7 +1266,7 @@ int do_buffer(int action, int start, int dir, int count, int forceit) if (buf != curbuf) { close_windows(buf, false); if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows <= 0) { - close_buffer(NULL, buf, action, false); + close_buffer(NULL, buf, action, false, false); } return OK; } @@ -1485,7 +1492,7 @@ void set_curbuf(buf_T *buf, int action) ? action : (action == DOBUF_GOTO && !buf_hide(prevbuf) && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0, - false); + false, false); if (curwin != previouswin && win_valid(previouswin)) { // autocommands changed curwin, Grr! curwin = previouswin; @@ -2805,7 +2812,7 @@ int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, bool message) return FAIL; } // delete from the list - close_buffer(NULL, obuf, DOBUF_WIPE, false); + close_buffer(NULL, obuf, DOBUF_WIPE, false, false); } sfname = vim_strsave(sfname); #ifdef USE_FNAME_CASE @@ -5650,7 +5657,7 @@ void wipe_buffer(buf_T *buf, bool aucmd) // Don't trigger BufDelete autocommands here. block_autocmds(); } - close_buffer(NULL, buf, DOBUF_WIPE, false); + close_buffer(NULL, buf, DOBUF_WIPE, false, true); if (!aucmd) { unblock_autocmds(); } diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h index 850ab175a5..7f4bbcc9e5 100644 --- a/src/nvim/buffer.h +++ b/src/nvim/buffer.h @@ -58,9 +58,10 @@ enum dobuf_start_values { // flags for buf_freeall() enum bfa_values { - BFA_DEL = 1, // buffer is going to be deleted - BFA_WIPE = 2, // buffer is going to be wiped out - BFA_KEEP_UNDO = 4, // do not free undo information + BFA_DEL = 1, // buffer is going to be deleted + BFA_WIPE = 2, // buffer is going to be wiped out + BFA_KEEP_UNDO = 4, // do not free undo information + BFA_IGNORE_ABORT = 8, // do not abort for aborting() }; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/change.c b/src/nvim/change.c index 0644b1d601..44abd69733 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -286,9 +286,11 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra set_topline(wp, wp->w_topline); } - // Relative numbering may require updating more. + // If lines have been added or removed, relative numbering always + // requires a redraw. if (wp->w_p_rnu && xtra != 0) { - redraw_later(wp, SOME_VALID); + wp->w_last_cursor_lnum_rnu = 0; + redraw_later(wp, VALID); } // Cursor line highlighting probably need to be updated with diff --git a/src/nvim/diff.c b/src/nvim/diff.c index a6bbe40999..0b55fb877c 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -743,11 +743,16 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { for (char_u *s = ml_get_buf(buf, lnum, false); *s != NUL;) { if (diff_flags & DIFF_ICASE) { + int c; char_u cbuf[MB_MAXBYTES + 1]; - // xdiff doesn't support ignoring case, fold-case the text. - int c = utf_ptr2char(s); - c = utf_fold(c); + if (*s == NL) { + c = NUL; + } else { + // xdiff doesn't support ignoring case, fold-case the text. + c = utf_ptr2char(s); + c = utf_fold(c); + } const int orig_len = utfc_ptr2len(s); if (utf_char2bytes(c, cbuf) != orig_len) { // TODO(Bram): handle byte length difference @@ -759,7 +764,8 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din) s += orig_len; len += orig_len; } else { - ptr[len++] = *s++; + ptr[len++] = *s == NL ? NUL : *s; + s++; } } ptr[len++] = NL; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index da0b577056..3eb4ab9517 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -390,12 +390,9 @@ static void insert_enter(InsertState *s) trigger_modechanged(); stop_insert_mode = false; - // Need to recompute the cursor position, it might move when the cursor - // is on a TAB or special character. - // ptr2cells() treats a TAB character as double-width. - if (ptr2cells(get_cursor_pos_ptr()) > 1) { - curwin->w_valid &= ~VALID_VIRTCOL; - curs_columns(curwin, true); + // need to position cursor again when on a TAB + if (gchar_cursor() == TAB) { + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); } // Enable langmap or IME, indicated by 'iminsert'. @@ -1396,6 +1393,7 @@ static void insert_do_complete(InsertState *s) compl_cont_status = 0; } compl_busy = false; + can_si = true; // allow smartindenting } static void insert_do_cindent(InsertState *s) @@ -7330,21 +7328,21 @@ static void mb_replace_pop_ins(int cc) // Not a multi-byte char, put it back. replace_push(c); break; + } + + buf[0] = c; + assert(n > 1); + for (i = 1; i < n; i++) { + buf[i] = replace_pop(); + } + if (utf_iscomposing(utf_ptr2char(buf))) { + ins_bytes_len(buf, n); } else { - buf[0] = c; - assert(n > 1); - for (i = 1; i < n; i++) { - buf[i] = replace_pop(); - } - if (utf_iscomposing(utf_ptr2char(buf))) { - ins_bytes_len(buf, n); - } else { - // Not a composing char, put it back. - for (i = n - 1; i >= 0; i--) { - replace_push(buf[i]); - } - break; + // Not a composing char, put it back. + for (i = n - 1; i >= 0; i--) { + replace_push(buf[i]); } + break; } } } @@ -8054,8 +8052,10 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) State = NORMAL; trigger_modechanged(); - // need to position cursor again (e.g. when on a TAB ) - changed_cline_bef_curs(); + // need to position cursor again when on a TAB + if (gchar_cursor() == TAB) { + curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); + } setmouse(); ui_cursor_shape(); // may show different cursor shape diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 5d5b342c35..98aabe89b3 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2527,9 +2527,9 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new // Close the link to the current buffer. This will set // oldwin->w_buffer to NULL. u_sync(false); - const bool did_decrement = close_buffer(oldwin, curbuf, - (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD, - false); + const bool did_decrement + = close_buffer(oldwin, curbuf, (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD, + false, false); // Autocommands may have closed the window. if (win_valid(the_curwin)) { @@ -2875,7 +2875,7 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new redraw_curbuf_later(NOT_VALID); // redraw this buffer later } - if (p_im) { + if (p_im && (State & INSERT) == 0) { need_start_insertmode = true; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index bb6f3ba395..1f17101aca 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1248,6 +1248,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe const int save_msg_scroll = msg_scroll; cmdmod_T save_cmdmod; const int save_reg_executing = reg_executing; + const bool save_pending_end_reg_executing = pending_end_reg_executing; char_u *cmd; memset(&ea, 0, sizeof(ea)); @@ -2018,6 +2019,7 @@ doend: undo_cmdmod(&ea, save_msg_scroll); cmdmod = save_cmdmod; reg_executing = save_reg_executing; + pending_end_reg_executing = save_pending_end_reg_executing; if (ea.did_sandbox) { sandbox--; @@ -8529,6 +8531,7 @@ bool save_current_state(save_state_T *sst) sst->save_finish_op = finish_op; sst->save_opcount = opcount; sst->save_reg_executing = reg_executing; + sst->save_pending_end_reg_executing = pending_end_reg_executing; msg_scroll = false; // no msg scrolling in Normal mode restart_edit = 0; // don't go to Insert mode @@ -8559,6 +8562,7 @@ void restore_current_state(save_state_T *sst) finish_op = sst->save_finish_op; opcount = sst->save_opcount; reg_executing = sst->save_reg_executing; + pending_end_reg_executing = sst->save_pending_end_reg_executing; // don't reset msg_didout now msg_didout |= sst->save_msg_didout; diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h index be9f97e27d..874e0e599e 100644 --- a/src/nvim/ex_docmd.h +++ b/src/nvim/ex_docmd.h @@ -29,6 +29,7 @@ typedef struct { bool save_finish_op; long save_opcount; int save_reg_executing; + bool save_pending_end_reg_executing; tasave_T tabuf; } save_state_T; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 9104a2dd5a..dd6e4630d2 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -6544,7 +6544,7 @@ static int open_cmdwin(void) // win_close() may have already wiped the buffer when 'bh' is // set to 'wipe', autocommands may have closed other windows if (bufref_valid(&bufref) && bufref.br_buf != curbuf) { - close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false); + close_buffer(NULL, bufref.br_buf, DOBUF_WIPE, false, false); } // Restore window sizes. diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index d68dda15f3..d4407b4982 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1015,27 +1015,27 @@ retry: } read_buf_col += n; break; - } else { - // Append whole line and new-line. Change NL - // to NUL to reverse the effect done below. - for (ni = 0; ni < n; ni++) { - if (p[ni] == NL) { - ptr[tlen++] = NUL; - } else { - ptr[tlen++] = p[ni]; - } + } + + // Append whole line and new-line. Change NL + // to NUL to reverse the effect done below. + for (ni = 0; ni < n; ni++) { + if (p[ni] == NL) { + ptr[tlen++] = NUL; + } else { + ptr[tlen++] = p[ni]; } - ptr[tlen++] = NL; - read_buf_col = 0; - if (++read_buf_lnum > from) { - // When the last line didn't have an - // end-of-line don't add it now either. - if (!curbuf->b_p_eol) { - --tlen; - } - size = tlen; - break; + } + ptr[tlen++] = NL; + read_buf_col = 0; + if (++read_buf_lnum > from) { + // When the last line didn't have an + // end-of-line don't add it now either. + if (!curbuf->b_p_eol) { + tlen--; } + size = tlen; + break; } } } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index eddd5ccd14..299385cb17 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2060,7 +2060,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth) } /// unget one character (can only be done once!) -/// If the character was stuffed, vgetc() will get it next time it was called. +/// If the character was stuffed, vgetc() will get it next time it is called. /// Otherwise vgetc() will only get it when the stuff buffer is empty. void vungetc(int c) { @@ -2072,6 +2072,20 @@ void vungetc(int c) old_KeyStuffed = KeyStuffed; } +/// When peeking and not getting a character, reg_executing cannot be cleared +/// yet, so set a flag to clear it later. +void check_end_reg_executing(bool advance) +{ + if (reg_executing != 0 && (typebuf.tb_maplen == 0 || pending_end_reg_executing)) { + if (advance) { + reg_executing = 0; + pending_end_reg_executing = false; + } else { + pending_end_reg_executing = true; + } + } +} + /// Gets a byte: /// 1. from the stuffbuffer /// This is used for abbreviated commands like "D" -> "d$". @@ -2126,9 +2140,7 @@ static int vgetorpeek(bool advance) init_typebuf(); start_stuff(); - if (advance && typebuf.tb_maplen == 0) { - reg_executing = 0; - } + check_end_reg_executing(advance); do { // get a character: 1. from the stuffbuffer if (typeahead_char != 0) { @@ -2155,6 +2167,7 @@ static int vgetorpeek(bool advance) // If a mapped key sequence is found we go back to the start to // try re-mapping. for (;;) { + check_end_reg_executing(advance); // os_breakcheck() is slow, don't use it too often when // inside a mapping. But call it each time for typed // characters. diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ace7647b35..4aa49337cf 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -643,6 +643,8 @@ EXTERN bool ex_no_reprint INIT(=false); // No need to print after z or p. EXTERN int reg_recording INIT(= 0); // register for recording or zero EXTERN int reg_executing INIT(= 0); // register being executed or zero +// Flag set when peeking a character and found the end of executed register +EXTERN bool pending_end_reg_executing INIT(= false); EXTERN int reg_recorded INIT(= 0); // last recorded register or zero EXTERN int no_mapping INIT(= false); // currently no mapping allowed diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 418887a6b1..5f6e1ea273 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -2327,95 +2327,88 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, b * We are finished, break the loop here. */ break; - } else { // pointer block full - /* - * split the pointer block - * allocate a new pointer block - * move some of the pointer into the new block - * prepare for updating the parent block - */ - for (;;) { // do this twice when splitting block 1 - hp_new = ml_new_ptr(mfp); - if (hp_new == NULL) { // TODO: try to fix tree - return FAIL; - } - pp_new = hp_new->bh_data; - - if (hp->bh_bnum != 1) { - break; - } - - /* - * if block 1 becomes full the tree is given an extra level - * The pointers from block 1 are moved into the new block. - * block 1 is updated to point to the new block - * then continue to split the new block - */ - memmove(pp_new, pp, (size_t)page_size); - pp->pb_count = 1; - pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum; - pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count; - pp->pb_pointer[0].pe_old_lnum = 1; - pp->pb_pointer[0].pe_page_count = 1; - mf_put(mfp, hp, true, false); // release block 1 - hp = hp_new; // new block is to be split - pp = pp_new; - CHECK(stack_idx != 0, _("stack_idx should be 0")); - ip->ip_index = 0; - ++stack_idx; // do block 1 again later - } - /* - * move the pointers after the current one to the new block - * If there are none, the new entry will be in the new block. - */ - total_moved = pp->pb_count - pb_idx - 1; - if (total_moved) { - memmove(&pp_new->pb_pointer[0], - &pp->pb_pointer[pb_idx + 1], - (size_t)(total_moved) * sizeof(PTR_EN)); - pp_new->pb_count = total_moved; - pp->pb_count -= total_moved - 1; - pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right; - pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right; - pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right; - if (lnum_right) { - pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right; - } - } else { - pp_new->pb_count = 1; - pp_new->pb_pointer[0].pe_bnum = bnum_right; - pp_new->pb_pointer[0].pe_line_count = line_count_right; - pp_new->pb_pointer[0].pe_page_count = page_count_right; - pp_new->pb_pointer[0].pe_old_lnum = lnum_right; - } - pp->pb_pointer[pb_idx].pe_bnum = bnum_left; - pp->pb_pointer[pb_idx].pe_line_count = line_count_left; - pp->pb_pointer[pb_idx].pe_page_count = page_count_left; - if (lnum_left) { - pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left; + } + // pointer block full + // + // split the pointer block + // allocate a new pointer block + // move some of the pointer into the new block + // prepare for updating the parent block + for (;;) { // do this twice when splitting block 1 + hp_new = ml_new_ptr(mfp); + if (hp_new == NULL) { // TODO(vim): try to fix tree + return FAIL; } - lnum_left = 0; - lnum_right = 0; + pp_new = hp_new->bh_data; - /* - * recompute line counts - */ - line_count_right = 0; - for (i = 0; i < (int)pp_new->pb_count; ++i) { - line_count_right += pp_new->pb_pointer[i].pe_line_count; + if (hp->bh_bnum != 1) { + break; } - line_count_left = 0; - for (i = 0; i < (int)pp->pb_count; ++i) { - line_count_left += pp->pb_pointer[i].pe_line_count; + + // if block 1 becomes full the tree is given an extra level + // The pointers from block 1 are moved into the new block. + // block 1 is updated to point to the new block + // then continue to split the new block + memmove(pp_new, pp, (size_t)page_size); + pp->pb_count = 1; + pp->pb_pointer[0].pe_bnum = hp_new->bh_bnum; + pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count; + pp->pb_pointer[0].pe_old_lnum = 1; + pp->pb_pointer[0].pe_page_count = 1; + mf_put(mfp, hp, true, false); // release block 1 + hp = hp_new; // new block is to be split + pp = pp_new; + CHECK(stack_idx != 0, _("stack_idx should be 0")); + ip->ip_index = 0; + stack_idx++; // do block 1 again later + } + // move the pointers after the current one to the new block + // If there are none, the new entry will be in the new block. + total_moved = pp->pb_count - pb_idx - 1; + if (total_moved) { + memmove(&pp_new->pb_pointer[0], + &pp->pb_pointer[pb_idx + 1], + (size_t)(total_moved) * sizeof(PTR_EN)); + pp_new->pb_count = total_moved; + pp->pb_count -= total_moved - 1; + pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right; + pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right; + pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right; + if (lnum_right) { + pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right; } + } else { + pp_new->pb_count = 1; + pp_new->pb_pointer[0].pe_bnum = bnum_right; + pp_new->pb_pointer[0].pe_line_count = line_count_right; + pp_new->pb_pointer[0].pe_page_count = page_count_right; + pp_new->pb_pointer[0].pe_old_lnum = lnum_right; + } + pp->pb_pointer[pb_idx].pe_bnum = bnum_left; + pp->pb_pointer[pb_idx].pe_line_count = line_count_left; + pp->pb_pointer[pb_idx].pe_page_count = page_count_left; + if (lnum_left) { + pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left; + } + lnum_left = 0; + lnum_right = 0; - bnum_left = hp->bh_bnum; - bnum_right = hp_new->bh_bnum; - page_count_left = 1; - page_count_right = 1; - mf_put(mfp, hp, true, false); - mf_put(mfp, hp_new, true, false); + // recompute line counts + line_count_right = 0; + for (i = 0; i < (int)pp_new->pb_count; i++) { + line_count_right += pp_new->pb_pointer[i].pe_line_count; } + line_count_left = 0; + for (i = 0; i < (int)pp->pb_count; i++) { + line_count_left += pp->pb_pointer[i].pe_line_count; + } + + bnum_left = hp->bh_bnum; + bnum_right = hp_new->bh_bnum; + page_count_left = 1; + page_count_right = 1; + mf_put(mfp, hp, true, false); + mf_put(mfp, hp_new, true, false); } /* diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 6cdc4f1fde..c895cc1ec6 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -691,7 +691,7 @@ void free_all_mem(void) bufref_T bufref; set_bufref(&bufref, buf); nextbuf = buf->b_next; - close_buffer(NULL, buf, DOBUF_WIPE, false); + close_buffer(NULL, buf, DOBUF_WIPE, false, false); // Didn't work, try next one. buf = bufref_valid(&bufref) ? nextbuf : firstbuf; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 9fd0e0b222..551bc1fbdf 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -5140,43 +5140,43 @@ char *set_option_value(const char *const name, const long number, const char *co s = ""; } return set_string_option(opt_idx, s, opt_flags); - } else { - varp = get_varp_scope(&(options[opt_idx]), opt_flags); - if (varp != NULL) { // hidden option is not changed - if (number == 0 && string != NULL) { - int idx; - - // Either we are given a string or we are setting option - // to zero. - for (idx = 0; string[idx] == '0'; idx++) {} - if (string[idx] != NUL || idx == 0) { - // There's another character after zeros or the string - // is empty. In both cases, we are trying to set a - // num option using a string. - semsg(_("E521: Number required: &%s = '%s'"), - name, string); - return NULL; // do nothing as we hit an error - } - } - long numval = number; - if (opt_flags & OPT_CLEAR) { - if ((int *)varp == &curbuf->b_p_ar) { - numval = -1; - } else if ((long *)varp == &curbuf->b_p_ul) { - numval = NO_LOCAL_UNDOLEVEL; - } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { - numval = -1; - } else { - char *s = NULL; - (void)get_option_value(name, &numval, (char_u **)&s, OPT_GLOBAL); - } + } + + varp = get_varp_scope(&(options[opt_idx]), opt_flags); + if (varp != NULL) { // hidden option is not changed + if (number == 0 && string != NULL) { + int idx; + + // Either we are given a string or we are setting option + // to zero. + for (idx = 0; string[idx] == '0'; idx++) {} + if (string[idx] != NUL || idx == 0) { + // There's another character after zeros or the string + // is empty. In both cases, we are trying to set a + // num option using a string. + semsg(_("E521: Number required: &%s = '%s'"), + name, string); + return NULL; // do nothing as we hit an error } - if (flags & P_NUM) { - return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + } + long numval = number; + if (opt_flags & OPT_CLEAR) { + if ((int *)varp == &curbuf->b_p_ar) { + numval = -1; + } else if ((long *)varp == &curbuf->b_p_ul) { + numval = NO_LOCAL_UNDOLEVEL; + } else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) { + numval = -1; } else { - return set_bool_option(opt_idx, varp, (int)numval, opt_flags); + char *s = NULL; + (void)get_option_value(name, &numval, (char_u **)&s, OPT_GLOBAL); } } + if (flags & P_NUM) { + return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags); + } else { + return set_bool_option(opt_idx, varp, (int)numval, opt_flags); + } } } return NULL; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1d589e8ca0..4ad5e40fee 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1721,7 +1721,7 @@ static void wipe_qf_buffer(qf_info_T *qi) if (qfbuf != NULL && qfbuf->b_nwindows == 0) { // If the quickfix buffer is not loaded in any window, then // wipe the buffer. - close_buffer(NULL, qfbuf, DOBUF_WIPE, false); + close_buffer(NULL, qfbuf, DOBUF_WIPE, false, false); qi->qf_bufnr = INVALID_QFBUFNR; } } @@ -5843,7 +5843,7 @@ static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start) static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) { if (curbuf != buf) { // safety check - close_buffer(NULL, buf, DOBUF_UNLOAD, false); + close_buffer(NULL, buf, DOBUF_UNLOAD, false, true); // When autocommands/'autochdir' option changed directory: go back. restore_start_dir(dirname_start); diff --git a/src/nvim/state.c b/src/nvim/state.c index 3a7636085b..34e3ddf654 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -40,7 +40,7 @@ void state_enter(VimState *s) int key; getkey: - // Expand mappings first by calling vpeekc() directly. + // Apply mappings first by calling vpeekc() directly. // - If vpeekc() returns non-NUL, there is a character already available for processing, so // don't block for events. vgetc() may still block, in case of an incomplete UTF-8 sequence. // - If vpeekc() returns NUL, vgetc() will block, and there are three cases: @@ -76,6 +76,9 @@ getkey: } if (key == K_EVENT) { + // An event handler may use the value of reg_executing. + // Clear it if it should be cleared when getting the next character. + check_end_reg_executing(true); may_sync_undo(); } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index a82e8fa103..d884ad704b 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -2289,55 +2289,52 @@ static void check_state_ends(void) next_match_idx = 0; next_match_col = MAXCOL; break; - } else { - // handle next_list, unless at end of line and no "skipnl" or - // "skipempty" - current_next_list = cur_si->si_next_list; - current_next_flags = cur_si->si_flags; - if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)) - && syn_getcurline()[current_col] == NUL) { - current_next_list = NULL; - } + } + + // handle next_list, unless at end of line and no "skipnl" or + // "skipempty" + current_next_list = cur_si->si_next_list; + current_next_flags = cur_si->si_flags; + if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)) + && syn_getcurline()[current_col] == NUL) { + current_next_list = NULL; + } + + // When the ended item has "extend", another item with + // "keepend" now needs to check for its end. + had_extend = (cur_si->si_flags & HL_EXTEND); - // When the ended item has "extend", another item with - // "keepend" now needs to check for its end. - had_extend = (cur_si->si_flags & HL_EXTEND); + pop_current_state(); - pop_current_state(); + if (GA_EMPTY(¤t_state)) { + break; + } + if (had_extend && keepend_level >= 0) { + syn_update_ends(false); if (GA_EMPTY(¤t_state)) { break; } + } - if (had_extend && keepend_level >= 0) { - syn_update_ends(false); - if (GA_EMPTY(¤t_state)) { - break; - } - } - - cur_si = &CUR_STATE(current_state.ga_len - 1); + cur_si = &CUR_STATE(current_state.ga_len - 1); - /* - * Only for a region the search for the end continues after - * the end of the contained item. If the contained match - * included the end-of-line, break here, the region continues. - * Don't do this when: - * - "keepend" is used for the contained item - * - not at the end of the line (could be end="x$"me=e-1). - * - "excludenl" is used (HL_HAS_EOL won't be set) - */ - if (cur_si->si_idx >= 0 - && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type - == SPTYPE_START - && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) { - update_si_end(cur_si, (int)current_col, true); - check_keepend(); - if ((current_next_flags & HL_HAS_EOL) - && keepend_level < 0 - && syn_getcurline()[current_col] == NUL) { - break; - } + // Only for a region the search for the end continues after + // the end of the contained item. If the contained match + // included the end-of-line, break here, the region continues. + // Don't do this when: + // - "keepend" is used for the contained item + // - not at the end of the line (could be end="x$"me=e-1). + // - "excludenl" is used (HL_HAS_EOL won't be set) + if (cur_si->si_idx >= 0 + && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type == SPTYPE_START + && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) { + update_si_end(cur_si, (int)current_col, true); + check_keepend(); + if ((current_next_flags & HL_HAS_EOL) + && keepend_level < 0 + && syn_getcurline()[current_col] == NUL) { + break; } } } else { diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 76c69ad10b..c1a120efa4 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -299,6 +299,40 @@ func Test_WinClosed() unlet g:triggered endfunc +func Test_WinClosed_throws() + vnew + let bnr = bufnr() + call assert_equal(1, bufloaded(bnr)) + augroup test-WinClosed + autocmd WinClosed * throw 'foo' + augroup END + try + close + catch /.*/ + endtry + call assert_equal(0, bufloaded(bnr)) + + autocmd! test-WinClosed + augroup! test-WinClosed +endfunc + +func Test_WinClosed_throws_with_tabs() + tabnew + let bnr = bufnr() + call assert_equal(1, bufloaded(bnr)) + augroup test-WinClosed + autocmd WinClosed * throw 'foo' + augroup END + try + close + catch /.*/ + endtry + call assert_equal(0, bufloaded(bnr)) + + autocmd! test-WinClosed + augroup! test-WinClosed +endfunc + func s:AddAnAutocmd() augroup vimBarTest au BufReadCmd * echo 'hello' diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 10eb979b45..be9a77ee75 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -1295,4 +1295,41 @@ func Test_diff_filler_cursorcolumn() endfunc +func Test_diff_binary() + CheckScreendump + + let content =<< trim END + call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g']) + vnew + call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g']) + windo diffthis + wincmd p + norm! gg0 + redraw! + END + call writefile(content, 'Xtest_diff_bin') + let buf = RunVimInTerminal('-S Xtest_diff_bin', {}) + + " Test using internal diff + call VerifyScreenDump(buf, 'Test_diff_bin_01', {}) + + " Test using internal diff and case folding + call term_sendkeys(buf, ":set diffopt+=icase\<cr>") + call term_sendkeys(buf, "\<C-l>") + call VerifyScreenDump(buf, 'Test_diff_bin_02', {}) + " Test using external diff + call term_sendkeys(buf, ":set diffopt=filler\<cr>") + call term_sendkeys(buf, "\<C-l>") + call VerifyScreenDump(buf, 'Test_diff_bin_03', {}) + " Test using external diff and case folding + call term_sendkeys(buf, ":set diffopt=filler,icase\<cr>") + call term_sendkeys(buf, "\<C-l>") + call VerifyScreenDump(buf, 'Test_diff_bin_04', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('Xtest_diff_bin') + set diffopt&vim +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index 360b3aaaa0..eea5d190b2 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -1627,6 +1627,29 @@ func Test_edit_is_a_directory() call delete(dirname, 'rf') endfunc +" Using :edit without leaving 'insertmode' should not cause Insert mode to be +" re-entered immediately after <C-L> +func Test_edit_insertmode_ex_edit() + CheckRunVimInTerminal + + let lines =<< trim END + set insertmode noruler + inoremap <C-B> <Cmd>edit Xfoo<CR> + END + call writefile(lines, 'Xtest_edit_insertmode_ex_edit') + + let buf = RunVimInTerminal('-S Xtest_edit_insertmode_ex_edit', #{rows: 6}) + call TermWait(buf, 50) + call assert_match('^-- INSERT --\s*$', term_getline(buf, 6)) + call term_sendkeys(buf, "\<C-B>\<C-L>") + call TermWait(buf, 50) + call assert_notmatch('^-- INSERT --\s*$', term_getline(buf, 6)) + + " clean up + call StopVimInTerminal(buf) + call delete('Xtest_edit_insertmode_ex_edit') +endfunc + func Test_edit_browse() " in the GUI this opens a file picker, we only test the terminal behavior CheckNotGui diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index a31ff50a48..42271a014d 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -395,7 +395,7 @@ let s:filename_checks = { \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'], \ 'pf': ['pf.conf'], \ 'pfmain': ['main.cf'], - \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'], + \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'], \ 'lpc': ['file.lpc', 'file.ulpc'], \ 'pike': ['file.pike', 'file.pmod'], \ 'cmod': ['file.cmod'], diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index 5588e515e1..efdf44a0d6 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -615,6 +615,14 @@ func Test_cursorcolumn_insert_on_tab() call TermWait(buf) call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {}) + call term_sendkeys(buf, "\<C-O>") + call TermWait(buf) + call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_3', {}) + + call term_sendkeys(buf, 'i') + call TermWait(buf) + call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {}) + call StopVimInTerminal(buf) call delete('Xcuc_insert_on_tab') endfunc diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 186fa8871f..24eaf9e8b1 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -707,4 +707,23 @@ func Test_z1_complete_no_history() close! endfunc +func FooBarComplete(findstart, base) + if a:findstart + return col('.') - 1 + else + return ["Foo", "Bar", "}"] + endif +endfunc + +func Test_complete_smartindent() + new + setlocal smartindent completefunc=FooBarComplete + + exe "norm! o{\<cr>\<c-x>\<c-u>\<c-p>}\<cr>\<esc>" + let result = getline(1,'$') + call assert_equal(['', '{','}',''], result) + bw! + delfunction! FooBarComplete +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim index f78b748d71..c623edd5a1 100644 --- a/src/nvim/testdir/test_registers.vim +++ b/src/nvim/testdir/test_registers.vim @@ -690,5 +690,23 @@ func Test_record_in_select_mode() bwipe! endfunc +func Test_end_reg_executing() + nnoremap s <Nop> + let @a = 's' + call feedkeys("@aqaq\<Esc>", 'tx') + call assert_equal('', @a) + call assert_equal('', getline(1)) + + call setline(1, 'aaa') + nnoremap s qa + let @a = 'fa' + call feedkeys("@asq\<Esc>", 'tx') + call assert_equal('', @a) + call assert_equal('aaa', getline(1)) + + nunmap s + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim index 7e513180a3..adc1745b39 100644 --- a/src/nvim/testdir/test_trycatch.vim +++ b/src/nvim/testdir/test_trycatch.vim @@ -1972,6 +1972,29 @@ func Test_builtin_func_error() call assert_equal('jlmnpqrtueghivyzACD', g:Xpath) endfunc -" Modelines {{{1 +func Test_reload_in_try_catch() + call writefile(['x'], 'Xreload') + set autoread + edit Xreload + tabnew + call writefile(['xx'], 'Xreload') + augroup ReLoad + au FileReadPost Xreload let x = doesnotexist + au BufReadPost Xreload let x = doesnotexist + augroup END + try + edit Xreload + catch + endtry + tabnew + + tabclose + tabclose + autocmd! ReLoad + set noautoread + bwipe! Xreload + call delete('Xreload') +endfunc + +" Modeline {{{1 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker -"------------------------------------------------------------------------------- diff --git a/src/nvim/window.c b/src/nvim/window.c index cc21bf25b0..9aa2f947cb 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2541,6 +2541,41 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev return true; } +/// Close the buffer of "win" and unload it if "free_buf" is true. +/// "abort_if_last" is passed to close_buffer(): abort closing if all other +/// windows are closed. +static void win_close_buffer(win_T *win, bool free_buf, bool abort_if_last) +{ + // Free independent synblock before the buffer is freed. + if (win->w_buffer != NULL) { + reset_synblock(win); + } + + // When a quickfix/location list window is closed and the buffer is + // displayed in only one window, then unlist the buffer. + if (win->w_buffer != NULL && bt_quickfix(win->w_buffer) + && win->w_buffer->b_nwindows == 1) { + win->w_buffer->b_p_bl = false; + } + + // Close the link to the buffer. + if (win->w_buffer != NULL) { + bufref_T bufref; + set_bufref(&bufref, curbuf); + win->w_closing = true; + close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, abort_if_last, true); + if (win_valid_any_tab(win)) { + win->w_closing = false; + } + + // Make sure curbuf is valid. It can become invalid if 'bufhidden' is + // "wipe". + if (!bufref_valid(&bufref)) { + curbuf = firstbuf; + } + } +} + // Close window "win". Only works for the current tab page. // If "free_buf" is true related buffer may be unloaded. // @@ -2679,36 +2714,7 @@ int win_close(win_T *win, bool free_buf, bool force) return OK; } - // Free independent synblock before the buffer is freed. - if (win->w_buffer != NULL) { - reset_synblock(win); - } - - // When a quickfix/location list window is closed and the buffer is - // displayed in only one window, then unlist the buffer. - if (win->w_buffer != NULL && bt_quickfix(win->w_buffer) - && win->w_buffer->b_nwindows == 1) { - win->w_buffer->b_p_bl = false; - } - - /* - * Close the link to the buffer. - */ - if (win->w_buffer != NULL) { - bufref_T bufref; - set_bufref(&bufref, curbuf); - win->w_closing = true; - close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, true); - if (win_valid_any_tab(win)) { - win->w_closing = false; - } - - // Make sure curbuf is valid. It can become invalid if 'bufhidden' is - // "wipe". - if (!bufref_valid(&bufref)) { - curbuf = firstbuf; - } - } + win_close_buffer(win, free_buf, true); if (only_one_window() && win_valid(win) && win->w_buffer == NULL && (last_window(win) || curtab != prev_curtab @@ -2879,7 +2885,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) if (win->w_buffer != NULL) { // Close the link to the buffer. - close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false); + close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, false, true); } // Careful: Autocommands may have closed the tab page or made it the diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua index c0c9256af2..d4cf6b28fd 100644 --- a/test/functional/editor/macro_spec.lua +++ b/test/functional/editor/macro_spec.lua @@ -6,11 +6,14 @@ local feed = helpers.feed local clear = helpers.clear local expect = helpers.expect local command = helpers.command +local funcs = helpers.funcs +local meths = helpers.meths local insert = helpers.insert local curbufmeths = helpers.curbufmeths +before_each(clear) + describe('macros', function() - before_each(clear) it('can be recorded and replayed', function() feed('qiahello<esc>q') expect('hello') @@ -47,9 +50,47 @@ hello]] end) end) -describe('reg_recorded()', function() - before_each(clear) +describe('immediately after a macro has finished executing,', function() + before_each(function() + command([[let @a = 'gg0']]) + end) + + describe('reg_executing() from RPC returns an empty string', function() + it('if the macro does not end with a <Nop> mapping', function() + feed('@a') + eq('', funcs.reg_executing()) + end) + + it('if the macro ends with a <Nop> mapping', function() + command('nnoremap 0 <Nop>') + feed('@a') + eq('', funcs.reg_executing()) + end) + end) + describe('characters from a mapping are not treated as a part of the macro #18015', function() + before_each(function() + command('nnoremap s qa') + end) + + it('if the macro does not end with a <Nop> mapping', function() + feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op + eq({mode = 'n', blocking = false}, meths.get_mode()) + expect('') + eq('', eval('@a')) + end) + + it('if the macro ends with a <Nop> mapping', function() + command('nnoremap 0 <Nop>') + feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op + eq({mode = 'n', blocking = false}, meths.get_mode()) + expect('') + eq('', eval('@a')) + end) + end) +end) + +describe('reg_recorded()', function() it('returns the correct value', function() feed [[qqyyq]] eq('q', eval('reg_recorded()')) diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index 528e228121..c38acbe96a 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -6,6 +6,8 @@ local expect = helpers.expect local command = helpers.command local eq = helpers.eq local eval = helpers.eval +local meths = helpers.meths +local poke_eventloop = helpers.poke_eventloop describe('insert-mode', function() before_each(function() @@ -128,4 +130,26 @@ describe('insert-mode', function() expect('<M-1><D-2><M-7><D-8>') end) end) + + describe([[With 'insertmode', Insert mode is not re-entered immediately after <C-L>]], function() + before_each(function() + command('set insertmode') + poke_eventloop() + eq({mode = 'i', blocking = false}, meths.get_mode()) + end) + + it('after calling :edit from <Cmd> mapping', function() + command('inoremap <C-B> <Cmd>edit Xfoo<CR>') + feed('<C-B><C-L>') + poke_eventloop() + eq({mode = 'n', blocking = false}, meths.get_mode()) + end) + + it('after calling :edit from RPC #16823', function() + command('edit Xfoo') + feed('<C-L>') + poke_eventloop() + eq({mode = 'n', blocking = false}, meths.get_mode()) + end) + end) end) diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 3a25d7e813..6f67dea2be 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -1226,3 +1226,130 @@ it('Align the filler lines when changing text in diff mode', function() | ]]} end) + +it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function() + clear() + local screen = Screen.new(40, 20) + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray}; + [2] = {reverse = true}; + [3] = {background = Screen.colors.LightBlue}; + [4] = {background = Screen.colors.LightMagenta}; + [5] = {background = Screen.colors.Red, bold = true}; + [6] = {foreground = Screen.colors.Blue, bold = true}; + [7] = {background = Screen.colors.Red, foreground = Screen.colors.Blue, bold = true}; + [8] = {reverse = true, bold = true}; + }) + screen:attach() + exec([[ + call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g']) + vnew + call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g']) + windo diffthis + wincmd p + norm! gg0 + redraw! + ]]) + + -- Test using internal diff + screen:expect([[ + {1: }{5:^A}{4: }{2:│}{1: }{5:a}{4: }| + {1: }b {2:│}{1: }b | + {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }| + {1: }d {2:│}{1: }d | + {1: }{5:E}{4: }{2:│}{1: }{5:e}{4: }| + {1: }f {2:│}{1: }f | + {1: }g {2:│}{1: }g | + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {8:[No Name] [+] }{2:[No Name] [+] }| + | + ]]) + + -- Test using internal diff and case folding + command('set diffopt+=icase') + feed('<C-L>') + screen:expect([[ + {1: }^A {2:│}{1: }a | + {1: }b {2:│}{1: }b | + {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }| + {1: }d {2:│}{1: }d | + {1: }E {2:│}{1: }e | + {1: }f {2:│}{1: }f | + {1: }g {2:│}{1: }g | + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {8:[No Name] [+] }{2:[No Name] [+] }| + | + ]]) + + -- Test using external diff + command('set diffopt=filler') + feed('<C-L>') + screen:expect([[ + {1: }{5:^A}{4: }{2:│}{1: }{5:a}{4: }| + {1: }b {2:│}{1: }b | + {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }| + {1: }d {2:│}{1: }d | + {1: }{5:E}{4: }{2:│}{1: }{5:e}{4: }| + {1: }f {2:│}{1: }f | + {1: }g {2:│}{1: }g | + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {8:[No Name] [+] }{2:[No Name] [+] }| + | + ]]) + + -- Test using external diff and case folding + command('set diffopt+=filler,icase') + feed('<C-L>') + screen:expect([[ + {1: }^A {2:│}{1: }a | + {1: }b {2:│}{1: }b | + {1: }{4:c }{2:│}{1: }{4:c}{7:^@}{4: }| + {1: }d {2:│}{1: }d | + {1: }E {2:│}{1: }e | + {1: }f {2:│}{1: }f | + {1: }g {2:│}{1: }g | + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {6:~ }{2:│}{6:~ }| + {8:[No Name] [+] }{2:[No Name] [+] }| + | + ]]) +end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4b63b09a5b..8afc69a649 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1345,6 +1345,28 @@ describe('CursorColumn highlight', function() {2:~ }| {3:-- INSERT --} | ]]) + feed('<C-O>') + screen:expect([[ + 1234567{1:8}9 | + a ^ b | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {3:-- (insert) --} | + ]]) + feed('i') + screen:expect([[ + 1{1:2}3456789 | + a^ b | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {3:-- INSERT --} | + ]]) end) it('is updated if cursor is moved from timer', function() diff --git a/test/unit/buffer_spec.lua b/test/unit/buffer_spec.lua index 34c88248e6..833b21b00b 100644 --- a/test/unit/buffer_spec.lua +++ b/test/unit/buffer_spec.lua @@ -17,8 +17,8 @@ describe('buffer functions', function() return buffer.buflist_new(c_file, c_file, 1, flags) end - local close_buffer = function(win, buf, action, abort_if_last) - return buffer.close_buffer(win, buf, action, abort_if_last) + local close_buffer = function(win, buf, action, abort_if_last, ignore_abort) + return buffer.close_buffer(win, buf, action, abort_if_last, ignore_abort) end local path1 = 'test_file_path' @@ -53,7 +53,7 @@ describe('buffer functions', function() itp('should view a closed and hidden buffer as valid', function() local buf = buflist_new(path1, buffer.BLN_LISTED) - close_buffer(NULL, buf, 0, 0) + close_buffer(NULL, buf, 0, 0, 0) eq(true, buffer.buf_valid(buf)) end) @@ -61,7 +61,7 @@ describe('buffer functions', function() itp('should view a closed and unloaded buffer as valid', function() local buf = buflist_new(path1, buffer.BLN_LISTED) - close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0) + close_buffer(NULL, buf, buffer.DOBUF_UNLOAD, 0, 0) eq(true, buffer.buf_valid(buf)) end) @@ -69,7 +69,7 @@ describe('buffer functions', function() itp('should view a closed and wiped buffer as invalid', function() local buf = buflist_new(path1, buffer.BLN_LISTED) - close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0) eq(false, buffer.buf_valid(buf)) end) @@ -90,7 +90,7 @@ describe('buffer functions', function() eq(buf.handle, buflist_findpat(path1, ONLY_LISTED)) - close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0, 0) end) itp('should prefer to match the start of a file path', function() @@ -102,9 +102,9 @@ describe('buffer functions', function() eq(buf2.handle, buflist_findpat("file", ONLY_LISTED)) eq(buf3.handle, buflist_findpat("path", ONLY_LISTED)) - close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0) end) itp('should prefer to match the end of a file over the middle', function() @@ -118,7 +118,7 @@ describe('buffer functions', function() --} --{ When: We close buf2 - close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0) -- And: Open buf1, which has 'file' in the middle of its name local buf1 = buflist_new(path1, buffer.BLN_LISTED) @@ -127,8 +127,8 @@ describe('buffer functions', function() eq(buf3.handle, buflist_findpat("file", ONLY_LISTED)) --} - close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0) end) itp('should match a unique fragment of a file path', function() @@ -138,9 +138,9 @@ describe('buffer functions', function() eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED)) - close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0) end) itp('should include / ignore unlisted buffers based on the flag.', function() @@ -152,7 +152,7 @@ describe('buffer functions', function() --} --{ When: We unlist the buffer - close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0) + close_buffer(NULL, buf3, buffer.DOBUF_DEL, 0, 0) -- Then: It should not find the buffer when searching only listed buffers eq(-1, buflist_findpat("_test_", ONLY_LISTED)) @@ -162,7 +162,7 @@ describe('buffer functions', function() --} --{ When: We wipe the buffer - close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf3, buffer.DOBUF_WIPE, 0, 0) -- Then: It should not find the buffer at all eq(-1, buflist_findpat("_test_", ONLY_LISTED)) @@ -180,7 +180,7 @@ describe('buffer functions', function() --} --{ When: The first buffer is unlisted - close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0) + close_buffer(NULL, buf1, buffer.DOBUF_DEL, 0, 0) -- Then: The second buffer is preferred because -- unlisted buffers are not allowed @@ -194,7 +194,7 @@ describe('buffer functions', function() --} --{ When: We unlist the second buffer - close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0) + close_buffer(NULL, buf2, buffer.DOBUF_DEL, 0, 0) -- Then: The first buffer is preferred again -- because buf1 matches better which takes precedence @@ -205,8 +205,8 @@ describe('buffer functions', function() eq(-1, buflist_findpat("test", ONLY_LISTED)) --} - close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0) - close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0) + close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0, 0) + close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0, 0) end) end) |