aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/health/nvim.vim2
-rw-r--r--runtime/autoload/health/provider.vim23
-rw-r--r--runtime/autoload/man.vim4
-rw-r--r--runtime/autoload/provider/node.vim2
-rw-r--r--runtime/doc/api.txt44
-rw-r--r--runtime/doc/channel.txt4
-rw-r--r--runtime/doc/develop.txt6
-rw-r--r--runtime/doc/vim_diff.txt1
-rw-r--r--runtime/plugin/health.vim9
-rw-r--r--scripts/gen_api_vimdoc.py2
-rwxr-xr-xscripts/vim-patch.sh110
-rwxr-xr-xscripts/vimpatch.lua67
-rw-r--r--src/nvim/api/vim.c2
-rw-r--r--src/nvim/ex_cmds.c6
-rw-r--r--src/nvim/ex_docmd.c1
-rw-r--r--src/nvim/quickfix.c76
-rw-r--r--src/nvim/testdir/test_cmdline.vim32
-rw-r--r--src/nvim/version.c455
-rw-r--r--src/nvim/window.c26
-rw-r--r--test/functional/autocmd/tabclose_spec.lua87
-rw-r--r--test/functional/autocmd/termclose_spec.lua9
-rw-r--r--third-party/CMakeLists.txt20
22 files changed, 664 insertions, 324 deletions
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
index 58033f0405..017c047ef4 100644
--- a/runtime/autoload/health/nvim.vim
+++ b/runtime/autoload/health/nvim.vim
@@ -174,7 +174,7 @@ function! s:check_terminal() abort
\ .(empty(kbs_entry) ? '? (not found)' : kdch1_entry))
endif
for env_var in ['XTERM_VERSION', 'VTE_VERSION', 'TERM_PROGRAM', 'COLORTERM', 'SSH_TTY']
- if !exists('$'.env_var)
+ if exists('$'.env_var)
call health#report_info(printf("$%s='%s'", env_var, eval('$'.env_var)))
endif
endfor
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 39e592c471..d1239db605 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -370,27 +370,16 @@ function! s:check_python(version) abort
let python_bin = ''
endif
- " Check if $VIRTUAL_ENV is active
- let virtualenv_inactive = 0
-
+ " Check if $VIRTUAL_ENV is valid.
if exists('$VIRTUAL_ENV')
- if !empty(pyenv)
- let pyenv_prefix = resolve(s:trim(s:system([pyenv, 'prefix'])))
- if $VIRTUAL_ENV != pyenv_prefix
- let virtualenv_inactive = 1
- endif
- elseif !empty(pyname) && exepath(pyname) !~# '^'.$VIRTUAL_ENV.'/'
- let virtualenv_inactive = 1
+ if !empty(pyname) && $VIRTUAL_ENV !=# matchstr(exepath(pyname), '^\V'.$VIRTUAL_ENV)
+ call health#report_warn(
+ \ '$VIRTUAL_ENV exists but appears to be inactive. '
+ \ . 'This could lead to unexpected results.',
+ \ [ 'If you are using Zsh, see: http://vi.stackexchange.com/a/7654' ])
endif
endif
- if virtualenv_inactive
- call health#report_warn(
- \ '$VIRTUAL_ENV exists but appears to be inactive. '
- \ . 'This could lead to unexpected results.',
- \ [ 'If you are using Zsh, see: http://vi.stackexchange.com/a/7654/5229' ])
- endif
-
" Diagnostic output
call health#report_info('Executable: ' . (empty(python_bin) ? 'Not found' : python_bin))
if len(python_multiple)
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index dd71ede680..af5c4dbd60 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -65,9 +65,9 @@ function! man#open_page(count, count1, mods, ...) abort
try
set eventignore+=BufReadCmd
if a:mods !~# 'tab' && s:find_man()
- execute 'silent edit' fnameescape(bufname)
+ execute 'silent keepalt edit' fnameescape(bufname)
else
- execute 'silent' a:mods 'split' fnameescape(bufname)
+ execute 'silent keepalt' a:mods 'split' fnameescape(bufname)
endif
finally
set eventignore-=BufReadCmd
diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim
index adcc926074..3dde18022e 100644
--- a/runtime/autoload/provider/node.vim
+++ b/runtime/autoload/provider/node.vim
@@ -114,7 +114,7 @@ let s:err = ''
let s:prog = provider#node#Detect()
if empty(s:prog)
- let s:err = 'Cannot find the "neovim" node package. Try :CheckHealth'
+ let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'
endif
call remote#host#RegisterPlugin('node-provider', 'node', [])
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 6c2a3a8632..fd6918de43 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -512,27 +512,27 @@ nvim_parse_expression({expr}, {flags}, {highlight})
[start_col, end_col)).
Return:~
- AST: top-level dictionary holds keys "error": Dictionary
- with error, present only if parser saw some error.
- Contains the following keys: "message": String, error
- message in printf format, translated. Must contain exactly
- one "%.*s". "arg": String, error message argument. "len":
- Amount of bytes successfully parsed. With flags equal to
- "" that should be equal to the length of expr string.
- @note: “Sucessfully parsed” here means “participated in
- AST creation”, not “till the first error”. "ast": AST,
- either nil or a dictionary with these keys: "type": node
- type, one of the value names from ExprASTNodeType
- stringified without "kExprNode" prefix. "start": a pair
- [line, column] describing where node is “started” where
- "line" is always 0 (will not be 0 if you will be using
- nvim_parse_viml() on e.g. ":let", but that is not present
- yet). Both elements are Integers. "len": “length” of the
- node. This and "start" are there for debugging purposes
- primary (debugging parser and providing debug
- information). "children": a list of nodes described in
- top/"ast". There always is zero, one or two children, key
- will not be present if node has no children. Maximum
+ AST: top-level dictionary with these keys: "error":
+ Dictionary with error, present only if parser saw some
+ error. Contains the following keys: "message": String,
+ error message in printf format, translated. Must contain
+ exactly one "%.*s". "arg": String, error message argument.
+ "len": Amount of bytes successfully parsed. With flags
+ equal to "" that should be equal to the length of expr
+ string. @note: “Sucessfully parsed” here means
+ “participated in AST creation”, not “till the first
+ error”. "ast": AST, either nil or a dictionary with these
+ keys: "type": node type, one of the value names from
+ ExprASTNodeType stringified without "kExprNode" prefix.
+ "start": a pair [line, column] describing where node is
+ “started” where "line" is always 0 (will not be 0 if you
+ will be using nvim_parse_viml() on e.g. ":let", but that
+ is not present yet). Both elements are Integers. "len":
+ “length” of the node. This and "start" are there for
+ debugging purposes primary (debugging parser and providing
+ debug information). "children": a list of nodes described
+ in top/"ast". There always is zero, one or two children,
+ key will not be present if node has no children. Maximum
number of children may be found in node_maxchildren array.
Local values (present only for certain nodes): "scope": a
single Integer, specifies scope for "Option" and
@@ -1047,4 +1047,4 @@ nvim_ui_try_resize({width}, {height}) *nvim_ui_try_resize()*
nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
TODO: Documentation
- vim:tw=78:ts=8:ft=help:norl: \ No newline at end of file
+ vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt
index c4f7eb1ff1..eb2bac6fce 100644
--- a/runtime/doc/channel.txt
+++ b/runtime/doc/channel.txt
@@ -4,9 +4,9 @@
NVIM REFERENCE MANUAL by Thiago de Arruda
-Nvim's facilities for async io *channel*
+Nvim asynchronous IO *channel*
- Type <M-]> to see the table of contents.
+ Type |gO| to see the table of contents.
==============================================================================
1. Introduction *channel-intro*
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 36826e2479..4e77f40035 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -270,9 +270,9 @@ External UIs are expected to implement these common features:
- Send the "super" key (Windows key, Apple key) as a |<D-| chord.
Implementation ~
-- Options can be monitored for changes by the |OptionSet| autocmd. E.g. if the
- user sets the 'guifont' option, this autocmd notifies channel 42: >
- autocmd OptionSet guifont call rpcnotify(42, 'option-changed', 'guifont', &guifont)
+- UI-related options ('guifont', 'ambiwidth', …) are published in the
+ "option_set" |ui-global| event. The event is triggered when the UI first
+ connects to Nvim and whenever an option is changed by the user or a plugin.
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 7061f01316..9643777975 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -70,6 +70,7 @@ Providers
Ruby plugins |provider-ruby|
Shared data |shada|
Embedded terminal |terminal|
+VimL parser |nvim_parse_expression()|
XDG base directories |xdg|
USER EXPERIENCE ~
diff --git a/runtime/plugin/health.vim b/runtime/plugin/health.vim
index e3482cb0fe..66ae8fb239 100644
--- a/runtime/plugin/health.vim
+++ b/runtime/plugin/health.vim
@@ -1,8 +1 @@
-function! s:complete(lead, _line, _pos) abort
- return sort(filter(map(globpath(&runtimepath, 'autoload/health/*', 1, 1),
- \ 'fnamemodify(v:val, ":t:r")'),
- \ 'empty(a:lead) || v:val[:strlen(a:lead)-1] ==# a:lead'))
-endfunction
-
-command! -nargs=* -complete=customlist,s:complete CheckHealth
- \ call health#check([<f-args>])
+autocmd CmdUndefined CheckHealth checkhealth
diff --git a/scripts/gen_api_vimdoc.py b/scripts/gen_api_vimdoc.py
index 4ddf415f1a..69f70f6e2b 100644
--- a/scripts/gen_api_vimdoc.py
+++ b/scripts/gen_api_vimdoc.py
@@ -478,7 +478,7 @@ def gen_docs(config):
docs += '\n\n\n'
docs = docs.rstrip() + '\n\n'
- docs += ' vim:tw=78:ts=8:ft=help:norl:'
+ docs += ' vim:tw=78:ts=8:ft=help:norl:\n'
doc_file = os.path.join(base_dir, 'runtime/doc', doc_filename)
delete_lines_below(doc_file, section_start_token)
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 530701e223..ac5e326e9d 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -14,27 +14,26 @@ readonly BRANCH_PREFIX="vim-"
CREATED_FILES=()
usage() {
- echo "Helper script for porting Vim patches. For more information, see"
+ echo "Port Vim patches to Neovim"
echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim"
echo
echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]"
echo
echo "Options:"
echo " -h Show this message and exit."
- echo " -l Show list of missing Vim patches."
- echo " -L Print missing Vim patches in machine-readable form."
- echo " -p {vim-revision} Download and generate the specified Vim patch."
- echo " vim-revision can be a version number '8.0.xxx'"
- echo " or a valid Git ref (hash, tag, etc.)."
- echo " -P {vim-revision} Download, generate and apply the Vim patch."
- echo " -g {vim-revision} Download 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 " -l List missing Vim patches."
+ echo " -L List missing Vim patches (for scripts)."
+ echo " -M List all merged patch-numbers (at current v:version)."
+ echo " -p {vim-revision} Download and generate a Vim patch. vim-revision"
+ echo " can be a Vim version (8.0.xxx) or a Git hash."
+ echo " -P {vim-revision} Download, generate and apply a Vim patch."
+ echo " -g {vim-revision} Download a Vim patch."
+ echo " -s Create a vim-patch pull request."
+ echo " -r {pr-number} Review a vim-patch pull request."
+ echo ' -V Clone the Vim source code to $VIM_SOURCE_DIR.'
echo
- echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored."
- echo "Default is '${VIM_SOURCE_DIR_DEFAULT}'."
+ echo ' $VIM_SOURCE_DIR controls where Vim sources are found'
+ echo " (default: '${VIM_SOURCE_DIR_DEFAULT}')"
}
# Checks if a program is in the user's PATH, and is executable.
@@ -173,7 +172,7 @@ preprocess_patch() {
"$file" > "$file".tmp && mv "$file".tmp "$file"
}
-get_vim_patch() {
+get_vimpatch() {
get_vim_sources
assign_commit_details "${1}"
@@ -199,7 +198,7 @@ get_vim_patch() {
}
stage_patch() {
- get_vim_patch "$1"
+ get_vimpatch "$1"
local try_apply="${2:-}"
local git_remote
@@ -235,7 +234,7 @@ stage_patch() {
printf "\n✘ 'patch' command not found\n"
else
printf "\nApplying patch...\n"
- patch -p1 --posix < "${patch_file}"
+ patch -p1 --posix < "${patch_file}" || true
fi
printf "\nInstructions:\n Proceed to port the patch.\n"
else
@@ -328,31 +327,52 @@ submit_pr() {
done
}
-# Prints a newline-delimited list of Vim commits, for use by scripts.
-list_vim_patches() {
- # Get missing Vim commits
- local vim_commits
- vim_commits="$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD)"
+# Gets all Vim commits since the "start" commit.
+list_vim_commits() { (
+ cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD
+) }
- # Find all "vim-patch:xxx" tokens in the Nvim git log.
+# Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log.
+list_vimpatch_tokens() {
local tokens
+ # Find all "vim-patch:xxx" tokens in the Nvim git log.
tokens="$(cd "${NVIM_SOURCE_DIR}" && git log -E --grep='vim-patch:[^ ]+' | grep 'vim-patch')"
- tokens="$(for i in $tokens ; do echo "$i" | grep -E 'vim-patch:[^ ]{7}' | sed 's/.*\(vim-patch:[.0-9a-z]\+\).*/\1/' ; done)"
+ echo "$tokens" | grep -E 'vim-patch:[^ ,{]{7,}' \
+ | sed 's/.*\(vim-patch:[.0-9a-z]\+\).*/\1/' \
+ | sort \
+ | uniq
+}
+
+# Prints all patch-numbers (for the current v:version) for which there is
+# a "vim-patch:xxx" token in the Nvim git log.
+list_vimpatch_numbers() {
+ # Transform "vim-patch:X.Y.ZZZZ" to "ZZZZ".
+ list_vimpatch_tokens | while read vimpatch_token; do
+ echo "$vimpatch_token" | grep '8\.0\.' | sed 's/.*vim-patch:8\.0\.\([0-9a-z]\+\).*/\1/'
+ done
+}
+
+# Prints a newline-delimited list of Vim commits, for use by scripts.
+list_missing_vimpatches() {
+ local tokens vim_commit vim_commits is_missing vim_tag patch_number
- local vim_commit
+ # Find all "vim-patch:xxx" tokens in the Nvim git log.
+ tokens="$(list_vimpatch_tokens)"
+
+ # Get missing Vim commits
+ vim_commits="$(list_vim_commits)"
for vim_commit in ${vim_commits}; do
- local is_missing
- local vim_tag
- # This fails for untagged commits (e.g., runtime file updates) so mask the return status
- vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true
- if [[ -n "${vim_tag}" ]]; then
+ # Check for vim-patch:<commit_hash> (usually runtime updates).
+ is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${vim_commit:0:7}" && echo false || echo true)"
+
+ if ! [ "$is_missing" = "false" ] \
+ && vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)"
+ then
# Vim version number (not commit hash).
- local patch_number="${vim_tag:1}" # "v7.4.0001" => "7.4.0001"
+ # Check for vim-patch:<tag> (not commit hash).
+ patch_number="${vim_tag:1}" # "v7.4.0001" => "7.4.0001"
is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${patch_number}" && echo false || echo true)"
vim_commit="${vim_tag#v}"
- else
- # Untagged Vim patch (e.g. runtime updates).
- is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${vim_commit:0:7}" && echo false || echo true)"
fi
if ! [ "$is_missing" = "false" ]; then
@@ -362,11 +382,11 @@ list_vim_patches() {
}
# Prints a human-formatted list of Vim commits, with instructional messages.
-show_vim_patches() {
+show_vimpatches() {
get_vim_sources
printf "\nVim patches missing from Neovim:\n"
- list_vim_patches | while read vim_commit; do
+ list_missing_vimpatches | while read vim_commit; do
if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then
printf " • ${vim_commit} (+runtime)\n"
else
@@ -440,7 +460,7 @@ review_commit() {
echo "✔ Saved pull request diff to '${NVIM_SOURCE_DIR}/n${patch_file}'."
CREATED_FILES+=("${NVIM_SOURCE_DIR}/n${patch_file}")
- get_vim_patch "${vim_version}"
+ get_vimpatch "${vim_version}"
CREATED_FILES+=("${NVIM_SOURCE_DIR}/${patch_file}")
echo
@@ -481,18 +501,22 @@ review_pr() {
clean_files
}
-while getopts "hlLp:P:g:r:s" opt; do
+while getopts "hlLMVp:P:g:r:s" opt; do
case ${opt} in
h)
usage
exit 0
;;
l)
- show_vim_patches
+ show_vimpatches
exit 0
;;
L)
- list_vim_patches
+ list_missing_vimpatches
+ exit 0
+ ;;
+ M)
+ list_vimpatch_numbers
exit 0
;;
p)
@@ -504,7 +528,7 @@ while getopts "hlLp:P:g:r:s" opt; do
exit 0
;;
g)
- get_vim_patch "${OPTARG}"
+ get_vimpatch "${OPTARG}"
exit 0
;;
r)
@@ -515,6 +539,10 @@ while getopts "hlLp:P:g:r:s" opt; do
submit_pr
exit 0
;;
+ V)
+ get_vim_sources
+ exit 0
+ ;;
*)
exit 1
;;
diff --git a/scripts/vimpatch.lua b/scripts/vimpatch.lua
new file mode 100755
index 0000000000..0924f3d718
--- /dev/null
+++ b/scripts/vimpatch.lua
@@ -0,0 +1,67 @@
+-- Updates version.c list of applied Vim patches.
+--
+-- Usage:
+-- VIM_SOURCE_DIR=~/neovim/.vim-src/ nvim -i NONE -u NONE --headless +'luafile ./scripts/vimpatch.lua' +q
+
+local nvim = vim.api
+
+local function pprint(o)
+ print(nvim.nvim_call_function('string', { o }))
+end
+
+local function systemlist(...)
+ local rv = nvim.nvim_call_function('systemlist', ...)
+ local err = nvim.nvim_get_vvar('shell_error')
+ local args_str = nvim.nvim_call_function('string', ...)
+ if 0 ~= err then
+ error('command failed: '..args_str)
+ end
+ return rv
+end
+
+local function vimpatch_sh_list_numbers()
+ return systemlist( { { 'bash', '-c', 'scripts/vim-patch.sh -M', } } )
+end
+
+-- Generates the lines to be inserted into the src/version.c
+-- `included_patches[]` definition.
+local function gen_version_c_lines()
+ -- Set of merged Vim 8.0.zzzz patch numbers.
+ local merged_patch_numbers = {}
+ local highest = 0
+ for _, n in ipairs(vimpatch_sh_list_numbers()) do
+ if n then
+ merged_patch_numbers[tonumber(n)] = true
+ highest = math.max(highest, n)
+ end
+ end
+
+ local lines = {}
+ for i = highest, 0, -1 do
+ local is_merged = (nil ~= merged_patch_numbers[i])
+ if is_merged then
+ table.insert(lines, string.format(' %s,', i))
+ else
+ table.insert(lines, string.format(' // %s,', i))
+ end
+ end
+
+ return lines
+end
+
+local function patch_version_c()
+ local lines = gen_version_c_lines()
+
+ nvim.nvim_command('silent noswapfile noautocmd edit src/nvim/version.c')
+ nvim.nvim_command('/static const int included_patches')
+ -- Delete the existing lines.
+ nvim.nvim_command('silent normal! j0d/};\rk')
+ -- Insert the lines.
+ nvim.nvim_call_function('append', {
+ nvim.nvim_eval('line(".")'),
+ lines,
+ })
+ nvim.nvim_command('silent write')
+end
+
+patch_version_c()
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index c0daac8085..172f2ce18e 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -929,7 +929,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// starting column and ending column (latter exclusive:
/// one should highlight region [start_col, end_col)).
///
-/// @return AST: top-level dictionary holds keys
+/// @return AST: top-level dictionary with these keys:
///
/// "error": Dictionary with error, present only if parser saw some
/// error. Contains the following keys:
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 4f54d4c88b..c5825963c0 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4619,7 +4619,8 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
"/\\(\\)", "/\\%(\\)",
"?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?",
"/\\?", "/\\z(\\)", "\\=", ":s\\=",
- "[count]", "[quotex]", "[range]",
+ "[count]", "[quotex]",
+ "[range]", ":[range]",
"[pattern]", "\\|", "\\%$",
"s/\\~", "s/\\U", "s/\\L",
"s/\\1", "s/\\2", "s/\\3", "s/\\9"};
@@ -4628,7 +4629,8 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
"/\\\\(\\\\)", "/\\\\%(\\\\)",
"?", ":?", "?<CR>", "g?", "g?g?", "g??", "z?",
"/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
- "\\[count]", "\\[quotex]", "\\[range]",
+ "\\[count]", "\\[quotex]",
+ "\\[range]", ":\\[range]",
"\\[pattern]", "\\\\bar", "/\\\\%\\$",
"s/\\\\\\~", "s/\\\\U", "s/\\\\L",
"s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"};
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index f6a5f59676..a0ede4f3c5 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -6230,7 +6230,6 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
if (!valid_tabpage(tp) || tp->tp_firstwin == wp)
break;
}
- apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, FALSE, curbuf);
redraw_tabline = TRUE;
if (h != tabline_height())
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index f85009dca8..120a449690 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -1121,6 +1121,7 @@ qf_init_ext(
}
if (qf_add_entry(qi,
+ qi->qf_curlist,
qi->qf_directory,
(*fields.namebuf || qi->qf_directory)
? fields.namebuf : ((qi->qf_currfile && fields.valid)
@@ -1182,13 +1183,14 @@ qf_init_end:
return retval;
}
-static void qf_store_title(qf_info_T *qi, char_u *title)
+static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
{
if (title != NULL) {
- char_u *p = xmalloc(STRLEN(title) + 2);
+ size_t len = STRLEN(title) + 1;
+ char_u *p = xmallocz(len);
- qi->qf_lists[qi->qf_curlist].qf_title = p;
- sprintf((char *)p, ":%s", (char *)title);
+ qi->qf_lists[qf_idx].qf_title = p;
+ snprintf((char *)p, len + 1, ":%s", (char *)title);
}
}
@@ -1217,7 +1219,7 @@ static void qf_new_list(qf_info_T *qi, char_u *qf_title)
} else
qi->qf_curlist = qi->qf_listcount++;
memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
- qf_store_title(qi, qf_title);
+ qf_store_title(qi, qi->qf_curlist, qf_title);
}
/*
@@ -1260,6 +1262,7 @@ void qf_free_all(win_T *wp)
/// Add an entry to the end of the list of errors.
///
/// @param qi quickfix list
+/// @param qf_idx list index
/// @param dir optional directory name
/// @param fname file name or NULL
/// @param bufnum buffer number or zero
@@ -1273,9 +1276,10 @@ void qf_free_all(win_T *wp)
/// @param valid valid entry
///
/// @returns OK or FAIL.
-static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
- char_u *mesg, long lnum, int col, char_u vis_col,
- char_u *pattern, int nr, char_u type, char_u valid)
+static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname,
+ int bufnum, char_u *mesg, long lnum, int col,
+ char_u vis_col, char_u *pattern, int nr, char_u type,
+ char_u valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
qfline_T **lastp; // pointer to qf_last or NULL
@@ -1306,12 +1310,12 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
qfp->qf_type = (char_u)type;
qfp->qf_valid = valid;
- lastp = &qi->qf_lists[qi->qf_curlist].qf_last;
- if (qi->qf_lists[qi->qf_curlist].qf_count == 0) {
- /* first element in the list */
- qi->qf_lists[qi->qf_curlist].qf_start = qfp;
- qi->qf_lists[qi->qf_curlist].qf_ptr = qfp;
- qi->qf_lists[qi->qf_curlist].qf_index = 0;
+ lastp = &qi->qf_lists[qf_idx].qf_last;
+ if (qi->qf_lists[qf_idx].qf_count == 0) {
+ // first element in the list
+ qi->qf_lists[qf_idx].qf_start = qfp;
+ qi->qf_lists[qf_idx].qf_ptr = qfp;
+ qi->qf_lists[qf_idx].qf_index = 0;
qfp->qf_prev = NULL;
} else {
assert(*lastp);
@@ -1321,12 +1325,11 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum,
qfp->qf_next = NULL;
qfp->qf_cleared = false;
*lastp = qfp;
- qi->qf_lists[qi->qf_curlist].qf_count++;
- if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) {
- /* first valid entry */
- qi->qf_lists[qi->qf_curlist].qf_index =
- qi->qf_lists[qi->qf_curlist].qf_count;
- qi->qf_lists[qi->qf_curlist].qf_ptr = qfp;
+ qi->qf_lists[qf_idx].qf_count++;
+ if (qi->qf_lists[qf_idx].qf_index == 0 && qfp->qf_valid) {
+ // first valid entry
+ qi->qf_lists[qf_idx].qf_index = qi->qf_lists[qf_idx].qf_count;
+ qi->qf_lists[qf_idx].qf_ptr = qfp;
}
return OK;
@@ -1429,6 +1432,7 @@ void copy_loclist(win_T *from, win_T *to)
i < from_qfl->qf_count && from_qfp != NULL;
i++, from_qfp = from_qfp->qf_next) {
if (qf_add_entry(to->w_llist,
+ to->w_llist->qf_curlist,
NULL,
NULL,
0,
@@ -3704,6 +3708,7 @@ void ex_vimgrep(exarg_T *eap)
// dummy buffer, unless duplicate_name is set, then the
// buffer will be wiped out below.
if (qf_add_entry(qi,
+ qi->qf_curlist,
NULL, // dir
fname,
duplicate_name ? 0 : buf->b_fnum,
@@ -4164,23 +4169,24 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
/// Add list of entries to quickfix/location list. Each list entry is
/// a dictionary with item information.
-static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
- int action)
+static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
+ char_u *title, int action)
{
dict_T *d;
qfline_T *old_last = NULL;
int retval = OK;
bool did_bufnr_emsg = false;
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
+ if (action == ' ' || qf_idx == qi->qf_listcount) {
// make place for a new list
qf_new_list(qi, title);
- } else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) {
+ qf_idx = qi->qf_curlist;
+ } else if (action == 'a' && qi->qf_lists[qf_idx].qf_count > 0) {
// Adding to existing list, use last entry.
- old_last = qi->qf_lists[qi->qf_curlist].qf_last;
+ old_last = qi->qf_lists[qf_idx].qf_last;
} else if (action == 'r') {
- qf_free(qi, qi->qf_curlist);
- qf_store_title(qi, title);
+ qf_free(qi, qf_idx);
+ qf_store_title(qi, qf_idx, title);
}
TV_LIST_ITER_CONST(list, li, {
@@ -4228,6 +4234,7 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
}
int status = qf_add_entry(qi,
+ qf_idx,
NULL, // dir
(char_u *)filename,
bufnum,
@@ -4250,16 +4257,16 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title,
}
});
- if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
+ if (qi->qf_lists[qf_idx].qf_index == 0) {
// no valid entry
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = true;
+ qi->qf_lists[qf_idx].qf_nonevalid = true;
} else {
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = false;
+ qi->qf_lists[qf_idx].qf_nonevalid = false;
}
if (action != 'a') {
- qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
- if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
- qi->qf_lists[qi->qf_curlist].qf_index = 1;
+ qi->qf_lists[qf_idx].qf_ptr = qi->qf_lists[qf_idx].qf_start;
+ if (qi->qf_lists[qf_idx].qf_count > 0) {
+ qi->qf_lists[qf_idx].qf_index = 1;
}
}
@@ -4400,7 +4407,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
} else if (what != NULL) {
retval = qf_set_properties(qi, what, action);
} else {
- retval = qf_add_entries(qi, list, title, action);
+ retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
}
return retval;
@@ -4718,6 +4725,7 @@ void ex_helpgrep(exarg_T *eap)
line[--l] = NUL;
if (qf_add_entry(qi,
+ qi->qf_curlist,
NULL, // dir
fnames[fi],
0,
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index ac44e09a5a..dc9790a39c 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -330,4 +330,36 @@ func Test_cmdline_search_range()
bwipe!
endfunc
+" Tests for getcmdline(), getcmdpos() and getcmdtype()
+func Check_cmdline(cmdtype)
+ call assert_equal('MyCmd a', getcmdline())
+ call assert_equal(8, getcmdpos())
+ call assert_equal(a:cmdtype, getcmdtype())
+ return ''
+endfunc
+
+func Test_getcmdtype()
+ call feedkeys(":MyCmd a\<C-R>=Check_cmdline(':')\<CR>\<Esc>", "xt")
+
+ let cmdtype = ''
+ debuggreedy
+ call feedkeys(":debug echo 'test'\<CR>", "t")
+ call feedkeys("let cmdtype = \<C-R>=string(getcmdtype())\<CR>\<CR>", "t")
+ call feedkeys("cont\<CR>", "xt")
+ 0debuggreedy
+ call assert_equal('>', cmdtype)
+
+ call feedkeys("/MyCmd a\<C-R>=Check_cmdline('/')\<CR>\<Esc>", "xt")
+ call feedkeys("?MyCmd a\<C-R>=Check_cmdline('?')\<CR>\<Esc>", "xt")
+
+ call feedkeys(":call input('Answer?')\<CR>", "t")
+ call feedkeys("MyCmd a\<C-R>=Check_cmdline('@')\<CR>\<Esc>", "xt")
+
+ call feedkeys(":insert\<CR>MyCmd a\<C-R>=Check_cmdline('-')\<CR>\<Esc>", "xt")
+
+ cnoremap <expr> <F6> Check_cmdline('=')
+ call feedkeys("a\<C-R>=MyCmd a\<F6>\<Esc>\<Esc>", "xt")
+ cunmap <F6>
+endfunc
+
set cpo&
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 8ab9fc1a4b..e35b803b4e 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -146,7 +146,7 @@ static const int included_patches[] = {
// 1292,
// 1291,
// 1290,
- // 1289,
+ 1289,
// 1288,
// 1287,
// 1286,
@@ -228,8 +228,187 @@ static const int included_patches[] = {
// 1210,
// 1209,
// 1208,
- // 1207,
+ 1207,
1206,
+ // 1205,
+ // 1204,
+ // 1203,
+ // 1202,
+ // 1201,
+ // 1200,
+ // 1199,
+ // 1198,
+ // 1197,
+ // 1196,
+ // 1195,
+ // 1194,
+ // 1193,
+ // 1192,
+ // 1191,
+ // 1190,
+ 1189,
+ // 1188,
+ // 1187,
+ // 1186,
+ // 1185,
+ // 1184,
+ // 1183,
+ // 1182,
+ // 1181,
+ // 1180,
+ // 1179,
+ // 1178,
+ // 1177,
+ // 1176,
+ // 1175,
+ // 1174,
+ // 1173,
+ // 1172,
+ // 1171,
+ // 1170,
+ // 1169,
+ // 1168,
+ // 1167,
+ // 1166,
+ // 1165,
+ // 1164,
+ // 1163,
+ // 1162,
+ // 1161,
+ // 1160,
+ // 1159,
+ // 1158,
+ // 1157,
+ // 1156,
+ // 1155,
+ // 1154,
+ // 1153,
+ // 1152,
+ // 1151,
+ // 1150,
+ // 1149,
+ // 1148,
+ // 1147,
+ // 1146,
+ // 1145,
+ // 1144,
+ // 1143,
+ // 1142,
+ // 1141,
+ // 1140,
+ // 1139,
+ // 1138,
+ // 1137,
+ // 1136,
+ // 1135,
+ // 1134,
+ // 1133,
+ // 1132,
+ // 1131,
+ // 1130,
+ // 1129,
+ // 1128,
+ // 1127,
+ // 1126,
+ // 1125,
+ // 1124,
+ // 1123,
+ // 1122,
+ // 1121,
+ // 1120,
+ // 1119,
+ // 1118,
+ // 1117,
+ // 1116,
+ // 1115,
+ // 1114,
+ // 1113,
+ // 1112,
+ // 1111,
+ // 1110,
+ // 1109,
+ 1108,
+ // 1107,
+ // 1106,
+ // 1105,
+ // 1104,
+ // 1103,
+ // 1102,
+ // 1101,
+ // 1100,
+ // 1099,
+ // 1098,
+ // 1097,
+ // 1096,
+ // 1095,
+ // 1094,
+ // 1093,
+ // 1092,
+ // 1091,
+ // 1090,
+ // 1089,
+ // 1088,
+ // 1087,
+ // 1086,
+ // 1085,
+ // 1084,
+ // 1083,
+ // 1082,
+ // 1081,
+ // 1080,
+ // 1079,
+ // 1078,
+ // 1077,
+ // 1076,
+ // 1075,
+ // 1074,
+ // 1073,
+ // 1072,
+ // 1071,
+ // 1070,
+ // 1069,
+ // 1068,
+ // 1067,
+ // 1066,
+ // 1065,
+ // 1064,
+ // 1063,
+ // 1062,
+ // 1061,
+ // 1060,
+ // 1059,
+ // 1058,
+ // 1057,
+ // 1056,
+ // 1055,
+ // 1054,
+ // 1053,
+ // 1052,
+ // 1051,
+ // 1050,
+ // 1049,
+ // 1048,
+ // 1047,
+ // 1046,
+ // 1045,
+ // 1044,
+ // 1043,
+ // 1042,
+ // 1041,
+ // 1040,
+ // 1039,
+ // 1038,
+ // 1037,
+ // 1036,
+ // 1035,
+ // 1034,
+ // 1033,
+ // 1032,
+ // 1031,
+ // 1030,
+ // 1029,
+ // 1028,
+ // 1027,
// 1026,
1025,
1024,
@@ -237,7 +416,7 @@ static const int included_patches[] = {
// 1022,
// 1021,
// 1020,
- // 1019,
+ 1019,
// 1018,
// 1017,
// 1016,
@@ -294,7 +473,7 @@ static const int included_patches[] = {
// 965,
// 964,
// 963,
- // 962,
+ 962,
// 961,
// 960,
// 959,
@@ -650,7 +829,7 @@ static const int included_patches[] = {
// 609,
// 608,
607,
- // 606,
+ 606,
605,
// 604,
// 603,
@@ -659,30 +838,30 @@ static const int included_patches[] = {
// 600,
// 599,
// 598,
- // 597,
+ 597,
// 596,
- // 595,
+ 595,
// 594,
// 593,
// 592,
// 591,
- // 590,
+ 590,
// 589,
// 588,
// 587,
// 586,
// 585,
- // 584,
+ 584,
// 583,
// 582,
// 581,
- // 580,
- // 579,
+ 580,
+ 579,
// 578,
// 577,
// 576,
// 575,
- // 574,
+ 574,
// 573,
// 572,
571,
@@ -691,7 +870,7 @@ static const int included_patches[] = {
// 568,
// 567,
// 566,
- // 565,
+ 565,
// 564,
// 563,
// 562,
@@ -720,7 +899,7 @@ static const int included_patches[] = {
// 539,
// 538,
// 537,
- // 536,
+ 536,
// 535,
// 534,
// 533,
@@ -739,7 +918,7 @@ static const int included_patches[] = {
// 520,
// 519,
518,
- // 517,
+ 517,
// 516,
// 515,
// 514,
@@ -772,7 +951,7 @@ static const int included_patches[] = {
487,
486,
485,
- // 484,
+ 484,
483,
482,
// 481,
@@ -836,7 +1015,7 @@ static const int included_patches[] = {
// 423,
// 422,
// 421,
- // 420,
+ 420,
// 419,
// 418,
// 417,
@@ -851,12 +1030,12 @@ static const int included_patches[] = {
408,
407,
// 406,
- // 405 NA
- // 404,
+ 405,
+ 404,
// 403,
// 402,
// 401,
- // 400 NA
+ 400,
// 399,
// 398,
// 397,
@@ -877,7 +1056,7 @@ static const int included_patches[] = {
// 382,
// 381,
// 380,
- // 379,
+ 379,
378,
377,
376,
@@ -936,7 +1115,7 @@ static const int included_patches[] = {
// 323,
322,
// 321,
- // 320,
+ 320,
319,
// 318,
// 317,
@@ -946,18 +1125,18 @@ static const int included_patches[] = {
// 313,
// 312,
311,
- // 310,
- // 309,
+ 310,
+ 309,
308,
307,
306,
305,
// 304,
// 303,
- // 302 NA
+ 302,
// 301,
300,
- // 299,
+ 299,
298,
297,
// 296,
@@ -968,38 +1147,38 @@ static const int included_patches[] = {
291,
290,
289,
- // 288 NA
+ 288,
287,
// 286,
- // 285 NA
- // 284 NA
+ 285,
+ 284,
283,
282,
- // 281 NA
+ 281,
280,
- // 279 NA
- // 278 NA
- // 277 NA
- // 276 NA
+ 279,
+ 278,
+ 277,
+ 276,
275,
274,
- // 273 NA
- // 272 NA
- // 271 NA
- // 270 NA
- // 269 NA
- // 268 NA
- // 267 NA
+ 273,
+ 272,
+ 271,
+ 270,
+ 269,
+ 268,
+ 267,
266,
// 265,
// 264,
// 263,
// 262,
// 261,
- // 260 NA
+ 260,
259,
258,
- // 257 NA
+ 257,
// 256,
// 255,
// 254,
@@ -1007,45 +1186,45 @@ static const int included_patches[] = {
// 252,
// 251,
250,
- // 249 NA
- // 248 NA
+ 249,
+ 248,
247,
- // 246 NA
+ 246,
245,
- // 244 NA
+ 244,
243,
242,
- // 241 NA
- // 240 NA
- // 239 NA
+ 241,
+ 240,
+ 239,
// 238,
237,
// 236,
235,
// 234,
// 233,
- // 232 NA
+ 232,
// 231,
// 230,
229,
// 228,
- // 227,
+ 227,
226,
// 225,
224,
223,
// 222,
- // 221 NA
+ 221,
// 220,
219,
218,
- // 217 NA
+ 217,
// 216,
- // 215 NA
+ 215,
// 214,
- // 213 NA
+ 213,
// 212,
- // 211 NA
+ 211,
// 210,
209,
208,
@@ -1053,49 +1232,49 @@ static const int included_patches[] = {
206,
205,
// 204,
- // 203 NA
+ 203,
// 202,
// 201,
// 200,
- // 199 NA
+ 199,
// 198,
// 197,
196,
195,
194,
- // 193 NA
- // 192 NA
- // 191 NA
+ 193,
+ 192,
+ 191,
190,
189,
188,
- // 187 NA
+ 187,
186,
// 185,
// 184,
- // 183 NA
+ 183,
182,
181,
- // 180 NA
+ 180,
179,
178,
177,
176,
// 175,
174,
- // 173 NA
+ 173,
172,
- // 171 NA
- // 170 NA
- // 169 NA
+ 171,
+ 170,
+ 169,
168,
167,
- // 166 NA
+ 166,
165,
164,
- // 163 NA
- // 162 NA
- // 161 NA
+ 163,
+ 162,
+ 161,
// 160,
159,
158,
@@ -1104,21 +1283,21 @@ static const int included_patches[] = {
155,
// 154,
// 153,
- // 152 NA
+ 152,
// 151,
150,
149,
148,
147,
146,
- // 145 NA
- // 144 NA
+ 145,
+ 144,
143,
142,
- // 141 NA
+ 141,
140,
- // 139 NA
- // 138 NA
+ 139,
+ 138,
137,
136,
135,
@@ -1126,137 +1305,137 @@ static const int included_patches[] = {
133,
132,
131,
- // 130 NA
- // 129 NA
+ 130,
+ 129,
128,
127,
126,
125,
124,
- // 123 NA
- // 122 NA
+ 123,
+ 122,
121,
- // 120 NA
+ 120,
119,
118,
- // 117 NA
+ 117,
116,
- // 115 NA
- // 114 NA
- // 113 NA
+ 115,
+ 114,
+ 113,
112,
111,
110,
- // 109 NA
- // 108 NA
- // 107 NA
+ 109,
+ 108,
+ 107,
106,
- // 105 NA
+ 105,
104,
- // 103 NA
+ 103,
102,
101,
100,
99,
- // 98 NA
- // 97 NA
+ 98,
+ 97,
96,
- // 95 NA
- // 94 NA
- // 93 NA
+ 95,
+ 94,
+ 93,
92,
91,
90,
- // 89 NA
+ 89,
88,
- // 87 NA
+ 87,
86,
85,
84,
83,
- // 82 NA
+ 82,
81,
- // 80 NA
+ 80,
79,
78,
- // 77 NA
- // 76 NA
+ 77,
+ 76,
75,
74,
73,
- // 72 NA
- // 71 NA
- // 70 NA
+ 72,
+ 71,
+ 70,
69,
68,
- // 67 NA
+ 67,
66,
- // 65 NA
+ 65,
64,
- // 63 NA
+ 63,
62,
- // 61 NA
+ 61,
60,
- // 59 NA
+ 59,
58,
57,
56,
- // 55 NA
- // 54 NA
+ 55,
+ 54,
53,
52,
- // 51 NA
- // 50 NA
+ 51,
+ 50,
49,
- // 48 NA
+ 48,
47,
46,
- // 45 NA
+ 45,
44,
43,
42,
41,
40,
- // 39 NA
+ 39,
38,
37,
- // 36 NA
+ 36,
35,
34,
33,
32,
31,
- // 30 NA
- // 29 NA
- // 28 NA
- // 27 NA
+ 30,
+ 29,
+ 28,
+ 27,
26,
25,
- // 24 NA
+ 24,
23,
- // 22 NA
- // 21 NA
+ 22,
+ 21,
20,
19,
- // 18 NA
+ 18,
17,
- // 16 NA
- // 15 NA
- // 14 NA
- // 13 NA
+ 16,
+ 15,
+ 14,
+ 13,
12,
- // 11 NA
- // 10 NA
- // 9 NA
+ 11,
+ 10,
+ 9,
8,
- // 7 NA
+ 7,
6,
- // 5 NA
+ 5,
4,
3,
2,
1,
- 0
+ 0,
};
// clang-format on
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 5e85a9bede..b687781dfb 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1724,7 +1724,6 @@ void close_windows(buf_T *buf, int keep_curwin)
{
tabpage_T *tp, *nexttp;
int h = tabline_height();
- int count = tabpage_index(NULL);
++RedrawingDisabled;
@@ -1762,10 +1761,6 @@ void close_windows(buf_T *buf, int keep_curwin)
--RedrawingDisabled;
- if (count != tabpage_index(NULL)) {
- apply_autocmds(EVENT_TABCLOSED, NULL, NULL, false, curbuf);
- }
-
redraw_tabline = true;
if (h != tabline_height()) {
shell_new_rows();
@@ -1848,7 +1843,6 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
// that now.
- apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
if (old_curbuf != curbuf) {
@@ -2108,19 +2102,29 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
/* When closing the last window in a tab page remove the tab page. */
if (tp->tp_firstwin == tp->tp_lastwin) {
- if (tp == first_tabpage)
+ char_u prev_idx[NUMBUFLEN];
+ if (has_event(EVENT_TABCLOSED)) {
+ vim_snprintf((char *)prev_idx, NUMBUFLEN, "%i", tabpage_index(tp));
+ }
+
+ if (tp == first_tabpage) {
first_tabpage = tp->tp_next;
- else {
+ } else {
for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tp;
- ptp = ptp->tp_next)
- ;
+ ptp = ptp->tp_next) {
+ // loop
+ }
if (ptp == NULL) {
internal_error("win_close_othertab()");
return;
}
ptp->tp_next = tp->tp_next;
}
- free_tp = TRUE;
+ free_tp = true;
+
+ if (has_event(EVENT_TABCLOSED)) {
+ apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, win->w_buffer);
+ }
}
/* Free the memory used for the window. */
diff --git a/test/functional/autocmd/tabclose_spec.lua b/test/functional/autocmd/tabclose_spec.lua
index 1431c69589..fb777e7eea 100644
--- a/test/functional/autocmd/tabclose_spec.lua
+++ b/test/functional/autocmd/tabclose_spec.lua
@@ -2,32 +2,67 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, eq = helpers.clear, helpers.nvim, helpers.eq
describe('TabClosed', function()
- describe('au TabClosed', function()
- describe('with * as <afile>', function()
- it('matches when closing any tab', function()
- clear()
- nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
- repeat
- nvim('command', 'tabnew')
- until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6
- eq("\ntabclosed:6:6:5", nvim('command_output', 'tabclose')) -- close last 6, current tab is now 5
- eq("\ntabclosed:5:5:4", nvim('command_output', 'close')) -- close last window on tab, closes tab
- eq("\ntabclosed:2:2:3", nvim('command_output', '2tabclose')) -- close tab 2, current tab is now 3
- eq("\ntabclosed:1:1:2\ntabclosed:1:1:1", nvim('command_output', 'tabonly')) -- close tabs 1 and 2
- end)
- end)
- describe('with NR as <afile>', function()
- it('matches when closing a tab whose index is NR', function()
- nvim('command', 'au! TabClosed 2 echom "tabclosed:match"')
- repeat
- nvim('command', 'tabnew')
- until nvim('eval', 'tabpagenr()') == 5 -- current tab is now 5
- -- sanity check, we shouldn't match on tabs with numbers other than 2
- eq("\ntabclosed:5:5:4", nvim('command_output', 'tabclose'))
- -- close tab page 2, current tab is now 3
- eq("\ntabclosed:2:2:3\ntabclosed:match", nvim('command_output', '2tabclose'))
- end)
- end)
+ before_each(clear)
+
+ describe('au TabClosed', function()
+ describe('with * as <afile>', function()
+ it('matches when closing any tab', function()
+ nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
+ repeat
+ nvim('command', 'tabnew')
+ until nvim('eval', 'tabpagenr()') == 6 -- current tab is now 6
+ eq("\ntabclosed:6:6:5", nvim('command_output', 'tabclose')) -- close last 6, current tab is now 5
+ eq("\ntabclosed:5:5:4", nvim('command_output', 'close')) -- close last window on tab, closes tab
+ eq("\ntabclosed:2:2:3", nvim('command_output', '2tabclose')) -- close tab 2, current tab is now 3
+ eq("\ntabclosed:1:1:2\ntabclosed:1:1:1", nvim('command_output', 'tabonly')) -- close tabs 1 and 2
+ end)
+
+ it('is triggered when closing a window via bdelete from another tab', function()
+ nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
+ nvim('command', '1tabedit Xtestfile')
+ nvim('command', '1tabedit Xtestfile')
+ nvim('command', 'normal! 1gt')
+ eq({1, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
+ eq("\ntabclosed:2:2:1\ntabclosed:2:2:1", nvim('command_output', 'bdelete Xtestfile'))
+ eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
+ end)
+
+ it('is triggered when closing a window via bdelete from current tab', function()
+ nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
+ nvim('command', 'file Xtestfile1')
+ nvim('command', '1tabedit Xtestfile2')
+ nvim('command', '1tabedit Xtestfile2')
+
+ -- Only one tab is closed, and the alternate file is used for the other.
+ eq({2, 3}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
+ eq("\ntabclosed:2:2:2", nvim('command_output', 'bdelete Xtestfile2'))
+ eq('Xtestfile1', nvim('eval', 'bufname("")'))
+ end)
+ end)
+
+ describe('with NR as <afile>', function()
+ it('matches when closing a tab whose index is NR', function()
+ nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
+ nvim('command', 'au! TabClosed 2 echom "tabclosed:match"')
+ repeat
+ nvim('command', 'tabnew')
+ until nvim('eval', 'tabpagenr()') == 7 -- current tab is now 7
+ -- sanity check, we shouldn't match on tabs with numbers other than 2
+ eq("\ntabclosed:7:7:6", nvim('command_output', 'tabclose'))
+ -- close tab page 2, current tab is now 5
+ eq("\ntabclosed:2:2:5\ntabclosed:match", nvim('command_output', '2tabclose'))
+ end)
+ end)
+
+ describe('with close', function()
+ it('is triggered', function()
+ nvim('command', 'au! TabClosed * echom "tabclosed:".expand("<afile>").":".expand("<amatch>").":".tabpagenr()')
+ nvim('command', 'tabedit Xtestfile')
+ eq({2, 2}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
+ eq("\ntabclosed:2:2:1", nvim('command_output', 'close'))
+ eq({1, 1}, nvim('eval', '[tabpagenr(), tabpagenr("$")]'))
+ end)
end)
+ end)
end)
diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua
index c6c30494dd..e64df502a6 100644
--- a/test/functional/autocmd/termclose_spec.lua
+++ b/test/functional/autocmd/termclose_spec.lua
@@ -4,6 +4,7 @@ local clear, command, nvim, nvim_dir =
helpers.clear, helpers.command, helpers.nvim, helpers.nvim_dir
local eval, eq, retry =
helpers.eval, helpers.eq, helpers.retry
+local ok = helpers.ok
if helpers.pending_win32(pending) then return end
@@ -41,7 +42,9 @@ describe('TermClose event', function()
command('call jobstop(g:test_job)')
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
local duration = os.time() - start
- eq(2, duration)
+ -- nvim starts sending SIGTERM after KILL_TIMEOUT_MS
+ ok(duration >= 2)
+ ok(duration <= 4) -- <= 2 + delta because of slow CI
end)
it('kills pty job trapping SIGHUP and SIGTERM', function()
@@ -58,8 +61,8 @@ describe('TermClose event', function()
retry(nil, nil, function() eq(1, eval('get(g:, "test_job_exited", 0)')) end)
local duration = os.time() - start
-- nvim starts sending kill after 2*KILL_TIMEOUT_MS
- helpers.ok(4 <= duration)
- helpers.ok(duration <= 7) -- <= 4 + delta because of slow CI
+ ok(duration >= 4)
+ ok(duration <= 7) -- <= 4 + delta because of slow CI
end)
it('reports the correct <abuf>', function()
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 66f921ffcc..9bfcee4ed4 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -90,18 +90,18 @@ include(ExternalProject)
set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.12.0.tar.gz)
set(LIBUV_SHA256 41ce914a88da21d3b07a76023beca57576ca5b376c6ac440c80bc581cbca1250)
-set(MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/cpp-2.1.3.tar.gz)
-set(MSGPACK_SHA256 42ff5c213fd24bd4388c45c1f21d84b476678ce6366ea4d4f4086618a1d2cd23)
+set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-2.1.5/msgpack-2.1.5.tar.gz)
+set(MSGPACK_SHA256 6126375af9b204611b9d9f154929f4f747e4599e6ae8443b337915dcf2899d2b)
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/82151a4514e6538086f3f5e01cb8d4b22287b14f.tar.gz)
-set(LUAJIT_SHA256 8bc4e96ebab74e12ab84e751360e864714289bb089b51b6f396fa9a97df69798)
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/7dbf0b05f1228c1c719866db5e5f3d58f87f74c8.tar.gz)
+set(LUAJIT_SHA256 cbae019b5e396164eb5f0d07777b55cc03931bb944f83c61a010c053c9f5fd5b)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)
# NOTE: Version must match LUAROCKS_VERSION in third-party/cmake/BuildLuarocks.cmake
-set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.2.tar.gz)
-set(LUAROCKS_SHA256 eef88c2429c715a7beb921e4b1ba571dddb7c74a250fbb0d3cc0d4be7a5865d9)
+set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.3.tar.gz)
+set(LUAROCKS_SHA256 ea1881d6954f2a98c34f93674571c8f0cbdbc28dedb3fa3cb56b6a91886d1a99)
set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v1.2.1.tar.gz)
set(UNIBILIUM_SHA256 6045b4f6adca7b1123284007675ca71f718f70942d3a93d8b9fa5bd442006ec1)
@@ -117,8 +117,8 @@ endif()
set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/a9c7c6fd20fa35e0ad3e0e98901ca12dfca9c25c.tar.gz)
set(LIBVTERM_SHA256 1a4272be91d9614dc183a503786df83b6584e4afaab7feaaa5409f841afbd796)
-set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/4.5.0/jemalloc-4.5.0.tar.bz2)
-set(JEMALLOC_SHA256 9409d85664b4f135b77518b0b118c549009dc10f6cba14557d170476611f6780)
+set(JEMALLOC_URL https://github.com/jemalloc/jemalloc/releases/download/5.0.1/jemalloc-5.0.1.tar.bz2)
+set(JEMALLOC_SHA256 4814781d395b0ef093b21a08e8e6e0bd3dab8762f9935bbfb71679b0dea7c3e9)
set(LUV_URL https://github.com/luvit/luv/archive/1.9.1-1.tar.gz)
set(LUV_SHA256 562b9efaad30aa051a40eac9ade0c3df48bb8186763769abe47ec3fb3edb1268)
@@ -139,8 +139,8 @@ set(WIN32YANK_X86_SHA256 62f34e5a46c5d4a7b3f3b512e1ff7b77fedd432f42581cbe825233a
set(WIN32YANK_X86_64_URL https://github.com/equalsraf/win32yank/releases/download/v0.0.4/win32yank-x64.zip)
set(WIN32YANK_X86_64_SHA256 33a747a92da60fb65e668edbf7661d3d902411a2d545fe9dc08623cecd142a20)
-set(WINPTY_URL https://github.com/rprichard/winpty/releases/download/0.4.2/winpty-0.4.2-msvc2015.zip)
-set(WINPTY_SHA256 b465f2584ff394b3fe27c01aa1dcfc679583c1ee951d0e83de3f859d8b8305b8)
+set(WINPTY_URL https://github.com/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msvc2015.zip)
+set(WINPTY_SHA256 35a48ece2ff4acdcbc8299d4920de53eb86b1fb41e64d2fe5ae7898931bcee89)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)