aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig3
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--.github/workflows/squash-typos.yml33
-rw-r--r--CMakeLists.txt23
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--cmake/RunTests.cmake4
-rw-r--r--config/CMakeLists.txt13
-rw-r--r--config/config.h.in1
-rw-r--r--runtime/autoload/dist/ft.vim19
-rw-r--r--runtime/autoload/health.vim36
-rw-r--r--runtime/autoload/msgpack.vim6
-rw-r--r--runtime/doc/api.txt36
-rw-r--r--runtime/doc/autocmd.txt12
-rw-r--r--runtime/doc/diagnostic.txt18
-rw-r--r--runtime/doc/editing.txt10
-rw-r--r--runtime/doc/eval.txt44
-rw-r--r--runtime/doc/helphelp.txt2
-rw-r--r--runtime/doc/index.txt2
-rw-r--r--runtime/doc/intro.txt4
-rw-r--r--runtime/doc/lsp.txt99
-rw-r--r--runtime/doc/lua.txt32
-rw-r--r--runtime/doc/map.txt7
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt2
-rw-r--r--runtime/doc/options.txt19
-rw-r--r--runtime/doc/quickref.txt4
-rw-r--r--runtime/doc/repeat.txt6
-rw-r--r--runtime/doc/sign.txt5
-rw-r--r--runtime/doc/syntax.txt2
-rw-r--r--runtime/doc/treesitter.txt14
-rw-r--r--runtime/doc/usr_41.txt1
-rw-r--r--runtime/doc/various.txt2
-rw-r--r--runtime/doc/vim_diff.txt5
-rw-r--r--runtime/doc/windows.txt10
-rw-r--r--runtime/filetype.vim19
-rw-r--r--runtime/ftplugin/checkhealth.vim20
-rw-r--r--runtime/ftplugin/i3config.vim13
-rw-r--r--runtime/ftplugin/solution.vim37
-rw-r--r--runtime/ftplugin/zsh.vim8
-rw-r--r--runtime/indent/sh.vim2
-rw-r--r--runtime/indent/xml.vim8
-rw-r--r--runtime/lua/vim/diagnostic.lua56
-rw-r--r--runtime/lua/vim/lsp.lua62
-rw-r--r--runtime/lua/vim/lsp/sync.lua15
-rw-r--r--runtime/lua/vim/lsp/util.lua81
-rw-r--r--runtime/lua/vim/treesitter/query.lua22
-rw-r--r--runtime/optwin.vim4
-rw-r--r--runtime/pack/dist/opt/matchit/autoload/matchit.vim251
-rw-r--r--runtime/pack/dist/opt/matchit/doc/matchit.txt10
-rw-r--r--runtime/pack/dist/opt/matchit/plugin/matchit.vim42
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim57
-rw-r--r--runtime/syntax/c.vim3
-rw-r--r--runtime/syntax/checkhealth.vim28
-rw-r--r--runtime/syntax/css.vim29
-rw-r--r--runtime/syntax/debcontrol.vim20
-rw-r--r--runtime/syntax/dep3patch.vim57
-rw-r--r--runtime/syntax/dtd.vim6
-rw-r--r--runtime/syntax/i3config.vim256
-rw-r--r--runtime/syntax/python.vim5
-rw-r--r--runtime/syntax/texinfo.vim406
-rw-r--r--runtime/syntax/xml.vim12
-rw-r--r--runtime/syntax/zsh.vim223
-rw-r--r--scripts/squash_typos.py263
-rw-r--r--src/mpack/lmpack.c3
-rw-r--r--src/nvim/CMakeLists.txt5
-rw-r--r--src/nvim/api/vim.c14
-rw-r--r--src/nvim/auevents.lua4
-rw-r--r--src/nvim/autocmd.c6
-rw-r--r--src/nvim/edit.c9
-rw-r--r--src/nvim/eval.lua2
-rw-r--r--src/nvim/eval/funcs.c101
-rw-r--r--src/nvim/ex_cmds.c3
-rw-r--r--src/nvim/ex_docmd.c43
-rw-r--r--src/nvim/ex_docmd.h1
-rw-r--r--src/nvim/file_search.c15
-rw-r--r--src/nvim/generators/gen_char_blob.lua52
-rw-r--r--src/nvim/getchar.c4
-rw-r--r--src/nvim/globals.h1
-rw-r--r--src/nvim/lua/executor.c20
-rw-r--r--src/nvim/lua/spell.c99
-rw-r--r--src/nvim/lua/spell.h12
-rw-r--r--src/nvim/lua/stdlib.c11
-rw-r--r--src/nvim/mbyte.c10
-rw-r--r--src/nvim/move.c4
-rw-r--r--src/nvim/normal.c21
-rw-r--r--src/nvim/ops.c21
-rw-r--r--src/nvim/option.c35
-rw-r--r--src/nvim/option.h1
-rw-r--r--src/nvim/option_defs.h1
-rw-r--r--src/nvim/options.lua8
-rw-r--r--src/nvim/os/pty_process_unix.c120
-rw-r--r--src/nvim/popupmnu.c43
-rw-r--r--src/nvim/quickfix.c3
-rw-r--r--src/nvim/regexp_nfa.c36
-rw-r--r--src/nvim/screen.c9
-rw-r--r--src/nvim/sign.c3
-rw-r--r--src/nvim/terminal.c13
-rw-r--r--src/nvim/testdir/runtest.vim6
-rw-r--r--src/nvim/testdir/setup.vim2
-rw-r--r--src/nvim/testdir/test_autocmd.vim90
-rw-r--r--src/nvim/testdir/test_blob.vim8
-rw-r--r--src/nvim/testdir/test_cmdline.vim37
-rw-r--r--src/nvim/testdir/test_display.vim25
-rw-r--r--src/nvim/testdir/test_edit.vim3
-rw-r--r--src/nvim/testdir/test_ex_mode.vim2
-rw-r--r--src/nvim/testdir/test_filechanged.vim149
-rw-r--r--src/nvim/testdir/test_fileformat.vim246
-rw-r--r--src/nvim/testdir/test_filetype.vim47
-rw-r--r--src/nvim/testdir/test_listchars.vim16
-rw-r--r--src/nvim/testdir/test_messages.vim8
-rw-r--r--src/nvim/testdir/test_options.vim21
-rw-r--r--src/nvim/testdir/test_signs.vim25
-rw-r--r--src/nvim/testdir/test_substitute.vim2
-rw-r--r--src/nvim/testdir/test_timers.vim2
-rw-r--r--src/nvim/testdir/test_visual.vim2
-rw-r--r--src/nvim/tui/input.c6
-rw-r--r--src/nvim/tui/tui.c43
-rw-r--r--test/README.md6
-rw-r--r--test/functional/api/vim_spec.lua74
-rw-r--r--test/functional/autocmd/cursormoved_spec.lua8
-rw-r--r--test/functional/autocmd/recording_spec.lua52
-rw-r--r--test/functional/editor/macro_spec.lua27
-rw-r--r--test/functional/editor/mode_insert_spec.lua11
-rw-r--r--test/functional/editor/mode_visual_spec.lua27
-rw-r--r--test/functional/legacy/options_spec.lua5
-rw-r--r--test/functional/lua/spell_spec.lua53
-rw-r--r--test/functional/lua/vim_spec.lua90
-rw-r--r--test/functional/plugin/health_spec.lua6
-rw-r--r--test/functional/plugin/lsp/incremental_sync_spec.lua269
-rw-r--r--test/functional/plugin/lsp_spec.lua37
-rw-r--r--test/functional/terminal/channel_spec.lua28
-rw-r--r--test/functional/terminal/scrollback_spec.lua70
-rw-r--r--test/functional/terminal/tui_spec.lua74
-rw-r--r--test/functional/ui/popupmenu_spec.lua130
-rw-r--r--test/functional/vimscript/screenpos_spec.lua51
-rw-r--r--third-party/CMakeLists.txt8
-rw-r--r--third-party/cmake/BuildLuajit.cmake10
136 files changed, 3298 insertions, 1707 deletions
diff --git a/.editorconfig b/.editorconfig
index bb6a1423ef..22fee54b22 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -8,6 +8,9 @@ end_of_line = lf
insert_final_newline = true
charset = utf-8
+[*.{c,h,in,lua}]
+max_line_length = 100
+
[{Makefile,**/Makefile,runtime/doc/*.txt}]
indent_style = tab
indent_size = 8
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6a81ee4238..d2eef13098 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,6 +10,11 @@ on:
- 'master'
- 'release-[0-9]+.[0-9]+'
+# Cancel any in-progress CI runs for a PR if it is updated
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
+ cancel-in-progress: true
+
jobs:
unixish:
name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
diff --git a/.github/workflows/squash-typos.yml b/.github/workflows/squash-typos.yml
deleted file mode 100644
index 6779589dc6..0000000000
--- a/.github/workflows/squash-typos.yml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Squash Typo Pull Requests
-
-on:
- pull_request_target:
- types: labeled
-concurrency:
- group: ${{ github.workflow }}
-jobs:
- build:
- if: github.event.label.name == 'typo'
- runs-on: ubuntu-latest
-
- permissions:
- contents: write
- pull-requests: write
-
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 0
- - uses: actions/setup-python@v2
-
- - name: Setup git config
- run: |
- git config --global user.name 'marvim'
- git config --global user.email 'marvim@users.noreply.github.com'
-
- - run: python scripts/squash_typos.py
- env:
- PR_NUMBER: ${{ github.event.number }}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b62ca8556..9f1829cf55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -543,6 +543,29 @@ endif()
message(STATUS "Using Lua interpreter: ${LUA_PRG}")
+option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
+
+if(COMPILE_LUA AND NOT WIN32)
+ if(PREFER_LUA)
+ foreach(CURRENT_LUAC_PRG luac5.1 luac)
+ find_program(_CHECK_LUAC_PRG ${CURRENT_LUAC_PRG})
+ if(_CHECK_LUAC_PRG)
+ set(LUAC_PRG "${_CHECK_LUAC_PRG} -s -o - %s" CACHE STRING "Format for compiling to Lua bytecode")
+ break()
+ endif()
+ endforeach()
+ elseif(LUA_PRG MATCHES "luajit")
+ check_lua_module(${LUA_PRG} "jit.bcsave" LUAJIT_HAS_JIT_BCSAVE)
+ if(LUAJIT_HAS_JIT_BCSAVE)
+ set(LUAC_PRG "${LUA_PRG} -b -s %s -" CACHE STRING "Format for compiling to Lua bytecode")
+ endif()
+ endif()
+endif()
+
+if(LUAC_PRG)
+ message(STATUS "Using Lua compiler: ${LUAC_PRG}")
+endif()
+
# Setup busted.
find_program(BUSTED_PRG NAMES busted busted.bat)
find_program(BUSTED_LUA_PRG busted-lua)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index faf9181a2c..b02aeb1ed1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@ If you want to help but don't know where to start, here are some
low-risk/isolated tasks:
- [Merge a Vim patch].
-- Try a [good first issue](../../labels/good-first-issue) or [complexity:low] issue.
+- Try a [complexity:low] issue.
- Fix bugs found by [Clang](#clang-scan-build), [PVS](#pvs-studio) or
[Coverity](#coverity).
- [Improve documentation][wiki-contribute-help]
diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake
index e78392562f..3adbcbbfc5 100644
--- a/cmake/RunTests.cmake
+++ b/cmake/RunTests.cmake
@@ -46,6 +46,10 @@ if(DEFINED ENV{TEST_FILTER} AND NOT "$ENV{TEST_FILTER}" STREQUAL "")
list(APPEND BUSTED_ARGS --filter $ENV{TEST_FILTER})
endif()
+if(DEFINED ENV{TEST_FILTER_OUT} AND NOT "$ENV{TEST_FILTER_OUT}" STREQUAL "")
+ list(APPEND BUSTED_ARGS --filter-out $ENV{TEST_FILTER_OUT})
+endif()
+
# TMPDIR: use relative test path (for parallel test runs / isolation).
set(ENV{TMPDIR} "${BUILD_DIR}/Xtest_tmpdir/${TEST_PATH}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory $ENV{TMPDIR})
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 30f08c5297..8f93e1eb27 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -50,6 +50,19 @@ check_function_exists(strcasecmp HAVE_STRCASECMP)
check_function_exists(strncasecmp HAVE_STRNCASECMP)
check_function_exists(strptime HAVE_STRPTIME)
+if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ check_c_source_compiles("
+#include <termios.h>
+int
+main(void)
+{
+ return forkpty(0, NULL, NULL, NULL);
+}
+" HAVE_FORKPTY)
+else()
+ set(HAVE_FORKPTY 1)
+endif()
+
# Symbols
check_symbol_exists(FD_CLOEXEC "fcntl.h" HAVE_FD_CLOEXEC)
if(HAVE_LANGINFO_H)
diff --git a/config/config.h.in b/config/config.h.in
index b0635fb52b..b44b7238d2 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -50,6 +50,7 @@
# undef HAVE_SYS_UIO_H
# endif
#endif
+#cmakedefine HAVE_FORKPTY
#cmakedefine FEAT_TUI
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index a3db4ae87a..9933ace8c2 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -1,7 +1,7 @@
" Vim functions for file type detection
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2021 Nov 27
+" Last Change: 2021 Dec 17
" These functions are moved here from runtime/filetype.vim to make startup
" faster.
@@ -811,6 +811,23 @@ func dist#ft#Redif()
endwhile
endfunc
+" This function is called for all files under */debian/patches/*, make sure not
+" to non-dep3patch files, such as README and other text files.
+func dist#ft#Dep3patch()
+ if expand('%:t') ==# 'series'
+ return
+ endif
+
+ for ln in getline(1, 100)
+ if ln =~# '^\%(Description\|Subject\|Origin\|Bug\|Forwarded\|Author\|From\|Reviewed-by\|Acked-by\|Last-Updated\|Applied-Upstream\):'
+ setf dep3patch
+ return
+ elseif ln =~# '^---'
+ " end of headers found. stop processing
+ return
+ endif
+ endfor
+endfunc
" Restore 'cpoptions'
let &cpo = s:cpo_save
diff --git a/runtime/autoload/health.vim b/runtime/autoload/health.vim
index 73c1459f86..1d462ad02c 100644
--- a/runtime/autoload/health.vim
+++ b/runtime/autoload/health.vim
@@ -1,27 +1,3 @@
-function! s:enhance_syntax() abort
- syntax case match
-
- syntax keyword healthError ERROR[:]
- \ containedin=markdownCodeBlock,mkdListItemLine
- highlight default link healthError Error
-
- syntax keyword healthWarning WARNING[:]
- \ containedin=markdownCodeBlock,mkdListItemLine
- highlight default link healthWarning WarningMsg
-
- syntax keyword healthSuccess OK[:]
- \ containedin=markdownCodeBlock,mkdListItemLine
- highlight default healthSuccess guibg=#5fff00 guifg=#080808 ctermbg=82 ctermfg=232
-
- syntax match healthHelp "|.\{-}|" contains=healthBar
- \ containedin=markdownCodeBlock,mkdListItemLine
- syntax match healthBar "|" contained conceal
- highlight default link healthHelp Identifier
-
- " We do not care about markdown syntax errors in :checkhealth output.
- highlight! link markdownError Normal
-endfunction
-
" Runs the specified healthchecks.
" Runs all discovered healthchecks if a:plugin_names is empty.
function! health#check(plugin_names) abort
@@ -29,13 +5,9 @@ function! health#check(plugin_names) abort
\ ? s:discover_healthchecks()
\ : s:get_healthcheck(a:plugin_names)
- tabnew
- setlocal wrap breakindent linebreak
- setlocal filetype=markdown
- setlocal conceallevel=2 concealcursor=nc
- setlocal keywordprg=:help
- let &l:iskeyword='!-~,^*,^|,^",192-255'
- call s:enhance_syntax()
+ " create scratch-buffer
+ execute 'tab sbuffer' nvim_create_buf(v:true, v:true)
+ setfiletype checkhealth
if empty(healthchecks)
call setline(1, 'ERROR: No healthchecks found.')
@@ -70,8 +42,6 @@ function! health#check(plugin_names) abort
" needed for plasticboy/vim-markdown, because it uses fdm=expr
normal! zR
- setlocal nomodified
- setlocal bufhidden=hide
redraw|echo ''
endfunction
diff --git a/runtime/autoload/msgpack.vim b/runtime/autoload/msgpack.vim
index 7dd225e3d9..7f98a5b230 100644
--- a/runtime/autoload/msgpack.vim
+++ b/runtime/autoload/msgpack.vim
@@ -56,6 +56,7 @@ function s:msgpack_init_python() abort
\. " time = datetime.datetime.fromtimestamp(timestamp)\n"
\. " return time.strftime(fmt)\n"
\. "def shada_dict_strptime():\n"
+ \. " import calendar\n"
\. " import datetime\n"
\. " import vim\n"
\. " fmt = vim.eval('a:format')\n"
@@ -64,7 +65,10 @@ function s:msgpack_init_python() abort
\. " try:\n"
\. " timestamp = int(timestamp.timestamp())\n"
\. " except:\n"
- \. " timestamp = int(timestamp.strftime('%s'))\n"
+ \. " try:\n"
+ \. " timestamp = int(timestamp.strftime('%s'))\n"
+ \. " except:\n"
+ \. " timestamp = calendar.timegm(timestamp.utctimetuple())\n"
\. " if timestamp > 2 ** 31:\n"
\. " tsabs = abs(timestamp)\n"
\. " return ('{\"_TYPE\": v:msgpack_types.integer,'\n"
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index d2d010882e..8fb6290e50 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1018,7 +1018,7 @@ nvim_get_mode() *nvim_get_mode()*
{fast}
nvim_get_option({name}) *nvim_get_option()*
- Gets an option value string.
+ Gets the global value of an option.
Parameters: ~
{name} Option name
@@ -1049,6 +1049,24 @@ nvim_get_option_info({name}) *nvim_get_option_info()*
Return: ~
Option Information
+nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
+ Gets the value of an option. The behavior of this function
+ matches that of |:set|: the local value of an option is
+ returned if it exists; otherwise, the global value is
+ returned. Local values always correspond to the current buffer
+ or window. To get a buffer-local or window-local option for a
+ specific buffer or window, use |nvim_buf_get_option()| or
+ |nvim_win_get_option()|.
+
+ Parameters: ~
+ {name} Option name
+ {opts} Optional parameters
+ • scope: One of 'global' or 'local'. Analagous to
+ |:setglobal| and |:setlocal|, respectively.
+
+ Return: ~
+ Option value
+
nvim_get_proc({pid}) *nvim_get_proc()*
Gets info describing process `pid` .
@@ -1510,11 +1528,25 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
key is an error.
nvim_set_option({name}, {value}) *nvim_set_option()*
- Sets an option value.
+ Sets the global value of an option.
+
+ Parameters: ~
+ {name} Option name
+ {value} New option value
+
+ *nvim_set_option_value()*
+nvim_set_option_value({name}, {value}, {*opts})
+ Sets the value of an option. The behavior of this function
+ matches that of |:set|: for global-local options, both the
+ global and local value are set unless otherwise specified with
+ {scope}.
Parameters: ~
{name} Option name
{value} New option value
+ {opts} Optional parameters
+ • scope: One of 'global' or 'local'. Analagous to
+ |:setglobal| and |:setlocal|, respectively.
nvim_set_var({name}, {value}) *nvim_set_var()*
Sets a global (g:) variable.
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 242631d98c..3df8d5ced4 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -828,6 +828,18 @@ RemoteReply When a reply from a Vim that functions as
SearchWrapped After making a search with |n| or |N| if the
search wraps around the document back to
the start/finish respectively.
+ *RecordingEnter*
+RecordingEnter When a macro starts recording.
+ The pattern is the current file name, and
+ |reg_recording()| is the current register that
+ is used.
+ *RecordingLeave*
+RecordingLeave When a macro stops recording.
+ The pattern is the current file name, and
+ |reg_recording()| is the recorded
+ register.
+ |reg_recorded()| is only updated after this
+ event.
*SessionLoadPost*
SessionLoadPost After loading the session file created using
the |:mksession| command.
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 0893f1f343..a825435179 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -347,9 +347,12 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• severity: Only show virtual text for
diagnostics matching the given severity
|diagnostic-severity|
- • source: (string) Include the diagnostic
- source in virtual text. One of "always"
- or "if_many".
+ • source: (boolean or string) Include the
+ diagnostic source in virtual text. Use
+ "if_many" to only show sources if there
+ is more than one diagnostic source in the
+ buffer. Otherwise, any truthy value means
+ to always show the diagnostic source.
• format: (function) A function that takes
a diagnostic as input and returns a
string. The return value is the text used
@@ -608,9 +611,12 @@ open_float({opts}, {...}) *vim.diagnostic.open_float()*
is interpreted as a [text, hl_group] tuple.
Overrides the setting from
|vim.diagnostic.config()|.
- • source: (string) Include the diagnostic source
- in the message. One of "always" or "if_many".
- Overrides the setting from
+ • source: (boolean or string) Include the
+ diagnostic source in the message. Use "if_many"
+ to only show sources if there is more than one
+ source of diagnostics in the buffer. Otherwise,
+ any truthy value means to always show the
+ diagnostic source. Overrides the setting from
|vim.diagnostic.config()|.
• format: (function) A function that takes a
diagnostic as input and returns a string. The
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 4e3173cfa9..14df41e6c8 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1253,10 +1253,12 @@ working directory. If a local working directory (tab or window) does not
exist, the next-higher scope in the hierarchy applies.
*:cd* *E747* *E472*
-:cd[!] On non-Unix systems: Print the current directory
- name. On Unix systems: Change the current directory
- to the home directory. Use |:pwd| to print the
- current directory on all systems.
+:cd[!] On non-Unix systems when 'cdhome' is off: Print the
+ current directory name.
+ Otherwise: Change the current directory to the home
+ directory. Clear any window-local directory.
+ Use |:pwd| to print the current directory on all
+ systems.
:cd[!] {path} Change the current directory to {path}.
If {path} is relative, it is searched for in the
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 75b782fbff..63f6c5628a 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2410,10 +2410,11 @@ foldlevel({lnum}) Number fold level at {lnum}
foldtext() String line displayed for closed fold
foldtextresult({lnum}) String text for closed fold at {lnum}
foreground() Number bring the Vim window to the foreground
+fullcommand({name}) String get full command from {name}
funcref({name} [, {arglist}] [, {dict}])
- Funcref reference to function {name}
+ Funcref reference to function {name}
function({name} [, {arglist}] [, {dict}])
- Funcref named reference to function {name}
+ Funcref named reference to function {name}
garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
@@ -2588,6 +2589,7 @@ readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
readfile({fname} [, {type} [, {max}]])
List get list of lines from file {fname}
reg_executing() String get the executing register name
+reg_recorded() String get the last recorded register name
reg_recording() String get the recording register name
reltime([{start} [, {end}]]) List get time value
reltimefloat({time}) Float turn the time value into a Float
@@ -4161,11 +4163,12 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
Can also be used as a |method|: >
Getpattern()->expand()
-expandcmd({expr}) *expandcmd()*
- Expand special items in {expr} like what is done for an Ex
- command such as `:edit`. This expands special keywords, like
- with |expand()|, and environment variables, anywhere in
- {expr}. "~user" and "~/path" are only expanded at the start.
+expandcmd({string}) *expandcmd()*
+ Expand special items in String {string} like what is done for
+ an Ex command such as `:edit`. This expands special keywords,
+ like with |expand()|, and environment variables, anywhere in
+ {string}. "~user" and "~/path" are only expanded at the
+ start.
Returns the expanded string. Example: >
:echo expandcmd('make %<.o')
@@ -4549,6 +4552,21 @@ foreground() Move the Vim window to the foreground. Useful when sent from
|remote_foreground()| instead.
{only in the Win32 GUI and console version}
+fullcommand({name}) *fullcommand()*
+ Get the full command name from a short abbreviated command
+ name; see |20.2| for details on command abbreviations.
+
+ The string argument {name} may start with a `:` and can
+ include a [range], these are skipped and not returned.
+ Returns an empty string if a command doesn't exist or if it's
+ ambiguous (for user-defined commands).
+
+ For example `fullcommand('s')`, `fullcommand('sub')`,
+ `fullcommand(':%substitute')` all return "substitute".
+
+ Can also be used as a |method|: >
+ GetName()->fullcommand()
+<
*funcref()*
funcref({name} [, {arglist}] [, {dict}])
Just like |function()|, but the returned Funcref will lookup
@@ -5419,8 +5437,9 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()*
The result is a String, which is the contents of register
{regname}. Example: >
:let cliptext = getreg('*')
-< When {regname} was not set the result is an empty string.
- The {regname} argument is a string.
+< When register {regname} was not set the result is an empty
+ string.
+ The {regname} argument must be a string.
getreg('=') returns the last evaluated value of the expression
register. (For use in maps.)
@@ -7201,7 +7220,7 @@ mode([expr]) Return a string that indicates the current mode.
Rvc Virtual Replace mode completion |compl-generic|
Rvx Virtual Replace mode |i_CTRL-X| completion
c Command-line editing
- cv Vim Ex mode |Q| or |gQ|
+ cv Vim Ex mode |gQ|
r Hit-enter prompt
rm The -- more -- prompt
r? A |:confirm| query of some sort
@@ -7825,6 +7844,11 @@ reg_executing() *reg_executing()*
Returns an empty string when no register is being executed.
See |@|.
+reg_recorded() *reg_recorded()*
+ Returns the single letter name of the last recorded register.
+ Returns an empty string string when nothing was recorded yet.
+ See |q| and |Q|.
+
reg_recording() *reg_recording()*
Returns the single letter name of the register being recorded.
Returns an empty string string when not recording. See |q|.
diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt
index e7b489d6e1..9cc7d063a8 100644
--- a/runtime/doc/helphelp.txt
+++ b/runtime/doc/helphelp.txt
@@ -164,7 +164,7 @@ If you would like to open the help in the current window, see this tip:
The initial height of the help window can be set with the 'helpheight' option
(default 20).
-
+ *help-buffer-options*
When the help buffer is created, several local options are set to make sure
the help text is displayed as it was intended:
'iskeyword' nearly all ASCII chars except ' ', '*', '"' and '|'
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index baa7bc1992..d8689e2c65 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -339,7 +339,6 @@ tag char note action in Normal mode ~
insert text, repeat N times
|P| ["x]P 2 put the text [from register x] before the
cursor N times
-|Q| Q switch to "Ex" mode
|R| R 2 enter replace mode: overtype existing
characters, repeat the entered text N-1
times
@@ -401,6 +400,7 @@ tag char note action in Normal mode ~
|q| q{0-9a-zA-Z"} record typed characters into named register
{0-9a-zA-Z"} (uppercase to append)
|q| q (while recording) stops recording
+|Q| Q replay last recorded macro
|q:| q: edit : command-line in command-line window
|q/| q/ edit / command-line in command-line window
|q?| q? edit ? command-line in command-line window
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index a89263861b..0e0156ac6b 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -563,8 +563,8 @@ The command CTRL-\ CTRL-G or <C-\><C-G> can be used to go to Insert mode when
make sure Vim is in the mode indicated by 'insertmode', without knowing in
what mode Vim currently is.
- *gQ* *Q* *mode-Ex* *Ex-mode* *Ex* *EX* *E501*
-Q or gQ Switch to Ex mode. This is like typing ":" commands
+ *gQ* *mode-Ex* *Ex-mode* *Ex* *EX* *E501*
+gQ Switch to Ex mode. This is like typing ":" commands
one after another, except:
- You don't have to keep pressing ":".
- The screen doesn't get updated after each command.
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 11f9d62e69..a3929aeab9 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -485,6 +485,16 @@ buf_attach_client({bufnr}, {client_id}) *vim.lsp.buf_attach_client()*
{bufnr} (number) Buffer handle, or 0 for current
{client_id} (number) Client id
+buf_detach_client({bufnr}, {client_id}) *vim.lsp.buf_detach_client()*
+ Detaches client from the specified buffer. Note: While the
+ server is notified that the text document (buffer) was closed,
+ it is still able to send notifications should it ignore this
+ notification.
+
+ Parameters: ~
+ {bufnr} number Buffer handle, or 0 for current
+ {client_id} number Client id
+
buf_get_clients({bufnr}) *vim.lsp.buf_get_clients()*
Gets a map of client_id:client pairs for the given buffer,
where each value is a |vim.lsp.client| object.
@@ -630,6 +640,12 @@ client() *vim.lsp.client*
server.
• {handlers} (table): The handlers used by the client as
described in |lsp-handler|.
+ • {requests} (table): The current pending requests in flight
+ to the server. Entries are key-value pairs with the key
+ being the request ID while the value is a table with
+ `type` , `bufnr` , and `method` key-value pairs. `type` is
+ either "pending" for an active request, or "cancel" for a
+ cancel request.
• {config} (table): copy of the table that was passed by the
user to |vim.lsp.start_client()|.
• {server_capabilities} (table): Response from the server
@@ -1326,12 +1342,14 @@ apply_text_document_edit({text_document_edit}, {index})
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
*vim.lsp.util.apply_text_edits()*
-apply_text_edits({text_edits}, {bufnr})
+apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
Applies a list of text edits to a buffer.
Parameters: ~
- {text_edits} table list of `TextEdit` objects
- {bufnr} number Buffer id
+ {text_edits} table list of `TextEdit` objects
+ {bufnr} number Buffer id
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to encoding of first client of `bufnr`
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
@@ -1358,37 +1376,30 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding})
{references} table List of `DocumentHighlight`
objects to highlight
{offset_encoding} string One of "utf-8", "utf-16",
- "utf-32", or nil. Defaults to utf-16
+ "utf-32", or nil. Defaults to
+ `offset_encoding` of first client of
+ `bufnr`
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
*vim.lsp.util.character_offset()*
-character_offset({bufnr}, {row}, {col})
+character_offset({buf}, {row}, {col}, {offset_encoding})
Returns the UTF-32 and UTF-16 offsets for a position in a
certain buffer.
Parameters: ~
- {buf} buffer id (0 for current)
- {row} 0-indexed line
- {col} 0-indexed byte offset in line
+ {buf} buffer id (0 for current)
+ {row} 0-indexed line
+ {col} 0-indexed byte offset in line
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ `buf`
Return: ~
- (number, number) UTF-32 and UTF-16 index of the character
+ (number, number) `offset_encoding` index of the character
in line {row} column {col} in buffer {buf}
- *vim.lsp.util.close_preview_autocmd()*
-close_preview_autocmd({events}, {winnr})
- Creates autocommands to close a preview window when events
- happen.
-
- Parameters: ~
- {events} (table) list of events
- {winnr} (number) window id of preview window
-
- See also: ~
- |autocmd-events|
-
*vim.lsp.util.convert_input_to_markdown_lines()*
convert_input_to_markdown_lines({input}, {contents})
Converts any of `MarkedString` | `MarkedString[]` |
@@ -1528,47 +1539,73 @@ make_formatting_params({options})
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
*vim.lsp.util.make_given_range_params()*
-make_given_range_params({start_pos}, {end_pos})
+make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
Using the given range in the current buffer, creates an object
that is similar to |vim.lsp.util.make_range_params()|.
Parameters: ~
- {start_pos} ({number, number}, optional) mark-indexed
- position. Defaults to the start of the last
- visual selection.
- {end_pos} ({number, number}, optional) mark-indexed
- position. Defaults to the end of the last
- visual selection.
+ {start_pos} ({number, number}, optional)
+ mark-indexed position. Defaults to the
+ start of the last visual selection.
+ {end_pos} ({number, number}, optional)
+ mark-indexed position. Defaults to the
+ end of the last visual selection.
+ {bufnr} (optional, number): buffer handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ `bufnr`
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
start = `start_position` , end = `end_position` } }
-make_position_params() *vim.lsp.util.make_position_params()*
+ *vim.lsp.util.make_position_params()*
+make_position_params({window}, {offset_encoding})
Creates a `TextDocumentPositionParams` object for the current
buffer and cursor position.
+ Parameters: ~
+ {window} (optional, number): window handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ buffer of `window`
+
Return: ~
`TextDocumentPositionParams` object
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
-make_range_params() *vim.lsp.util.make_range_params()*
+ *vim.lsp.util.make_range_params()*
+make_range_params({window}, {offset_encoding})
Using the current position in the current buffer, creates an
object that can be used as a building block for several LSP
requests, such as `textDocument/codeAction` ,
`textDocument/colorPresentation` ,
`textDocument/rangeFormatting` .
+ Parameters: ~
+ {window} (optional, number): window handle or 0
+ for current, defaults to current
+ {offset_encoding} string utf-8|utf-16|utf-32|nil defaults
+ to `offset_encoding` of first client of
+ buffer of `window`
+
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
start = `current_position` , end = `current_position` } }
-make_text_document_params() *vim.lsp.util.make_text_document_params()*
+ *vim.lsp.util.make_text_document_params()*
+make_text_document_params({bufnr})
Creates a `TextDocumentIdentifier` object for the current
buffer.
+ Parameters: ~
+ {bufnr} (optional, number): Buffer handle, defaults to
+ current
+
Return: ~
`TextDocumentIdentifier`
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 630df16e79..97062e5986 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -708,6 +708,38 @@ vim.mpack.decode({str}) *vim.mpack.decode*
Decodes (or "unpacks") the msgpack-encoded {str} to a Lua object.
------------------------------------------------------------------------------
+VIM.SPELL *lua-spell*
+
+vim.spell.check({str}) *vim.spell.check()*
+ Check {str} for spelling errors. Similar to the Vimscript function
+ |spellbadword()|.
+
+ Note: The behaviour of this function is dependent on: 'spelllang',
+ 'spellfile', 'spellcapcheck' and 'spelloptions' which can all be local
+ to the buffer. Consider calling this with |nvim_buf_call()|.
+
+ Example: >
+ vim.spell.check("the quik brown fox")
+ -->
+ {
+ {'quik', 'bad', 4}
+ }
+<
+
+ Parameters: ~
+ {str} String to spell check.
+
+ Return: ~
+ List of tuples with three items:
+ - The badly spelled word.
+ - The type of the spelling error:
+ "bad" spelling mistake
+ "rare" rare word
+ "local" word only valid in another region
+ "caps" word should start with Capital
+ - The position in {str} where the word begins.
+
+------------------------------------------------------------------------------
VIM *lua-builtin*
vim.api.{func}({...}) *vim.api*
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 0ea2565694..238ef39bd3 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -158,7 +158,7 @@ type "a", then "bar" will get inserted.
"<unique>" can be used in any order. They must appear right after the
command, before any other arguments.
- *:map-local* *:map-<buffer>* *E224* *E225*
+ *:map-local* *:map-<buffer>* *:map-buffer* *E224* *E225*
If the first argument to one of these commands is "<buffer>" the mapping will
be effective in the current buffer only. Example: >
:map <buffer> ,w /[.,;]<CR>
@@ -211,7 +211,7 @@ Note: ":map <script>" and ":noremap <script>" do the same thing. The
"<script>" overrules the command name. Using ":noremap <script>" is
preferred, because it's clearer that remapping is (mostly) disabled.
- *:map-<unique>* *E226* *E227*
+ *:map-<unique>* *:map-unique* *E226* *E227*
If the first argument to one of these commands is "<unique>" and it is used to
define a new mapping or abbreviation, the command will fail if the mapping or
abbreviation already exists. Example: >
@@ -837,8 +837,7 @@ g@{motion} Call the function set by the 'operatorfunc' option.
"line" {motion} was |linewise|
"char" {motion} was |charwise|
"block" {motion} was |blockwise-visual|
- Although "block" would rarely appear, since it can
- only result from Visual mode where "g@" is not useful.
+ The type can be forced, see |forced-motion|.
Here is an example that counts the number of spaces with <F4>: >
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index e83b17f9a0..e1ae138d90 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -391,6 +391,8 @@ GDB command *termdebug-customizing*
To change the name of the gdb command, set the "termdebugger" variable before
invoking `:Termdebug`: >
let termdebugger = "mygdb"
+If the command needs an argument use a List: >
+ let g:termdebugger = ['rr', 'replay', '--']
To not use neovim floating windows for previewing variable evaluation, set the
`g:termdebug_useFloatingHover` variable like this: >
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 47633c750c..c929178f5a 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -953,7 +953,6 @@ A jump table for the options with a short description can be found at |Q_op|.
error Other Error occurred (e.g. try to join last line)
(mostly used in |Normal-mode| or |Cmdline-mode|).
esc hitting <Esc> in |Normal-mode|.
- ex In |Visual-mode|, hitting |Q| results in an error.
hangul Ignored.
insertmode Pressing <Esc> in 'insertmode'.
lang Calling the beep module for Lua/Mzscheme/TCL.
@@ -1160,6 +1159,14 @@ A jump table for the options with a short description can be found at |Q_op|.
case mapping, the current locale is not effective.
This probably only matters for Turkish.
+ *'cdhome'* *'cdh'*
+'cdhome' 'cdh' boolean (default: off)
+ global
+ When on, |:cd|, |:tcd| and |:lcd| without an argument changes the
+ current working directory to the |$HOME| directory like in Unix.
+ When off, those commands just print the current directory name.
+ On Unix this option has no effect.
+
*'cdpath'* *'cd'* *E344* *E346*
'cdpath' 'cd' string (default: equivalent to $CDPATH or ",,")
global
@@ -3229,10 +3236,14 @@ A jump table for the options with a short description can be found at |Q_op|.
'inccommand' 'icm' string (default "nosplit")
global
- "nosplit": Shows the effects of a command incrementally, as you type.
- "split" : Also shows partial off-screen results in a preview window.
+ When nonempty, shows the effects of |:substitute|, |:smagic|, and
+ |:snomagic| as you type.
- Works for |:substitute|, |:smagic|, |:snomagic|. |hl-Substitute|
+ Possible values:
+ nosplit Shows the effects of a command incrementally in the
+ buffer.
+ split Like "nosplit", but also shows partial off-screen
+ results in a preview window.
If the preview is too slow (exceeds 'redrawtime') then 'inccommand' is
automatically disabled until |Command-line-mode| is done.
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 8cabf05053..af8301f1a0 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -489,6 +489,7 @@ In Insert or Command-line mode:
|q| q{a-z} record typed characters into register {a-z}
|q| q{A-Z} record typed characters, appended to register {a-z}
|q| q stop recording
+|Q| Q replay last recorded macro
|@| N @{a-z} execute the contents of register {a-z} (N times)
|@@| N @@ repeat previous @{a-z} (N times)
|:@| :@{a-z} execute the contents of register {a-z} as an Ex
@@ -628,6 +629,7 @@ Short explanation of each option: *option-list*
'buflisted' 'bl' whether the buffer shows up in the buffer list
'buftype' 'bt' special type of buffer
'casemap' 'cmp' specifies how case of letters is changed
+'cdhome' 'cdh' change directory to the home directory by ":cd"
'cdpath' 'cd' list of directories searched with ":cd"
'cedit' key used to open the command-line window
'charconvert' 'ccv' expression for character encoding conversion
@@ -997,7 +999,7 @@ Short explanation of each option: *option-list*
|:version| :ve[rsion] show version information
|:normal| :norm[al][!] {commands}
execute Normal mode commands
-|Q| Q switch to "Ex" mode
+|gQ| gQ switch to "Ex" mode
|:redir| :redir >{file} redirect messages to {file}
|:silent| :silent[!] {command} execute {command} silently
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 7e8d93aa71..c7481ad290 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -103,7 +103,7 @@ Which is two characters shorter!
When using "global" in Ex mode, a special case is using ":visual" as a
command. This will move to a matching line, go to Normal mode to let you
-execute commands there until you use |Q| to return to Ex mode. This will be
+execute commands there until you use |gQ| to return to Ex mode. This will be
repeated for each matching line. While doing this you cannot use ":global".
To abort this type CTRL-C twice.
@@ -147,6 +147,10 @@ q Stops recording.
*@@* *E748*
@@ Repeat the previous @{0-9a-z":*} [count] times.
+ *Q*
+Q Repeat the last recorded register [count] times.
+ See |reg_recorded()|.
+
*:@*
:[addr]@{0-9a-z".=*+} Execute the contents of register {0-9a-z".=*+} as an Ex
command. First set cursor at line [addr] (default is
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index 68165f3d3d..5cfa06c33c 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -122,8 +122,9 @@ See |sign_define()| for the equivalent Vim script function.
in. Most useful is defining a background color.
numhl={group}
- Highlighting group used for 'number' column at the associated
- line. Overrides |hl-LineNr|, |hl-CursorLineNr|.
+ Highlighting group used for the line number on the line where
+ the sign is placed. Overrides |hl-LineNr|, |hl-LineNrAbove|,
+ |hl-LineNrBelow|, and |hl-CursorLineNr|.
text={text} *E239*
Define the text that is displayed when there is no icon or the
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index d49809599d..0fd481cd83 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -4455,7 +4455,7 @@ it marks the "\(\I\i*\)" sub-expression as external; in the end pattern, it
changes the \z1 back-reference into an external reference referring to the
first external sub-expression in the start pattern. External references can
also be used in skip patterns: >
- :syn region foo start="start \(\I\i*\)" skip="not end \z1" end="end \z1"
+ :syn region foo start="start \z(\I\i*\)" skip="not end \z1" end="end \z1"
Note that normal and external sub-expressions are completely orthogonal and
indexed separately; for instance, if the pattern "\z(..\)\(..\)" is applied
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 08dc0583ac..8f7241dd46 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -421,9 +421,9 @@ get_node_text({node}, {source}) *get_node_text()*
Gets the text corresponding to a given node
Parameters: ~
- {node} the node
- {bsource} The buffer or string from which the node is
- extracted
+ {node} the node
+ {source} The buffer or string from which the node is
+ extracted
get_query({lang}, {query_name}) *get_query()*
Returns the runtime query {query_name} for {lang}.
@@ -530,11 +530,9 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
for id, node in pairs(match) do
local name = query.captures[id]
-- `node` was captured by the `name` capture in the match
-<
->
- local node_data = metadata[id] -- Node level metadata
-<
->
+
+ local node_data = metadata[id] -- Node level metadata
+
... use the info here ...
end
end
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 6a9284dac9..7e611a47f3 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -852,6 +852,7 @@ Command line: *command-line-functions*
getcmdtype() return the current command-line type
getcmdwintype() return the current command-line window type
getcompletion() list of command-line completion matches
+ fullcommand() get full command name
Quickfix and location lists: *quickfix-functions*
getqflist() list of quickfix errors
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index b0e0bdcb84..8a4468a130 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -387,7 +387,7 @@ g8 Print the hex values of the bytes used in the
|:marks| - filter by text in the current file,
or file name for other files
|:oldfiles| - filter by file name
- |:set| - filter by variable name
+ |:set| - filter by option name
Only normal messages are filtered, error messages are
not.
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index bc59ea785e..4fcaf15717 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -180,6 +180,8 @@ Commands:
|:match| can be invoked before highlight group is defined
Events:
+ |RecordingEnter|
+ |RecordingLeave|
|SearchWrapped|
|Signal|
|TabNewEntered|
@@ -356,7 +358,8 @@ Motion:
The |jumplist| avoids useless/phantom jumps.
Normal commands:
- |Q| is the same as |gQ|
+ |Q| replays the last recorded macro instead of switching to Ex mode.
+ Instead |gQ| can be used to enter Ex mode.
Options:
'ttimeout', 'ttimeoutlen' behavior was simplified
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index e0c33fa2c9..bb31895c96 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -116,10 +116,12 @@ other windows. If 'mouse' is enabled, a status line can be dragged to resize
windows.
*filler-lines*
-The lines after the last buffer line in a window are called filler lines.
-These lines start with a tilde (~) character. By default, these are
-highlighted as NonText (|hl-NonText|). The EndOfBuffer highlight group
-(|hl-EndOfBuffer|) can be used to change the highlighting of filler lines.
+The lines after the last buffer line in a window are called filler lines. By
+default, these lines start with a tilde (~) character. The 'eob' item in the
+'fillchars' option can be used to change this character. By default, these
+characters are highlighted as NonText (|hl-NonText|). The EndOfBuffer
+highlight group (|hl-EndOfBuffer|) can be used to change the highlighting of
+the filler characters.
==============================================================================
3. Opening and closing a window *opening-window* *E36*
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 3e57ae7f0f..2c5064489b 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2021 Dec 03
+" Last Change: 2021 Dec 22
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -256,7 +256,7 @@ au BufNewFile,BufRead *.lpc,*.ulpc setf lpc
au BufNewFile,BufRead calendar setf calendar
" C#
-au BufNewFile,BufRead *.cs setf cs
+au BufNewFile,BufRead *.cs,*.csx setf cs
" CSDL
au BufNewFile,BufRead *.csdl setf csdl
@@ -486,6 +486,9 @@ au BufNewFile,BufRead dict.conf,.dictrc setf dictconf
" Dictd config
au BufNewFile,BufRead dictd*.conf setf dictdconf
+" DEP3 formatted patch files
+au BufNewFile,BufRead */debian/patches/* call dist#ft#Dep3patch()
+
" Diff files
au BufNewFile,BufRead *.diff,*.rej setf diff
au BufNewFile,BufRead *.patch
@@ -786,6 +789,10 @@ au BufNewFile,BufRead *.hb setf hb
" Httest
au BufNewFile,BufRead *.htt,*.htb setf httest
+" i3 (and sway)
+au BufNewFile,BufRead */i3/config,*/sway/config setf i3config
+au BufNewFile,BufRead */.i3/config,*/.sway/config setf i3config
+
" Icon
au BufNewFile,BufRead *.icn setf icon
@@ -1080,7 +1087,9 @@ au BufNewFile,BufRead *.mmp setf mmp
" Modsim III (or LambdaProlog)
au BufNewFile,BufRead *.mod
- \ if getline(1) =~ '\<module\>' |
+ \ if expand("<afile>") =~ '\<go.mod$' |
+ \ setf gomod |
+ \ elseif getline(1) =~ '\<module\>' |
\ setf lprolog |
\ else |
\ setf modsim3 |
@@ -1735,6 +1744,10 @@ au BufNewFile,BufRead *.speedup,*.spdata,*.spd setf spup
" Slice
au BufNewFile,BufRead *.ice setf slice
+" Microsoft Visual Studio Solution
+au BufNewFile,BufRead *.sln setf solution
+au BufNewFile,BufRead *.slnf setf json
+
" Spice
au BufNewFile,BufRead *.sp,*.spice setf spice
diff --git a/runtime/ftplugin/checkhealth.vim b/runtime/ftplugin/checkhealth.vim
new file mode 100644
index 0000000000..3d8e9ace1a
--- /dev/null
+++ b/runtime/ftplugin/checkhealth.vim
@@ -0,0 +1,20 @@
+" Vim filetype plugin
+" Language: Neovim checkhealth buffer
+" Last Change: 2021 Dec 15
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+runtime! ftplugin/markdown.vim ftplugin/markdown_*.vim ftplugin/markdown/*.vim
+
+setlocal wrap breakindent linebreak
+setlocal conceallevel=2 concealcursor=nc
+setlocal keywordprg=:help
+let &l:iskeyword='!-~,^*,^|,^",192-255'
+
+if exists("b:undo_ftplugin")
+ let b:undo_ftplugin .= "|setl wrap< bri< lbr< cole< cocu< kp< isk<"
+else
+ let b:undo_ftplugin = "setl wrap< bri< lbr< cole< cocu< kp< isk<"
+endif
diff --git a/runtime/ftplugin/i3config.vim b/runtime/ftplugin/i3config.vim
new file mode 100644
index 0000000000..4204510e64
--- /dev/null
+++ b/runtime/ftplugin/i3config.vim
@@ -0,0 +1,13 @@
+" Vim filetype plugin file
+" Language: i3 config file
+" Original Author: Mohamed Boughaba <mohamed dot bgb at gmail dot com>
+" Maintainer: Quentin Hibon
+" Version: 0.4
+" Last Change: 2021 Dec 14
+
+if exists("b:did_ftplugin") | finish | endif
+let b:did_ftplugin = 1
+
+let b:undo_ftplugin = "setlocal cms<"
+
+setlocal commentstring=#\ %s
diff --git a/runtime/ftplugin/solution.vim b/runtime/ftplugin/solution.vim
new file mode 100644
index 0000000000..bd30c7bb19
--- /dev/null
+++ b/runtime/ftplugin/solution.vim
@@ -0,0 +1,37 @@
+" Vim filetype plugin file
+" Language: Microsoft Visual Studio Solution
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2021 Dec 15
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+setlocal comments=:#
+setlocal commentstring=#\ %s
+
+let b:undo_ftplugin = "setl com< cms<"
+
+if exists("loaded_matchit") && !exists("b:match_words")
+ let b:match_words =
+ \ '\<Project\>:\<EndProject\>,' ..
+ \ '\<ProjectSection\>:\<EndProjectSection\>,' ..
+ \ '\<Global\>:\<EndGlobal\>,' ..
+ \ '\<GlobalSection\>:\<EndGlobalSection\>'
+ let b:undo_ftplugin ..= " | unlet! b:match_words"
+endif
+
+if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
+ let b:browsefilter = "Microsoft Visual Studio Solution Files\t*.sln\n" ..
+ \ "All Files (*.*)\t*.*\n"
+ let b:undo_ftplugin ..= " | unlet! b:browsefilter"
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: nowrap sw=2 sts=2 ts=8 noet:
diff --git a/runtime/ftplugin/zsh.vim b/runtime/ftplugin/zsh.vim
index 53ce1417dd..34410f1c62 100644
--- a/runtime/ftplugin/zsh.vim
+++ b/runtime/ftplugin/zsh.vim
@@ -18,13 +18,13 @@ setlocal comments=:# commentstring=#\ %s formatoptions-=t formatoptions+=croql
let b:undo_ftplugin = "setl com< cms< fo< "
-if executable('zsh')
+if executable('zsh') && &shell !~# '/\%(nologin\|false\)$'
if !has('gui_running') && executable('less')
- command! -buffer -nargs=1 RunHelp silent exe '!MANPAGER= zsh -ic "autoload -Uz run-help; run-help <args> 2>/dev/null | LESS= less"' | redraw!
+ command! -buffer -nargs=1 RunHelp silent exe '!MANPAGER= zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null | LESS= less"' | redraw!
elseif has('terminal')
- command! -buffer -nargs=1 RunHelp silent exe ':term zsh -ic "autoload -Uz run-help; run-help <args>"'
+ command! -buffer -nargs=1 RunHelp silent exe ':term zsh -c "autoload -Uz run-help; run-help <args>"'
else
- command! -buffer -nargs=1 RunHelp echo system('zsh -ic "autoload -Uz run-help; run-help <args> 2>/dev/null"')
+ command! -buffer -nargs=1 RunHelp echo system('zsh -c "autoload -Uz run-help; run-help <args> 2>/dev/null"')
endif
if !exists('current_compiler')
compiler zsh
diff --git a/runtime/indent/sh.vim b/runtime/indent/sh.vim
index d2fb1ba452..aa47c6d1bd 100644
--- a/runtime/indent/sh.vim
+++ b/runtime/indent/sh.vim
@@ -109,7 +109,7 @@ function! GetShIndent()
let ind += s:indent_value('continuation-line')
endif
elseif s:end_block(line) && !s:start_block(line)
- let ind -= s:indent_value('default')
+ let ind = indent(lnum)
elseif pnum != 0 &&
\ s:is_continuation_line(pline) &&
\ !s:end_block(curline) &&
diff --git a/runtime/indent/xml.vim b/runtime/indent/xml.vim
index da65417939..5bf53ad1f8 100644
--- a/runtime/indent/xml.vim
+++ b/runtime/indent/xml.vim
@@ -39,6 +39,8 @@ setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,},!^F
" autoindent: used when the indentexpr returns -1
setlocal autoindent
+let b:undo_indent = "setl ai< inde< indk<"
+
if !exists('b:xml_indent_open')
let b:xml_indent_open = '.\{-}<[:A-Z_a-z]'
" pre tag, e.g. <address>
@@ -51,6 +53,10 @@ if !exists('b:xml_indent_close')
" let b:xml_indent_close = '.\{-}</\(address\)\@!'
endif
+if !exists('b:xml_indent_continuation_filetype')
+ let b:xml_indent_continuation_filetype = 'xml'
+endif
+
let &cpo = s:keepcpo
unlet s:keepcpo
@@ -162,7 +168,7 @@ endfun
func! <SID>IsXMLContinuation(line)
" Checks, whether or not the line matches a start-of-tag
- return a:line !~ '^\s*<' && &ft is# 'xml'
+ return a:line !~ '^\s*<' && &ft =~# b:xml_indent_continuation_filetype
endfunc
func! <SID>HasNoTagEnd(line)
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 59cb9f8c5b..742ebf69b2 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -91,23 +91,22 @@ local function filter_by_severity(severity, diagnostics)
end
---@private
-local function prefix_source(source, diagnostics)
- vim.validate { source = {source, function(v)
- return v == "always" or v == "if_many"
- end, "'always' or 'if_many'" } }
-
- if source == "if_many" then
- local sources = {}
- for _, d in pairs(diagnostics) do
- if d.source then
- sources[d.source] = true
+local function count_sources(bufnr)
+ local seen = {}
+ local count = 0
+ for _, namespace_diagnostics in pairs(diagnostic_cache[bufnr]) do
+ for _, diagnostic in ipairs(namespace_diagnostics) do
+ if diagnostic.source and not seen[diagnostic.source] then
+ seen[diagnostic.source] = true
+ count = count + 1
end
end
- if #vim.tbl_keys(sources) <= 1 then
- return diagnostics
- end
end
+ return count
+end
+---@private
+local function prefix_source(diagnostics)
return vim.tbl_map(function(d)
if not d.source then
return d
@@ -272,6 +271,8 @@ end
---@private
local function set_diagnostic_cache(namespace, bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
+ assert(diagnostic.lnum, "Diagnostic line number is required")
+ assert(diagnostic.col, "Diagnostic column is required")
diagnostic.severity = diagnostic.severity and to_severity(diagnostic.severity) or M.severity.ERROR
diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum
diagnostic.end_col = diagnostic.end_col or diagnostic.col
@@ -297,11 +298,6 @@ local function restore_extmarks(bufnr, last)
if not found[extmark[1]] then
local opts = extmark[4]
opts.id = extmark[1]
- -- HACK: end_row should be end_line
- if opts.end_row then
- opts.end_line = opts.end_row
- opts.end_row = nil
- end
pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, extmark[2], extmark[3], opts)
end
end
@@ -563,8 +559,10 @@ end
--- - virtual_text: (default true) Use virtual text for diagnostics. Options:
--- * severity: Only show virtual text for diagnostics matching the given
--- severity |diagnostic-severity|
---- * source: (string) Include the diagnostic source in virtual
---- text. One of "always" or "if_many".
+--- * source: (boolean or string) Include the diagnostic source in virtual
+--- text. Use "if_many" to only show sources if there is more than
+--- one diagnostic source in the buffer. Otherwise, any truthy value
+--- means to always show the diagnostic source.
--- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display
--- the diagnostic. Example:
@@ -928,8 +926,11 @@ M.handlers.virtual_text = {
if opts.virtual_text.format then
diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics)
end
- if opts.virtual_text.source then
- diagnostics = prefix_source(opts.virtual_text.source, diagnostics)
+ if
+ opts.virtual_text.source
+ and (opts.virtual_text.source ~= "if_many" or count_sources(bufnr) > 1)
+ then
+ diagnostics = prefix_source(diagnostics)
end
if opts.virtual_text.severity then
severity = opts.virtual_text.severity
@@ -1154,8 +1155,11 @@ end
--- - header: (string or table) String to use as the header for the floating window. If a
--- table, it is interpreted as a [text, hl_group] tuple. Overrides the setting
--- from |vim.diagnostic.config()|.
---- - source: (string) Include the diagnostic source in the message. One of "always" or
---- "if_many". Overrides the setting from |vim.diagnostic.config()|.
+--- - source: (boolean or string) Include the diagnostic source in the message.
+--- Use "if_many" to only show sources if there is more than one source of
+--- diagnostics in the buffer. Otherwise, any truthy value means to always show
+--- the diagnostic source. Overrides the setting from
+--- |vim.diagnostic.config()|.
--- - format: (function) A function that takes a diagnostic as input and returns a
--- string. The return value is the text used to display the diagnostic.
--- Overrides the setting from |vim.diagnostic.config()|.
@@ -1267,8 +1271,8 @@ function M.open_float(opts, ...)
diagnostics = reformat_diagnostics(opts.format, diagnostics)
end
- if opts.source then
- diagnostics = prefix_source(opts.source, diagnostics)
+ if opts.source and (opts.source ~= "if_many" or count_sources(bufnr) > 1) then
+ diagnostics = prefix_source(diagnostics)
end
local prefix_opt = if_nil(opts.prefix, (scope == "cursor" and #diagnostics <= 1) and "" or function(_, i)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 72a84dcc53..00839ec181 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -777,6 +777,10 @@ function lsp.start_client(config)
---@param code (number) exit code of the process
---@param signal (number) the signal used to terminate (if any)
function dispatch.on_exit(code, signal)
+ if config.on_exit then
+ pcall(config.on_exit, code, signal, client_id)
+ end
+
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
@@ -792,10 +796,6 @@ function lsp.start_client(config)
vim.notify(msg, vim.log.levels.WARN)
end)
end
-
- if config.on_exit then
- pcall(config.on_exit, code, signal, client_id)
- end
end
-- Start the RPC client.
@@ -1112,9 +1112,9 @@ local text_document_did_change_handler
do
text_document_did_change_handler = function(_, bufnr, changedtick, firstline, lastline, new_lastline)
- -- Don't do anything if there are no clients attached.
+ -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached
if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then
- return
+ return true
end
util.buf_versions[bufnr] = changedtick
local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline)
@@ -1156,6 +1156,12 @@ function lsp.buf_attach_client(bufnr, client_id)
client_id = {client_id, 'n'};
}
bufnr = resolve_bufnr(bufnr)
+ if not vim.api.nvim_buf_is_loaded(bufnr) then
+ local _ = log.warn() and log.warn(
+ string.format("buf_attach_client called on unloaded buffer (id: %d): ", bufnr)
+ )
+ return false
+ end
local buffer_client_ids = all_buffer_active_clients[bufnr]
-- This is our first time attaching to this buffer.
if not buffer_client_ids then
@@ -1214,6 +1220,50 @@ function lsp.buf_attach_client(bufnr, client_id)
return true
end
+--- Detaches client from the specified buffer.
+--- Note: While the server is notified that the text document (buffer)
+--- was closed, it is still able to send notifications should it ignore this notification.
+---
+---@param bufnr number Buffer handle, or 0 for current
+---@param client_id number Client id
+function lsp.buf_detach_client(bufnr, client_id)
+ validate {
+ bufnr = {bufnr, 'n', true};
+ client_id = {client_id, 'n'};
+ }
+ bufnr = resolve_bufnr(bufnr)
+
+ local client = lsp.get_client_by_id(client_id)
+ if not client or not client.attached_buffers[bufnr] then
+ vim.notify(
+ string.format('Buffer (id: %d) is not attached to client (id: %d). Cannot detach.', client_id, bufnr)
+ )
+ return
+ end
+
+ changetracking.reset_buf(client, bufnr)
+
+ if client.resolved_capabilities.text_document_open_close then
+ local uri = vim.uri_from_bufnr(bufnr)
+ local params = { textDocument = { uri = uri; } }
+ client.notify('textDocument/didClose', params)
+ end
+
+ client.attached_buffers[bufnr] = nil
+ util.buf_versions[bufnr] = nil
+
+ all_buffer_active_clients[bufnr][client_id] = nil
+ if #vim.tbl_keys(all_buffer_active_clients[bufnr]) == 0 then
+ all_buffer_active_clients[bufnr] = nil
+ end
+
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ vim.diagnostic.reset(namespace, bufnr)
+
+ vim.notify(string.format('Detached buffer (id: %d) from client (id: %d)', bufnr, client_id))
+
+end
+
--- Checks if a buffer is attached for a particular client.
---
---@param bufnr (number) Buffer handle, or 0 for current
diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua
index 5df2a4d144..d01f45ad8f 100644
--- a/runtime/lua/vim/lsp/sync.lua
+++ b/runtime/lua/vim/lsp/sync.lua
@@ -105,15 +105,16 @@ local function align_end_position(line, byte, offset_encoding)
char = compute_line_length(line, offset_encoding) + 1
else
-- Modifying line, find the nearest utf codepoint
- local offset = str_utf_end(line, byte)
+ local offset = str_utf_start(line, byte)
-- If the byte does not fall on the start of the character, then
-- align to the start of the next character.
- if offset > 0 then
- char = byte_to_utf(line, byte, offset_encoding) + 1
- byte = byte + offset
- else
+ if offset < 0 then
+ byte = byte + str_utf_end(line, byte) + 1
+ end
+ if byte <= #line then
char = byte_to_utf(line, byte, offset_encoding)
- byte = byte + offset
+ else
+ char = compute_line_length(line, offset_encoding) + 1
end
-- Extending line, find the nearest utf codepoint for the last valid character
end
@@ -167,7 +168,7 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline,
char_idx = compute_line_length(prev_line, offset_encoding) + 1
else
byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx)
- char_idx = byte_to_utf(prev_line, start_byte_idx, offset_encoding)
+ char_idx = byte_to_utf(prev_line, byte_idx, offset_encoding)
end
-- Return the start difference (shared for new and prev lines)
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index b11925df53..5921eb5bf0 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -97,15 +97,17 @@ end
---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
---@return number `encoding` index of `index` in `line`
function M._str_utfindex_enc(line, index, encoding)
- if encoding ~= 'utf-8' then
- local col32, col16 = vim.str_utfindex(line, index)
- if encoding == 'utf-32' then
- return col32
- else
- return col16
- end
+ if not encoding then encoding = 'utf-16' end
+ if encoding == 'utf-8' then
+ if index then return index else return #line end
+ elseif encoding == 'utf-16' then
+ local _, col16 = vim.str_utfindex(line, index)
+ return col16
+ elseif encoding == 'utf-32' then
+ local col32, _ = vim.str_utfindex(line, index)
+ return col32
else
- return index
+ error("Invalid encoding: " .. vim.inspect(encoding))
end
end
@@ -117,10 +119,15 @@ end
---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16
---@return number byte (utf-8) index of `encoding` index `index` in `line`
function M._str_byteindex_enc(line, index, encoding)
- if encoding ~= 'utf-8' then
- return vim.str_byteindex(line, index, not encoding or encoding ~= 'utf-32')
+ if not encoding then encoding = 'utf-16' end
+ if encoding == 'utf-8' then
+ if index then return index else return #line end
+ elseif encoding == 'utf-16' then
+ return vim.str_byteindex(line, index, true)
+ elseif encoding == 'utf-32' then
+ return vim.str_byteindex(line, index)
else
- return index
+ error("Invalid encoding: " .. vim.inspect(encoding))
end
end
@@ -1253,17 +1260,57 @@ function M.stylize_markdown(bufnr, contents, opts)
return stripped
end
+---@private
--- Creates autocommands to close a preview window when events happen.
---
----@param events (table) list of events
----@param winnr (number) window id of preview window
+---@param events table list of events
+---@param winnr number window id of preview window
+---@param bufnrs table list of buffers where the preview window will remain visible
---@see |autocmd-events|
-function M.close_preview_autocmd(events, winnr)
+local function close_preview_autocmd(events, winnr, bufnrs)
+ local augroup = 'preview_window_'..winnr
+
+ -- close the preview window when entered a buffer that is not
+ -- the floating window buffer or the buffer that spawned it
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd!
+ autocmd BufEnter * lua vim.lsp.util._close_preview_window(%d, {%s})
+ augroup end
+ ]], augroup, winnr, table.concat(bufnrs, ',')))
+
if #events > 0 then
- api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd %s <buffer> lua vim.lsp.util._close_preview_window(%d)
+ augroup end
+ ]], augroup, table.concat(events, ','), winnr))
end
end
+---@private
+--- Closes the preview window
+---
+---@param winnr number window id of preview window
+---@param bufnrs table|nil optional list of ignored buffers
+function M._close_preview_window(winnr, bufnrs)
+ vim.schedule(function()
+ -- exit if we are in one of ignored buffers
+ if bufnrs and vim.tbl_contains(bufnrs, api.nvim_get_current_buf()) then
+ return
+ end
+
+ local augroup = 'preview_window_'..winnr
+ vim.cmd(string.format([[
+ augroup %s
+ autocmd!
+ augroup end
+ augroup! %s
+ ]], augroup, augroup))
+ pcall(vim.api.nvim_win_close, winnr, true)
+ end)
+end
+
---@internal
--- Computes size of float needed to show contents (with optional wrapping)
---
@@ -1370,7 +1417,7 @@ function M.open_floating_preview(contents, syntax, opts)
opts.wrap = opts.wrap ~= false -- wrapping by default
opts.stylize_markdown = opts.stylize_markdown ~= false
opts.focus = opts.focus ~= false
- opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre"}
+ opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "InsertCharPre"}
local bufnr = api.nvim_get_current_buf()
@@ -1439,7 +1486,7 @@ function M.open_floating_preview(contents, syntax, opts)
api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "<cmd>bdelete<cr>", {silent = true, noremap = true, nowait = true})
- M.close_preview_autocmd(opts.close_events, floating_winnr)
+ close_preview_autocmd(opts.close_events, floating_winnr, {floating_bufnr, bufnr})
-- save focus_id
if opts.focus_id then
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 5fa45289d8..ebed502c92 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -167,30 +167,31 @@ end
--- Gets the text corresponding to a given node
---
---@param node the node
----@param bsource The buffer or string from which the node is extracted
+---@param source The buffer or string from which the node is extracted
function M.get_node_text(node, source)
local start_row, start_col, start_byte = node:start()
local end_row, end_col, end_byte = node:end_()
if type(source) == "number" then
local lines
- local eof_row = vim.api.nvim_buf_line_count(source)
+ local eof_row = a.nvim_buf_line_count(source)
if start_row >= eof_row then
return nil
end
+
if end_col == 0 then
lines = a.nvim_buf_get_lines(source, start_row, end_row, true)
- end_col = #lines[#lines]
+ end_col = -1
else
lines = a.nvim_buf_get_lines(source, start_row, end_row + 1, true)
end
- lines[1] = string.sub(lines[1], start_col + 1)
- local end_index = end_col
if #lines == 1 then
- end_index = end_col - start_col
+ lines[1] = string.sub(lines[1], start_col+1, end_col)
+ else
+ lines[1] = string.sub(lines[1], start_col+1)
+ lines[#lines] = string.sub(lines[#lines], 1, end_col)
end
- lines[#lines] = string.sub(lines[#lines], 1, end_index)
return table.concat(lines, "\n")
elseif type(source) == "string" then
@@ -247,13 +248,8 @@ local predicate_handlers = {
return function(match, _, source, pred)
local node = match[pred[2]]
- local start_row, start_col, end_row, end_col = node:range()
- if start_row ~= end_row then
- return false
- end
-
local regex = compiled_vim_regexes[pred[3]]
- return regex:match_line(source, start_row, start_col, end_col)
+ return regex:match_str(M.get_node_text(node, source))
end
end)(),
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index d4c10f7afa..c873252909 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2020 Oct 27
+" Last Change: 2021 Dec 12
" If there already is an option window, jump to that one.
let buf = bufnr('option-window')
@@ -261,6 +261,8 @@ call <SID>OptionG("sect", &sect)
call append("$", "path\tlist of directory names used for file searching")
call append("$", "\t(global or local to buffer)")
call <SID>OptionG("pa", &pa)
+call <SID>AddOption("cdhome", ":cd without argument goes to the home directory")
+call <SID>BinOptionG("cdh", &cdh)
call append("$", "cdpath\tlist of directory names used for :cd")
call <SID>OptionG("cd", &cd)
if exists("+autochdir")
diff --git a/runtime/pack/dist/opt/matchit/autoload/matchit.vim b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
index 4f3dd8ff9e..e8689980ae 100644
--- a/runtime/pack/dist/opt/matchit/autoload/matchit.vim
+++ b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
@@ -1,6 +1,11 @@
" matchit.vim: (global plugin) Extended "%" matching
" autload script of matchit plugin, see ../plugin/matchit.vim
-" Last Change: Mar 01, 2020
+" Last Change: Jun 10, 2021
+
+" Neovim does not support scriptversion
+if has("vimscript-4")
+ scriptversion 4
+endif
let s:last_mps = ""
let s:last_words = ":"
@@ -30,11 +35,11 @@ function s:RestoreOptions()
" In s:CleanUp(), :execute "set" restore_options .
let restore_options = ""
if get(b:, 'match_ignorecase', &ic) != &ic
- let restore_options .= (&ic ? " " : " no") . "ignorecase"
+ let restore_options ..= (&ic ? " " : " no") .. "ignorecase"
let &ignorecase = b:match_ignorecase
endif
if &ve != ''
- let restore_options = " ve=" . &ve . restore_options
+ let restore_options = " ve=" .. &ve .. restore_options
set ve=
endif
return restore_options
@@ -42,22 +47,23 @@ endfunction
function matchit#Match_wrapper(word, forward, mode) range
let restore_options = s:RestoreOptions()
- " If this function was called from Visual mode, make sure that the cursor
- " is at the correct end of the Visual range:
- if a:mode == "v"
- execute "normal! gv\<Esc>"
- elseif a:mode == "o" && mode(1) !~# '[vV]'
- exe "norm! v"
- elseif a:mode == "n" && mode(1) =~# 'ni'
- exe "norm! v"
- endif
" In s:CleanUp(), we may need to check whether the cursor moved forward.
let startpos = [line("."), col(".")]
- " Use default behavior if called with a count.
+ " if a count has been applied, use the default [count]% mode (see :h N%)
if v:count
- exe "normal! " . v:count . "%"
+ exe "normal! " .. v:count .. "%"
return s:CleanUp(restore_options, a:mode, startpos)
end
+ if a:mode =~# "v" && mode(1) =~# 'ni'
+ exe "norm! gv"
+ elseif a:mode == "o" && mode(1) !~# '[vV]'
+ exe "norm! v"
+ " If this function was called from Visual mode, make sure that the cursor
+ " is at the correct end of the Visual range:
+ elseif a:mode == "v"
+ execute "normal! gv\<Esc>"
+ let startpos = [line("."), col(".")]
+ endif
" First step: if not already done, set the script variables
" s:do_BR flag for whether there are backrefs
@@ -78,30 +84,30 @@ function matchit#Match_wrapper(word, forward, mode) range
" quote the special chars in 'matchpairs', replace [,:] with \| and then
" append the builtin pairs (/*, */, #if, #ifdef, #ifndef, #else, #elif,
" #endif)
- let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
+ let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
\ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
" s:all = pattern with all the keywords
- let match_words = match_words . (strlen(match_words) ? "," : "") . default
+ let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
let s:last_words = match_words
- if match_words !~ s:notslash . '\\\d'
+ if match_words !~ s:notslash .. '\\\d'
let s:do_BR = 0
let s:pat = match_words
else
let s:do_BR = 1
let s:pat = s:ParseWords(match_words)
endif
- let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g')
+ let s:all = substitute(s:pat, s:notslash .. '\zs[,:]\+', '\\|', 'g')
" Just in case there are too many '\(...)' groups inside the pattern, make
" sure to use \%(...) groups, so that error E872 can be avoided
let s:all = substitute(s:all, '\\(', '\\%(', 'g')
- let s:all = '\%(' . s:all . '\)'
+ let s:all = '\%(' .. s:all .. '\)'
if exists("b:match_debug")
let b:match_pat = s:pat
endif
" Reconstruct the version with unresolved backrefs.
- let s:patBR = substitute(match_words.',',
- \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
- let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g')
+ let s:patBR = substitute(match_words .. ',',
+ \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
endif
" Second step: set the following local variables:
@@ -128,12 +134,15 @@ function matchit#Match_wrapper(word, forward, mode) range
let curcol = match(matchline, regexp)
" If there is no match, give up.
if curcol == -1
+ " Make sure macros abort properly
+ "exe "norm! \<esc>"
+ call feedkeys("\e", 'tni')
return s:CleanUp(restore_options, a:mode, startpos)
endif
let endcol = matchend(matchline, regexp)
let suf = strlen(matchline) - endcol
- let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(')
- let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$')
+ let prefix = (curcol ? '^.*\%' .. (curcol + 1) .. 'c\%(' : '^\%(')
+ let suffix = (suf ? '\)\%' .. (endcol + 1) .. 'c.*$' : '\)$')
endif
if exists("b:match_debug")
let b:match_match = matchstr(matchline, regexp)
@@ -150,7 +159,7 @@ function matchit#Match_wrapper(word, forward, mode) range
" 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
" group . "," . groupBR, and we pick it apart.
let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR)
- let i = matchend(group, s:notslash . ",")
+ let i = matchend(group, s:notslash .. ",")
let groupBR = strpart(group, i)
let group = strpart(group, 0, i-1)
" Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
@@ -159,32 +168,32 @@ function matchit#Match_wrapper(word, forward, mode) range
endif
if exists("b:match_debug")
let b:match_wholeBR = groupBR
- let i = matchend(groupBR, s:notslash . ":")
+ let i = matchend(groupBR, s:notslash .. ":")
let b:match_iniBR = strpart(groupBR, 0, i-1)
endif
" Fourth step: Set the arguments for searchpair().
- let i = matchend(group, s:notslash . ":")
- let j = matchend(group, '.*' . s:notslash . ":")
+ let i = matchend(group, s:notslash .. ":")
+ let j = matchend(group, '.*' .. s:notslash .. ":")
let ini = strpart(group, 0, i-1)
- let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g')
+ let mid = substitute(strpart(group, i,j-i-1), s:notslash .. '\zs:', '\\|', 'g')
let fin = strpart(group, j)
"Un-escape the remaining , and : characters.
- let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
- let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
- let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ let ini = substitute(ini, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
+ let mid = substitute(mid, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
+ let fin = substitute(fin, s:notslash .. '\zs\\\(:\|,\)', '\1', 'g')
" searchpair() requires that these patterns avoid \(\) groups.
- let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g')
- let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g')
- let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g')
+ let ini = substitute(ini, s:notslash .. '\zs\\(', '\\%(', 'g')
+ let mid = substitute(mid, s:notslash .. '\zs\\(', '\\%(', 'g')
+ let fin = substitute(fin, s:notslash .. '\zs\\(', '\\%(', 'g')
" Set mid. This is optimized for readability, not micro-efficiency!
- if a:forward && matchline =~ prefix . fin . suffix
- \ || !a:forward && matchline =~ prefix . ini . suffix
+ if a:forward && matchline =~ prefix .. fin .. suffix
+ \ || !a:forward && matchline =~ prefix .. ini .. suffix
let mid = ""
endif
" Set flag. This is optimized for readability, not micro-efficiency!
- if a:forward && matchline =~ prefix . fin . suffix
- \ || !a:forward && matchline !~ prefix . ini . suffix
+ if a:forward && matchline =~ prefix .. fin .. suffix
+ \ || !a:forward && matchline !~ prefix .. ini .. suffix
let flag = "bW"
else
let flag = "W"
@@ -193,14 +202,14 @@ function matchit#Match_wrapper(word, forward, mode) range
if exists("b:match_skip")
let skip = b:match_skip
elseif exists("b:match_comment") " backwards compatibility and testing!
- let skip = "r:" . b:match_comment
+ let skip = "r:" .. b:match_comment
else
let skip = 's:comment\|string'
endif
let skip = s:ParseSkip(skip)
if exists("b:match_debug")
let b:match_ini = ini
- let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin
+ let b:match_tail = (strlen(mid) ? mid .. '\|' : '') .. fin
endif
" Fifth step: actually start moving the cursor and call searchpair().
@@ -210,25 +219,29 @@ function matchit#Match_wrapper(word, forward, mode) range
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
let skip = "0"
else
- execute "if " . skip . "| let skip = '0' | endif"
+ execute "if " .. skip .. "| let skip = '0' | endif"
endif
let sp_return = searchpair(ini, mid, fin, flag, skip)
if &selection isnot# 'inclusive' && a:mode == 'v'
" move cursor one pos to the right, because selection is not inclusive
- " add virtualedit=onemore, to make it work even when the match ends the " line
+ " add virtualedit=onemore, to make it work even when the match ends the
+ " line
if !(col('.') < col('$')-1)
- set ve=onemore
+ let eolmark=1 " flag to set a mark on eol (since we cannot move there)
endif
norm! l
endif
- let final_position = "call cursor(" . line(".") . "," . col(".") . ")"
+ let final_position = "call cursor(" .. line(".") .. "," .. col(".") .. ")"
" Restore cursor position and original screen.
call winrestview(view)
normal! m'
if sp_return > 0
execute final_position
endif
- return s:CleanUp(restore_options, a:mode, startpos, mid.'\|'.fin)
+ if exists('eolmark') && eolmark
+ call setpos("''", [0, line('.'), col('$'), 0]) " set mark on the eol
+ endif
+ return s:CleanUp(restore_options, a:mode, startpos, mid .. '\|' .. fin)
endfun
" Restore options and do some special handling for Operator-pending mode.
@@ -270,16 +283,16 @@ endfun
" a:matchline = "123<tag>12" or "123</tag>12"
" then extract "tag" from a:matchline and return "<tag>:</tag>" .
fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
- if a:matchline !~ a:prefix .
- \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix
+ if a:matchline !~ a:prefix ..
+ \ substitute(a:group, s:notslash .. '\zs:', '\\|', 'g') .. a:suffix
return a:group
endif
- let i = matchend(a:groupBR, s:notslash . ':')
+ let i = matchend(a:groupBR, s:notslash .. ':')
let ini = strpart(a:groupBR, 0, i-1)
let tailBR = strpart(a:groupBR, i)
let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
\ a:groupBR)
- let i = matchend(word, s:notslash . ":")
+ let i = matchend(word, s:notslash .. ":")
let wordBR = strpart(word, i)
let word = strpart(word, 0, i-1)
" Now, a:matchline =~ a:prefix . word . a:suffix
@@ -289,10 +302,10 @@ fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
let table = ""
let d = 0
while d < 10
- if tailBR =~ s:notslash . '\\' . d
- let table = table . d
+ if tailBR =~ s:notslash .. '\\' .. d
+ let table = table .. d
else
- let table = table . "-"
+ let table = table .. "-"
endif
let d = d + 1
endwhile
@@ -300,13 +313,13 @@ fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
let d = 9
while d
if table[d] != "-"
- let backref = substitute(a:matchline, a:prefix.word.a:suffix,
- \ '\'.table[d], "")
+ let backref = substitute(a:matchline, a:prefix .. word .. a:suffix,
+ \ '\' .. table[d], "")
" Are there any other characters that should be escaped?
let backref = escape(backref, '*,:')
execute s:Ref(ini, d, "start", "len")
- let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len)
- let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d,
+ let ini = strpart(ini, 0, start) .. backref .. strpart(ini, start+len)
+ let tailBR = substitute(tailBR, s:notslash .. '\zs\\' .. d,
\ escape(backref, '\\&'), 'g')
endif
let d = d-1
@@ -320,7 +333,7 @@ fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
let b:match_word = ""
endif
endif
- return ini . ":" . tailBR
+ return ini .. ":" .. tailBR
endfun
" Input a comma-separated list of groups with backrefs, such as
@@ -328,25 +341,25 @@ endfun
" and return a comma-separated list of groups with backrefs replaced:
" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
fun! s:ParseWords(groups)
- let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
- let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g')
+ let groups = substitute(a:groups .. ",", s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let groups = substitute(groups, s:notslash .. '\zs:\{2,}', ':', 'g')
let parsed = ""
while groups =~ '[^,:]'
- let i = matchend(groups, s:notslash . ':')
- let j = matchend(groups, s:notslash . ',')
+ let i = matchend(groups, s:notslash .. ':')
+ let j = matchend(groups, s:notslash .. ',')
let ini = strpart(groups, 0, i-1)
- let tail = strpart(groups, i, j-i-1) . ":"
+ let tail = strpart(groups, i, j-i-1) .. ":"
let groups = strpart(groups, j)
- let parsed = parsed . ini
- let i = matchend(tail, s:notslash . ':')
+ let parsed = parsed .. ini
+ let i = matchend(tail, s:notslash .. ':')
while i != -1
" In 'if:else:endif', ini='if' and word='else' and then word='endif'.
let word = strpart(tail, 0, i-1)
let tail = strpart(tail, i)
- let i = matchend(tail, s:notslash . ':')
- let parsed = parsed . ":" . s:Resolve(ini, word, "word")
+ let i = matchend(tail, s:notslash .. ':')
+ let parsed = parsed .. ":" .. s:Resolve(ini, word, "word")
endwhile " Now, tail has been used up.
- let parsed = parsed . ","
+ let parsed = parsed .. ","
endwhile " groups =~ '[^,:]'
let parsed = substitute(parsed, ',$', '', '')
return parsed
@@ -364,14 +377,14 @@ endfun
" let j = matchend(getline("."), regexp)
" let match = matchstr(getline("."), regexp)
fun! s:Wholematch(string, pat, start)
- let group = '\%(' . a:pat . '\)'
- let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^')
+ let group = '\%(' .. a:pat .. '\)'
+ let prefix = (a:start ? '\(^.*\%<' .. (a:start + 2) .. 'c\)\zs' : '^')
let len = strlen(a:string)
- let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$')
- if a:string !~ prefix . group . suffix
+ let suffix = (a:start+1 < len ? '\(\%>' .. (a:start+1) .. 'c.*$\)\@=' : '$')
+ if a:string !~ prefix .. group .. suffix
let prefix = ''
endif
- return prefix . group . suffix
+ return prefix .. group .. suffix
endfun
" No extra arguments: s:Ref(string, d) will
@@ -392,7 +405,7 @@ fun! s:Ref(string, d, ...)
let match = a:string
while cnt
let cnt = cnt - 1
- let index = matchend(match, s:notslash . '\\(')
+ let index = matchend(match, s:notslash .. '\\(')
if index == -1
return ""
endif
@@ -404,7 +417,7 @@ fun! s:Ref(string, d, ...)
endif
let cnt = 1
while cnt
- let index = matchend(match, s:notslash . '\\(\|\\)') - 1
+ let index = matchend(match, s:notslash .. '\\(\|\\)') - 1
if index == -2
return ""
endif
@@ -418,7 +431,7 @@ fun! s:Ref(string, d, ...)
if a:0 == 1
return len
elseif a:0 == 2
- return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len
+ return "let " .. a:1 .. "=" .. start .. "| let " .. a:2 .. "=" .. len
else
return strpart(a:string, start, len)
endif
@@ -431,9 +444,9 @@ endfun
fun! s:Count(string, pattern, ...)
let pat = escape(a:pattern, '\\')
if a:0 > 1
- let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g")
+ let foo = substitute(a:string, '[^' .. a:pattern .. ']', "a:1", "g")
let foo = substitute(a:string, pat, a:2, "g")
- let foo = substitute(foo, '[^' . a:2 . ']', "", "g")
+ let foo = substitute(foo, '[^' .. a:2 .. ']', "", "g")
return strlen(foo)
endif
let result = 0
@@ -456,7 +469,7 @@ endfun
" unless it is preceded by "\".
fun! s:Resolve(source, target, output)
let word = a:target
- let i = matchend(word, s:notslash . '\\\d') - 1
+ let i = matchend(word, s:notslash .. '\\\d') - 1
let table = "----------"
while i != -2 " There are back references to be replaced.
let d = word[i]
@@ -477,28 +490,28 @@ fun! s:Resolve(source, target, output)
if table[s] == "-"
if w + b < 10
" let table[s] = w + b
- let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1)
+ let table = strpart(table, 0, s) .. (w+b) .. strpart(table, s+1)
endif
let b = b + 1
let s = s + 1
else
execute s:Ref(backref, b, "start", "len")
let ref = strpart(backref, start, len)
- let backref = strpart(backref, 0, start) . ":". table[s]
- \ . strpart(backref, start+len)
+ let backref = strpart(backref, 0, start) .. ":" .. table[s]
+ \ .. strpart(backref, start+len)
let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
endif
endwhile
- let word = strpart(word, 0, i-1) . backref . strpart(word, i+1)
- let i = matchend(word, s:notslash . '\\\d') - 1
+ let word = strpart(word, 0, i-1) .. backref .. strpart(word, i+1)
+ let i = matchend(word, s:notslash .. '\\\d') - 1
endwhile
- let word = substitute(word, s:notslash . '\zs:', '\\', 'g')
+ let word = substitute(word, s:notslash .. '\zs:', '\\', 'g')
if a:output == "table"
return table
elseif a:output == "word"
return word
else
- return table . word
+ return table .. word
endif
endfun
@@ -508,21 +521,21 @@ endfun
" If <patn> is the first pattern that matches a:string then return <patn>
" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
- let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma)
- let i = matchend(tail, s:notslash . a:comma)
+ let tail = (a:patterns =~ a:comma .. "$" ? a:patterns : a:patterns .. a:comma)
+ let i = matchend(tail, s:notslash .. a:comma)
if a:0
- let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma)
- let j = matchend(alttail, s:notslash . a:comma)
+ let alttail = (a:1 =~ a:comma .. "$" ? a:1 : a:1 .. a:comma)
+ let j = matchend(alttail, s:notslash .. a:comma)
endif
let current = strpart(tail, 0, i-1)
if a:branch == ""
let currpat = current
else
- let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
+ let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
endif
- while a:string !~ a:prefix . currpat . a:suffix
+ while a:string !~ a:prefix .. currpat .. a:suffix
let tail = strpart(tail, i)
- let i = matchend(tail, s:notslash . a:comma)
+ let i = matchend(tail, s:notslash .. a:comma)
if i == -1
return -1
endif
@@ -530,15 +543,15 @@ fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
if a:branch == ""
let currpat = current
else
- let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
+ let currpat = substitute(current, s:notslash .. a:branch, '\\|', 'g')
endif
if a:0
let alttail = strpart(alttail, j)
- let j = matchend(alttail, s:notslash . a:comma)
+ let j = matchend(alttail, s:notslash .. a:comma)
endif
endwhile
if a:0
- let current = current . a:comma . strpart(alttail, 0, j-1)
+ let current = current .. a:comma .. strpart(alttail, 0, j-1)
endif
return current
endfun
@@ -562,7 +575,7 @@ fun! matchit#Match_debug()
" fin = 'endif' piece, with all backrefs resolved from match
amenu &Matchit.&word :echo b:match_word<CR>
" '\'.d in ini refers to the same thing as '\'.table[d] in word.
- amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR>
+ amenu &Matchit.t&able :echo '0:' .. b:match_table .. ':9'<CR>
endfun
" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
@@ -598,26 +611,26 @@ fun! matchit#MultiMatch(spflag, mode)
endif
if (match_words != s:last_words) || (&mps != s:last_mps) ||
\ exists("b:match_debug")
- let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
+ let default = escape(&mps, '[$^.*~\\/?]') .. (strlen(&mps) ? "," : "") ..
\ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
let s:last_mps = &mps
- let match_words = match_words . (strlen(match_words) ? "," : "") . default
+ let match_words = match_words .. (strlen(match_words) ? "," : "") .. default
let s:last_words = match_words
- if match_words !~ s:notslash . '\\\d'
+ if match_words !~ s:notslash .. '\\\d'
let s:do_BR = 0
let s:pat = match_words
else
let s:do_BR = 1
let s:pat = s:ParseWords(match_words)
endif
- let s:all = '\%(' . substitute(s:pat, '[,:]\+', '\\|', 'g') . '\)'
+ let s:all = '\%(' .. substitute(s:pat, '[,:]\+', '\\|', 'g') .. '\)'
if exists("b:match_debug")
let b:match_pat = s:pat
endif
" Reconstruct the version with unresolved backrefs.
- let s:patBR = substitute(match_words.',',
- \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
- let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g')
+ let s:patBR = substitute(match_words .. ',',
+ \ s:notslash .. '\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash .. '\zs:\{2,}', ':', 'g')
endif
" Second step: figure out the patterns for searchpair()
@@ -625,23 +638,23 @@ fun! matchit#MultiMatch(spflag, mode)
" - TODO: A lot of this is copied from matchit#Match_wrapper().
" - maybe even more functionality should be split off
" - into separate functions!
- let openlist = split(s:pat . ',', s:notslash . '\zs:.\{-}' . s:notslash . ',')
- let midclolist = split(',' . s:pat, s:notslash . '\zs,.\{-}' . s:notslash . ':')
- call map(midclolist, {-> split(v:val, s:notslash . ':')})
+ let openlist = split(s:pat .. ',', s:notslash .. '\zs:.\{-}' .. s:notslash .. ',')
+ let midclolist = split(',' .. s:pat, s:notslash .. '\zs,.\{-}' .. s:notslash .. ':')
+ call map(midclolist, {-> split(v:val, s:notslash .. ':')})
let closelist = []
let middlelist = []
call map(midclolist, {i,v -> [extend(closelist, v[-1 : -1]),
\ extend(middlelist, v[0 : -2])]})
- call map(openlist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
- call map(middlelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
- call map(closelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
+ call map(openlist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
+ call map(middlelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
+ call map(closelist, {i,v -> v =~# s:notslash .. '\\|' ? '\%(' .. v .. '\)' : v})
let open = join(openlist, ',')
let middle = join(middlelist, ',')
let close = join(closelist, ',')
if exists("b:match_skip")
let skip = b:match_skip
elseif exists("b:match_comment") " backwards compatibility and testing!
- let skip = "r:" . b:match_comment
+ let skip = "r:" .. b:match_comment
else
let skip = 's:comment\|string'
endif
@@ -650,18 +663,18 @@ fun! matchit#MultiMatch(spflag, mode)
" Third step: call searchpair().
" Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
- let openpat = substitute(open, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let openpat = substitute(open, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
let openpat = substitute(openpat, ',', '\\|', 'g')
- let closepat = substitute(close, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let closepat = substitute(close, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
let closepat = substitute(closepat, ',', '\\|', 'g')
- let middlepat = substitute(middle, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let middlepat = substitute(middle, '\%(' .. s:notslash .. '\)\@<=\\(', '\\%(', 'g')
let middlepat = substitute(middlepat, ',', '\\|', 'g')
if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
let skip = '0'
else
try
- execute "if " . skip . "| let skip = '0' | endif"
+ execute "if " .. skip .. "| let skip = '0' | endif"
catch /^Vim\%((\a\+)\)\=:E363/
" We won't find anything, so skip searching, should keep Vim responsive.
return {}
@@ -744,11 +757,11 @@ fun! s:ParseSkip(str)
let skip = a:str
if skip[1] == ":"
if skip[0] == "s"
- let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" .
- \ strpart(skip,2) . "'"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" ..
+ \ strpart(skip,2) .. "'"
elseif skip[0] == "S"
- let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" .
- \ strpart(skip,2) . "'"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" ..
+ \ strpart(skip,2) .. "'"
elseif skip[0] == "r"
let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
elseif skip[0] == "R"
diff --git a/runtime/pack/dist/opt/matchit/doc/matchit.txt b/runtime/pack/dist/opt/matchit/doc/matchit.txt
index b719fae730..553359ffaf 100644
--- a/runtime/pack/dist/opt/matchit/doc/matchit.txt
+++ b/runtime/pack/dist/opt/matchit/doc/matchit.txt
@@ -4,7 +4,7 @@ For instructions on installing this file, type
`:help matchit-install`
inside Vim.
-For Vim version 8.1. Last change: 2021 Nov 13
+For Vim version 8.2. Last change: 2021 Dec 24
VIM REFERENCE MANUAL by Benji Fisher et al
@@ -150,6 +150,10 @@ To use the matchit plugin add this line to your |vimrc|: >
The script should start working the next time you start Vim.
+To use the matchit plugin after startup, you can use this command (note the
+omitted '!'): >
+ packadd matchit
+
(Earlier versions of the script did nothing unless a |buffer-variable| named
|b:match_words| was defined. Even earlier versions contained autocommands
that set this variable for various file types. Now, |b:match_words| is
@@ -378,8 +382,8 @@ The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in
5. Known Bugs and Limitations *matchit-bugs*
Repository: https://github.com/chrisbra/matchit/
-Bugs can be reported at the repository (alternatively you can send me a mail).
-The latest development snapshot can also be downloaded there.
+Bugs can be reported at the repository and the latest development snapshot can
+also be downloaded there.
Just because I know about a bug does not mean that it is on my todo list. I
try to respond to reports of bugs that cause real problems. If it does not
diff --git a/runtime/pack/dist/opt/matchit/plugin/matchit.vim b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
index b62cc3913a..51ba3a7f51 100644
--- a/runtime/pack/dist/opt/matchit/plugin/matchit.vim
+++ b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
@@ -1,7 +1,7 @@
" matchit.vim: (global plugin) Extended "%" matching
" Maintainer: Christian Brabandt
-" Version: 1.17
-" Last Change: 2019 Oct 24
+" Version: 1.18
+" Last Change: 2020 Dec 23
" Repository: https://github.com/chrisbra/matchit
" Previous URL:http://www.vim.org/script.php?script_id=39
" Previous Maintainer: Benji Fisher PhD <benji@member.AMS.org>
@@ -48,18 +48,12 @@ set cpo&vim
nnoremap <silent> <Plug>(MatchitNormalForward) :<C-U>call matchit#Match_wrapper('',1,'n')<CR>
nnoremap <silent> <Plug>(MatchitNormalBackward) :<C-U>call matchit#Match_wrapper('',0,'n')<CR>
-xnoremap <silent> <Plug>(MatchitVisualForward) :<C-U>call matchit#Match_wrapper('',1,'v')<CR>m'gv``
+xnoremap <silent> <Plug>(MatchitVisualForward) :<C-U>call matchit#Match_wrapper('',1,'v')<CR>
+ \:if col("''") != col("$") \| exe ":normal! m'" \| endif<cr>gv``
xnoremap <silent> <Plug>(MatchitVisualBackward) :<C-U>call matchit#Match_wrapper('',0,'v')<CR>m'gv``
onoremap <silent> <Plug>(MatchitOperationForward) :<C-U>call matchit#Match_wrapper('',1,'o')<CR>
onoremap <silent> <Plug>(MatchitOperationBackward) :<C-U>call matchit#Match_wrapper('',0,'o')<CR>
-nmap <silent> % <Plug>(MatchitNormalForward)
-nmap <silent> g% <Plug>(MatchitNormalBackward)
-xmap <silent> % <Plug>(MatchitVisualForward)
-xmap <silent> g% <Plug>(MatchitVisualBackward)
-omap <silent> % <Plug>(MatchitOperationForward)
-omap <silent> g% <Plug>(MatchitOperationBackward)
-
" Analogues of [{ and ]} using matching patterns:
nnoremap <silent> <Plug>(MatchitNormalMultiBackward) :<C-U>call matchit#MultiMatch("bW", "n")<CR>
nnoremap <silent> <Plug>(MatchitNormalMultiForward) :<C-U>call matchit#MultiMatch("W", "n")<CR>
@@ -68,16 +62,28 @@ xnoremap <silent> <Plug>(MatchitVisualMultiForward) :<C-U>call matchit#Multi
onoremap <silent> <Plug>(MatchitOperationMultiBackward) :<C-U>call matchit#MultiMatch("bW", "o")<CR>
onoremap <silent> <Plug>(MatchitOperationMultiForward) :<C-U>call matchit#MultiMatch("W", "o")<CR>
-nmap <silent> [% <Plug>(MatchitNormalMultiBackward)
-nmap <silent> ]% <Plug>(MatchitNormalMultiForward)
-xmap <silent> [% <Plug>(MatchitVisualMultiBackward)
-xmap <silent> ]% <Plug>(MatchitVisualMultiForward)
-omap <silent> [% <Plug>(MatchitOperationMultiBackward)
-omap <silent> ]% <Plug>(MatchitOperationMultiForward)
-
" text object:
xmap <silent> <Plug>(MatchitVisualTextObject) <Plug>(MatchitVisualMultiBackward)o<Plug>(MatchitVisualMultiForward)
-xmap a% <Plug>(MatchitVisualTextObject)
+
+if !exists("g:no_plugin_maps")
+ nmap <silent> % <Plug>(MatchitNormalForward)
+ nmap <silent> g% <Plug>(MatchitNormalBackward)
+ xmap <silent> % <Plug>(MatchitVisualForward)
+ xmap <silent> g% <Plug>(MatchitVisualBackward)
+ omap <silent> % <Plug>(MatchitOperationForward)
+ omap <silent> g% <Plug>(MatchitOperationBackward)
+
+ " Analogues of [{ and ]} using matching patterns:
+ nmap <silent> [% <Plug>(MatchitNormalMultiBackward)
+ nmap <silent> ]% <Plug>(MatchitNormalMultiForward)
+ xmap <silent> [% <Plug>(MatchitVisualMultiBackward)
+ xmap <silent> ]% <Plug>(MatchitVisualMultiForward)
+ omap <silent> [% <Plug>(MatchitOperationMultiBackward)
+ omap <silent> ]% <Plug>(MatchitOperationMultiForward)
+
+ " Text object
+ xmap a% <Plug>(MatchitVisualTextObject)
+endif
" Call this function to turn on debugging information. Every time the main
" script is run, buffer variables will be saved. These can be used directly
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 67d91360d8..f9978a6b00 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -2,7 +2,7 @@
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
-" Last Change: 2021 Nov 29
+" Last Change: 2021 Dec 16
"
" WORK IN PROGRESS - Only the basics work
" Note: On MS-Windows you need a recent version of gdb. The one included with
@@ -104,6 +104,10 @@ call s:Highlight(1, '', &background)
hi default debugBreakpoint term=reverse ctermbg=red guibg=red
hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
+func s:GetCommand()
+ return type(g:termdebugger) == v:t_list ? copy(g:termdebugger) : [g:termdebugger]
+endfunc
+
func s:StartDebug(bang, ...)
" First argument is the command to debug, second core file or process ID.
call s:StartDebug_internal({'gdb_args': a:000, 'bang': a:bang})
@@ -119,8 +123,9 @@ func s:StartDebug_internal(dict)
echoerr 'Terminal debugger already running, cannot run two'
return
endif
- if !executable(g:termdebugger)
- echoerr 'Cannot execute debugger program "' .. g:termdebugger .. '"'
+ let gdbcmd = s:GetCommand()
+ if !executable(gdbcmd[0])
+ echoerr 'Cannot execute debugger program "' .. gdbcmd[0] .. '"'
return
endif
@@ -192,7 +197,7 @@ endfunc
func s:CheckGdbRunning()
if nvim_get_chan_info(s:gdb_job_id) == {}
- echoerr string(g:termdebugger) . ' exited unexpectedly'
+ echoerr string(s:GetCommand()[0]) . ' exited unexpectedly'
call s:CloseBuffers()
return ''
endif
@@ -245,7 +250,7 @@ func s:StartDebug_term(dict)
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
- let gdb_cmd = [g:termdebugger]
+ let gdb_cmd = s:GetCommand()
" Add -quiet to avoid the intro message causing a hit-enter prompt.
let gdb_cmd += ['-quiet']
" Disable pagination, it causes everything to stop at the gdb
@@ -379,7 +384,7 @@ func s:StartDebug_prompt(dict)
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
- let gdb_cmd = [g:termdebugger]
+ let gdb_cmd = s:GetCommand()
" Add -quiet to avoid the intro message causing a hit-enter prompt.
let gdb_cmd += ['-quiet']
" Disable pagination, it causes everything to stop at the gdb, needs to be run early
@@ -609,7 +614,7 @@ endfunc
" to the next ", unescaping characters:
" - remove line breaks
" - change \\t to \t
-" - change \0xhh to \xhh
+" - change \0xhh to \xhh (disabled for now)
" - change \ooo to octal
" - change \\ to \
func s:DecodeMessage(quotedText)
@@ -618,12 +623,21 @@ func s:DecodeMessage(quotedText)
return
endif
return a:quotedText
- \->substitute('^"\|".*\|\\n', '', 'g')
- \->substitute('\\t', "\t", 'g')
- \->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
- \->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
- \->substitute('\\\\', '\', 'g')
+ \ ->substitute('^"\|".*\|\\n', '', 'g')
+ \ ->substitute('\\t', "\t", 'g')
+ " multi-byte characters arrive in octal form
+ " NULL-values must be kept encoded as those break the string otherwise
+ \ ->substitute('\\000', s:NullRepl, 'g')
+ \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
+ " Note: GDB docs also mention hex encodings - the translations below work
+ " but we keep them out for performance-reasons until we actually see
+ " those in mi-returns
+ " \ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
+ " \ ->substitute('\\0x00', s:NullRepl, 'g')
+ \ ->substitute('\\\\', '\', 'g')
+ \ ->substitute(s:NullRepl, '\\000', 'g')
endfunc
+const s:NullRepl = 'XXXNULLXXX'
" Extract the "name" value from a gdb message with fullname="name".
func s:GetFullname(msg)
@@ -1066,11 +1080,20 @@ let s:evalFromBalloonExprResult = ''
" Handle the result of data-evaluate-expression
func s:HandleEvaluate(msg)
- let value = substitute(a:msg, '.*value="\(.*\)"', '\1', '')
- let value = substitute(value, '\\"', '"', 'g')
- " multi-byte characters arrive in octal form
- let value = substitute(value, '\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
- let value = substitute(value, ' ', '\1', '')
+ let value = a:msg
+ \ ->substitute('.*value="\(.*\)"', '\1', '')
+ \ ->substitute('\\"', '"', 'g')
+ \ ->substitute('\\\\', '\\', 'g')
+ "\ multi-byte characters arrive in octal form, replace everthing but NULL values
+ \ ->substitute('\\000', s:NullRepl, 'g')
+ \ ->substitute('\\\o\o\o', {-> eval('"' .. submatch(0) .. '"')}, 'g')
+ "\ Note: GDB docs also mention hex encodings - the translations below work
+ "\ but we keep them out for performance-reasons until we actually see
+ "\ those in mi-returns
+ "\ ->substitute('\\0x00', s:NullRep, 'g')
+ "\ ->substitute('\\0x\(\x\x\)', {-> eval('"\x' .. submatch(1) .. '"')}, 'g')
+ \ ->substitute(s:NullRepl, '\\000', 'g')
+ \ ->substitute(' ', '\1', '')
if s:evalFromBalloonExpr
if s:evalFromBalloonExprResult == ''
let s:evalFromBalloonExprResult = s:evalexpr . ': ' . value
diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim
index 20f8632006..e86e1b8669 100644
--- a/runtime/syntax/c.vim
+++ b/runtime/syntax/c.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2021 May 24
+" Last Change: 2021 Dec 07
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
@@ -196,7 +196,6 @@ syn match cNumber display contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>"
" Flag the first zero of an octal number as something special
syn match cOctal display contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=cOctalZero
syn match cOctalZero display contained "\<0"
-syn match cFloat display contained "\d\+f"
"floating point number, with dot, optional exponent
syn match cFloat display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\="
"floating point number, starting with a dot, optional exponent
diff --git a/runtime/syntax/checkhealth.vim b/runtime/syntax/checkhealth.vim
new file mode 100644
index 0000000000..dff880a0bc
--- /dev/null
+++ b/runtime/syntax/checkhealth.vim
@@ -0,0 +1,28 @@
+" Vim syntax file
+" Language: Neovim checkhealth buffer
+" Last Change: 2021 Dec 15
+
+if exists("b:current_syntax")
+ finish
+endif
+
+runtime! syntax/markdown.vim
+unlet! b:current_syntax
+
+syn case match
+
+" We do not care about markdown syntax errors
+syn clear markdownError
+
+syn keyword healthError ERROR[:] containedin=markdownCodeBlock,mkdListItemLine
+syn keyword healthWarning WARNING[:] containedin=markdownCodeBlock,mkdListItemLine
+syn keyword healthSuccess OK[:] containedin=markdownCodeBlock,mkdListItemLine
+syn match healthHelp "|.\{-}|" containedin=markdownCodeBlock,mkdListItemLine contains=healthBar
+syn match healthBar "|" contained conceal
+
+hi def link healthError Error
+hi def link healthWarning WarningMsg
+hi def healthSuccess guibg=#5fff00 guifg=#080808 ctermbg=82 ctermfg=232
+hi def link healthHelp Identifier
+
+let b:current_syntax = "checkhealth"
diff --git a/runtime/syntax/css.vim b/runtime/syntax/css.vim
index 67ad1ea335..564dc151bc 100644
--- a/runtime/syntax/css.vim
+++ b/runtime/syntax/css.vim
@@ -7,7 +7,7 @@
" Nikolai Weibull (Add CSS2 support)
" URL: https://github.com/vim-language-dept/css-syntax.vim
" Maintainer: Jay Sitter <jay@jaysitter.com>
-" Last Change: 2021 Oct 15
+" Last Change: 2021 Oct 20
" quit when a syntax file was already loaded
if !exists("main_syntax")
@@ -116,7 +116,7 @@ syn keyword cssColor contained ActiveBorder ActiveCaption AppWorkspace ButtonFac
syn case ignore
syn match cssImportant contained "!\s*important\>"
-syn match cssCustomProp contained "--[a-zA-Z0-9-_]*"
+syn match cssCustomProp contained "\<--[a-zA-Z0-9-_]*\>"
syn match cssColor contained "\<transparent\>"
syn match cssColor contained "\<currentColor\>"
@@ -126,6 +126,7 @@ syn match cssColor contained "#\x\{6\}\>" contains=cssUnitDecorators
syn match cssColor contained "#\x\{8\}\>" contains=cssUnitDecorators
syn region cssURL contained matchgroup=cssFunctionName start="\<\(uri\|url\|local\|format\)\s*(" end=")" contains=cssStringQ,cssStringQQ oneline
+syn region cssMathGroup contained matchgroup=cssMathParens start="(" end=")" containedin=cssFunction,cssMathGroup contains=cssCustomProp,cssValue.*,cssFunction,cssColor,cssStringQ,cssStringQQ oneline
syn region cssFunction contained matchgroup=cssFunctionName start="\<\(var\|calc\)\s*(" end=")" contains=cssCustomProp,cssValue.*,cssFunction,cssColor,cssStringQ,cssStringQQ oneline
syn region cssFunction contained matchgroup=cssFunctionName start="\<\(rgb\|clip\|attr\|counter\|rect\|cubic-bezier\|steps\)\s*(" end=")" oneline contains=cssValueInteger,cssValueNumber,cssValueLength,cssFunctionComma
syn region cssFunction contained matchgroup=cssFunctionName start="\<\(rgba\|hsl\|hsla\|color-stop\|from\|to\)\s*(" end=")" oneline contains=cssColor,cssValueInteger,cssValueNumber,cssValueLength,cssFunctionComma,cssFunction
@@ -395,9 +396,9 @@ syn match cssUIAttr contained '\<preserve-3d\>'
syn match cssIEUIAttr contained '\<bicubic\>'
" Webkit/iOS specific properties
-syn match cssUIProp contained '\<tap-highlight-color\|user-select\|touch-callout\>'
+syn match cssUIProp contained '\<\(tap-highlight-color\|user-select\|touch-callout\)\>'
" IE specific properties
-syn match cssIEUIProp contained '\<interpolation-mode\|zoom\|filter\>'
+syn match cssIEUIProp contained '\<\(interpolation-mode\|zoom\|filter\)\>'
" Webkit/Firebox specific properties/attributes
syn keyword cssUIProp contained appearance
@@ -423,11 +424,15 @@ syn keyword cssAuralAttr contained male female child code digits continuous
syn match cssMobileTextProp contained "\<text-size-adjust\>"
syn keyword cssMediaProp contained width height orientation scan
-syn match cssMediaProp contained /\(\(max\|min\)-\)\=\(\(device\)-\)\=aspect-ratio/
-syn match cssMediaProp contained /\(\(max\|min\)-\)\=device-pixel-ratio/
-syn match cssMediaProp contained /\(\(max\|min\)-\)\=device-\(height\|width\)/
-syn match cssMediaProp contained /\(\(max\|min\)-\)\=\(height\|width\|resolution\|monochrome\|color\(-index\)\=\)/
+syn keyword cssMediaProp contained any-hover any-pointer color-gamut grid hover
+syn keyword cssMediaProp contained overflow-block overflow-inline pointer update
+syn match cssMediaProp contained /\<\(\(max\|min\)-\)\=\(\(device\)-\)\=aspect-ratio\>/
+syn match cssMediaProp contained /\<\(\(max\|min\)-\)\=device-pixel-ratio\>/
+syn match cssMediaProp contained /\<\(\(max\|min\)-\)\=device-\(height\|width\)\>/
+syn match cssMediaProp contained /\<\(\(max\|min\)-\)\=\(height\|width\|resolution\|monochrome\|color\(-index\)\=\)\>/
syn keyword cssMediaAttr contained portrait landscape progressive interlace
+syn keyword cssMediaAttr contained coarse fast fine hover infinite p3 paged
+syn keyword cssMediaAttr contained rec2020 scroll slow srgb
syn match cssKeyFrameProp contained /\(\d\+\(\.\d\+\)\?%\|\(\<from\|to\>\)\)/ nextgroup=cssDefinition
syn match cssPageMarginProp /@\(\(top\|left\|right\|bottom\)-\(left\|center\|right\|middle\|bottom\)\)\(-corner\)\=/ contained nextgroup=cssDefinition
syn keyword cssPageProp contained content size
@@ -445,17 +450,17 @@ syn match cssBraceError "}"
syn match cssAttrComma ","
" Pseudo class
-" http://www.w3.org/TR/css3-selectors/
+" https://www.w3.org/TR/selectors-4/
syn match cssPseudoClass ":[A-Za-z0-9_-]*" contains=cssNoise,cssPseudoClassId,cssUnicodeEscape,cssVendor,cssPseudoClassFn
syn keyword cssPseudoClassId contained link visited active hover before after left right
-syn keyword cssPseudoClassId contained root empty target enable disabled checked invalid
+syn keyword cssPseudoClassId contained root empty target enabled disabled checked invalid
syn match cssPseudoClassId contained "\<first-\(line\|letter\)\>"
syn match cssPseudoClassId contained "\<\(first\|last\|only\)-\(of-type\|child\)\>"
-syn region cssPseudoClassFn contained matchgroup=cssFunctionName start="\<\(not\|lang\|\(nth\|nth-last\)-\(of-type\|child\)\)(" end=")" contains=cssStringQ,cssStringQQ
+syn match cssPseudoClassId contained "\<focus\(-within\|-visible\)\=\>"
+syn region cssPseudoClassFn contained matchgroup=cssFunctionName start="\<\(not\|is\|lang\|\(nth\|nth-last\)-\(of-type\|child\)\)(" end=")" contains=cssStringQ,cssStringQQ,cssTagName,cssAttributeSelector,cssClassName,cssIdentifier
" ------------------------------------
" Vendor specific properties
syn match cssPseudoClassId contained "\<selection\>"
-syn match cssPseudoClassId contained "\<focus\(-inner\)\=\>"
syn match cssPseudoClassId contained "\<\(input-\)\=placeholder\>"
" Misc highlight groups
diff --git a/runtime/syntax/debcontrol.vim b/runtime/syntax/debcontrol.vim
index 25fc252de6..8b65ece4ca 100644
--- a/runtime/syntax/debcontrol.vim
+++ b/runtime/syntax/debcontrol.vim
@@ -3,7 +3,7 @@
" Maintainer: Debian Vim Maintainers
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
" Wichert Akkerman <wakkerma@debian.org>
-" Last Change: 2020 Oct 26
+" Last Change: 2021 Nov 26
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debcontrol.vim
" Standard syntax initialization
@@ -91,6 +91,11 @@ syn case ignore
" Handle all fields from deb-src-control(5)
+" Catch-all for the legal fields
+syn region debcontrolField matchgroup=debcontrolKey start="^\%(\%(XSBC-Original-\)\=Maintainer\|Standards-Version\|Bugs\|Origin\|X[SB]-Python-Version\|\%(XS-\)\=Vcs-Mtn\|\%(XS-\)\=Testsuite\%(-Triggers\)\=\|Build-Profiles\|Tag\|Subarchitecture\|Kernel-Version\|Installer-Menu-Item\): " end="$" contains=debcontrolVariable,debcontrolEmail oneline
+syn region debcontrolMultiField matchgroup=debcontrolKey start="^\%(Build-\%(Conflicts\|Depends\)\%(-Arch\|-Indep\)\=\|\%(Pre-\)\=Depends\|Recommends\|Suggests\|Breaks\|Enhances\|Replaces\|Conflicts\|Provides\|Built-Using\|Uploaders\|X[SBC]\{0,3\}\%(Private-\)\=-[-a-zA-Z0-9]\+\): *" skip="^[ \t]" end="^$"me=s-1 end="^[^ \t#]"me=s-1 contains=debcontrolEmail,debcontrolVariable,debcontrolComment
+syn region debcontrolMultiFieldSpell matchgroup=debcontrolKey start="^Description: *" skip="^[ \t]" end="^$"me=s-1 end="^[^ \t#]"me=s-1 contains=debcontrolEmail,debcontrolVariable,debcontrolComment,@Spell
+
" Fields for which we do strict syntax checking
syn region debcontrolStrictField matchgroup=debcontrolKey start="^Architecture: *" end="$" contains=debcontrolArchitecture,debcontrolSpace oneline
syn region debcontrolStrictField matchgroup=debcontrolKey start="^Multi-Arch: *" end="$" contains=debcontrolMultiArch oneline
@@ -99,20 +104,15 @@ syn region debcontrolStrictField matchgroup=debcontrolKey start="^Priority: *" e
syn region debcontrolStrictField matchgroup=debcontrolKey start="^Section: *" end="$" contains=debcontrolSection oneline
syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XC-\)\=Package-Type: *" end="$" contains=debcontrolPackageType oneline
syn region debcontrolStrictField matchgroup=debcontrolKey start="^Homepage: *" end="$" contains=debcontrolHTTPUrl oneline keepend
-syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-\)\=Vcs-\%(Browser\|Arch\|Bzr\|Darcs\|Hg\): *" end="$" contains=debcontrolHTTPUrl oneline keepend
-syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-\)\=Vcs-Svn: *" end="$" contains=debcontrolVcsSvn,debcontrolHTTPUrl oneline keepend
-syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-\)\=Vcs-Cvs: *" end="$" contains=debcontrolVcsCvs oneline keepend
-syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-\)\=Vcs-Git: *" end="$" contains=debcontrolVcsGit oneline keepend
+syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-[-a-zA-Z0-9]\+-\)\=Vcs-\%(Browser\|Arch\|Bzr\|Darcs\|Hg\): *" end="$" contains=debcontrolHTTPUrl oneline keepend
+syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-[-a-zA-Z0-9]\+-\)\=Vcs-Svn: *" end="$" contains=debcontrolVcsSvn,debcontrolHTTPUrl oneline keepend
+syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-[-a-zA-Z0-9]\+-\)\=Vcs-Cvs: *" end="$" contains=debcontrolVcsCvs oneline keepend
+syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(XS-[-a-zA-Z0-9]\+-\)\=Vcs-Git: *" end="$" contains=debcontrolVcsGit oneline keepend
syn region debcontrolStrictField matchgroup=debcontrolKey start="^Rules-Requires-Root: *" end="$" contains=debcontrolR3 oneline
syn region debcontrolStrictField matchgroup=debcontrolKey start="^\%(Build-\)\=Essential: *" end="$" contains=debcontrolYesNo oneline
syn region debcontrolStrictField matchgroup=debcontrolDeprecatedKey start="^\%(XS-\)\=DM-Upload-Allowed: *" end="$" contains=debcontrolDmUpload oneline
-" Catch-all for the other legal fields
-syn region debcontrolField matchgroup=debcontrolKey start="^\%(\%(XSBC-Original-\)\=Maintainer\|Standards-Version\|Bugs\|Origin\|X[SB]-Python-Version\|\%(XS-\)\=Vcs-Mtn\|\%(XS-\)\=Testsuite\%(-Triggers\)\=\|Build-Profiles\|Tag\|Subarchitecture\|Kernel-Version\|Installer-Menu-Item\): " end="$" contains=debcontrolVariable,debcontrolEmail oneline
-syn region debcontrolMultiField matchgroup=debcontrolKey start="^\%(Build-\%(Conflicts\|Depends\)\%(-Arch\|-Indep\)\=\|\%(Pre-\)\=Depends\|Recommends\|Suggests\|Breaks\|Enhances\|Replaces\|Conflicts\|Provides\|Built-Using\|Uploaders\|X[SBC]\{0,3\}\%(Private-\)\=-[-a-zA-Z0-9]\+\): *" skip="^[ \t]" end="^$"me=s-1 end="^[^ \t#]"me=s-1 contains=debcontrolEmail,debcontrolVariable,debcontrolComment
-syn region debcontrolMultiFieldSpell matchgroup=debcontrolKey start="^Description: *" skip="^[ \t]" end="^$"me=s-1 end="^[^ \t#]"me=s-1 contains=debcontrolEmail,debcontrolVariable,debcontrolComment,@Spell
-
" Associate our matches and regions with pretty colours
hi def link debcontrolKey Keyword
hi def link debcontrolField Normal
diff --git a/runtime/syntax/dep3patch.vim b/runtime/syntax/dep3patch.vim
new file mode 100644
index 0000000000..8b2cee629c
--- /dev/null
+++ b/runtime/syntax/dep3patch.vim
@@ -0,0 +1,57 @@
+" Vim syntax file
+" Language: Debian DEP3 Patch headers
+" Maintainer: Gabriel Filion <gabster@lelutin.ca>
+" Last Change: 2021-01-09
+" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/dep3patch.vim
+"
+" Specification of the DEP3 patch header format is available at:
+" https://dep-team.pages.debian.net/deps/dep3/
+
+" Standard syntax initialization
+if exists('b:current_syntax')
+ finish
+endif
+
+runtime! syntax/diff.vim
+unlet! b:current_syntax
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+syn region dep3patchHeaders start="\%^" end="^\%(---\)\@=" contains=dep3patchKey,dep3patchMultiField
+
+syn case ignore
+
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^\%(Description\|Subject\)\ze: *" skip="^[ \t]" end="^$"me=s-1 end="^[^ \t#]"me=s-1 contained contains=@Spell
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^Origin\ze: *" end="$" contained contains=dep3patchHTTPUrl,dep3patchCommitID,dep3patchOriginCategory oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^Bug\%(-[[:graph:]]\+\)\?\ze: *" end="$" contained contains=dep3patchHTTPUrl oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^Forwarded\ze: *" end="$" contained contains=dep3patchHTTPUrl,dep3patchForwardedShort oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^\%(Author\|From\)\ze: *" end="$" contained contains=dep3patchEmail oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^\%(Reviewed-by\|Acked-by\)\ze: *" end="$" contained contains=dep3patchEmail oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^Last-Updated\ze: *" end="$" contained contains=dep3patchISODate oneline keepend
+syn region dep3patchMultiField matchgroup=dep3patchKey start="^Applied-Upstream\ze: *" end="$" contained contains=dep3patchHTTPUrl,dep3patchCommitID oneline keepend
+
+syn match dep3patchHTTPUrl contained "\vhttps?://[[:alnum:]][-[:alnum:]]*[[:alnum:]]?(\.[[:alnum:]][-[:alnum:]]*[[:alnum:]]?)*\.[[:alpha:]][-[:alnum:]]*[[:alpha:]]?(:\d+)?(/[^[:space:]]*)?$"
+syn match dep3patchCommitID contained "commit:[[:alnum:]]\+"
+syn match dep3patchOriginCategory contained "\%(upstream\|backport\|vendor\|other\), "
+syn match dep3patchForwardedShort contained "\%(yes\|no\|not-needed\), "
+syn match dep3patchEmail "[_=[:alnum:]\.+-]\+@[[:alnum:]\./\-]\+"
+syn match dep3patchEmail "<.\{-}>"
+syn match dep3patchISODate "[[:digit:]]\{4}-[[:digit:]]\{2}-[[:digit:]]\{2}"
+
+" Associate our matches and regions with pretty colours
+hi def link dep3patchKey Keyword
+hi def link dep3patchOriginCategory Keyword
+hi def link dep3patchForwardedShort Keyword
+hi def link dep3patchMultiField Normal
+hi def link dep3patchHTTPUrl Identifier
+hi def link dep3patchCommitID Identifier
+hi def link dep3patchEmail Identifier
+hi def link dep3patchISODate Identifier
+
+let b:current_syntax = 'dep3patch'
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: ts=8 sw=2
diff --git a/runtime/syntax/dtd.vim b/runtime/syntax/dtd.vim
index ef0592e1d1..58f07c98dd 100644
--- a/runtime/syntax/dtd.vim
+++ b/runtime/syntax/dtd.vim
@@ -45,7 +45,7 @@ if !exists("dtd_no_tag_errors")
syn region dtdError contained start=+<!+lc=2 end=+>+
endif
-" if this is a html like comment hightlight also
+" if this is a html like comment highlight also
" the opening <! and the closing > as Comment.
syn region dtdComment start=+<![ \t]*--+ end=+-->+ contains=dtdTodo,@Spell
@@ -99,8 +99,8 @@ syn match dtdEntity "&[^; \t]*;" contains=dtdEntityPunct
syn match dtdEntityPunct contained "[&.;]"
" Strings are between quotes
-syn region dtdString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=dtdAttrDef,dtdAttrType,dtdEnum,dtdParamEntityInst,dtdEntity,dtdCard
-syn region dtdString start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=dtdAttrDef,dtdAttrType,dtdEnum,dtdParamEntityInst,dtdEntity,dtdCard
+syn region dtdString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=dtdAttrDef,dtdAttrType,dtdParamEntityInst,dtdEntity,dtdCard
+syn region dtdString start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=dtdAttrDef,dtdAttrType,dtdParamEntityInst,dtdEntity,dtdCard
" Enumeration of elements or data between parenthesis
"
diff --git a/runtime/syntax/i3config.vim b/runtime/syntax/i3config.vim
new file mode 100644
index 0000000000..a8b6637140
--- /dev/null
+++ b/runtime/syntax/i3config.vim
@@ -0,0 +1,256 @@
+" Vim syntax file
+" Language: i3 config file
+" Maintainer: Mohamed Boughaba <mohamed dot bgb at gmail dot com>
+" Version: 0.4
+" Last Change: 2021 Dec 14
+
+" References:
+" http://i3wm.org/docs/userguide.html#configuring
+" http://vimdoc.sourceforge.net/htmldoc/syntax.html
+"
+"
+" Quit when a syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+scriptencoding utf-8
+
+" Error
+syn match i3ConfigError /.*/
+
+" Todo
+syn keyword i3ConfigTodo TODO FIXME XXX contained
+
+" Comment
+" Comments are started with a # and can only be used at the beginning of a line
+syn match i3ConfigComment /^\s*#.*$/ contains=i3ConfigTodo
+
+" Font
+" A FreeType font description is composed by:
+" a font family, a style, a weight, a variant, a stretch and a size.
+syn match i3ConfigFontSeparator /,/ contained
+syn match i3ConfigFontSeparator /:/ contained
+syn keyword i3ConfigFontKeyword font contained
+syn match i3ConfigFontNamespace /\w\+:/ contained contains=i3ConfigFontSeparator
+syn match i3ConfigFontContent /-\?\w\+\(-\+\|\s\+\|,\)/ contained contains=i3ConfigFontNamespace,i3ConfigFontSeparator,i3ConfigFontKeyword
+syn match i3ConfigFontSize /\s\=\d\+\(px\)\?\s\?$/ contained
+syn match i3ConfigFont /^\s*font\s\+.*$/ contains=i3ConfigFontContent,i3ConfigFontSeparator,i3ConfigFontSize,i3ConfigFontNamespace
+syn match i3ConfigFont /^\s*font\s\+.*\(\\\_.*\)\?$/ contains=i3ConfigFontContent,i3ConfigFontSeparator,i3ConfigFontSize,i3ConfigFontNamespace
+syn match i3ConfigFont /^\s*font\s\+.*\(\\\_.*\)\?[^\\]\+$/ contains=i3ConfigFontContent,i3ConfigFontSeparator,i3ConfigFontSize,i3ConfigFontNamespace
+syn match i3ConfigFont /^\s*font\s\+\(\(.*\\\_.*\)\|\(.*[^\\]\+$\)\)/ contains=i3ConfigFontContent,i3ConfigFontSeparator,i3ConfigFontSize,i3ConfigFontNamespace
+
+" variables
+syn match i3ConfigString /\(['"]\)\(.\{-}\)\1/ contained
+syn match i3ConfigColor /#\w\{6}/ contained
+syn match i3ConfigVariableModifier /+/ contained
+syn match i3ConfigVariableAndModifier /+\w\+/ contained contains=i3ConfigVariableModifier
+syn match i3ConfigVariable /\$\w\+\(\(-\w\+\)\+\)\?\(\s\|+\)\?/ contains=i3ConfigVariableModifier,i3ConfigVariableAndModifier
+syn keyword i3ConfigInitializeKeyword set contained
+syn match i3ConfigInitialize /^\s*set\s\+.*$/ contains=i3ConfigVariable,i3ConfigInitializeKeyword,i3ConfigColor,i3ConfigString
+
+" Gaps
+syn keyword i3ConfigGapStyleKeyword inner outer horizontal vertical top right bottom left current all set plus minus toggle up down contained
+syn match i3ConfigGapStyle /^\s*\(gaps\)\s\+\(inner\|outer\|horizontal\|vertical\|left\|top\|right\|bottom\)\(\s\+\(current\|all\)\)\?\(\s\+\(set\|plus\|minus\|toggle\)\)\?\(\s\+\(-\?\d\+\|\$.*\)\)$/ contains=i3ConfigGapStyleKeyword,i3ConfigNumber,i3ConfigVariable
+syn keyword i3ConfigSmartGapKeyword on inverse_outer contained
+syn match i3ConfigSmartGap /^\s*smart_gaps\s\+\(on\|inverse_outer\)\s\?$/ contains=i3ConfigSmartGapKeyword
+syn keyword i3ConfigSmartBorderKeyword on no_gaps contained
+syn match i3ConfigSmartBorder /^\s*smart_borders\s\+\(on\|no_gaps\)\s\?$/ contains=i3ConfigSmartBorderKeyword
+
+" Keyboard bindings
+syn keyword i3ConfigAction toggle fullscreen restart key import kill shrink grow contained
+syn keyword i3ConfigAction focus move grow height width split layout resize restore reload mute unmute exit mode workspace container to contained
+syn match i3ConfigModifier /\w\++\w\+\(\(+\w\+\)\+\)\?/ contained contains=i3ConfigVariableModifier
+syn match i3ConfigNumber /\s\d\+/ contained
+syn match i3ConfigUnit /\sp\(pt\|x\)/ contained
+syn match i3ConfigUnitOr /\sor/ contained
+syn keyword i3ConfigBindKeyword bindsym bindcode exec gaps border contained
+syn match i3ConfigBindArgument /--\w\+\(\(-\w\+\)\+\)\?\s/ contained
+syn match i3ConfigBind /^\s*\(bindsym\|bindcode\)\s\+.*$/ contains=i3ConfigVariable,i3ConfigBindKeyword,i3ConfigVariableAndModifier,i3ConfigNumber,i3ConfigUnit,i3ConfigUnitOr,i3ConfigBindArgument,i3ConfigModifier,i3ConfigAction,i3ConfigString,i3ConfigGapStyleKeyword,i3ConfigBorderStyleKeyword
+
+" Floating
+syn keyword i3ConfigSizeSpecial x contained
+syn match i3ConfigNegativeSize /-/ contained
+syn match i3ConfigSize /-\?\d\+\s\?x\s\?-\?\d\+/ contained contains=i3ConfigSizeSpecial,i3ConfigNumber,i3ConfigNegativeSize
+syn match i3ConfigFloating /^\s*floating_modifier\s\+\$\w\+\d\?/ contains=i3ConfigVariable
+syn match i3ConfigFloating /^\s*floating_\(maximum\|minimum\)_size\s\+-\?\d\+\s\?x\s\?-\?\d\+/ contains=i3ConfigSize
+
+" Orientation
+syn keyword i3ConfigOrientationKeyword vertical horizontal auto contained
+syn match i3ConfigOrientation /^\s*default_orientation\s\+\(vertical\|horizontal\|auto\)\s\?$/ contains=i3ConfigOrientationKeyword
+
+" Layout
+syn keyword i3ConfigLayoutKeyword default stacking tabbed contained
+syn match i3ConfigLayout /^\s*workspace_layout\s\+\(default\|stacking\|tabbed\)\s\?$/ contains=i3ConfigLayoutKeyword
+
+" Border style
+syn keyword i3ConfigBorderStyleKeyword none normal pixel contained
+syn match i3ConfigBorderStyle /^\s*\(new_window\|new_float\|default_border\|default_floating_border\)\s\+\(none\|\(normal\|pixel\)\(\s\+\d\+\)\?\(\s\+\$\w\+\(\(-\w\+\)\+\)\?\(\s\|+\)\?\)\?\)\s\?$/ contains=i3ConfigBorderStyleKeyword,i3ConfigNumber,i3ConfigVariable
+
+" Hide borders and edges
+syn keyword i3ConfigEdgeKeyword none vertical horizontal both smart smart_no_gaps contained
+syn match i3ConfigEdge /^\s*hide_edge_borders\s\+\(none\|vertical\|horizontal\|both\|smart\|smart_no_gaps\)\s\?$/ contains=i3ConfigEdgeKeyword
+
+" Arbitrary commands for specific windows (for_window)
+syn keyword i3ConfigCommandKeyword for_window contained
+syn region i3ConfigWindowStringSpecial start=+"+ skip=+\\"+ end=+"+ contained contains=i3ConfigString
+syn region i3ConfigWindowCommandSpecial start="\[" end="\]" contained contains=i3ConfigWindowStringSpacial,i3ConfigString
+syn match i3ConfigArbitraryCommand /^\s*for_window\s\+.*$/ contains=i3ConfigWindowCommandSpecial,i3ConfigCommandKeyword,i3ConfigBorderStyleKeyword,i3ConfigLayoutKeyword,i3ConfigOrientationKeyword,Size,i3ConfigNumber
+
+" Disable focus open opening
+syn keyword i3ConfigNoFocusKeyword no_focus contained
+syn match i3ConfigDisableFocus /^\s*no_focus\s\+.*$/ contains=i3ConfigWindowCommandSpecial,i3ConfigNoFocusKeyword
+
+" Move client to specific workspace automatically
+syn keyword i3ConfigAssignKeyword assign contained
+syn match i3ConfigAssignSpecial /→/ contained
+syn match i3ConfigAssign /^\s*assign\s\+.*$/ contains=i3ConfigAssignKeyword,i3ConfigWindowCommandSpecial,i3ConfigAssignSpecial
+
+" X resources
+syn keyword i3ConfigResourceKeyword set_from_resource contained
+syn match i3ConfigResource /^\s*set_from_resource\s\+.*$/ contains=i3ConfigResourceKeyword,i3ConfigWindowCommandSpecial,i3ConfigColor,i3ConfigVariable
+
+" Auto start applications
+syn keyword i3ConfigExecKeyword exec exec_always contained
+syn match i3ConfigNoStartupId /--no-startup-id/ contained " We are not using i3ConfigBindArgument as only no-startup-id is supported here
+syn match i3ConfigExec /^\s*exec\(_always\)\?\s\+.*$/ contains=i3ConfigExecKeyword,i3ConfigNoStartupId,i3ConfigString
+
+" Automatically putting workspaces on specific screens
+syn keyword i3ConfigWorkspaceKeyword workspace contained
+syn keyword i3ConfigOutput output contained
+syn match i3ConfigWorkspace /^\s*workspace\s\+.*$/ contains=i3ConfigWorkspaceKeyword,i3ConfigNumber,i3ConfigString,i3ConfigOutput
+
+" Changing colors
+syn keyword i3ConfigClientColorKeyword client focused focused_inactive unfocused urgent placeholder background contained
+syn match i3ConfigClientColor /^\s*client.\w\+\s\+.*$/ contains=i3ConfigClientColorKeyword,i3ConfigColor,i3ConfigVariable
+
+syn keyword i3ConfigTitleAlignKeyword left center right contained
+syn match i3ConfigTitleAlign /^\s*title_align\s\+.*$/ contains=i3ConfigTitleAlignKeyword
+
+" Interprocess communication
+syn match i3ConfigInterprocessKeyword /ipc-socket/ contained
+syn match i3ConfigInterprocess /^\s*ipc-socket\s\+.*$/ contains=i3ConfigInterprocessKeyword
+
+" Mouse warping
+syn keyword i3ConfigMouseWarpingKeyword mouse_warping contained
+syn keyword i3ConfigMouseWarpingType output none contained
+syn match i3ConfigMouseWarping /^\s*mouse_warping\s\+\(output\|none\)\s\?$/ contains=i3ConfigMouseWarpingKeyword,i3ConfigMouseWarpingType
+
+" Focus follows mouse
+syn keyword i3ConfigFocusFollowsMouseKeyword focus_follows_mouse contained
+syn keyword i3ConfigFocusFollowsMouseType yes no contained
+syn match i3ConfigFocusFollowsMouse /^\s*focus_follows_mouse\s\+\(yes\|no\)\s\?$/ contains=i3ConfigFocusFollowsMouseKeyword,i3ConfigFocusFollowsMouseType
+
+" Popups during fullscreen mode
+syn keyword i3ConfigPopupOnFullscreenKeyword popup_during_fullscreen contained
+syn keyword i3ConfigPopuponFullscreenType smart ignore leave_fullscreen contained
+syn match i3ConfigPopupOnFullscreen /^\s*popup_during_fullscreen\s\+\w\+\s\?$/ contains=i3ConfigPopupOnFullscreenKeyword,i3ConfigPopupOnFullscreenType
+
+" Focus wrapping
+syn keyword i3ConfigFocusWrappingKeyword force_focus_wrapping focus_wrapping contained
+syn keyword i3ConfigFocusWrappingType yes no contained
+syn match i3ConfigFocusWrapping /^\s*\(force_\)\?focus_wrapping\s\+\(yes\|no\)\s\?$/ contains=i3ConfigFocusWrappingType,i3ConfigFocusWrappingKeyword
+
+" Forcing Xinerama
+syn keyword i3ConfigForceXineramaKeyword force_xinerama contained
+syn match i3ConfigForceXinerama /^\s*force_xinerama\s\+\(yes\|no\)\s\?$/ contains=i3ConfigFocusWrappingType,i3ConfigForceXineramaKeyword
+
+" Automatic back-and-forth when switching to the current workspace
+syn keyword i3ConfigAutomaticSwitchKeyword workspace_auto_back_and_forth contained
+syn match i3ConfigAutomaticSwitch /^\s*workspace_auto_back_and_forth\s\+\(yes\|no\)\s\?$/ contains=i3ConfigFocusWrappingType,i3ConfigAutomaticSwitchKeyword
+
+" Delay urgency hint
+syn keyword i3ConfigTimeUnit ms contained
+syn keyword i3ConfigDelayUrgencyKeyword force_display_urgency_hint contained
+syn match i3ConfigDelayUrgency /^\s*force_display_urgency_hint\s\+\d\+\s\+ms\s\?$/ contains=i3ConfigFocusWrappingType,i3ConfigDelayUrgencyKeyword,i3ConfigNumber,i3ConfigTimeUnit
+
+" Focus on window activation
+syn keyword i3ConfigFocusOnActivationKeyword focus_on_window_activation contained
+syn keyword i3ConfigFocusOnActivationType smart urgent focus none contained
+syn match i3ConfigFocusOnActivation /^\s*focus_on_window_activation\s\+\(smart\|urgent\|focus\|none\)\s\?$/ contains=i3ConfigFocusOnActivationKeyword,i3ConfigFocusOnActivationType
+
+" Automatic back-and-forth when switching to the current workspace
+syn keyword i3ConfigDrawingMarksKeyword show_marks contained
+syn match i3ConfigDrawingMarks /^\s*show_marks\s\+\(yes\|no\)\s\?$/ contains=i3ConfigFocusWrappingType,i3ConfigDrawingMarksKeyword
+
+" Group mode/bar
+syn keyword i3ConfigBlockKeyword mode bar colors i3bar_command status_command position exec mode hidden_state modifier id position output background statusline tray_output tray_padding separator separator_symbol workspace_buttons strip_workspace_numbers binding_mode_indicator focused_workspace active_workspace inactive_workspace urgent_workspace binding_mode contained
+syn region i3ConfigBlock start=+.*s\?{$+ end=+^}$+ contains=i3ConfigBlockKeyword,i3ConfigString,i3ConfigBind,i3ConfigComment,i3ConfigFont,i3ConfigFocusWrappingType,i3ConfigColor,i3ConfigVariable transparent keepend extend
+
+" Line continuation
+syn region i3ConfigLineCont start=/^.*\\$/ end=/^.*$/ contains=i3ConfigBlockKeyword,i3ConfigString,i3ConfigBind,i3ConfigComment,i3ConfigFont,i3ConfigFocusWrappingType,i3ConfigColor,i3ConfigVariable transparent keepend extend
+
+" Define the highlighting.
+hi def link i3ConfigError Error
+hi def link i3ConfigTodo Todo
+hi def link i3ConfigComment Comment
+hi def link i3ConfigFontContent Type
+hi def link i3ConfigFocusOnActivationType Type
+hi def link i3ConfigPopupOnFullscreenType Type
+hi def link i3ConfigOrientationKeyword Type
+hi def link i3ConfigMouseWarpingType Type
+hi def link i3ConfigFocusFollowsMouseType Type
+hi def link i3ConfigGapStyleKeyword Type
+hi def link i3ConfigTitleAlignKeyword Type
+hi def link i3ConfigSmartGapKeyword Type
+hi def link i3ConfigSmartBorderKeyword Type
+hi def link i3ConfigLayoutKeyword Type
+hi def link i3ConfigBorderStyleKeyword Type
+hi def link i3ConfigEdgeKeyword Type
+hi def link i3ConfigAction Type
+hi def link i3ConfigCommand Type
+hi def link i3ConfigOutput Type
+hi def link i3ConfigWindowCommandSpecial Type
+hi def link i3ConfigFocusWrappingType Type
+hi def link i3ConfigUnitOr Type
+hi def link i3ConfigFontSize Constant
+hi def link i3ConfigColor Constant
+hi def link i3ConfigNumber Constant
+hi def link i3ConfigUnit Constant
+hi def link i3ConfigVariableAndModifier Constant
+hi def link i3ConfigTimeUnit Constant
+hi def link i3ConfigModifier Constant
+hi def link i3ConfigString Constant
+hi def link i3ConfigNegativeSize Constant
+hi def link i3ConfigFontSeparator Special
+hi def link i3ConfigVariableModifier Special
+hi def link i3ConfigSizeSpecial Special
+hi def link i3ConfigWindowSpecial Special
+hi def link i3ConfigAssignSpecial Special
+hi def link i3ConfigFontNamespace PreProc
+hi def link i3ConfigBindArgument PreProc
+hi def link i3ConfigNoStartupId PreProc
+hi def link i3ConfigFontKeyword Identifier
+hi def link i3ConfigBindKeyword Identifier
+hi def link i3ConfigOrientation Identifier
+hi def link i3ConfigGapStyle Identifier
+hi def link i3ConfigTitleAlign Identifier
+hi def link i3ConfigSmartGap Identifier
+hi def link i3ConfigSmartBorder Identifier
+hi def link i3ConfigLayout Identifier
+hi def link i3ConfigBorderStyle Identifier
+hi def link i3ConfigEdge Identifier
+hi def link i3ConfigFloating Identifier
+hi def link i3ConfigCommandKeyword Identifier
+hi def link i3ConfigNoFocusKeyword Identifier
+hi def link i3ConfigInitializeKeyword Identifier
+hi def link i3ConfigAssignKeyword Identifier
+hi def link i3ConfigResourceKeyword Identifier
+hi def link i3ConfigExecKeyword Identifier
+hi def link i3ConfigWorkspaceKeyword Identifier
+hi def link i3ConfigClientColorKeyword Identifier
+hi def link i3ConfigInterprocessKeyword Identifier
+hi def link i3ConfigMouseWarpingKeyword Identifier
+hi def link i3ConfigFocusFollowsMouseKeyword Identifier
+hi def link i3ConfigPopupOnFullscreenKeyword Identifier
+hi def link i3ConfigFocusWrappingKeyword Identifier
+hi def link i3ConfigForceXineramaKeyword Identifier
+hi def link i3ConfigAutomaticSwitchKeyword Identifier
+hi def link i3ConfigDelayUrgencyKeyword Identifier
+hi def link i3ConfigFocusOnActivationKeyword Identifier
+hi def link i3ConfigDrawingMarksKeyword Identifier
+hi def link i3ConfigBlockKeyword Identifier
+hi def link i3ConfigVariable Statement
+hi def link i3ConfigArbitraryCommand Type
+
+let b:current_syntax = "i3config"
diff --git a/runtime/syntax/python.vim b/runtime/syntax/python.vim
index 3427aa06c8..2293163a5b 100644
--- a/runtime/syntax/python.vim
+++ b/runtime/syntax/python.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Python
" Maintainer: Zvezdan Petkovic <zpetkovic@acm.org>
-" Last Change: 2021 Feb 15
+" Last Change: 2021 Dec 10
" Credits: Neil Schemenauer <nas@python.ca>
" Dmitry Vasiliev
"
@@ -77,13 +77,14 @@ endif
"
" The list can be checked using:
"
-" python3 -c 'import keyword, pprint; pprint.pprint(keyword.kwlist, compact=True)'
+" python3 -c 'import keyword, pprint; pprint.pprint(keyword.kwlist + keyword.softkwlist, compact=True)'
"
syn keyword pythonStatement False None True
syn keyword pythonStatement as assert break continue del global
syn keyword pythonStatement lambda nonlocal pass return with yield
syn keyword pythonStatement class def nextgroup=pythonFunction skipwhite
syn keyword pythonConditional elif else if
+syn keyword pythonConditional case match
syn keyword pythonRepeat for while
syn keyword pythonOperator and in is not or
syn keyword pythonException except finally raise try
diff --git a/runtime/syntax/texinfo.vim b/runtime/syntax/texinfo.vim
index a4b7689707..79a4dfe821 100644
--- a/runtime/syntax/texinfo.vim
+++ b/runtime/syntax/texinfo.vim
@@ -1,396 +1,46 @@
" Vim syntax file
-" Language: Texinfo (macro package for TeX)
-" Maintainer: Sandor Kopanyi <sandor.kopanyi@mailbox.hu>
-" URL: <->
-" Last Change: 2004 Jun 23
-"
-" the file follows the Texinfo manual structure; this file is based
-" on manual for Texinfo version 4.0, 28 September 1999
-" since @ can have special meanings, everything is 'match'-ed and 'region'-ed
-" (including @ in 'iskeyword' option has unexpected effects)
+" Language: Texinfo (documentation format)
+" Maintainer: Robert Dodier <robert.dodier@gmail.com>
+" Latest Revision: 2021-12-15
-" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
-if !exists("main_syntax")
- let main_syntax = 'texinfo'
-endif
-
-"in Texinfo can be real big things, like tables; sync for that
-syn sync lines=200
-
-"some general stuff
-"syn match texinfoError "\S" contained TODO
-syn match texinfoIdent "\k\+" contained "IDENTifier
-syn match texinfoAssignment "\k\+\s*=\s*\k\+\s*$" contained "assigment statement ( var = val )
-syn match texinfoSinglePar "\k\+\s*$" contained "single parameter (used for several @-commands)
-syn match texinfoIndexPar "\k\k\s*$" contained "param. used for different *index commands (+ @documentlanguage command)
-
-
-"marking words and phrases (chap. 9 in Texinfo manual)
-"(almost) everything appears as 'contained' too; is for tables (@table)
-
-"this chapter is at the beginning of this file to avoid overwritings
-
-syn match texinfoSpecialChar "@acronym" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@acronym{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@b" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@b{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@cite" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@cite{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@code" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@code{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@command" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@command{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@dfn" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@dfn{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@email" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@email{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@emph" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@emph{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@env" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@env{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@file" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@file{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@i" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@i{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@kbd" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@kbd{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@key" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@key{" end="}" contains=texinfoSpecialChar
-syn match texinfoSpecialChar "@option" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@option{" end="}" contains=texinfoSpecialChar
-syn match texinfoSpecialChar "@r" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@r{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@samp" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@samp{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@sc" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@sc{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@strong" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@strong{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@t" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@t{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@url" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@url{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoSpecialChar "@var" contained
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@var{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn match texinfoAtCmd "^@kbdinputstyle" nextgroup=texinfoSinglePar skipwhite
-
-
-"overview of Texinfo (chap. 1 in Texinfo manual)
-syn match texinfoComment "@c .*"
-syn match texinfoComment "@c$"
-syn match texinfoComment "@comment .*"
-syn region texinfoMltlnAtCmd matchgroup=texinfoComment start="^@ignore\s*$" end="^@end ignore\s*$" contains=ALL
-
-
-"beginning a Texinfo file (chap. 3 in Texinfo manual)
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="@center " skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd oneline
-syn region texinfoMltlnDMAtCmd matchgroup=texinfoAtCmd start="^@detailmenu\s*$" end="^@end detailmenu\s*$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@setfilename " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@settitle " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@shorttitlepage " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@title " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@titlefont{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@titlepage\s*$" end="^@end titlepage\s*$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoMltlnDMAtCmd,texinfoAtCmd,texinfoPrmAtCmd,texinfoMltlnAtCmd
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@vskip " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn match texinfoAtCmd "^@exampleindent" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "^@headings" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "^\\input" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "^@paragraphindent" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "^@setchapternewpage" nextgroup=texinfoSinglePar skipwhite
-
-
-"ending a Texinfo file (chap. 4 in Texinfo manual)
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="@author " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-"all below @bye should be comment TODO
-syn match texinfoAtCmd "^@bye\s*$"
-syn match texinfoAtCmd "^@contents\s*$"
-syn match texinfoAtCmd "^@printindex" nextgroup=texinfoIndexPar skipwhite
-syn match texinfoAtCmd "^@setcontentsaftertitlepage\s*$"
-syn match texinfoAtCmd "^@setshortcontentsaftertitlepage\s*$"
-syn match texinfoAtCmd "^@shortcontents\s*$"
-syn match texinfoAtCmd "^@summarycontents\s*$"
-
-
-"chapter structuring (chap. 5 in Texinfo manual)
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@appendix" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@appendixsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@appendixsection" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@appendixsubsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@appendixsubsubsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@centerchap" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@chapheading" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@chapter" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@heading" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@majorheading" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@section" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@subheading " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@subsection" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@subsubheading" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@subsubsection" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@subtitle" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@unnumbered" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@unnumberedsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@unnumberedsubsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@unnumberedsubsubsec" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn match texinfoAtCmd "^@lowersections\s*$"
-syn match texinfoAtCmd "^@raisesections\s*$"
-
-
-"nodes (chap. 6 in Texinfo manual)
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@anchor{" end="}"
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@top" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@node" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-
-
-"menus (chap. 7 in Texinfo manual)
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@menu\s*$" end="^@end menu\s*$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoMltlnDMAtCmd
-
-
-"cross references (chap. 8 in Texinfo manual)
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@inforef{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@pxref{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@ref{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@uref{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@xref{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-
-
-"marking words and phrases (chap. 9 in Texinfo manual)
-"(almost) everything appears as 'contained' too; is for tables (@table)
-
-"this chapter is at the beginning of this file to avoid overwritings
-
-
-"quotations and examples (chap. 10 in Texinfo manual)
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@cartouche\s*$" end="^@end cartouche\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@display\s*$" end="^@end display\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@example\s*$" end="^@end example\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@flushleft\s*$" end="^@end flushleft\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@flushright\s*$" end="^@end flushright\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@format\s*$" end="^@end format\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@lisp\s*$" end="^@end lisp\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@quotation\s*$" end="^@end quotation\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@smalldisplay\s*$" end="^@end smalldisplay\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@smallexample\s*$" end="^@end smallexample\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@smallformat\s*$" end="^@end smallformat\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@smalllisp\s*$" end="^@end smalllisp\s*$" contains=ALL
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@exdent" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn match texinfoAtCmd "^@noindent\s*$"
-syn match texinfoAtCmd "^@smallbook\s*$"
-
-
-"lists and tables (chap. 11 in Texinfo manual)
-syn match texinfoAtCmd "@asis" contained
-syn match texinfoAtCmd "@columnfractions" contained
-syn match texinfoAtCmd "@item" contained
-syn match texinfoAtCmd "@itemx" contained
-syn match texinfoAtCmd "@tab" contained
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@enumerate" end="^@end enumerate\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ftable" end="^@end ftable\s*$" contains=ALL
-syn region texinfoMltlnNAtCmd matchgroup=texinfoAtCmd start="^@itemize" end="^@end itemize\s*$" contains=ALL
-syn region texinfoMltlnNAtCmd matchgroup=texinfoAtCmd start="^@multitable" end="^@end multitable\s*$" contains=ALL
-syn region texinfoMltlnNAtCmd matchgroup=texinfoAtCmd start="^@table" end="^@end table\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@vtable" end="^@end vtable\s*$" contains=ALL
+let s:cpo_save = &cpo
+set cpo&vim
+syn match texinfoControlSequence display '\(@end [a-zA-Z@]\+\|@[a-zA-Z@]\+\)'
-"indices (chap. 12 in Texinfo manual)
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@\(c\|f\|k\|p\|t\|v\)index" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@..index" skip="\\$" end="$" contains=texinfoSpecialChar oneline
-"@defcodeindex and @defindex is defined after chap. 15's @def* commands (otherwise those ones will overwrite these ones)
-syn match texinfoSIPar "\k\k\s*\k\k\s*$" contained
-syn match texinfoAtCmd "^@syncodeindex" nextgroup=texinfoSIPar skipwhite
-syn match texinfoAtCmd "^@synindex" nextgroup=texinfoSIPar skipwhite
+syn match texinfoComment display '^\s*\(@comment\|@c\)\>.*$'
-"special insertions (chap. 13 in Texinfo manual)
-syn match texinfoSpecialChar "@\(!\|?\|@\|\s\)"
-syn match texinfoSpecialChar "@{"
-syn match texinfoSpecialChar "@}"
-"accents
-syn match texinfoSpecialChar "@=."
-syn match texinfoSpecialChar "@\('\|\"\|\^\|`\)[aeiouyAEIOUY]"
-syn match texinfoSpecialChar "@\~[aeinouyAEINOUY]"
-syn match texinfoSpecialChar "@dotaccent{.}"
-syn match texinfoSpecialChar "@H{.}"
-syn match texinfoSpecialChar "@,{[cC]}"
-syn match texinfoSpecialChar "@AA{}"
-syn match texinfoSpecialChar "@aa{}"
-syn match texinfoSpecialChar "@L{}"
-syn match texinfoSpecialChar "@l{}"
-syn match texinfoSpecialChar "@O{}"
-syn match texinfoSpecialChar "@o{}"
-syn match texinfoSpecialChar "@ringaccent{.}"
-syn match texinfoSpecialChar "@tieaccent{..}"
-syn match texinfoSpecialChar "@u{.}"
-syn match texinfoSpecialChar "@ubaraccent{.}"
-syn match texinfoSpecialChar "@udotaccent{.}"
-syn match texinfoSpecialChar "@v{.}"
-"ligatures
-syn match texinfoSpecialChar "@AE{}"
-syn match texinfoSpecialChar "@ae{}"
-syn match texinfoSpecialChar "@copyright{}"
-syn match texinfoSpecialChar "@bullet" contained "for tables and lists
-syn match texinfoSpecialChar "@bullet{}"
-syn match texinfoSpecialChar "@dotless{i}"
-syn match texinfoSpecialChar "@dotless{j}"
-syn match texinfoSpecialChar "@dots{}"
-syn match texinfoSpecialChar "@enddots{}"
-syn match texinfoSpecialChar "@equiv" contained "for tables and lists
-syn match texinfoSpecialChar "@equiv{}"
-syn match texinfoSpecialChar "@error{}"
-syn match texinfoSpecialChar "@exclamdown{}"
-syn match texinfoSpecialChar "@expansion{}"
-syn match texinfoSpecialChar "@minus" contained "for tables and lists
-syn match texinfoSpecialChar "@minus{}"
-syn match texinfoSpecialChar "@OE{}"
-syn match texinfoSpecialChar "@oe{}"
-syn match texinfoSpecialChar "@point" contained "for tables and lists
-syn match texinfoSpecialChar "@point{}"
-syn match texinfoSpecialChar "@pounds{}"
-syn match texinfoSpecialChar "@print{}"
-syn match texinfoSpecialChar "@questiondown{}"
-syn match texinfoSpecialChar "@result" contained "for tables and lists
-syn match texinfoSpecialChar "@result{}"
-syn match texinfoSpecialChar "@ss{}"
-syn match texinfoSpecialChar "@TeX{}"
-"other
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@dmn{" end="}"
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@footnote{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@image{" end="}"
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@math{" end="}"
-syn match texinfoAtCmd "@footnotestyle" nextgroup=texinfoSinglePar skipwhite
+syn region texinfoCode matchgroup=texinfoControlSequence start="@code{" end="}" contains=ALL
+syn region texinfoVerb matchgroup=texinfoControlSequence start="@verb{" end="}" contains=ALL
+syn region texinfoArgument matchgroup=texinfoBrace start="{" end="}" contains=ALLBUT
-"making and preventing breaks (chap. 14 in Texinfo manual)
-syn match texinfoSpecialChar "@\(\*\|-\|\.\)"
-syn match texinfoAtCmd "^@need" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "^@page\s*$"
-syn match texinfoAtCmd "^@sp" nextgroup=texinfoSinglePar skipwhite
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@group\s*$" end="^@end group\s*$" contains=ALL
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@hyphenation{" end="}"
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@w{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
+syn region texinfoExample matchgroup=texinfoControlSequence start="^@example\s*$" end="^@end example\s*$" contains=ALL
+syn region texinfoVerbatim matchgroup=texinfoControlSequence start="^@verbatim\s*$" end="^@end verbatim\s*$"
-"definition commands (chap. 15 in Texinfo manual)
-syn match texinfoMltlnAtCmdFLine "^@def\k\+" contained
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@def\k\+" end="^@end def\k\+$" contains=ALL
-
-"next 2 commands are from chap. 12; must be defined after @def* commands above to overwrite them
-syn match texinfoAtCmd "@defcodeindex" nextgroup=texinfoIndexPar skipwhite
-syn match texinfoAtCmd "@defindex" nextgroup=texinfoIndexPar skipwhite
-
-
-"conditionally visible text (chap. 16 in Texinfo manual)
-syn match texinfoAtCmd "^@clear" nextgroup=texinfoSinglePar skipwhite
-syn region texinfoMltln2AtCmd matchgroup=texinfoAtCmd start="^@html\s*$" end="^@end html\s*$"
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifclear" end="^@end ifclear\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifhtml" end="^@end ifhtml\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifinfo" end="^@end ifinfo\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifnothtml" end="^@end ifnothtml\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifnotinfo" end="^@end ifnotinfo\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifnottex" end="^@end ifnottex\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@ifset" end="^@end ifset\s*$" contains=ALL
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@iftex" end="^@end iftex\s*$" contains=ALL
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@set " skip="\\$" end="$" contains=texinfoSpecialChar oneline
-syn region texinfoTexCmd start="\$\$" end="\$\$" contained
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@tex" end="^@end tex\s*$" contains=texinfoTexCmd
-syn region texinfoBrcPrmAtCmd matchgroup=texinfoAtCmd start="@value{" end="}" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-
-
-"internationalization (chap. 17 in Texinfo manual)
-syn match texinfoAtCmd "@documentencoding" nextgroup=texinfoSinglePar skipwhite
-syn match texinfoAtCmd "@documentlanguage" nextgroup=texinfoIndexPar skipwhite
-
-
-"defining new texinfo commands (chap. 18 in Texinfo manual)
-syn match texinfoAtCmd "@alias" nextgroup=texinfoAssignment skipwhite
-syn match texinfoDIEPar "\S*\s*,\s*\S*\s*,\s*\S*\s*$" contained
-syn match texinfoAtCmd "@definfoenclose" nextgroup=texinfoDIEPar skipwhite
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@macro" end="^@end macro\s*$" contains=ALL
-
-
-"formatting hardcopy (chap. 19 in Texinfo manual)
-syn match texinfoAtCmd "^@afourlatex\s*$"
-syn match texinfoAtCmd "^@afourpaper\s*$"
-syn match texinfoAtCmd "^@afourwide\s*$"
-syn match texinfoAtCmd "^@finalout\s*$"
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@pagesizes" end="$" oneline
-
-
-"creating and installing Info Files (chap. 20 in Texinfo manual)
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@dircategory" skip="\\$" end="$" oneline
-syn region texinfoMltlnAtCmd matchgroup=texinfoAtCmd start="^@direntry\s*$" end="^@end direntry\s*$" contains=texinfoSpecialChar
-syn match texinfoAtCmd "^@novalidate\s*$"
-
-
-"include files (appendix E in Texinfo manual)
-syn match texinfoAtCmd "^@include" nextgroup=texinfoSinglePar skipwhite
-
-
-"page headings (appendix F in Texinfo manual)
-syn match texinfoHFSpecialChar "@|" contained
-syn match texinfoThisAtCmd "@thischapter" contained
-syn match texinfoThisAtCmd "@thischaptername" contained
-syn match texinfoThisAtCmd "@thisfile" contained
-syn match texinfoThisAtCmd "@thispage" contained
-syn match texinfoThisAtCmd "@thistitle" contained
-syn match texinfoThisAtCmd "@today{}" contained
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@evenfooting" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@evenheading" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@everyfooting" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@everyheading" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@oddfooting" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-syn region texinfoPrmAtCmd matchgroup=texinfoAtCmd start="^@oddheading" skip="\\$" end="$" contains=texinfoSpecialChar,texinfoBrcPrmAtCmd,texinfoThisAtCmd,texinfoHFSpecialChar oneline
-
-
-"refilling paragraphs (appendix H in Texinfo manual)
-syn match texinfoAtCmd "@refill"
-
-
-syn cluster texinfoAll contains=ALLBUT,texinfoThisAtCmd,texinfoHFSpecialChar
-syn cluster texinfoReducedAll contains=texinfoSpecialChar,texinfoBrcPrmAtCmd
-"==============================================================================
-" highlighting
-
-" Only when an item doesn't have highlighting yet
-
-hi def link texinfoSpecialChar Special
-hi def link texinfoHFSpecialChar Special
-
-hi def link texinfoError Error
-hi def link texinfoIdent Identifier
-hi def link texinfoAssignment Identifier
-hi def link texinfoSinglePar Identifier
-hi def link texinfoIndexPar Identifier
-hi def link texinfoSIPar Identifier
-hi def link texinfoDIEPar Identifier
-hi def link texinfoTexCmd PreProc
-
-
-hi def link texinfoAtCmd Statement "@-command
-hi def link texinfoPrmAtCmd String "@-command in one line with unknown nr. of parameters
- "is String because is found as a region and is 'matchgroup'-ed
- "to texinfoAtCmd
-hi def link texinfoBrcPrmAtCmd String "@-command with parameter(s) in braces ({})
- "is String because is found as a region and is 'matchgroup'-ed to texinfoAtCmd
-hi def link texinfoMltlnAtCmdFLine texinfoAtCmd "repeated embedded First lines in @-commands
-hi def link texinfoMltlnAtCmd String "@-command in multiple lines
- "is String because is found as a region and is 'matchgroup'-ed to texinfoAtCmd
-hi def link texinfoMltln2AtCmd PreProc "@-command in multiple lines (same as texinfoMltlnAtCmd, just with other colors)
-hi def link texinfoMltlnDMAtCmd PreProc "@-command in multiple lines (same as texinfoMltlnAtCmd, just with other colors; used for @detailmenu, which can be included in @menu)
-hi def link texinfoMltlnNAtCmd Normal "@-command in multiple lines (same as texinfoMltlnAtCmd, just with other colors)
-hi def link texinfoThisAtCmd Statement "@-command used in headers and footers (@this... series)
-
-hi def link texinfoComment Comment
+syn region texinfoMenu matchgroup=texinfoControlSequence start="^@menu\s*$" end="^@end menu\s*$"
+if exists("g:texinfo_delimiters")
+ syn match texinfoDelimiter display '[][{}]'
+endif
+hi def link texinfoDelimiter Delimiter
+hi def link texinfoComment Comment
+hi def link texinfoControlSequence Identifier
+hi def link texinfoBrace Operator
+hi def link texinfoArgument Special
+hi def link texinfoExample String
+hi def link texinfoVerbatim String
+hi def link texinfoVerb String
+hi def link texinfoCode String
+hi def link texinfoMenu String
let b:current_syntax = "texinfo"
-if main_syntax == 'texinfo'
- unlet main_syntax
-endif
-
-" vim: ts=8
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/xml.vim b/runtime/syntax/xml.vim
index 7c9791a7cc..d99f8b467a 100644
--- a/runtime/syntax/xml.vim
+++ b/runtime/syntax/xml.vim
@@ -10,6 +10,7 @@
" 20190923 - Fix xmlEndTag to match xmlTag (vim/vim#884)
" 20190924 - Fix xmlAttribute property (amadeus/vim-xml@d8ce1c946)
" 20191103 - Enable spell checking globally
+" 20210428 - Improve syntax synchronizing
" CONFIGURATION:
" syntax folding can be turned on by
@@ -302,9 +303,12 @@ unlet b:current_syntax
" synchronizing
-" TODO !!! to be improved !!!
-syn sync match xmlSyncDT grouphere xmlDocType +\_.\(<!DOCTYPE\)\@=+
+syn sync match xmlSyncComment grouphere xmlComment +<!--+
+syn sync match xmlSyncComment groupthere NONE +-->+
+
+" The following is slow on large documents (and the doctype is optional
+" syn sync match xmlSyncDT grouphere xmlDocType +\_.\(<!DOCTYPE\)\@=+
" syn sync match xmlSyncDT groupthere NONE +]>+
if exists('g:xml_syntax_folding')
@@ -313,7 +317,7 @@ if exists('g:xml_syntax_folding')
syn sync match xmlSync groupthere xmlRegion +</[^ /!?<>"']\+>+
endif
-syn sync minlines=100
+syn sync minlines=100 maxlines=200
" The default highlighting.
@@ -354,4 +358,4 @@ let b:current_syntax = "xml"
let &cpo = s:xml_cpo_save
unlet s:xml_cpo_save
-" vim: ts=8
+" vim: ts=4
diff --git a/runtime/syntax/zsh.vim b/runtime/syntax/zsh.vim
index 819c419228..bab89b916e 100644
--- a/runtime/syntax/zsh.vim
+++ b/runtime/syntax/zsh.vim
@@ -41,11 +41,12 @@ if get(g:, 'zsh_fold_enable', 0)
setlocal foldmethod=syntax
endif
+syn match zshQuoted '\\.'
syn match zshPOSIXQuoted '\\[xX][0-9a-fA-F]\{1,2}'
syn match zshPOSIXQuoted '\\[0-7]\{1,3}'
syn match zshPOSIXQuoted '\\u[0-9a-fA-F]\{1,4}'
syn match zshPOSIXQuoted '\\U[1-9a-fA-F]\{1,8}'
-syn match zshQuoted '\\.'
+
syn region zshString matchgroup=zshStringDelimiter start=+"+ end=+"+
\ contains=zshQuoted,@zshDerefs,@zshSubst fold
syn region zshString matchgroup=zshStringDelimiter start=+'+ end=+'+ fold
@@ -133,217 +134,15 @@ syn keyword zshCommands alias autoload bg bindkey break bye cap cd
\ zmodload zparseopts zprof zpty zrecompile
\ zregexparse zsocket zstyle ztcp
-" Options, generated by: echo ${(j:\n:)options[(I)*]} | sort
-" Create a list of option names from zsh source dir:
-" #!/bin/zsh
-" topdir=/path/to/zsh-xxx
-" grep '^pindex([A-Za-z_]*)$' $topdir/Doc/Zsh/options.yo |
-" while read opt
-" do
-" echo ${${(L)opt#pindex\(}%\)}
-" done
-
+" Options, generated by from the zsh source with the make-options.zsh script.
syn case ignore
-
-syn match zshOptStart /^\s*\%(\%(\%(un\)\?setopt\)\|set\s+[-+]o\)/ nextgroup=zshOption skipwhite
-syn match zshOption /
- \ \%(\%(\<no_\?\)\?aliases\>\)\|
- \ \%(\%(\<no_\?\)\?aliasfuncdef\>\)\|\%(\%(no_\?\)\?alias_func_def\>\)\|
- \ \%(\%(\<no_\?\)\?allexport\>\)\|\%(\%(no_\?\)\?all_export\>\)\|
- \ \%(\%(\<no_\?\)\?alwayslastprompt\>\)\|\%(\%(no_\?\)\?always_last_prompt\>\)\|\%(\%(no_\?\)\?always_lastprompt\>\)\|
- \ \%(\%(\<no_\?\)\?alwaystoend\>\)\|\%(\%(no_\?\)\?always_to_end\>\)\|
- \ \%(\%(\<no_\?\)\?appendcreate\>\)\|\%(\%(no_\?\)\?append_create\>\)\|
- \ \%(\%(\<no_\?\)\?appendhistory\>\)\|\%(\%(no_\?\)\?append_history\>\)\|
- \ \%(\%(\<no_\?\)\?autocd\>\)\|\%(\%(no_\?\)\?auto_cd\>\)\|
- \ \%(\%(\<no_\?\)\?autocontinue\>\)\|\%(\%(no_\?\)\?auto_continue\>\)\|
- \ \%(\%(\<no_\?\)\?autolist\>\)\|\%(\%(no_\?\)\?auto_list\>\)\|
- \ \%(\%(\<no_\?\)\?automenu\>\)\|\%(\%(no_\?\)\?auto_menu\>\)\|
- \ \%(\%(\<no_\?\)\?autonamedirs\>\)\|\%(\%(no_\?\)\?auto_name_dirs\>\)\|
- \ \%(\%(\<no_\?\)\?autoparamkeys\>\)\|\%(\%(no_\?\)\?auto_param_keys\>\)\|
- \ \%(\%(\<no_\?\)\?autoparamslash\>\)\|\%(\%(no_\?\)\?auto_param_slash\>\)\|
- \ \%(\%(\<no_\?\)\?autopushd\>\)\|\%(\%(no_\?\)\?auto_pushd\>\)\|
- \ \%(\%(\<no_\?\)\?autoremoveslash\>\)\|\%(\%(no_\?\)\?auto_remove_slash\>\)\|
- \ \%(\%(\<no_\?\)\?autoresume\>\)\|\%(\%(no_\?\)\?auto_resume\>\)\|
- \ \%(\%(\<no_\?\)\?badpattern\>\)\|\%(\%(no_\?\)\?bad_pattern\>\)\|
- \ \%(\%(\<no_\?\)\?banghist\>\)\|\%(\%(no_\?\)\?bang_hist\>\)\|
- \ \%(\%(\<no_\?\)\?bareglobqual\>\)\|\%(\%(no_\?\)\?bare_glob_qual\>\)\|
- \ \%(\%(\<no_\?\)\?bashautolist\>\)\|\%(\%(no_\?\)\?bash_auto_list\>\)\|
- \ \%(\%(\<no_\?\)\?bashrematch\>\)\|\%(\%(no_\?\)\?bash_rematch\>\)\|
- \ \%(\%(\<no_\?\)\?beep\>\)\|
- \ \%(\%(\<no_\?\)\?bgnice\>\)\|\%(\%(no_\?\)\?bg_nice\>\)\|
- \ \%(\%(\<no_\?\)\?braceccl\>\)\|\%(\%(no_\?\)\?brace_ccl\>\)\|
- \ \%(\%(\<no_\?\)\?braceexpand\>\)\|\%(\%(no_\?\)\?brace_expand\>\)\|
- \ \%(\%(\<no_\?\)\?bsdecho\>\)\|\%(\%(no_\?\)\?bsd_echo\>\)\|
- \ \%(\%(\<no_\?\)\?caseglob\>\)\|\%(\%(no_\?\)\?case_glob\>\)\|
- \ \%(\%(\<no_\?\)\?casematch\>\)\|\%(\%(no_\?\)\?case_match\>\)\|
- \ \%(\%(\<no_\?\)\?cbases\>\)\|\%(\%(no_\?\)\?c_bases\>\)\|
- \ \%(\%(\<no_\?\)\?cdablevars\>\)\|\%(\%(no_\?\)\?cdable_vars\>\)\|\%(\%(no_\?\)\?cd_able_vars\>\)\|
- \ \%(\%(\<no_\?\)\?cdsilent\>\)\|\%(\%(no_\?\)\?cd_silent\>\)\|\%(\%(no_\?\)\?cd_silent\>\)\|
- \ \%(\%(\<no_\?\)\?chasedots\>\)\|\%(\%(no_\?\)\?chase_dots\>\)\|
- \ \%(\%(\<no_\?\)\?chaselinks\>\)\|\%(\%(no_\?\)\?chase_links\>\)\|
- \ \%(\%(\<no_\?\)\?checkjobs\>\)\|\%(\%(no_\?\)\?check_jobs\>\)\|
- \ \%(\%(\<no_\?\)\?checkrunningjobs\>\)\|\%(\%(no_\?\)\?check_running_jobs\>\)\|
- \ \%(\%(\<no_\?\)\?clobber\>\)\|
- \ \%(\%(\<no_\?\)\?clobberempty\>\)\|\%(\%(no_\?\)\?clobber_empty\>\)\|
- \ \%(\%(\<no_\?\)\?combiningchars\>\)\|\%(\%(no_\?\)\?combining_chars\>\)\|
- \ \%(\%(\<no_\?\)\?completealiases\>\)\|\%(\%(no_\?\)\?complete_aliases\>\)\|
- \ \%(\%(\<no_\?\)\?completeinword\>\)\|\%(\%(no_\?\)\?complete_in_word\>\)\|
- \ \%(\%(\<no_\?\)\?continueonerror\>\)\|\%(\%(no_\?\)\?continue_on_error\>\)\|
- \ \%(\%(\<no_\?\)\?correct\>\)\|
- \ \%(\%(\<no_\?\)\?correctall\>\)\|\%(\%(no_\?\)\?correct_all\>\)\|
- \ \%(\%(\<no_\?\)\?cprecedences\>\)\|\%(\%(no_\?\)\?c_precedences\>\)\|
- \ \%(\%(\<no_\?\)\?cshjunkiehistory\>\)\|\%(\%(no_\?\)\?csh_junkie_history\>\)\|
- \ \%(\%(\<no_\?\)\?cshjunkieloops\>\)\|\%(\%(no_\?\)\?csh_junkie_loops\>\)\|
- \ \%(\%(\<no_\?\)\?cshjunkiequotes\>\)\|\%(\%(no_\?\)\?csh_junkie_quotes\>\)\|
- \ \%(\%(\<no_\?\)\?csh_nullcmd\>\)\|\%(\%(no_\?\)\?csh_null_cmd\>\)\|\%(\%(no_\?\)\?cshnullcmd\>\)\|\%(\%(no_\?\)\?csh_null_cmd\>\)\|
- \ \%(\%(\<no_\?\)\?cshnullglob\>\)\|\%(\%(no_\?\)\?csh_null_glob\>\)\|
- \ \%(\%(\<no_\?\)\?debugbeforecmd\>\)\|\%(\%(no_\?\)\?debug_before_cmd\>\)\|
- \ \%(\%(\<no_\?\)\?dotglob\>\)\|\%(\%(no_\?\)\?dot_glob\>\)\|
- \ \%(\%(\<no_\?\)\?dvorak\>\)\|
- \ \%(\%(\<no_\?\)\?emacs\>\)\|
- \ \%(\%(\<no_\?\)\?equals\>\)\|
- \ \%(\%(\<no_\?\)\?errexit\>\)\|\%(\%(no_\?\)\?err_exit\>\)\|
- \ \%(\%(\<no_\?\)\?errreturn\>\)\|\%(\%(no_\?\)\?err_return\>\)\|
- \ \%(\%(\<no_\?\)\?evallineno\>\)\|\%(\%(no_\?\)\?eval_lineno\>\)\|
- \ \%(\%(\<no_\?\)\?exec\>\)\|
- \ \%(\%(\<no_\?\)\?extendedglob\>\)\|\%(\%(no_\?\)\?extended_glob\>\)\|
- \ \%(\%(\<no_\?\)\?extendedhistory\>\)\|\%(\%(no_\?\)\?extended_history\>\)\|
- \ \%(\%(\<no_\?\)\?flowcontrol\>\)\|\%(\%(no_\?\)\?flow_control\>\)\|
- \ \%(\%(\<no_\?\)\?forcefloat\>\)\|\%(\%(no_\?\)\?force_float\>\)\|
- \ \%(\%(\<no_\?\)\?functionargzero\>\)\|\%(\%(no_\?\)\?function_argzero\>\)\|\%(\%(no_\?\)\?function_arg_zero\>\)\|
- \ \%(\%(\<no_\?\)\?glob\>\)\|
- \ \%(\%(\<no_\?\)\?globalexport\>\)\|\%(\%(no_\?\)\?global_export\>\)\|
- \ \%(\%(\<no_\?\)\?globalrcs\>\)\|\%(\%(no_\?\)\?global_rcs\>\)\|
- \ \%(\%(\<no_\?\)\?globassign\>\)\|\%(\%(no_\?\)\?glob_assign\>\)\|
- \ \%(\%(\<no_\?\)\?globcomplete\>\)\|\%(\%(no_\?\)\?glob_complete\>\)\|
- \ \%(\%(\<no_\?\)\?globdots\>\)\|\%(\%(no_\?\)\?glob_dots\>\)\|
- \ \%(\%(\<no_\?\)\?glob_subst\>\)\|\%(\%(no_\?\)\?globsubst\>\)\|
- \ \%(\%(\<no_\?\)\?globstarshort\>\)\|\%(\%(no_\?\)\?glob_star_short\>\)\|
- \ \%(\%(\<no_\?\)\?hashall\>\)\|\%(\%(no_\?\)\?hash_all\>\)\|
- \ \%(\%(\<no_\?\)\?hashcmds\>\)\|\%(\%(no_\?\)\?hash_cmds\>\)\|
- \ \%(\%(\<no_\?\)\?hashdirs\>\)\|\%(\%(no_\?\)\?hash_dirs\>\)\|
- \ \%(\%(\<no_\?\)\?hashexecutablesonly\>\)\|\%(\%(no_\?\)\?hash_executables_only\>\)\|
- \ \%(\%(\<no_\?\)\?hashlistall\>\)\|\%(\%(no_\?\)\?hash_list_all\>\)\|
- \ \%(\%(\<no_\?\)\?histallowclobber\>\)\|\%(\%(no_\?\)\?hist_allow_clobber\>\)\|
- \ \%(\%(\<no_\?\)\?histappend\>\)\|\%(\%(no_\?\)\?hist_append\>\)\|
- \ \%(\%(\<no_\?\)\?histbeep\>\)\|\%(\%(no_\?\)\?hist_beep\>\)\|
- \ \%(\%(\<no_\?\)\?hist_expand\>\)\|\%(\%(no_\?\)\?histexpand\>\)\|
- \ \%(\%(\<no_\?\)\?hist_expire_dups_first\>\)\|\%(\%(no_\?\)\?histexpiredupsfirst\>\)\|
- \ \%(\%(\<no_\?\)\?histfcntllock\>\)\|\%(\%(no_\?\)\?hist_fcntl_lock\>\)\|
- \ \%(\%(\<no_\?\)\?histfindnodups\>\)\|\%(\%(no_\?\)\?hist_find_no_dups\>\)\|
- \ \%(\%(\<no_\?\)\?histignorealldups\>\)\|\%(\%(no_\?\)\?hist_ignore_all_dups\>\)\|
- \ \%(\%(\<no_\?\)\?histignoredups\>\)\|\%(\%(no_\?\)\?hist_ignore_dups\>\)\|
- \ \%(\%(\<no_\?\)\?histignorespace\>\)\|\%(\%(no_\?\)\?hist_ignore_space\>\)\|
- \ \%(\%(\<no_\?\)\?histlexwords\>\)\|\%(\%(no_\?\)\?hist_lex_words\>\)\|
- \ \%(\%(\<no_\?\)\?histnofunctions\>\)\|\%(\%(no_\?\)\?hist_no_functions\>\)\|
- \ \%(\%(\<no_\?\)\?histnostore\>\)\|\%(\%(no_\?\)\?hist_no_store\>\)\|
- \ \%(\%(\<no_\?\)\?histreduceblanks\>\)\|\%(\%(no_\?\)\?hist_reduce_blanks\>\)\|
- \ \%(\%(\<no_\?\)\?histsavebycopy\>\)\|\%(\%(no_\?\)\?hist_save_by_copy\>\)\|
- \ \%(\%(\<no_\?\)\?histsavenodups\>\)\|\%(\%(no_\?\)\?hist_save_no_dups\>\)\|
- \ \%(\%(\<no_\?\)\?histsubstpattern\>\)\|\%(\%(no_\?\)\?hist_subst_pattern\>\)\|
- \ \%(\%(\<no_\?\)\?histverify\>\)\|\%(\%(no_\?\)\?hist_verify\>\)\|
- \ \%(\%(\<no_\?\)\?hup\>\)\|
- \ \%(\%(\<no_\?\)\?ignorebraces\>\)\|\%(\%(no_\?\)\?ignore_braces\>\)\|
- \ \%(\%(\<no_\?\)\?ignoreclosebraces\>\)\|\%(\%(no_\?\)\?ignore_close_braces\>\)\|
- \ \%(\%(\<no_\?\)\?ignoreeof\>\)\|\%(\%(no_\?\)\?ignore_eof\>\)\|
- \ \%(\%(\<no_\?\)\?incappendhistory\>\)\|\%(\%(no_\?\)\?inc_append_history\>\)\|
- \ \%(\%(\<no_\?\)\?incappendhistorytime\>\)\|\%(\%(no_\?\)\?inc_append_history_time\>\)\|
- \ \%(\%(\<no_\?\)\?interactive\>\)\|
- \ \%(\%(\<no_\?\)\?interactivecomments\>\)\|\%(\%(no_\?\)\?interactive_comments\>\)\|
- \ \%(\%(\<no_\?\)\?ksharrays\>\)\|\%(\%(no_\?\)\?ksh_arrays\>\)\|
- \ \%(\%(\<no_\?\)\?kshautoload\>\)\|\%(\%(no_\?\)\?ksh_autoload\>\)\|
- \ \%(\%(\<no_\?\)\?kshglob\>\)\|\%(\%(no_\?\)\?ksh_glob\>\)\|
- \ \%(\%(\<no_\?\)\?kshoptionprint\>\)\|\%(\%(no_\?\)\?ksh_option_print\>\)\|
- \ \%(\%(\<no_\?\)\?kshtypeset\>\)\|\%(\%(no_\?\)\?ksh_typeset\>\)\|
- \ \%(\%(\<no_\?\)\?kshzerosubscript\>\)\|\%(\%(no_\?\)\?ksh_zero_subscript\>\)\|
- \ \%(\%(\<no_\?\)\?listambiguous\>\)\|\%(\%(no_\?\)\?list_ambiguous\>\)\|
- \ \%(\%(\<no_\?\)\?listbeep\>\)\|\%(\%(no_\?\)\?list_beep\>\)\|
- \ \%(\%(\<no_\?\)\?listpacked\>\)\|\%(\%(no_\?\)\?list_packed\>\)\|
- \ \%(\%(\<no_\?\)\?listrowsfirst\>\)\|\%(\%(no_\?\)\?list_rows_first\>\)\|
- \ \%(\%(\<no_\?\)\?listtypes\>\)\|\%(\%(no_\?\)\?list_types\>\)\|
- \ \%(\%(\<no_\?\)\?localloops\>\)\|\%(\%(no_\?\)\?local_loops\>\)\|
- \ \%(\%(\<no_\?\)\?localoptions\>\)\|\%(\%(no_\?\)\?local_options\>\)\|
- \ \%(\%(\<no_\?\)\?localpatterns\>\)\|\%(\%(no_\?\)\?local_patterns\>\)\|
- \ \%(\%(\<no_\?\)\?localtraps\>\)\|\%(\%(no_\?\)\?local_traps\>\)\|
- \ \%(\%(\<no_\?\)\?log\>\)\|
- \ \%(\%(\<no_\?\)\?login\>\)\|
- \ \%(\%(\<no_\?\)\?longlistjobs\>\)\|\%(\%(no_\?\)\?long_list_jobs\>\)\|
- \ \%(\%(\<no_\?\)\?magicequalsubst\>\)\|\%(\%(no_\?\)\?magic_equal_subst\>\)\|
- \ \%(\%(\<no_\?\)\?mark_dirs\>\)\|
- \ \%(\%(\<no_\?\)\?mailwarn\>\)\|\%(\%(no_\?\)\?mail_warn\>\)\|
- \ \%(\%(\<no_\?\)\?mailwarning\>\)\|\%(\%(no_\?\)\?mail_warning\>\)\|
- \ \%(\%(\<no_\?\)\?markdirs\>\)\|
- \ \%(\%(\<no_\?\)\?menucomplete\>\)\|\%(\%(no_\?\)\?menu_complete\>\)\|
- \ \%(\%(\<no_\?\)\?monitor\>\)\|
- \ \%(\%(\<no_\?\)\?multibyte\>\)\|\%(\%(no_\?\)\?multi_byte\>\)\|
- \ \%(\%(\<no_\?\)\?multifuncdef\>\)\|\%(\%(no_\?\)\?multi_func_def\>\)\|
- \ \%(\%(\<no_\?\)\?multios\>\)\|\%(\%(no_\?\)\?multi_os\>\)\|
- \ \%(\%(\<no_\?\)\?nomatch\>\)\|\%(\%(no_\?\)\?no_match\>\)\|
- \ \%(\%(\<no_\?\)\?notify\>\)\|
- \ \%(\%(\<no_\?\)\?nullglob\>\)\|\%(\%(no_\?\)\?null_glob\>\)\|
- \ \%(\%(\<no_\?\)\?numericglobsort\>\)\|\%(\%(no_\?\)\?numeric_glob_sort\>\)\|
- \ \%(\%(\<no_\?\)\?octalzeroes\>\)\|\%(\%(no_\?\)\?octal_zeroes\>\)\|
- \ \%(\%(\<no_\?\)\?onecmd\>\)\|\%(\%(no_\?\)\?one_cmd\>\)\|
- \ \%(\%(\<no_\?\)\?overstrike\>\)\|\%(\%(no_\?\)\?over_strike\>\)\|
- \ \%(\%(\<no_\?\)\?pathdirs\>\)\|\%(\%(no_\?\)\?path_dirs\>\)\|
- \ \%(\%(\<no_\?\)\?pathscript\>\)\|\%(\%(no_\?\)\?path_script\>\)\|
- \ \%(\%(\<no_\?\)\?physical\>\)\|
- \ \%(\%(\<no_\?\)\?pipefail\>\)\|\%(\%(no_\?\)\?pipe_fail\>\)\|
- \ \%(\%(\<no_\?\)\?posixaliases\>\)\|\%(\%(no_\?\)\?posix_aliases\>\)\|
- \ \%(\%(\<no_\?\)\?posixargzero\>\)\|\%(\%(no_\?\)\?posix_arg_zero\>\)\|\%(\%(no_\?\)\?posix_argzero\>\)\|
- \ \%(\%(\<no_\?\)\?posixbuiltins\>\)\|\%(\%(no_\?\)\?posix_builtins\>\)\|
- \ \%(\%(\<no_\?\)\?posixcd\>\)\|\%(\%(no_\?\)\?posix_cd\>\)\|
- \ \%(\%(\<no_\?\)\?posixidentifiers\>\)\|\%(\%(no_\?\)\?posix_identifiers\>\)\|
- \ \%(\%(\<no_\?\)\?posixjobs\>\)\|\%(\%(no_\?\)\?posix_jobs\>\)\|
- \ \%(\%(\<no_\?\)\?posixstrings\>\)\|\%(\%(no_\?\)\?posix_strings\>\)\|
- \ \%(\%(\<no_\?\)\?posixtraps\>\)\|\%(\%(no_\?\)\?posix_traps\>\)\|
- \ \%(\%(\<no_\?\)\?printeightbit\>\)\|\%(\%(no_\?\)\?print_eight_bit\>\)\|
- \ \%(\%(\<no_\?\)\?printexitvalue\>\)\|\%(\%(no_\?\)\?print_exit_value\>\)\|
- \ \%(\%(\<no_\?\)\?privileged\>\)\|
- \ \%(\%(\<no_\?\)\?promptbang\>\)\|\%(\%(no_\?\)\?prompt_bang\>\)\|
- \ \%(\%(\<no_\?\)\?promptcr\>\)\|\%(\%(no_\?\)\?prompt_cr\>\)\|
- \ \%(\%(\<no_\?\)\?promptpercent\>\)\|\%(\%(no_\?\)\?prompt_percent\>\)\|
- \ \%(\%(\<no_\?\)\?promptsp\>\)\|\%(\%(no_\?\)\?prompt_sp\>\)\|
- \ \%(\%(\<no_\?\)\?promptsubst\>\)\|\%(\%(no_\?\)\?prompt_subst\>\)\|
- \ \%(\%(\<no_\?\)\?promptvars\>\)\|\%(\%(no_\?\)\?prompt_vars\>\)\|
- \ \%(\%(\<no_\?\)\?pushdignoredups\>\)\|\%(\%(no_\?\)\?pushd_ignore_dups\>\)\|
- \ \%(\%(\<no_\?\)\?pushdminus\>\)\|\%(\%(no_\?\)\?pushd_minus\>\)\|
- \ \%(\%(\<no_\?\)\?pushdsilent\>\)\|\%(\%(no_\?\)\?pushd_silent\>\)\|
- \ \%(\%(\<no_\?\)\?pushdtohome\>\)\|\%(\%(no_\?\)\?pushd_to_home\>\)\|
- \ \%(\%(\<no_\?\)\?rcexpandparam\>\)\|\%(\%(no_\?\)\?rc_expandparam\>\)\|\%(\%(no_\?\)\?rc_expand_param\>\)\|
- \ \%(\%(\<no_\?\)\?rcquotes\>\)\|\%(\%(no_\?\)\?rc_quotes\>\)\|
- \ \%(\%(\<no_\?\)\?rcs\>\)\|
- \ \%(\%(\<no_\?\)\?recexact\>\)\|\%(\%(no_\?\)\?rec_exact\>\)\|
- \ \%(\%(\<no_\?\)\?rematchpcre\>\)\|\%(\%(no_\?\)\?re_match_pcre\>\)\|\%(\%(no_\?\)\?rematch_pcre\>\)\|
- \ \%(\%(\<no_\?\)\?restricted\>\)\|
- \ \%(\%(\<no_\?\)\?rmstarsilent\>\)\|\%(\%(no_\?\)\?rm_star_silent\>\)\|
- \ \%(\%(\<no_\?\)\?rmstarwait\>\)\|\%(\%(no_\?\)\?rm_star_wait\>\)\|
- \ \%(\%(\<no_\?\)\?sharehistory\>\)\|\%(\%(no_\?\)\?share_history\>\)\|
- \ \%(\%(\<no_\?\)\?shfileexpansion\>\)\|\%(\%(no_\?\)\?sh_file_expansion\>\)\|
- \ \%(\%(\<no_\?\)\?shglob\>\)\|\%(\%(no_\?\)\?sh_glob\>\)\|
- \ \%(\%(\<no_\?\)\?shinstdin\>\)\|\%(\%(no_\?\)\?shin_stdin\>\)\|
- \ \%(\%(\<no_\?\)\?shnullcmd\>\)\|\%(\%(no_\?\)\?sh_nullcmd\>\)\|
- \ \%(\%(\<no_\?\)\?shoptionletters\>\)\|\%(\%(no_\?\)\?sh_option_letters\>\)\|
- \ \%(\%(\<no_\?\)\?shortloops\>\)\|\%(\%(no_\?\)\?short_loops\>\)\|
- \ \%(\%(\<no_\?\)\?shortrepeat\>\)\|\%(\%(no_\?\)\?short_repeat\>\)\|
- \ \%(\%(\<no_\?\)\?shwordsplit\>\)\|\%(\%(no_\?\)\?sh_word_split\>\)\|
- \ \%(\%(\<no_\?\)\?singlecommand\>\)\|\%(\%(no_\?\)\?single_command\>\)\|
- \ \%(\%(\<no_\?\)\?singlelinezle\>\)\|\%(\%(no_\?\)\?single_line_zle\>\)\|
- \ \%(\%(\<no_\?\)\?sourcetrace\>\)\|\%(\%(no_\?\)\?source_trace\>\)\|
- \ \%(\%(\<no_\?\)\?stdin\>\)\|
- \ \%(\%(\<no_\?\)\?sunkeyboardhack\>\)\|\%(\%(no_\?\)\?sun_keyboard_hack\>\)\|
- \ \%(\%(\<no_\?\)\?trackall\>\)\|\%(\%(no_\?\)\?track_all\>\)\|
- \ \%(\%(\<no_\?\)\?transientrprompt\>\)\|\%(\%(no_\?\)\?transient_rprompt\>\)\|
- \ \%(\%(\<no_\?\)\?trapsasync\>\)\|\%(\%(no_\?\)\?traps_async\>\)\|
- \ \%(\%(\<no_\?\)\?typesetsilent\>\)\|\%(\%(no_\?\)\?type_set_silent\>\)\|\%(\%(no_\?\)\?typeset_silent\>\)\|
- \ \%(\%(\<no_\?\)\?unset\>\)\|
- \ \%(\%(\<no_\?\)\?verbose\>\)\|
- \ \%(\%(\<no_\?\)\?vi\>\)\|
- \ \%(\%(\<no_\?\)\?warnnestedvar\>\)\|\%(\%(no_\?\)\?warn_nested_var\>\)\|
- \ \%(\%(\<no_\?\)\?warncreateglobal\>\)\|\%(\%(no_\?\)\?warn_create_global\>\)\|
- \ \%(\%(\<no_\?\)\?xtrace\>\)\|
- \ \%(\%(\<no_\?\)\?zle\>\)/ nextgroup=zshOption,zshComment skipwhite contained
-
+syn match zshOptStart
+ \ /\v^\s*%(%(un)?setopt|set\s+[-+]o)/
+ \ nextgroup=zshOption skipwhite
+syn match zshOption nextgroup=zshOption,zshComment skipwhite contained /\v
+ \ <%(no_?)?%(
+ \ auto_?cd|auto_?pushd|cdable_?vars|cd_?silent|chase_?dots|chase_?links|posix_?cd|pushd_?ignore_?dups|pushd_?minus|pushd_?silent|pushd_?to_?home|always_?last_?prompt|always_?to_?end|auto_?list|auto_?menu|auto_?name_?dirs|auto_?param_?keys|auto_?param_?slash|auto_?remove_?slash|bash_?auto_?list|complete_?aliases|complete_?in_?word|glob_?complete|hash_?list_?all|list_?ambiguous|list_?beep|list_?packed|list_?rows_?first|list_?types|menu_?complete|rec_?exact|bad_?pattern|bare_?glob_?qual|brace_?ccl|case_?glob|case_?match|case_?paths|csh_?null_?glob|equals|extended_?glob|force_?float|glob|glob_?assign|glob_?dots|glob_?star_?short|glob_?subst|hist_?subst_?pattern|ignore_?braces|ignore_?close_?braces|ksh_?glob|magic_?equal_?subst|mark_?dirs|multibyte|nomatch|null_?glob|numeric_?glob_?sort|rc_?expand_?param|rematch_?pcre|sh_?glob|unset|warn_?create_?global|warn_?nested_?var|warnnestedvar|append_?history|bang_?hist|extended_?history|hist_?allow_?clobber|hist_?beep|hist_?expire_?dups_?first|hist_?fcntl_?lock|hist_?find_?no_?dups|hist_?ignore_?all_?dups|hist_?ignore_?dups|hist_?ignore_?space|hist_?lex_?words|hist_?no_?functions|hist_?no_?store|hist_?reduce_?blanks|hist_?save_?by_?copy|hist_?save_?no_?dups|hist_?verify|inc_?append_?history|inc_?append_?history_?time|share_?history|all_?export|global_?export|global_?rcs|rcs|aliases|clobber|clobber_?empty|correct|correct_?all|dvorak|flow_?control|ignore_?eof|interactive_?comments|hash_?cmds|hash_?dirs|hash_?executables_?only|mail_?warning|path_?dirs|path_?script|print_?eight_?bit|print_?exit_?value|rc_?quotes|rm_?star_?silent|rm_?star_?wait|short_?loops|short_?repeat|sun_?keyboard_?hack|auto_?continue|auto_?resume|bg_?nice|check_?jobs|check_?running_?jobs|hup|long_?list_?jobs|monitor|notify|posix_?jobs|prompt_?bang|prompt_?cr|prompt_?sp|prompt_?percent|prompt_?subst|transient_?rprompt|alias_?func_?def|c_?bases|c_?precedences|debug_?before_?cmd|err_?exit|err_?return|eval_?lineno|exec|function_?argzero|local_?loops|local_?options|local_?patterns|local_?traps|multi_?func_?def|multios|octal_?zeroes|pipe_?fail|source_?trace|typeset_?silent|typeset_?to_?unset|verbose|xtrace|append_?create|bash_?rematch|bsd_?echo|continue_?on_?error|csh_?junkie_?history|csh_?junkie_?loops|csh_?junkie_?quotes|csh_?nullcmd|ksh_?arrays|ksh_?autoload|ksh_?option_?print|ksh_?typeset|ksh_?zero_?subscript|posix_?aliases|posix_?argzero|posix_?builtins|posix_?identifiers|posix_?strings|posix_?traps|sh_?file_?expansion|sh_?nullcmd|sh_?option_?letters|sh_?word_?split|traps_?async|interactive|login|privileged|restricted|shin_?stdin|single_?command|beep|combining_?chars|emacs|overstrike|single_?line_?zle|vi|zle|brace_?expand|dot_?glob|hash_?all|hist_?append|hist_?expand|log|mail_?warn|one_?cmd|physical|prompt_?vars|stdin|track_?all|no_?match
+ \)>/
syn case match
syn keyword zshTypes float integer local typeset declare private readonly
@@ -365,7 +164,7 @@ syn region zshGlob start='(#' end=')'
syn region zshMathSubst matchgroup=zshSubstDelim transparent
\ start='\%(\$\?\)[<=>]\@<!((' skip='\\)' end='))'
\ contains=zshParentheses,@zshSubst,zshNumber,
- \ @zshDerefs,zshString keepend fold
+ \ @zshDerefs,zshString fold
" The ms=s+1 prevents matching zshBrackets several times on opening brackets
" (see https://github.com/chrisbra/vim-zsh/issues/21#issuecomment-576330348)
syn region zshBrackets contained transparent start='{'ms=s+1 skip='\\}'
diff --git a/scripts/squash_typos.py b/scripts/squash_typos.py
deleted file mode 100644
index b403a9b7c8..0000000000
--- a/scripts/squash_typos.py
+++ /dev/null
@@ -1,263 +0,0 @@
-#!/usr/bin/env python
-"""
-
-This script squashes a PR tagged with the "typo" label into a single, dedicated
-"squash PR".
-
-"""
-
-import subprocess
-import sys
-import os
-
-
-def get_authors_and_emails_from_pr():
- """
-
- Return all contributing authors and their emails for the PR on current branch.
- This includes co-authors, meaning that if two authors are credited for a
- single commit, which is possible with GitHub, then both will get credited.
-
- """
-
- # Get a list of all authors involved in the pull request (including co-authors).
- authors = subprocess.check_output(
- [
- "gh",
- "pr",
- "view",
- os.environ["PR_NUMBER"],
- "--json",
- "commits",
- "--jq",
- ".[][].authors.[].name",
- ],
- text=True,
- ).splitlines()
-
- # Get a list of emails of the aforementioned authors.
- emails = subprocess.check_output(
- [
- "gh",
- "pr",
- "view",
- os.environ["PR_NUMBER"],
- "--json",
- "commits",
- "--jq",
- ".[][].authors.[].email",
- ],
- text=True,
- ).splitlines()
-
- authors_and_emails = [(author, mail) for author, mail in zip(authors, emails)]
-
- return authors_and_emails
-
-
-def rebase_onto_pr():
- """
-
- Rebase current branch onto the PR.
-
- """
-
- # Check out the pull request.
- subprocess.call(["gh", "pr", "checkout", os.environ["PR_NUMBER"]])
-
- rebase_onto_master()
-
- # Change back to the original branch.
- subprocess.call(["git", "switch", "-"])
-
- # Rebase onto the pull request, aka include the commits in the pull request
- # in the current branch. Abort with error message if rebase fails.
-
- try:
- subprocess.check_call(["git", "rebase", "-"])
- except subprocess.CalledProcessError:
- subprocess.call(["git", "rebase", "--abort"])
- squash_url = subprocess.check_output(
- ["gh", "pr", "view", "--json", "url", "--jq", ".url"], text=True
- ).strip()
-
- subprocess.call(
- [
- "gh",
- "pr",
- "comment",
- os.environ["PR_NUMBER"],
- "--body",
- f"Your edit conflicts with an already scheduled fix \
- ({squash_url}). Please check that batch PR whether your fix is \
- already included; if not, then please wait until the batch PR \
- is merged and then rebase your PR on top of master.",
- ]
- )
-
- sys.exit(
- f"\n\nERROR: Your edit conflicts with an already scheduled fix \
-{squash_url} \n\n"
- )
-
-
-def rebase_onto_master():
- """
-
- Rebase current branch onto the master i.e. make sure current branch is up
- to date. Abort on error.
-
- """
-
- default_branch = f"{os.environ['GITHUB_BASE_REF']}"
- subprocess.check_call(["git", "rebase", default_branch])
-
-
-def squash_all_commits(message_body_before):
- """
-
- Squash all commits on the PR into a single commit. Credit all authors by
- name and email.
-
- """
-
- default_branch = f"{os.environ['GITHUB_BASE_REF']}"
- subprocess.call(["git", "reset", "--soft", default_branch])
-
- authors_and_emails = get_authors_and_emails_from_pr()
- commit_message_coauthors = (
- "\n"
- + "\n".join([f"Co-authored-by: {i[0]} <{i[1]}>" for i in authors_and_emails])
- + "\n"
- + message_body_before
- )
- subprocess.call(
- ["git", "commit", "-m", "chore: typo fixes", "-m", commit_message_coauthors]
- )
-
-
-def force_push(branch):
- """
-
- Like the name implies, force push <branch>.
-
- """
-
- gh_actor = os.environ["GITHUB_ACTOR"]
- gh_token = os.environ["GITHUB_TOKEN"]
- gh_repo = os.environ["GITHUB_REPOSITORY"]
- subprocess.call(
- [
- "git",
- "push",
- "--force",
- f"https://{gh_actor}:{gh_token}@github.com/{gh_repo}",
- branch,
- ]
- )
-
-
-def checkout_branch(branch):
- """
-
- Create and checkout <branch>. Check if branch exists on remote, if so then
- sync local branch to remote.
-
- Return True if remote branch exists, else False.
-
- """
-
- # FIXME I'm not sure why the local branch isn't tracking the remote branch
- # automatically. This works but I'm pretty sure it can be done in a more
- # "elegant" fashion
-
- show_ref_output = subprocess.check_output(["git", "show-ref"], text=True).strip()
-
- if branch in show_ref_output:
- subprocess.call(["git", "checkout", "-b", branch, f"origin/{branch}"])
- return True
-
- subprocess.call(["git", "checkout", "-b", branch])
- return False
-
-
-def get_all_pr_urls(pr_branch_exists):
- """
-
- Return a list of URLs for the pull requests with the typo fixes. If a
- squash branch exists then extract the URLs from the body text.
-
- """
-
- all_pr_urls = ""
- if pr_branch_exists:
- all_pr_urls += subprocess.check_output(
- ["gh", "pr", "view", "--json", "body", "--jq", ".body"], text=True
- )
-
- all_pr_urls += subprocess.check_output(
- ["gh", "pr", "view", os.environ["PR_NUMBER"], "--json", "url", "--jq", ".url"],
- text=True,
- ).strip()
-
- return all_pr_urls
-
-
-def main():
- pr_branch = "marvim/squash-typos"
-
- pr_branch_exists = checkout_branch(pr_branch)
-
- rebase_onto_master()
- force_push(pr_branch)
-
- message_body_before = "\n".join(
- subprocess.check_output(
- ["git", "log", "--format=%B", "-n1", pr_branch], text=True
- ).splitlines()[2:]
- )
-
- rebase_onto_pr()
- force_push(pr_branch)
-
- subprocess.call(
- [
- "gh",
- "pr",
- "create",
- "--fill",
- "--head",
- pr_branch,
- "--title",
- "chore: typo fixes (automated)",
- ],
- text=True,
- )
-
- squash_all_commits(message_body_before)
- force_push(pr_branch)
-
- all_pr_urls = get_all_pr_urls(pr_branch_exists)
- subprocess.call(["gh", "pr", "edit", "--add-label", "typo", "--body", all_pr_urls])
-
- subprocess.call(["gh", "pr", "close", os.environ["PR_NUMBER"]])
-
- squash_url = subprocess.check_output(
- ["gh", "pr", "view", "--json", "url", "--jq", ".url"], text=True
- ).strip()
- subprocess.call(
- [
- "gh",
- "pr",
- "comment",
- os.environ["PR_NUMBER"],
- "--body",
- f"Thank you for your contribution! We collect all typo fixes \
- into a single pull request and merge it once it gets big enough: \
- {squash_url}",
- ]
- )
-
-
-if __name__ == "__main__":
- main()
diff --git a/src/mpack/lmpack.c b/src/mpack/lmpack.c
index 87acf46592..126f2f3824 100644
--- a/src/mpack/lmpack.c
+++ b/src/mpack/lmpack.c
@@ -595,6 +595,7 @@ static void lmpack_unparse_enter(mpack_parser_t *parser, mpack_node_t *node)
/* push the pair */
result = lua_next(L, -2);
assert(result); /* should not be here if the map was fully processed */
+ (void)result; /* ignore unused warning */
if (parent->key_visited) {
/* release the current key */
lmpack_unref(L, packer->reg, (int)parent->data[1].i);
@@ -1010,6 +1011,7 @@ static int lmpack_session_reply(lua_State *L)
"invalid request id");
result = mpack_rpc_reply(session->session, &b, &bl, (mpack_uint32_t)id);
assert(result == MPACK_OK);
+ (void)result; /* ignore unused warning */
lua_pushlstring(L, buf, sizeof(buf) - bl);
return 1;
}
@@ -1027,6 +1029,7 @@ static int lmpack_session_notify(lua_State *L)
session = lmpack_check_session(L, 1);
result = mpack_rpc_notify(session->session, &b, &bl);
assert(result == MPACK_OK);
+ (void)result; /* ignore unused warning */
lua_pushlstring(L, buf, sizeof(buf) - bl);
return 1;
}
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index bb16459a7f..9c4b778169 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -326,7 +326,9 @@ add_custom_command(
add_custom_command(
OUTPUT ${VIM_MODULE_FILE}
- COMMAND ${LUA_PRG} ${CHAR_BLOB_GENERATOR} ${VIM_MODULE_FILE}
+ COMMAND ${CMAKE_COMMAND} -E env
+ "LUAC_PRG=${LUAC_PRG}"
+ ${LUA_PRG} ${CHAR_BLOB_GENERATOR} -c ${VIM_MODULE_FILE}
${LUA_VIM_MODULE_SOURCE} vim_module
${LUA_SHARED_MODULE_SOURCE} shared_module
${LUA_INSPECT_MODULE_SOURCE} inspect_module
@@ -339,6 +341,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE}
${LUA_F_MODULE_SOURCE}
${LUA_META_MODULE_SOURCE}
+ VERBATIM
)
list(APPEND NVIM_GENERATED_SOURCES
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 4f7c320129..f81cdf9deb 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -696,7 +696,17 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
rv = INTEGER_OBJ(numval);
break;
case 2:
- rv = BOOLEAN_OBJ(!!numval);
+ switch (numval) {
+ case 0:
+ case 1:
+ rv = BOOLEAN_OBJ(numval);
+ break;
+ default:
+ // Boolean options that return something other than 0 or 1 should return nil. Currently this
+ // only applies to 'autoread' which uses -1 as a local value to indicate "unset"
+ rv = NIL;
+ break;
+ }
break;
default:
api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data);
@@ -749,7 +759,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error
stringval = value.data.string.data;
break;
case kObjectTypeNil:
- // Do nothing
+ scope |= OPT_CLEAR;
break;
default:
api_set_error(err, kErrorTypeValidation, "invalid value for option");
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index 6227b08b26..8fe623fc96 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -75,6 +75,8 @@ return {
'QuickFixCmdPost', -- after :make, :grep etc.
'QuickFixCmdPre', -- before :make, :grep etc.
'QuitPre', -- before :quit
+ 'RecordingEnter', -- when starting to record a macro
+ 'RecordingLeave', -- just before a macro stops recording
'RemoteReply', -- upon string reception from a remote vim
'SearchWrapped', -- after the search wrapped around
'SessionLoadPost', -- after loading a session file
@@ -131,6 +133,8 @@ return {
BufModifiedSet=true,
DiagnosticChanged=true,
DirChanged=true,
+ RecordingEnter=true,
+ RecordingLeave=true,
Signal=true,
TabClosed=true,
TabNew=true,
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 3780cad1d6..463bd5e0e6 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -932,6 +932,12 @@ static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, c
last_mode = get_mode();
}
+ // If the event is CursorMoved, update the last cursor position
+ // position to avoid immediately triggering the autocommand
+ if (event == EVENT_CURSORMOVED && !has_event(EVENT_CURSORMOVED)) {
+ curwin->w_last_cursormoved = curwin->w_cursor;
+ }
+
ap->cmds = NULL;
*prev_ap = ap;
last_autopat[(int)event] = ap;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 2135d0bcd2..2e3eec3642 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -643,7 +643,10 @@ static int insert_check(VimState *state)
update_curswant();
s->old_topline = curwin->w_topline;
s->old_topfill = curwin->w_topfill;
- s->lastc = s->c; // remember previous char for CTRL-D
+
+ if (s->c != K_EVENT) {
+ s->lastc = s->c; // remember previous char for CTRL-D
+ }
// After using CTRL-G U the next cursor key will not break undo.
if (dont_sync_undo == kNone) {
@@ -1685,7 +1688,7 @@ static void init_prompt(int cmdchar_todo)
// Insert always starts after the prompt, allow editing text after it.
if (Insstart_orig.lnum != curwin->w_cursor.lnum || Insstart_orig.col != (colnr_T)STRLEN(prompt)) {
Insstart.lnum = curwin->w_cursor.lnum;
- Insstart.col = STRLEN(prompt);
+ Insstart.col = (colnr_T)STRLEN(prompt);
Insstart_orig = Insstart;
Insstart_textlen = Insstart.col;
Insstart_blank_vcol = MAXCOL;
@@ -1696,7 +1699,7 @@ static void init_prompt(int cmdchar_todo)
coladvance(MAXCOL);
}
if (curwin->w_cursor.col < (colnr_T)STRLEN(prompt)) {
- curwin->w_cursor.col = STRLEN(prompt);
+ curwin->w_cursor.col = (colnr_T)STRLEN(prompt);
}
// Make sure the cursor is in a valid position.
check_cursor();
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 9a76b67de6..e445a08227 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -133,6 +133,7 @@ return {
foldtext={},
foldtextresult={args=1, base=1},
foreground={},
+ fullcommand={args=1, base=1},
funcref={args={1, 3}, base=1},
['function']={args={1, 3}, base=1},
garbagecollect={args={0, 1}},
@@ -277,6 +278,7 @@ return {
readfile={args={1, 3}, base=1},
reg_executing={},
reg_recording={},
+ reg_recorded={},
reltime={args={0, 2}, base=1},
reltimefloat={args=1, base=1},
reltimestr={args=1, base=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 5252c940f7..32026282cf 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -1082,15 +1082,13 @@ static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Return the current directory
cwd = xmalloc(MAXPATHL);
- if (cwd != NULL) {
- if (os_dirname(cwd, MAXPATHL) != FAIL) {
+ if (os_dirname(cwd, MAXPATHL) != FAIL) {
#ifdef BACKSLASH_IN_FILENAME
- slash_adjust(cwd);
+ slash_adjust(cwd);
#endif
- rettv->vval.v_string = vim_strsave(cwd);
- }
- xfree(cwd);
+ rettv->vval.v_string = vim_strsave(cwd);
}
+ xfree(cwd);
if (curwin->w_localdir != NULL) {
scope = kCdScopeWindow;
@@ -3920,34 +3918,46 @@ static void f_getqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
get_qf_loc_list(true, NULL, &argvars[0], rettv);
}
-/// "getreg()" function
-static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+/// Common between getreg(), getreginfo() and getregtype(): get the register
+/// name from the first argument.
+/// Returns zero on error.
+static int getreg_get_regname(typval_T *argvars)
{
- const char *strregname;
- int arg2 = false;
- bool return_list = false;
- bool error = false;
+ const char_u *strregname;
if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = tv_get_string_chk(&argvars[0]);
- error = strregname == NULL;
- if (argvars[1].v_type != VAR_UNKNOWN) {
- arg2 = tv_get_number_chk(&argvars[1], &error);
- if (!error && argvars[2].v_type != VAR_UNKNOWN) {
- return_list = tv_get_number_chk(&argvars[2], &error);
- }
+ strregname = (const char_u *)tv_get_string_chk(&argvars[0]);
+ if (strregname == NULL) { // type error; errmsg already given
+ return 0;
}
} else {
- strregname = _(get_vim_var_str(VV_REG));
+ // Default to v:register
+ strregname = get_vim_var_str(VV_REG);
}
- if (error) {
+ return *strregname == 0 ? '"' : *strregname;
+}
+
+/// "getreg()" function
+static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ int arg2 = false;
+ bool return_list = false;
+
+ int regname = getreg_get_regname(argvars);
+ if (regname == 0) {
return;
}
- int regname = (uint8_t)(strregname == NULL ? '"' : *strregname);
- if (regname == 0) {
- regname = '"';
+ if (argvars[0].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_UNKNOWN) {
+ bool error = false;
+ arg2 = (int)tv_get_number_chk(&argvars[1], &error);
+ if (!error && argvars[2].v_type != VAR_UNKNOWN) {
+ return_list = (bool)tv_get_number_chk(&argvars[2], &error);
+ }
+ if (error) {
+ return;
+ }
}
if (return_list) {
@@ -3964,28 +3974,16 @@ static void f_getreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "getregtype()" function
- */
+/// "getregtype()" function
static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- const char *strregname;
-
- if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = tv_get_string_chk(&argvars[0]);
- if (strregname == NULL) { // Type error; errmsg already given.
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- return;
- }
- } else {
- // Default to v:register.
- strregname = _(get_vim_var_str(VV_REG));
- }
+ // on error return an empty string
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
- int regname = (uint8_t)(strregname == NULL ? '"' : *strregname);
+ int regname = getreg_get_regname(argvars);
if (regname == 0) {
- regname = '"';
+ return;
}
colnr_T reglen = 0;
@@ -7333,18 +7331,12 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "getreginfo()" function
static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- const char *strregname;
- if (argvars[0].v_type != VAR_UNKNOWN) {
- strregname = tv_get_string_chk(&argvars[0]);
- if (strregname == NULL) {
- return;
- }
- } else {
- strregname = (const char *)get_vim_var_str(VV_REG);
+ int regname = getreg_get_regname(argvars);
+ if (regname == 0) {
+ return;
}
- int regname = (strregname == NULL ? '"' : *strregname);
- if (regname == 0 || regname == '@') {
+ if (regname == '@') {
regname = '"';
}
@@ -7398,6 +7390,11 @@ static void f_reg_recording(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return_register(reg_recording, rettv);
}
+static void f_reg_recorded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ return_register(reg_recorded, rettv);
+}
+
/// list2proftime - convert a List to proftime_T
///
/// @param arg The input list, must be of type VAR_LIST and have
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index c0cb17fa61..4965eb9c20 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4584,6 +4584,9 @@ void ex_global(exarg_T *eap)
// a match on this line?
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL, NULL);
+ if (regmatch.regprog == NULL) {
+ break; // re-compiling regprog failed
+ }
if ((type == 'g' && match) || (type == 'v' && !match)) {
ml_setmarked(lnum);
ndone++;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 9f0f8d93a3..230cbd4b60 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2900,6 +2900,31 @@ int cmd_exists(const char *const name)
return ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1);
}
+// "fullcommand" function
+void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ exarg_T ea;
+ char_u *name = argvars[0].vval.v_string;
+
+ while (name[0] != NUL && name[0] == ':') {
+ name++;
+ }
+ name = skip_range(name, NULL);
+
+ rettv->v_type = VAR_STRING;
+
+ ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name;
+ ea.cmdidx = (cmdidx_T)0;
+ char_u *p = find_command(&ea, NULL);
+ if (p == NULL || ea.cmdidx == CMD_SIZE) {
+ return;
+ }
+
+ rettv->vval.v_string = vim_strsave(IS_USER_CMDIDX(ea.cmdidx)
+ ? get_user_commands(NULL, ea.useridx)
+ : cmdnames[ea.cmdidx].cmd_name);
+}
+
/// This is all pretty much copied from do_one_cmd(), with all the extra stuff
/// we don't need/want deleted. Maybe this could be done better if we didn't
/// repeat all this stuff. The only problem is that they may not stay
@@ -7807,17 +7832,21 @@ bool changedir_func(char_u *new_dir, CdScope scope)
prev_dir = pdir;
}
+ // For UNIX ":cd" means: go to home directory.
+ // On other systems too if 'cdhome' is set.
#if defined(UNIX)
- // On Unix ":cd" means: go to home directory.
if (*new_dir == NUL) {
+#else
+ if (*new_dir == NUL && p_cdh) {
+#endif
// Use NameBuff for home directory name.
expand_env((char_u *)"$HOME", NameBuff, MAXPATHL);
new_dir = NameBuff;
}
-#endif
- if (vim_chdir(new_dir) == 0) {
- bool dir_differs = pdir == NULL || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
+ bool dir_differs = new_dir == NULL || pdir == NULL
+ || pathcmp((char *)pdir, (char *)new_dir, -1) != 0;
+ if (new_dir != NULL && (!dir_differs || vim_chdir(new_dir) == 0)) {
post_chdir(scope, dir_differs);
retval = true;
} else {
@@ -7833,9 +7862,9 @@ void ex_cd(exarg_T *eap)
{
char_u *new_dir;
new_dir = eap->arg;
-#if !defined(UNIX) && !defined(VMS)
- // for non-UNIX ":cd" means: print current directory
- if (*new_dir == NUL) {
+#if !defined(UNIX)
+ // for non-UNIX ":cd" means: print current directory unless 'cdhome' is set
+ if (*new_dir == NUL && !p_cdh) {
ex_pwd(NULL);
} else
#endif
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index 7ec4fad277..a302d4a3c5 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -2,6 +2,7 @@
#define NVIM_EX_DOCMD_H
#include "nvim/ex_cmds_defs.h"
+#include "nvim/eval/funcs.h"
#include "nvim/globals.h"
// flags for do_cmdline()
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index d31021b3ef..1884dd49c5 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1667,14 +1667,19 @@ int vim_chdirfile(char_u *fname, CdCause cause)
NameBuff[0] = NUL;
}
- if (os_chdir(dir) == 0) {
- if (cause != kCdCauseOther && pathcmp(dir, (char *)NameBuff, -1) != 0) {
- do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
- }
- } else {
+ if (pathcmp(dir, (char *)NameBuff, -1) == 0) {
+ // nothing to do
+ return OK;
+ }
+
+ if (os_chdir(dir) != 0) {
return FAIL;
}
+ if (cause != kCdCauseOther) {
+ do_autocmd_dirchanged(dir, kCdScopeWindow, cause);
+ }
+
return OK;
}
diff --git a/src/nvim/generators/gen_char_blob.lua b/src/nvim/generators/gen_char_blob.lua
index a7dad50d48..3ec1ff2caf 100644
--- a/src/nvim/generators/gen_char_blob.lua
+++ b/src/nvim/generators/gen_char_blob.lua
@@ -1,12 +1,26 @@
if arg[1] == '--help' then
print('Usage:')
- print(' '..arg[0]..' target source varname [source varname]...')
+ print(' '..arg[0]..' [-c] target source varname [source varname]...')
print('')
print('Generates C file with big uint8_t blob.')
print('Blob will be stored in a static const array named varname.')
os.exit()
end
+-- Recognized options:
+-- -c compile Lua bytecode
+local options = {}
+
+while true do
+ local opt = string.match(arg[1], "^-(%w)")
+ if not opt then
+ break
+ end
+
+ options[opt] = true
+ table.remove(arg, 1)
+end
+
assert(#arg >= 3 and (#arg - 1) % 2 == 0)
local target_file = arg[1] or error('Need a target file')
@@ -14,6 +28,7 @@ local target = io.open(target_file, 'w')
target:write('#include <stdint.h>\n\n')
+local warn_on_missing_compiler = true
local varnames = {}
for argi = 2, #arg, 2 do
local source_file = arg[argi]
@@ -23,11 +38,26 @@ for argi = 2, #arg, 2 do
end
varnames[varname] = source_file
- local source = io.open(source_file, 'r')
- or error(string.format("source_file %q doesn't exist", source_file))
-
target:write(('static const uint8_t %s[] = {\n'):format(varname))
+ local output
+ if options.c then
+ local luac = os.getenv("LUAC_PRG")
+ if luac and luac ~= "" then
+ output = io.popen(luac:format(source_file), "r"):read("*a")
+ elseif warn_on_missing_compiler then
+ print("LUAC_PRG is missing, embedding raw source")
+ warn_on_missing_compiler = false
+ end
+ end
+
+ if not output then
+ local source = io.open(source_file, "r")
+ or error(string.format("source_file %q doesn't exist", source_file))
+ output = source:read("*a")
+ source:close()
+ end
+
local num_bytes = 0
local MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line
target:write(' ')
@@ -41,19 +71,13 @@ for argi = 2, #arg, 2 do
end
end
- for line in source:lines() do
- for i = 1, string.len(line) do
- local byte = line:byte(i)
- assert(byte ~= 0)
- target:write(string.format(' %3u,', byte))
- increase_num_bytes()
- end
- target:write(string.format(' %3u,', string.byte('\n', 1)))
+ for i = 1, string.len(output) do
+ local byte = output:byte(i)
+ target:write(string.format(' %3u,', byte))
increase_num_bytes()
end
- target:write(' 0};\n')
- source:close()
+ target:write(' 0};\n')
end
target:close()
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 05c38a5233..6b1150cefa 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1894,7 +1894,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
// buffer right here. Otherwise, use the mapping (loop around).
if (mp == NULL) {
*keylenp = keylen;
- return map_result_get; // got character, break for loop
+ return map_result_get; // get character from typeahead
} else {
keylen = mp_match_len;
}
@@ -2166,7 +2166,7 @@ static int vgetorpeek(bool advance)
KeyNoremap = typebuf.tb_noremap[typebuf.tb_off];
del_typebuf(1, 0);
}
- break;
+ break; // got character, break the for loop
}
// not enough characters, get more
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index dfbc80066e..697d4b11a7 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -632,6 +632,7 @@ 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
+EXTERN int reg_recorded INIT(= 0); // last recorded register or zero
EXTERN int no_mapping INIT(= false); // currently no mapping allowed
EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index b09d133495..107ff22913 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -404,9 +404,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
const char *code = (char *)&shared_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/shared.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(shared_module) - 1, "@vim/shared.lua")
|| nlua_pcall(lstate, 0, 0)) {
- nlua_error(lstate, _("E5106: Error while creating shared module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating shared module: %.*s\n"));
return 1;
}
}
@@ -416,18 +416,18 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_getfield(lstate, -1, "loaded"); // [package, loaded]
const char *code = (char *)&inspect_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/inspect.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(inspect_module) - 1, "@vim/inspect.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating inspect module: %.*s\n"));
return 1;
}
// [package, loaded, inspect]
lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded]
code = (char *)&lua_F_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/F.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(lua_F_module) - 1, "@vim/F.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s\n"));
return 1;
}
// [package, loaded, module]
@@ -438,9 +438,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
const char *code = (char *)&vim_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(vim_module) - 1, "@vim.lua")
|| nlua_pcall(lstate, 0, 0)) {
- nlua_error(lstate, _("E5106: Error while creating vim module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim module: %.*s\n"));
return 1;
}
}
@@ -450,9 +450,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_getfield(lstate, -1, "loaded"); // [package, loaded]
const char *code = (char *)&lua_meta_module[0];
- if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/_meta.lua")
+ if (luaL_loadbuffer(lstate, code, sizeof(lua_meta_module) - 1, "@vim/_meta.lua")
|| nlua_pcall(lstate, 0, 1)) {
- nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s"));
+ nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s\n"));
return 1;
}
// [package, loaded, module]
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
new file mode 100644
index 0000000000..b84124bc19
--- /dev/null
+++ b/src/nvim/lua/spell.c
@@ -0,0 +1,99 @@
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "nvim/spell.h"
+#include "nvim/vim.h"
+#include "nvim/lua/spell.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/spell.c.generated.h"
+#endif
+
+int nlua_spell_check(lua_State *lstate)
+{
+ if (lua_gettop(lstate) < 1) {
+ return luaL_error(lstate, "Expected 1 argument");
+ }
+
+ if (lua_type(lstate, 1) != LUA_TSTRING) {
+ luaL_argerror(lstate, 1, "expected string");
+ }
+
+ const char *str = lua_tolstring(lstate, 1, NULL);
+
+ // spell.c requires that 'spell' is enabled, so we need to temporarily enable
+ // it before we can call spell functions.
+ const int wo_spell_save = curwin->w_p_spell;
+
+ if (!curwin->w_p_spell) {
+ did_set_spelllang(curwin);
+ curwin->w_p_spell = true;
+ }
+
+ // Check 'spelllang'
+ if (*curwin->w_s->b_p_spl == NUL) {
+ emsg(_(e_no_spell));
+ curwin->w_p_spell = wo_spell_save;
+ return 0;
+ }
+
+ hlf_T attr = HLF_COUNT;
+ size_t len = 0;
+ size_t pos = 0;
+ int capcol = -1;
+ int no_res = 0;
+ const char * result;
+
+ lua_createtable(lstate, 0, 0);
+
+ while (*str != NUL) {
+ attr = HLF_COUNT;
+ len = spell_check(curwin, (char_u *)str, &attr, &capcol, false);
+ assert(len <= INT_MAX);
+
+ if (attr != HLF_COUNT) {
+ lua_createtable(lstate, 3, 0);
+
+ lua_pushlstring(lstate, str, len);
+ lua_rawseti(lstate, -2, 1);
+
+ result = attr == HLF_SPB ? "bad" :
+ attr == HLF_SPR ? "rare" :
+ attr == HLF_SPL ? "local" :
+ attr == HLF_SPC ? "caps" :
+ NULL;
+
+ assert(result != NULL);
+
+ lua_pushstring(lstate, result);
+ lua_rawseti(lstate, -2, 2);
+
+ // +1 for 1-indexing
+ lua_pushinteger(lstate, (long)pos + 1);
+ lua_rawseti(lstate, -2, 3);
+
+ lua_rawseti(lstate, -2, ++no_res);
+ }
+
+ str += len;
+ pos += len;
+ capcol -= (int)len;
+ }
+
+ // Restore 'spell'
+ curwin->w_p_spell = wo_spell_save;
+ return 1;
+}
+
+static const luaL_Reg spell_functions[] = {
+ { "check", nlua_spell_check },
+ { NULL , NULL }
+};
+
+int luaopen_spell(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_register(L, NULL, spell_functions);
+ return 1;
+}
diff --git a/src/nvim/lua/spell.h b/src/nvim/lua/spell.h
new file mode 100644
index 0000000000..8f798a5191
--- /dev/null
+++ b/src/nvim/lua/spell.h
@@ -0,0 +1,12 @@
+#ifndef NVIM_LUA_SPELL_H
+#define NVIM_LUA_SPELL_H
+
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/spell.h.generated.h"
+#endif
+
+#endif // NVIM_LUA_SPELL_H
diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c
index b746e03625..18a579ed0f 100644
--- a/src/nvim/lua/stdlib.c
+++ b/src/nvim/lua/stdlib.c
@@ -30,6 +30,7 @@
#include "nvim/lua/stdlib.h"
#include "nvim/lua/treesitter.h"
#include "nvim/lua/xdiff.h"
+#include "nvim/lua/spell.h"
#include "nvim/macros.h"
#include "nvim/map.h"
#include "nvim/memline.h"
@@ -230,8 +231,8 @@ static int nlua_str_utf_start(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int tail_offset = mb_head_off((char_u *)s1, (char_u *)s1 + (char_u)offset - 1);
- lua_pushinteger(lstate, tail_offset);
+ int head_offset = mb_head_off((char_u *)s1, (char_u *)s1 + offset - 1);
+ lua_pushinteger(lstate, head_offset);
return 1;
}
@@ -250,7 +251,7 @@ static int nlua_str_utf_end(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
if (offset < 0 || offset > (intptr_t)s1_len) {
return luaL_error(lstate, "index out of range");
}
- int tail_offset = mb_tail_off((char_u *)s1, (char_u *)s1 + (char_u)offset - 1);
+ int tail_offset = mb_tail_off((char_u *)s1, (char_u *)s1 + offset - 1);
lua_pushinteger(lstate, tail_offset);
return 1;
}
@@ -518,6 +519,10 @@ void nlua_state_add_stdlib(lua_State *const lstate)
lua_pushcfunction(lstate, &nlua_xdl_diff);
lua_setfield(lstate, -2, "diff");
+ // vim.spell
+ luaopen_spell(lstate);
+ lua_setfield(lstate, -2, "spell");
+
lua_cjson_new(lstate);
lua_setfield(lstate, -2, "json");
}
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index ce44f6c619..5eb209a6f6 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1609,7 +1609,8 @@ void show_utf8(void)
msg((char *)IObuff);
}
-/// Return offset from "p" to the first byte of the character it points into.
+/// Return offset from "p" to the start of a character, including composing characters.
+/// "base" must be the start of the string, which must be NUL terminated.
/// If "p" points to the NUL at the end of the string return 0.
/// Returns 0 when already at the first byte of a character.
int utf_head_off(const char_u *base, const char_u *p)
@@ -1850,10 +1851,9 @@ int mb_off_next(char_u *base, char_u *p)
return i;
}
-/*
- * Return the offset from "p" to the last byte of the character it points
- * into. Can start anywhere in a stream of bytes.
- */
+/// Return the offset from "p" to the last byte of the character it points
+/// into. Can start anywhere in a stream of bytes.
+/// Composing characters are not included.
int mb_tail_off(char_u *base, char_u *p)
{
int i;
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 0a672000e4..15ba6645f5 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -1011,7 +1011,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
col -= wp->w_leftcol;
if (col >= 0 && col < wp->w_width) {
- coloff = col - scol + (local ? 0 : wp->w_wincol) + 1;
+ coloff = col - scol + (local ? 0 : wp->w_wincol + wp->w_border_adj[3]) + 1;
} else {
scol = ccol = ecol = 0;
// character is left or right of the window
@@ -1022,7 +1022,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
}
}
}
- *rowp = (local ? 0 : wp->w_winrow) + row + rowoff;
+ *rowp = (local ? 0 : wp->w_winrow + wp->w_border_adj[0]) + row + rowoff;
*scolp = scol + coloff;
*ccolp = ccol + coloff;
*ecolp = ecol + coloff;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 95a521c0d8..3246596f16 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -229,7 +229,7 @@ static const struct nv_cmd {
{ 'N', nv_next, 0, SEARCH_REV },
{ 'O', nv_open, 0, 0 },
{ 'P', nv_put, 0, 0 },
- { 'Q', nv_exmode, NV_NCW, 0 },
+ { 'Q', nv_regreplay, 0, 0 },
{ 'R', nv_Replace, 0, false },
{ 'S', nv_subst, NV_KEEPREG, 0 },
{ 'T', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD },
@@ -4028,15 +4028,18 @@ dozet:
/*
* "Q" command.
*/
-static void nv_exmode(cmdarg_T *cap)
+static void nv_regreplay(cmdarg_T *cap)
{
- /*
- * Ignore 'Q' in Visual mode, just give a beep.
- */
- if (VIsual_active) {
- vim_beep(BO_EX);
- } else if (!checkclearop(cap->oap)) {
- do_exmode();
+ if (checkclearop(cap->oap)) {
+ return;
+ }
+
+ while (cap->count1-- && !got_int) {
+ if (do_execreg(reg_recorded, false, false, false) == false) {
+ clearopbeep(cap->oap);
+ break;
+ }
+ line_breakcheck();
}
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 9bc63477e9..c6f9c5f04f 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -912,13 +912,14 @@ int do_record(int c)
showmode();
regname = c;
retval = OK;
- }
- } else { // stop recording
- /*
- * Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
- * needs to be removed again to put it in a register. exec_reg then
- * adds the escaping back later.
- */
+ apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf);
+ }
+ } else { // stop recording
+ // Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
+ // needs to be removed again to put it in a register. exec_reg then
+ // adds the escaping back later.
+ apply_autocmds(EVENT_RECORDINGLEAVE, NULL, NULL, false, curbuf);
+ reg_recorded = reg_recording;
reg_recording = 0;
if (ui_has(kUIMessages)) {
showmode();
@@ -932,10 +933,8 @@ int do_record(int c)
// Remove escaping for CSI and K_SPECIAL in multi-byte chars.
vim_unescape_csi(p);
- /*
- * We don't want to change the default register here, so save and
- * restore the current register name.
- */
+ // We don't want to change the default register here, so save and
+ // restore the current register name.
old_y_previous = y_previous;
retval = stuff_yank(regname, p);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 2ceb1bd992..65adda3c01 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2991,7 +2991,7 @@ ambw_end:
}
} else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) {
// 'foldcolumn'
- if (check_opt_strings(*varp, p_fdc_values, false) != OK) {
+ if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) {
errmsg = e_invarg;
}
} else if (varp == &p_pt) {
@@ -3370,6 +3370,9 @@ static int int_cmp(const void *a, const void *b)
/// @return OK when the value is valid, FAIL otherwise
int check_signcolumn(char_u *val)
{
+ if (*val == NUL) {
+ return FAIL;
+ }
// check for basic match
if (check_opt_strings(val, p_scl_values, false) == OK) {
return OK;
@@ -3610,7 +3613,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
c2 = c3 = 0;
s = p + len + 1;
c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || utf_char2cells(c1) > 1) {
+ if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg;
}
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
@@ -3618,12 +3621,12 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
return e_invarg;
}
c2 = get_encoded_char_adv(&s);
- if (c2 == 0 || utf_char2cells(c2) > 1) {
+ if (c2 == 0 || char2cells(c2) > 1) {
return e_invarg;
}
if (!(*s == ',' || *s == NUL)) {
c3 = get_encoded_char_adv(&s);
- if (c3 == 0 || utf_char2cells(c3) > 1) {
+ if (c3 == 0 || char2cells(c3) > 1) {
return e_invarg;
}
}
@@ -3657,7 +3660,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
multispace_len = 0;
while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s);
- if (c1 == 0 || utf_char2cells(c1) > 1) {
+ if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg;
}
multispace_len++;
@@ -5059,6 +5062,9 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
/// @param[in] number New value for the number or boolean option.
/// @param[in] string New value for string option.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
+/// If OPT_CLEAR is set, the value of the option
+/// is cleared (the exact semantics of this depend
+/// on the option).
///
/// @return NULL on success, error message on error.
char *set_option_value(const char *const name, const long number, const char *const string,
@@ -5084,7 +5090,7 @@ char *set_option_value(const char *const name, const long number, const char *co
}
if (flags & P_STRING) {
const char *s = string;
- if (s == NULL) {
+ if (s == NULL || opt_flags & OPT_CLEAR) {
s = "";
}
return set_string_option(opt_idx, s, opt_flags);
@@ -5106,10 +5112,23 @@ char *set_option_value(const char *const name, const long number, const char *co
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);
+ }
+ }
if (flags & P_NUM) {
- return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags);
+ return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags);
} else {
- return set_bool_option(opt_idx, varp, (int)number, opt_flags);
+ return set_bool_option(opt_idx, varp, (int)numval, opt_flags);
}
}
}
diff --git a/src/nvim/option.h b/src/nvim/option.h
index 452494172f..f7dbaafeec 100644
--- a/src/nvim/option.h
+++ b/src/nvim/option.h
@@ -22,6 +22,7 @@ typedef enum {
OPT_ONECOLUMN = 64, ///< list options one per line
OPT_NO_REDRAW = 128, ///< ignore redraw flags on option
OPT_SKIPRTP = 256, ///< "skiprtp" in 'sessionoptions'
+ OPT_CLEAR = 512, ///< Clear local value of an option.
} OptionFlags;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 19cb33a354..09c3bf3800 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -743,6 +743,7 @@ EXTERN int p_write; // 'write'
EXTERN int p_wa; // 'writeany'
EXTERN int p_wb; // 'writebackup'
EXTERN long p_wd; // 'writedelay'
+EXTERN int p_cdh; // 'cdhome'
EXTERN int p_force_on; ///< options that cannot be turned off.
EXTERN int p_force_off; ///< options that cannot be turned on.
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 71208dfc68..28b4eb9fe2 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -275,6 +275,14 @@ return {
defaults={if_true="internal,keepascii"}
},
{
+ full_name='cdhome', abbreviation='cdh',
+ short_desc=N_(":cd without argument goes to the home directory"),
+ type='bool', scope={'global'},
+ secure=true,
+ varname='p_cdh',
+ defaults={if_true=false}
+ },
+ {
full_name='cdpath', abbreviation='cd',
short_desc=N_("list of directories searched with \":cd\""),
type='string', list='comma', scope={'global'},
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 450bc75ffb..3459646bad 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -15,7 +15,13 @@
# include <libutil.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
# include <util.h>
-#elif !defined(__sun)
+#elif defined(__sun)
+# include <sys/stream.h>
+# include <sys/syscall.h>
+# include <fcntl.h>
+# include <unistd.h>
+# include <signal.h>
+#else
# include <pty.h>
#endif
@@ -38,6 +44,118 @@
# include "os/pty_process_unix.c.generated.h"
#endif
+#if defined(__sun) && !defined(HAVE_FORKPTY)
+
+// this header defines STR, just as nvim.h, but it is defined as ('S'<<8),
+// to avoid #undef STR, #undef STR, #define STR ('S'<<8) just delay the
+// inclusion of the header even though it gets include out of order.
+#include <sys/stropts.h>
+
+static int openpty(int *amaster, int *aslave, char *name,
+ struct termios *termp, struct winsize *winp)
+{
+ int slave = -1;
+ int master = open("/dev/ptmx", O_RDWR);
+ if (master == -1) {
+ goto error;
+ }
+
+ // grantpt will invoke a setuid program to change permissions
+ // and might fail if SIGCHLD handler is set, temporarily reset
+ // while running
+ void(*sig_saved)(int) = signal(SIGCHLD, SIG_DFL);
+ int res = grantpt(master);
+ signal(SIGCHLD, sig_saved);
+
+ if (res == -1 || unlockpt(master) == -1) {
+ goto error;
+ }
+
+ char *slave_name = ptsname(master);
+ if (slave_name == NULL) {
+ goto error;
+ }
+
+ slave = open(slave_name, O_RDWR|O_NOCTTY);
+ if (slave == -1) {
+ goto error;
+ }
+
+ // ptem emulates a terminal when used on a pseudo terminal driver,
+ // must be pushed before ldterm
+ ioctl(slave, I_PUSH, "ptem");
+ // ldterm provides most of the termio terminal interface
+ ioctl(slave, I_PUSH, "ldterm");
+ // ttcompat compatability with older terminal ioctls
+ ioctl(slave, I_PUSH, "ttcompat");
+
+ if (termp) {
+ tcsetattr(slave, TCSAFLUSH, termp);
+ }
+ if (winp) {
+ ioctl(slave, TIOCSWINSZ, winp);
+ }
+
+ *amaster = master;
+ *aslave = slave;
+ // ignoring name, not passed and size is unknown in the API
+
+ return 0;
+
+error:
+ if (slave != -1) {
+ close(slave);
+ }
+ if (master != -1) {
+ close(master);
+ }
+ return -1;
+}
+
+static int login_tty(int fd)
+{
+ setsid();
+ if (ioctl(fd, TIOCSCTTY, NULL) == -1) {
+ return -1;
+ }
+
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO) {
+ close(fd);
+ }
+
+ return 0;
+}
+
+static pid_t forkpty(int *amaster, char *name,
+ struct termios *termp, struct winsize *winp)
+{
+ int master, slave;
+ if (openpty(&master, &slave, name, termp, winp) == -1) {
+ return -1;
+ }
+
+ pid_t pid = fork();
+ switch (pid) {
+ case -1:
+ close(master);
+ close(slave);
+ return -1;
+ case 0:
+ close(master);
+ login_tty(slave);
+ return 0;
+ default:
+ close(slave);
+ *amaster = master;
+ return pid;
+ }
+}
+
+#endif
+
/// termios saved at startup (for TUI) or initialized by pty_process_spawn().
static struct termios termios_default;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 606c03f838..da2ada791f 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -386,7 +386,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
void pum_redraw(void)
{
int row = 0;
- int col;
+ int grid_col;
int attr_norm = win_hl_attr(curwin, HLF_PNI);
int attr_select = win_hl_attr(curwin, HLF_PSI);
int attr_scroll = win_hl_attr(curwin, HLF_PSB);
@@ -479,7 +479,7 @@ void pum_redraw(void)
// Display each entry, use two spaces for a Tab.
// Do this 3 times: For the main text, kind and extra info
- col = col_off;
+ grid_col = col_off;
totwidth = 0;
for (round = 1; round <= 3; ++round) {
@@ -537,24 +537,15 @@ void pum_redraw(void)
}
}
grid_puts_len(&pum_grid, rt, (int)STRLEN(rt), row,
- col - size + 1, attr);
+ grid_col - size + 1, attr);
xfree(rt_start);
xfree(st);
- col -= width;
+ grid_col -= width;
} else {
- int size = (int)STRLEN(st);
- int cells = (int)mb_string2cells(st);
-
- // only draw the text that fits
- while (size > 0 && col + cells > pum_width + pum_col) {
- size--;
- size -= utf_head_off(st, st + size);
- cells -= utf_ptr2cells(st + size);
- }
-
- grid_puts_len(&pum_grid, st, size, row, col, attr);
+ // use grid_puts_len() to truncate the text
+ grid_puts(&pum_grid, st, row, grid_col, attr);
xfree(st);
- col += width;
+ grid_col += width;
}
if (*p != TAB) {
@@ -563,12 +554,12 @@ void pum_redraw(void)
// Display two spaces for a Tab.
if (pum_rl) {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col - 1,
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col - 1,
attr);
- col -= 2;
+ grid_col -= 2;
} else {
- grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col, attr);
- col += 2;
+ grid_puts_len(&pum_grid, (char_u *)" ", 2, row, grid_col, attr);
+ grid_col += 2;
}
totwidth += 2;
// start text at next char
@@ -599,21 +590,21 @@ void pum_redraw(void)
if (pum_rl) {
grid_fill(&pum_grid, row, row + 1, col_off - pum_base_width - n + 1,
- col + 1, ' ', ' ', attr);
- col = col_off - pum_base_width - n + 1;
+ grid_col + 1, ' ', ' ', attr);
+ grid_col = col_off - pum_base_width - n + 1;
} else {
- grid_fill(&pum_grid, row, row + 1, col,
+ grid_fill(&pum_grid, row, row + 1, grid_col,
col_off + pum_base_width + n, ' ', ' ', attr);
- col = col_off + pum_base_width + n;
+ grid_col = col_off + pum_base_width + n;
}
totwidth = pum_base_width + n;
}
if (pum_rl) {
- grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, col + 1,
+ grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, grid_col + 1,
' ', ' ', attr);
} else {
- grid_fill(&pum_grid, row, row + 1, col, col_off + pum_width, ' ', ' ',
+ grid_fill(&pum_grid, row, row + 1, grid_col, col_off + pum_width, ' ', ' ',
attr);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2204e2a62a..32d0ebe8eb 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -657,7 +657,8 @@ static int qf_get_next_str_line(qfstate_T *state)
state->linebuf = IObuff;
state->linelen = len;
}
- STRLCPY(state->linebuf, p_str, state->linelen + 1);
+ memcpy(state->linebuf, p_str, state->linelen);
+ state->linebuf[state->linelen] = '\0';
// Increment using len in order to discard the rest of the line if it
// exceeds LINE_MAXLEN.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 3e7306bad3..41c927eaa6 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -18,22 +18,20 @@
#include "nvim/garray.h"
#include "nvim/os/input.h"
-/*
- * Logging of NFA engine.
- *
- * The NFA engine can write four log files:
- * - Error log: Contains NFA engine's fatal errors.
- * - Dump log: Contains compiled NFA state machine's information.
- * - Run log: Contains information of matching procedure.
- * - Debug log: Contains detailed information of matching procedure. Can be
- * disabled by undefining NFA_REGEXP_DEBUG_LOG.
- * The first one can also be used without debug mode.
- * The last three are enabled when compiled as debug mode and individually
- * disabled by commenting them out.
- * The log files can get quite big!
- * Do disable all of this when compiling Vim for debugging, undefine REGEXP_DEBUG in
- * regexp.c
- */
+// Logging of NFA engine.
+//
+// The NFA engine can write four log files:
+// - Error log: Contains NFA engine's fatal errors.
+// - Dump log: Contains compiled NFA state machine's information.
+// - Run log: Contains information of matching procedure.
+// - Debug log: Contains detailed information of matching procedure. Can be
+// disabled by undefining NFA_REGEXP_DEBUG_LOG.
+// The first one can also be used without debug mode.
+// The last three are enabled when compiled as debug mode and individually
+// disabled by commenting them out.
+// The log files can get quite big!
+// To disable all of this when compiling Vim for debugging, undefine REGEXP_DEBUG in
+// regexp.c
#ifdef REGEXP_DEBUG
# define NFA_REGEXP_ERROR_LOG "nfa_regexp_error.log"
# define NFA_REGEXP_DUMP_LOG "nfa_regexp_dump.log"
@@ -2567,20 +2565,20 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
ga_concat(indent, (char_u *)"| ");
else
ga_concat(indent, (char_u *)" ");
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
nfa_print_state2(debugf, state->out, indent);
/* replace last part of indent for state->out1 */
indent->ga_len -= 3;
ga_concat(indent, (char_u *)" ");
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
nfa_print_state2(debugf, state->out1, indent);
/* shrink indent */
indent->ga_len -= 3;
- ga_append(indent, '\0');
+ ga_append(indent, NUL);
}
/*
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index a938a3b062..e62e3ca7bc 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -5933,6 +5933,8 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
// Only 1 cell left, but character requires 2 cells:
// display a '>' in the last column to avoid wrapping. */
c = '>';
+ u8c = '>';
+ u8cc[0] = 0;
mbyte_cells = 1;
}
@@ -5963,6 +5965,13 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col
clear_next_cell = true;
}
+ // When at the start of the text and overwriting the right half of a
+ // two-cell character in the same grid, truncate that into a '>'.
+ if (ptr == text && col > 0 && grid->chars[off][0] == 0) {
+ grid->chars[off - 1][0] = '>';
+ grid->chars[off - 1][1] = 0;
+ }
+
schar_copy(grid->chars[off], buf);
grid->attrs[off] = attr;
if (mbyte_cells == 2) {
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 32be714184..a308df07d1 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -1740,7 +1740,7 @@ char_u *get_sign_name(expand_T *xp, int idx)
case EXP_SUBCMD:
return (char_u *)cmds[idx];
case EXP_DEFINE: {
- char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
+ char *define_arg[] = { "culhl=", "icon=", "linehl=", "numhl=", "text=", "texthl=",
NULL };
return (char_u *)define_arg[idx];
}
@@ -1849,6 +1849,7 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
case SIGNCMD_DEFINE:
if (STRNCMP(last, "texthl", 6) == 0
|| STRNCMP(last, "linehl", 6) == 0
+ || STRNCMP(last, "culhl", 5) == 0
|| STRNCMP(last, "numhl", 5) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
} else if (STRNCMP(last, "icon", 4) == 0) {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 04068a3cb8..d97c24dcf7 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -1466,6 +1466,17 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
int width, height;
vterm_get_size(term->vt, &height, &width);
+ // May still have pending scrollback after increase in terminal height if the
+ // scrollback wasn't refreshed in time; append these to the top of the buffer.
+ int row_offset = term->sb_pending;
+ while (term->sb_pending > 0 && buf->b_ml.ml_line_count < height) {
+ fetch_row(term, term->sb_pending - row_offset - 1, width);
+ ml_append(0, (uint8_t *)term->textbuf, 0, false);
+ appended_lines(0, 1);
+ term->sb_pending--;
+ }
+
+ row_offset -= term->sb_pending;
while (term->sb_pending > 0) {
// This means that either the window height has decreased or the screen
// became full and libvterm had to push all rows up. Convert the first
@@ -1476,7 +1487,7 @@ static void refresh_scrollback(Terminal *term, buf_T *buf)
ml_delete(1, false);
deleted_lines(1, 1);
}
- fetch_row(term, -term->sb_pending, width);
+ fetch_row(term, -term->sb_pending - row_offset, width);
int buf_index = (int)buf->b_ml.ml_line_count - height;
ml_append(buf_index, (uint8_t *)term->textbuf, 0, false);
appended_lines(buf_index, 1);
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index ab047fd2a8..b0d872e392 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -64,6 +64,9 @@ if has('reltime')
let s:start_time = reltime()
endif
+" Always use forward slashes.
+set shellslash
+
" Common with all tests on all systems.
source setup.vim
@@ -104,9 +107,6 @@ lang mess C
" Nvim: append runtime from build dir, which contains the generated doc/tags.
let &runtimepath .= ','.expand($BUILD_DIR).'/runtime/'
-" Always use forward slashes.
-set shellslash
-
let s:t_bold = &t_md
let s:t_normal = &t_me
if has('win32')
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index b3df8c63e6..fdae0697c3 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -13,7 +13,7 @@ set fillchars=vert:\|,fold:-
set laststatus=1
set listchars=eol:$
set joinspaces
-set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
+set nohidden nosmarttab noautoindent noautoread complete-=i noruler noshowcmd
set nrformats+=octal
set shortmess-=F
set sidescroll=0
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 4e1a24af61..45285b69a1 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -2380,95 +2380,7 @@ func Test_autocmd_was_using_freed_memory()
pclose
endfunc
-func Test_FileChangedShell_reload()
- if !has('unix')
- return
- endif
- augroup testreload
- au FileChangedShell Xchanged let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
- augroup END
- new Xchanged
- call setline(1, 'reload this')
- write
- " Need to wait until the timestamp would change by at least a second.
- sleep 2
- silent !echo 'extra line' >>Xchanged
- checktime
- call assert_equal('changed', g:reason)
- call assert_equal(2, line('$'))
- call assert_equal('extra line', getline(2))
-
- " Only triggers once
- let g:reason = ''
- checktime
- call assert_equal('', g:reason)
-
- " When deleted buffer is not reloaded
- silent !rm Xchanged
- let g:reason = ''
- checktime
- call assert_equal('deleted', g:reason)
- call assert_equal(2, line('$'))
- call assert_equal('extra line', getline(2))
-
- " When recreated buffer is reloaded
- call setline(1, 'buffer is changed')
- silent !echo 'new line' >>Xchanged
- let g:reason = ''
- checktime
- call assert_equal('conflict', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- " Only mode changed
- silent !chmod +x Xchanged
- let g:reason = ''
- checktime
- call assert_equal('mode', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- " Only time changed
- sleep 2
- silent !touch Xchanged
- let g:reason = ''
- checktime
- call assert_equal('time', g:reason)
- call assert_equal(1, line('$'))
- call assert_equal('new line', getline(1))
-
- if has('persistent_undo')
- " With an undo file the reload can be undone and a change before the
- " reload.
- set undofile
- call setline(2, 'before write')
- write
- call setline(2, 'after write')
- sleep 2
- silent !echo 'different line' >>Xchanged
- let g:reason = ''
- checktime
- call assert_equal('conflict', g:reason)
- call assert_equal(3, line('$'))
- call assert_equal('before write', getline(2))
- call assert_equal('different line', getline(3))
- " undo the reload
- undo
- call assert_equal(2, line('$'))
- call assert_equal('after write', getline(2))
- " undo the change before reload
- undo
- call assert_equal(2, line('$'))
- call assert_equal('before write', getline(2))
-
- set noundofile
- endif
-
-
- au! testreload
- bwipe!
- call delete('Xchanged')
-endfunc
+" FileChangedShell tested in test_filechanged.vim
func LogACmd()
call add(g:logged, line('$'))
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index 20758b0c0a..af42b3857d 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -346,4 +346,12 @@ func Test_blob_sort()
endif
endfunc
+" The following used to cause an out-of-bounds memory access
+func Test_blob2string()
+ let v = '0z' .. repeat('01010101.', 444)
+ let v ..= '01'
+ exe 'let b = ' .. v
+ call assert_equal(v, string(b))
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 49a5386337..1672b0e840 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -467,6 +467,43 @@ func Test_getcompletion()
call assert_fails('call getcompletion("abc", [])', 'E475:')
endfunc
+func Test_fullcommand()
+ let tests = {
+ \ '': '',
+ \ ':': '',
+ \ ':::': '',
+ \ ':::5': '',
+ \ 'not_a_cmd': '',
+ \ 'Check': '',
+ \ 'syntax': 'syntax',
+ \ ':syntax': 'syntax',
+ \ '::::syntax': 'syntax',
+ \ 'sy': 'syntax',
+ \ 'syn': 'syntax',
+ \ 'synt': 'syntax',
+ \ ':sy': 'syntax',
+ \ '::::sy': 'syntax',
+ \ 'match': 'match',
+ \ '2match': 'match',
+ \ '3match': 'match',
+ \ 'aboveleft': 'aboveleft',
+ \ 'abo': 'aboveleft',
+ \ 's': 'substitute',
+ \ '5s': 'substitute',
+ \ ':5s': 'substitute',
+ \ "'<,'>s": 'substitute',
+ \ ":'<,'>s": 'substitute',
+ \ 'CheckUni': 'CheckUnix',
+ \ 'CheckUnix': 'CheckUnix',
+ \ }
+
+ for [in, want] in items(tests)
+ call assert_equal(want, fullcommand(in))
+ endfor
+
+ call assert_equal('syntax', 'syn'->fullcommand())
+endfunc
+
func Test_shellcmd_completion()
let save_path = $PATH
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 12327f34d6..c2a9683f7c 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -263,6 +263,31 @@ func Test_display_scroll_at_topline()
call StopVimInTerminal(buf)
endfunc
+" Test for 'eob' (EndOfBuffer) item in 'fillchars'
+func Test_eob_fillchars()
+ " default value (skipped)
+ " call assert_match('eob:\~', &fillchars)
+ " invalid values
+ call assert_fails(':set fillchars=eob:', 'E474:')
+ call assert_fails(':set fillchars=eob:xy', 'E474:')
+ call assert_fails(':set fillchars=eob:\255', 'E474:')
+ call assert_fails(':set fillchars=eob:<ff>', 'E474:')
+ call assert_fails(":set fillchars=eob:\x01", 'E474:')
+ call assert_fails(':set fillchars=eob:\\x01', 'E474:')
+ " default is ~
+ new
+ redraw
+ call assert_equal('~', Screenline(2))
+ set fillchars=eob:+
+ redraw
+ call assert_equal('+', Screenline(2))
+ set fillchars=eob:\
+ redraw
+ call assert_equal(' ', nr2char(screenchar(2, 1)))
+ set fillchars&
+ close
+endfunc
+
func Test_display_linebreak_breakat()
new
vert resize 25
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 37786f3ca0..fc4e80f0d6 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1294,6 +1294,7 @@ func Test_edit_forbidden()
call assert_fails(':Sandbox', 'E48:')
delcom Sandbox
call assert_equal(['a'], getline(1,'$'))
+
" 2) edit with textlock set
fu! DoIt()
call feedkeys("i\<del>\<esc>", 'tnix')
@@ -1313,6 +1314,7 @@ func Test_edit_forbidden()
catch /^Vim\%((\a\+)\)\=:E117/ " catch E117: unknown function
endtry
au! InsertCharPre
+
" 3) edit when completion is shown
fun! Complete(findstart, base)
if a:findstart
@@ -1330,6 +1332,7 @@ func Test_edit_forbidden()
endtry
delfu Complete
set completefunc=
+
if has("rightleft") && exists("+fkmap")
" 4) 'R' when 'fkmap' and 'revins' is set.
set revins fkmap
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 1c645ad0f8..92e0559618 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -85,7 +85,7 @@ endfunc
func Test_ex_mode_count_overflow()
" this used to cause a crash
let lines =<< trim END
- call feedkeys("\<Esc>Q\<CR>")
+ call feedkeys("\<Esc>gQ\<CR>")
v9|9silent! vi|333333233333y32333333%O
call writefile(['done'], 'Xdidexmode')
qall!
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
new file mode 100644
index 0000000000..b95cd5faf8
--- /dev/null
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -0,0 +1,149 @@
+" Tests for when a file was changed outside of Vim.
+
+func Test_FileChangedShell_reload()
+ if !has('unix')
+ return
+ endif
+ augroup testreload
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
+ augroup END
+ new Xchanged_r
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_r
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " Only triggers once
+ let g:reason = ''
+ checktime
+ call assert_equal('', g:reason)
+
+ " When deleted buffer is not reloaded
+ silent !rm Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('deleted', g:reason)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+
+ " When recreated buffer is reloaded
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed
+ silent !chmod +x Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('mode', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed
+ sleep 2
+ silent !touch Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('time', g:reason)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ if has('persistent_undo')
+ " With an undo file the reload can be undone and a change before the
+ " reload.
+ set undofile
+ call setline(2, 'before write')
+ write
+ call setline(2, 'after write')
+ sleep 2
+ silent !echo 'different line' >>Xchanged_r
+ let g:reason = ''
+ checktime
+ call assert_equal('conflict', g:reason)
+ call assert_equal(3, line('$'))
+ call assert_equal('before write', getline(2))
+ call assert_equal('different line', getline(3))
+ " undo the reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('after write', getline(2))
+ " undo the change before reload
+ undo
+ call assert_equal(2, line('$'))
+ call assert_equal('before write', getline(2))
+
+ set noundofile
+ endif
+
+ au! testreload
+ bwipe!
+ call delete(undofile('Xchanged_r'))
+ call delete('Xchanged_r')
+endfunc
+
+func Test_file_changed_dialog()
+ throw 'skipped: TODO: '
+ if !has('unix') || has('gui_running')
+ return
+ endif
+ au! FileChangedShell
+
+ new Xchanged_d
+ call setline(1, 'reload this')
+ write
+ " Need to wait until the timestamp would change by at least a second.
+ sleep 2
+ silent !echo 'extra line' >>Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W11:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('reload this', getline(1))
+ call assert_equal('extra line', getline(2))
+
+ " delete buffer, only shows an error, no prompt
+ silent !rm Xchanged_d
+ checktime
+ call assert_match('E211:', v:warningmsg)
+ call assert_equal(2, line('$'))
+ call assert_equal('extra line', getline(2))
+ let v:warningmsg = 'empty'
+
+ " change buffer, recreate the file and reload
+ call setline(1, 'buffer is changed')
+ silent !echo 'new line' >Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W12:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only mode changed, reload
+ silent !chmod +x Xchanged_d
+ call feedkeys('L', 'L')
+ checktime
+ call assert_match('W16:', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ " Only time changed, no prompt
+ sleep 2
+ silent !touch Xchanged_d
+ let v:warningmsg = ''
+ checktime
+ call assert_equal('', v:warningmsg)
+ call assert_equal(1, line('$'))
+ call assert_equal('new line', getline(1))
+
+ bwipe!
+ call delete('Xchanged_d')
+endfunc
diff --git a/src/nvim/testdir/test_fileformat.vim b/src/nvim/testdir/test_fileformat.vim
index 465613f1cf..81127ea59a 100644
--- a/src/nvim/testdir/test_fileformat.vim
+++ b/src/nvim/testdir/test_fileformat.vim
@@ -1,5 +1,4 @@
" Test behavior of fileformat after bwipeout of last buffer
-
func Test_fileformat_after_bw()
bwipeout
set fileformat&
@@ -32,6 +31,251 @@ func Test_fileformat_autocommand()
bw!
endfunc
+" Convert the contents of a file into a literal string
+func s:file2str(fname)
+ let b = readfile(a:fname, 'B')
+ let s = ''
+ for c in b
+ let s .= nr2char(c)
+ endfor
+ return s
+endfunc
+
+" Concatenate the contents of files 'f1' and 'f2' and create 'destfile'
+func s:concat_files(f1, f2, destfile)
+ let b1 = readfile(a:f1, 'B')
+ let b2 = readfile(a:f2, 'B')
+ let b3 = b1 + b2
+ call writefile(b3, a:destfile)
+endfun
+
+" Test for a lot of variations of the 'fileformats' option
+func Test_fileformats()
+ " create three test files, one in each format
+ call writefile(['unix', 'unix'], 'XXUnix')
+ call writefile(["dos\r", "dos\r"], 'XXDos')
+ call writefile(["mac\rmac\r"], 'XXMac', 'b')
+ " create a file with no End Of Line
+ call writefile(["noeol"], 'XXEol', 'b')
+ " create mixed format files
+ call s:concat_files('XXUnix', 'XXDos', 'XXUxDs')
+ call s:concat_files('XXUnix', 'XXMac', 'XXUxMac')
+ call s:concat_files('XXDos', 'XXMac', 'XXDosMac')
+ call s:concat_files('XXMac', 'XXEol', 'XXMacEol')
+ call s:concat_files('XXUxDs', 'XXMac', 'XXUxDsMc')
+
+ new
+
+ " Test 1: try reading and writing with 'fileformats' empty
+ set fileformats=
+
+ " try with 'fileformat' set to 'unix'
+ set fileformat=unix
+ e! XXUnix
+ w! Xtest
+ call assert_equal("unix\nunix\n", s:file2str('Xtest'))
+ e! XXDos
+ w! Xtest
+ call assert_equal("dos\r\ndos\r\n", s:file2str('Xtest'))
+ e! XXMac
+ w! Xtest
+ call assert_equal("mac\rmac\r\n", s:file2str('Xtest'))
+ bwipe XXUnix XXDos XXMac
+
+ " try with 'fileformat' set to 'dos'
+ set fileformat=dos
+ e! XXUnix
+ w! Xtest
+ call assert_equal("unix\r\nunix\r\n", s:file2str('Xtest'))
+ e! XXDos
+ w! Xtest
+ call assert_equal("dos\r\ndos\r\n", s:file2str('Xtest'))
+ e! XXMac
+ w! Xtest
+ call assert_equal("mac\rmac\r\r\n", s:file2str('Xtest'))
+ bwipe XXUnix XXDos XXMac
+
+ " try with 'fileformat' set to 'mac'
+ set fileformat=mac
+ e! XXUnix
+ w! Xtest
+ call assert_equal("unix\nunix\n\r", s:file2str('Xtest'))
+ e! XXDos
+ w! Xtest
+ call assert_equal("dos\r\ndos\r\n\r", s:file2str('Xtest'))
+ e! XXMac
+ w! Xtest
+ call assert_equal("mac\rmac\r", s:file2str('Xtest'))
+ bwipe XXUnix XXDos XXMac
+
+ " Test 2: try reading and writing with 'fileformats' set to one format
+
+ " try with 'fileformats' set to 'unix'
+ set fileformats=unix
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ " try with 'fileformats' set to 'dos'
+ set fileformats=dos
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\r\nunix\r\ndos\r\ndos\r\nmac\rmac\r\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ " try with 'fileformats' set to 'mac'
+ set fileformats=mac
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ " Test 3: try reading and writing with 'fileformats' set to two formats
+
+ " try with 'fileformats' set to 'unix,dos'
+ set fileformats=unix,dos
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXUxMac
+ w! Xtest
+ call assert_equal("unix\nunix\nmac\rmac\r\n", s:file2str('Xtest'))
+ bwipe XXUxMac
+
+ e! XXDosMac
+ w! Xtest
+ call assert_equal("dos\r\ndos\r\nmac\rmac\r\r\n", s:file2str('Xtest'))
+ bwipe XXDosMac
+
+ " try with 'fileformats' set to 'unix,mac'
+ set fileformats=unix,mac
+ e! XXUxDs
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\n", s:file2str('Xtest'))
+ bwipe XXUxDs
+
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXDosMac
+ w! Xtest
+ call assert_equal("dos\r\ndos\r\nmac\rmac\r", s:file2str('Xtest'))
+ bwipe XXDosMac
+
+ e! XXEol
+ exe "normal ggO\<C-R>=&ffs\<CR>:\<C-R>=&ff\<CR>"
+ w! Xtest
+ call assert_equal("unix,mac:unix\nnoeol\n", s:file2str('Xtest'))
+ bwipe! XXEol
+
+ " try with 'fileformats' set to 'dos,mac'
+ set fileformats=dos,mac
+ e! XXUxDs
+ w! Xtest
+ call assert_equal("unix\r\nunix\r\ndos\r\ndos\r\n", s:file2str('Xtest'))
+ bwipe XXUxDs
+
+ e! XXUxMac
+ exe "normal ggO\<C-R>=&ffs\<CR>:\<C-R>=&ff\<CR>"
+ w! Xtest
+ call assert_equal("dos,mac:dos\r\nunix\r\nunix\r\nmac\rmac\r\r\n",
+ \ s:file2str('Xtest'))
+ bwipe! XXUxMac
+
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\r\nunix\r\ndos\r\ndos\r\nmac\rmac\r\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXMacEol
+ exe "normal ggO\<C-R>=&ffs\<CR>:\<C-R>=&ff\<CR>"
+ w! Xtest
+ call assert_equal("dos,mac:mac\rmac\rmac\rnoeol\r", s:file2str('Xtest'))
+ bwipe! XXMacEol
+
+ " Test 4: try reading and writing with 'fileformats' set to three formats
+ set fileformats=unix,dos,mac
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXEol
+ exe "normal ggO\<C-R>=&ffs\<CR>:\<C-R>=&ff\<CR>"
+ w! Xtest
+ call assert_equal("unix,dos,mac:unix\nnoeol\n", s:file2str('Xtest'))
+ bwipe! XXEol
+
+ set fileformats=mac,dos,unix
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r\n",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXEol
+ exe "normal ggO\<C-R>=&ffs\<CR>:\<C-R>=&ff\<CR>"
+ w! Xtest
+ call assert_equal("mac,dos,unix:mac\rnoeol\r", s:file2str('Xtest'))
+ bwipe! XXEol
+
+ " Test 5: try with 'binary' set
+ set fileformats=mac,unix,dos
+ set binary
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ set fileformats=mac
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ set fileformats=dos
+ e! XXUxDsMc
+ w! Xtest
+ call assert_equal("unix\nunix\ndos\r\ndos\r\nmac\rmac\r",
+ \ s:file2str('Xtest'))
+ bwipe XXUxDsMc
+
+ e! XXUnix
+ w! Xtest
+ call assert_equal("unix\nunix\n", s:file2str('Xtest'))
+ bwipe! XXUnix
+
+ set nobinary ff& ffs&
+
+ " cleanup
+ only
+ %bwipe!
+ call delete('XXUnix')
+ call delete('XXDos')
+ call delete('XXMac')
+ call delete('XXEol')
+ call delete('XXUxDs')
+ call delete('XXUxMac')
+ call delete('XXDosMac')
+ call delete('XXMacEol')
+ call delete('XXUxDsMc')
+ call delete('Xtest')
+endfunc
+
" Test for changing the fileformat using ++read
func Test_fileformat_plusplus_read()
new
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 31052ce47d..1ee23bb646 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -117,7 +117,7 @@ let s:filename_checks = {
\ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
\ 'crm': ['file.crm'],
\ 'crontab': ['crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'],
- \ 'cs': ['file.cs'],
+ \ 'cs': ['file.cs', 'file.csx'],
\ 'csc': ['file.csc'],
\ 'csdl': ['file.csdl'],
\ 'csp': ['file.csp', 'file.fdr'],
@@ -204,6 +204,7 @@ let s:filename_checks = {
\ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
\ 'gnuplot': ['file.gpi'],
\ 'go': ['file.go'],
+ \ 'gomod': ['go.mod'],
\ 'gp': ['file.gp', '.gprc'],
\ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'],
\ 'grads': ['file.gs'],
@@ -226,6 +227,7 @@ let s:filename_checks = {
\ 'hollywood': ['file.hws'],
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
+ \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
\ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
@@ -261,7 +263,7 @@ let s:filename_checks = {
\ 'jgraph': ['file.jgr'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'],
\ 'jsonc': ['file.jsonc'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
@@ -455,6 +457,7 @@ let s:filename_checks = {
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
\ 'slang': ['file.sl'],
\ 'slice': ['file.ice'],
+ \ 'solution': ['file.sln'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
\ 'slpreg': ['/etc/slp.reg', 'any/etc/slp.reg'],
\ 'slpspi': ['/etc/slp.spi', 'any/etc/slp.spi'],
@@ -1002,4 +1005,44 @@ func Test_fs_file()
filetype off
endfunc
+func Test_dep3patch_file()
+ filetype on
+
+ call assert_true(mkdir('debian/patches', 'p'))
+
+ " series files are not patches
+ call writefile(['Description: some awesome patch'], 'debian/patches/series')
+ split debian/patches/series
+ call assert_notequal('dep3patch', &filetype)
+ bwipe!
+
+ " diff/patch files without the right headers should still show up as ft=diff
+ call writefile([], 'debian/patches/foo.diff')
+ split debian/patches/foo.diff
+ call assert_equal('diff', &filetype)
+ bwipe!
+
+ " Files with the right headers are detected as dep3patch, even if they don't
+ " have a diff/patch extension
+ call writefile(['Subject: dep3patches'], 'debian/patches/bar')
+ split debian/patches/bar
+ call assert_equal('dep3patch', &filetype)
+ bwipe!
+
+ " Files in sub-directories are detected
+ call assert_true(mkdir('debian/patches/s390x', 'p'))
+ call writefile(['Subject: dep3patches'], 'debian/patches/s390x/bar')
+ split debian/patches/s390x/bar
+ call assert_equal('dep3patch', &filetype)
+ bwipe!
+
+ " The detection stops when seeing the "header end" marker
+ call writefile(['---', 'Origin: the cloud'], 'debian/patches/baz')
+ split debian/patches/baz
+ call assert_notequal('dep3patch', &filetype)
+ bwipe!
+
+ call delete('debian/patches', 'rf')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index f4ee539803..0bcbd9c4a5 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -331,7 +331,7 @@ func Test_listchars_invalid()
call assert_fails('set listchars=space:xx', 'E474:')
call assert_fails('set listchars=tab:xxxx', 'E474:')
- " Has non-single width character
+ " Has double-width character
call assert_fails('set listchars=space:·', 'E474:')
call assert_fails('set listchars=tab:·x', 'E474:')
call assert_fails('set listchars=tab:x·', 'E474:')
@@ -339,6 +339,20 @@ func Test_listchars_invalid()
call assert_fails('set listchars=multispace:·', 'E474:')
call assert_fails('set listchars=multispace:xxx·', 'E474:')
+ " Has control character
+ call assert_fails("set listchars=space:\x01", 'E474:')
+ call assert_fails("set listchars=tab:\x01x", 'E474:')
+ call assert_fails("set listchars=tab:x\x01", 'E474:')
+ call assert_fails("set listchars=tab:xx\x01", 'E474:')
+ call assert_fails("set listchars=multispace:\x01", 'E474:')
+ call assert_fails("set listchars=multispace:xxx\x01", 'E474:')
+ call assert_fails('set listchars=space:\\x01', 'E474:')
+ call assert_fails('set listchars=tab:\\x01x', 'E474:')
+ call assert_fails('set listchars=tab:x\\x01', 'E474:')
+ call assert_fails('set listchars=tab:xx\\x01', 'E474:')
+ call assert_fails('set listchars=multispace:\\x01', 'E474:')
+ call assert_fails('set listchars=multispace:xxx\\x01', 'E474:')
+
enew!
set ambiwidth& listchars& ff&
endfunction
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 2140fe21ea..e0286548d9 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -108,3 +108,11 @@ func Test_echospace()
set ruler& showcmd&
endfunc
+
+" this was missing a terminating NUL
+func Test_echo_string_partial()
+ function CountSpaces()
+ endfunction
+ call assert_equal("function('CountSpaces', [{'ccccccccccc': ['ab', 'cd'], 'aaaaaaaaaaa': v:false, 'bbbbbbbbbbbb': ''}])", string(function('CountSpaces', [#{aaaaaaaaaaa: v:false, bbbbbbbbbbbb: '', ccccccccccc: ['ab', 'cd']}])))
+endfunc
+
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 7d9cada074..5946732937 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -732,4 +732,25 @@ func Test_opt_reset_scroll()
call delete('Xscroll')
endfunc
+" Test for the 'cdhome' option
+func Test_opt_cdhome()
+ if has('unix') || has('vms')
+ throw 'Skipped: only works on non-Unix'
+ endif
+
+ set cdhome&
+ call assert_equal(0, &cdhome)
+ set cdhome
+
+ " This paragraph is copied from Test_cd_no_arg().
+ let path = getcwd()
+ cd
+ call assert_equal($HOME, getcwd())
+ call assert_notequal(path, getcwd())
+ exe 'cd ' .. fnameescape(path)
+ call assert_equal(path, getcwd())
+
+ set cdhome&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index 799e6cb57b..ff9ba3d8ed 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -218,15 +218,13 @@ func Test_sign_completion()
call assert_equal('"sign define jump list place undefine unplace', @:)
call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"sign define Sign icon= linehl= numhl= text= texthl=', @:)
+ call assert_equal('"sign define Sign culhl= icon= linehl= numhl= text= texthl=', @:)
- call feedkeys(":sign define Sign linehl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' .
- \ 'SpellLocal SpellRare', @:)
-
- call feedkeys(":sign define Sign texthl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' .
- \ 'SpellLocal SpellRare', @:)
+ for hl in ['culhl', 'linehl', 'numhl', 'texthl']
+ call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign '..hl..'=SpellBad SpellCap ' .
+ \ 'SpellLocal SpellRare', @:)
+ endfor
call writefile(repeat(["Sun is shining"], 30), "XsignOne")
call writefile(repeat(["Sky is blue"], 30), "XsignTwo")
@@ -417,20 +415,21 @@ func Test_sign_funcs()
" Tests for sign_define()
let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error',
- \ 'culhl': 'Visual'}
+ \ 'culhl': 'Visual', 'numhl': 'Number'}
call assert_equal(0, "sign1"->sign_define(attr))
- call assert_equal([{'name' : 'sign1', 'texthl' : 'Error',
- \ 'linehl' : 'Search', 'culhl': 'Visual', 'text' : '=>'}],
+ call assert_equal([{'name' : 'sign1', 'texthl' : 'Error', 'linehl': 'Search',
+ \ 'culhl': 'Visual', 'numhl': 'Number', 'text' : '=>'}],
\ sign_getdefined())
" Define a new sign without attributes and then update it
call sign_define("sign2")
let attr = {'text' : '!!', 'linehl' : 'DiffAdd', 'texthl' : 'DiffChange',
- \ 'culhl': 'DiffDelete', 'icon' : 'sign2.ico'}
+ \ 'culhl': 'DiffDelete', 'numhl': 'Number', 'icon' : 'sign2.ico'}
call Sign_define_ignore_error("sign2", attr)
call assert_equal([{'name' : 'sign2', 'texthl' : 'DiffChange',
\ 'linehl' : 'DiffAdd', 'culhl' : 'DiffDelete', 'text' : '!!',
- \ 'icon' : 'sign2.ico'}], "sign2"->sign_getdefined())
+ \ 'numhl': 'Number', 'icon' : 'sign2.ico'}],
+ \ "sign2"->sign_getdefined())
" Test for a sign name with digits
call assert_equal(0, sign_define(0002, {'linehl' : 'StatusLine'}))
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 113c85acef..20b760ac15 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -137,7 +137,7 @@ func Test_substitute_repeat()
" This caused an invalid memory access.
split Xfile
s/^/x
- call feedkeys("Qsc\<CR>y", 'tx')
+ call feedkeys("gQsc\<CR>y", 'tx')
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 5cc0da2586..aae315b2c5 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -279,7 +279,7 @@ func Test_ex_mode()
endfunc
let timer = timer_start(40, function('g:Foo'), {'repeat':-1})
" This used to throw error E749.
- exe "normal Qsleep 100m\rvi\r"
+ exe "normal gQsleep 100m\rvi\r"
call timer_stop(timer)
endfunc
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index dbabdcf427..8344598486 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -144,7 +144,6 @@ endfun
" Test Virtual replace mode.
func Test_virtual_replace()
- throw 'skipped: TODO: '
if exists('&t_kD')
let save_t_kD = &t_kD
endif
@@ -166,7 +165,6 @@ func Test_virtual_replace()
\ ], getline(1, 6))
normal G
mark a
- inoremap <C-D> <Del>
exe "normal o0\<C-D>\nabcdefghi\njk\tlmn\n opq\trst\n\<C-D>uvwxyz\n"
exe "normal 'ajgR0\<C-D> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" . repeat("\<BS>", 29)
call assert_equal([' 1',
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 5bb6059fa7..5fec41f9a5 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -114,6 +114,12 @@ static void tinput_done_event(void **argv)
static void tinput_wait_enqueue(void **argv)
{
TermInput *input = argv[0];
+ if (rbuffer_size(input->key_buffer) == 0 && input->paste == 3) {
+ const String keys = { .data = "", .size = 0 };
+ String copy = copy_string(keys);
+ multiqueue_put(main_loop.events, tinput_paste_event, 3,
+ copy.data, copy.size, (intptr_t)input->paste);
+ }
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
const String keys = { .data = buf, .size = len };
if (input->paste) {
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index bb75286369..e7a60aca49 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -308,23 +308,39 @@ static void terminfo_start(UI *ui)
// Enable bracketed paste
unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
+ int ret;
uv_loop_init(&data->write_loop);
if (data->out_isatty) {
- uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
+ ret = uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
+ if (ret) {
+ ELOG("uv_tty_init failed: %s", uv_strerror(ret));
+ }
#ifdef WIN32
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
+ ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
#else
int retry_count = 10;
// A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
// few times. #12322
- while (uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO) == UV_EINTR
+ while ((ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO)) == UV_EINTR
&& retry_count > 0) {
retry_count--;
}
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
#endif
} else {
- uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
- uv_pipe_open(&data->output_handle.pipe, data->out_fd);
+ ret = uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
+ if (ret) {
+ ELOG("uv_pipe_init failed: %s", uv_strerror(ret));
+ }
+ ret = uv_pipe_open(&data->output_handle.pipe, data->out_fd);
+ if (ret) {
+ ELOG("uv_pipe_open failed: %s", uv_strerror(ret));
+ }
}
flush_buf(ui);
}
@@ -1086,8 +1102,14 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
// after calling uv_tty_set_mode. So, set the mode of the TTY again here.
// #13073
if (data->is_starting && data->input.in_fd == STDERR_FILENO) {
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
- uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ int ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
+ ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ if (ret) {
+ ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
+ }
}
#endif
tui_set_mode(ui, (ModeShape)mode_idx);
@@ -2081,8 +2103,11 @@ static void flush_buf(UI *ui)
fwrite(bufs[i].base, bufs[i].len, 1, data->screenshot);
}
} else {
- uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
- bufs, (unsigned)(bufp - bufs), NULL);
+ int ret = uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
+ bufs, (unsigned)(bufp - bufs), NULL);
+ if (ret) {
+ ELOG("uv_write failed: %s", uv_strerror(ret));
+ }
uv_run(&data->write_loop, UV_RUN_DEFAULT);
}
data->bufpos = 0;
diff --git a/test/README.md b/test/README.md
index 37aa54c157..c6e173ead2 100644
--- a/test/README.md
+++ b/test/README.md
@@ -116,7 +116,7 @@ Filtering Tests
### Filter by name
-Another filter method is by setting a pattern of test name to `TEST_FILTER`.
+Another filter method is by setting a pattern of test name to `TEST_FILTER` or `TEST_FILTER_OUT`.
``` lua
it('foo api',function()
@@ -131,6 +131,10 @@ To run only test with filter name:
TEST_FILTER='foo.*api' make functionaltest
+To run all tests except ones matching a filter:
+
+ TEST_FILTER_OUT='foo.*api' make functionaltest
+
### Filter by file
To run a *specific* unit test:
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index d53208a915..22201e21a2 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -974,6 +974,40 @@ describe('API', function()
eq('hello', nvim('get_option_value', 'makeprg', {}))
eq('', nvim('get_option_value', 'makeprg', {scope = 'local'}))
end)
+
+ it('clears the local value of an option with nil', function()
+ -- Set global value
+ nvim('set_option_value', 'shiftwidth', 42, {})
+ eq(42, nvim('get_option_value', 'shiftwidth', {}))
+
+ -- Set local value
+ nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
+ eq(8, nvim('get_option_value', 'shiftwidth', {}))
+ eq(8, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
+ eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'global'}))
+
+ -- Clear value without scope
+ nvim('set_option_value', 'shiftwidth', NIL, {})
+ eq(42, nvim('get_option_value', 'shiftwidth', {}))
+ eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
+
+ -- Clear value with explicit scope
+ nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
+ nvim('set_option_value', 'shiftwidth', NIL, {scope = 'local'})
+ eq(42, nvim('get_option_value', 'shiftwidth', {}))
+ eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
+
+ -- Now try with options with a special "local is unset" value (e.g. 'undolevels')
+ nvim('set_option_value', 'undolevels', 1000, {})
+ eq(1000, nvim('get_option_value', 'undolevels', {scope = 'local'}))
+ nvim('set_option_value', 'undolevels', NIL, {scope = 'local'})
+ eq(-123456, nvim('get_option_value', 'undolevels', {scope = 'local'}))
+
+ nvim('set_option_value', 'autoread', true, {})
+ eq(true, nvim('get_option_value', 'autoread', {scope = 'local'}))
+ nvim('set_option_value', 'autoread', NIL, {scope = 'local'})
+ eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'}))
+ end)
end)
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()
@@ -1120,8 +1154,8 @@ describe('API', function()
end)
end)
- describe('RPC (K_EVENT) #6166', function()
- it('does not complete ("interrupt") normal-mode operator-pending', function()
+ describe('RPC (K_EVENT)', function()
+ it('does not complete ("interrupt") normal-mode operator-pending #6166', function()
helpers.insert([[
FIRST LINE
SECOND LINE]])
@@ -1157,7 +1191,7 @@ describe('API', function()
]])
end)
- it('does not complete ("interrupt") normal-mode map-pending', function()
+ it('does not complete ("interrupt") normal-mode map-pending #6166', function()
command("nnoremap dd :let g:foo='it worked...'<CR>")
helpers.insert([[
FIRST LINE
@@ -1173,7 +1207,8 @@ describe('API', function()
SECOND LINE]])
eq('it worked...', helpers.eval('g:foo'))
end)
- it('does not complete ("interrupt") insert-mode map-pending', function()
+
+ it('does not complete ("interrupt") insert-mode map-pending #6166', function()
command('inoremap xx foo')
command('set timeoutlen=9999')
helpers.insert([[
@@ -1188,6 +1223,37 @@ describe('API', function()
FIRST LINE
SECOND LINfooE]])
end)
+
+ it('does not interrupt Insert mode i_CTRL-O #10035', function()
+ feed('iHello World<c-o>')
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('dd')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ expect('') -- executed the command
+ end)
+
+ it('does not interrupt Select mode v_CTRL-O #15688', function()
+ feed('iHello World<esc>gh<c-o>')
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('^')
+ eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ feed('h')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
+ expect('h') -- selection is the whole line and is replaced
+ end)
+
+ it('does not interrupt Insert mode i_0_CTRL-D #13997', function()
+ command('set timeoutlen=9999')
+ feed('i<Tab><Tab>a0')
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ feed('<C-D>')
+ expect('a') -- recognized i_0_CTRL-D
+ end)
end)
describe('nvim_get_context', function()
diff --git a/test/functional/autocmd/cursormoved_spec.lua b/test/functional/autocmd/cursormoved_spec.lua
index d0f46e689b..9641d4b096 100644
--- a/test/functional/autocmd/cursormoved_spec.lua
+++ b/test/functional/autocmd/cursormoved_spec.lua
@@ -31,4 +31,12 @@ describe('CursorMoved', function()
eq({'aaa'}, funcs.nvim_buf_get_lines(eval('g:buf'), 0, -1, true))
eq(0, eval('g:cursormoved'))
end)
+
+ it("is not triggered by cursor movement prior to first CursorMoved instantiation", function()
+ source([[
+ let g:cursormoved = 0
+ autocmd CursorMoved * let g:cursormoved += 1
+ ]])
+ eq(0, eval('g:cursormoved'))
+ end)
end)
diff --git a/test/functional/autocmd/recording_spec.lua b/test/functional/autocmd/recording_spec.lua
new file mode 100644
index 0000000000..81152758de
--- /dev/null
+++ b/test/functional/autocmd/recording_spec.lua
@@ -0,0 +1,52 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local source_vim = helpers.source
+
+describe('RecordingEnter', function()
+ before_each(clear)
+ it('works', function()
+ source_vim [[
+ let g:recorded = 0
+ autocmd RecordingEnter * let g:recorded += 1
+ execute "normal! qqyyq"
+ ]]
+ eq(1, eval('g:recorded'))
+ end)
+
+ it('gives a correct reg_recording()', function()
+ source_vim [[
+ let g:recording = ''
+ autocmd RecordingEnter * let g:recording = reg_recording()
+ execute "normal! qqyyq"
+ ]]
+ eq('q', eval('g:recording'))
+ end)
+end)
+
+describe('RecordingLeave', function()
+ before_each(clear)
+ it('works', function()
+ source_vim [[
+ let g:recorded = 0
+ autocmd RecordingLeave * let g:recorded += 1
+ execute "normal! qqyyq"
+ ]]
+ eq(1, eval('g:recorded'))
+ end)
+
+ it('gives the correct reg_recorded()', function()
+ source_vim [[
+ let g:recorded = 'a'
+ let g:recording = ''
+ autocmd RecordingLeave * let g:recording = reg_recording()
+ autocmd RecordingLeave * let g:recorded = reg_recorded()
+ execute "normal! qqyyq"
+ ]]
+ eq('q', eval 'g:recording')
+ eq('', eval 'g:recorded')
+ eq('q', eval 'reg_recorded()')
+ end)
+end)
diff --git a/test/functional/editor/macro_spec.lua b/test/functional/editor/macro_spec.lua
index 102d8fc723..c0c9256af2 100644
--- a/test/functional/editor/macro_spec.lua
+++ b/test/functional/editor/macro_spec.lua
@@ -6,6 +6,8 @@ local feed = helpers.feed
local clear = helpers.clear
local expect = helpers.expect
local command = helpers.command
+local insert = helpers.insert
+local curbufmeths = helpers.curbufmeths
describe('macros', function()
before_each(clear)
@@ -27,4 +29,29 @@ describe('macros', function()
expect('llllll')
eq(eval('@i'), 'lxxx')
end)
+
+ it('can be replayed with Q', function()
+ insert [[hello
+hello
+hello]]
+ feed [[gg]]
+
+ feed [[qqAFOO<esc>q]]
+ eq({'helloFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false))
+
+ feed[[Q]]
+ eq({'helloFOOFOO', 'hello', 'hello'}, curbufmeths.get_lines(0, -1, false))
+
+ feed[[G3Q]]
+ eq({'helloFOOFOO', 'hello', 'helloFOOFOOFOO'}, curbufmeths.get_lines(0, -1, false))
+ end)
+end)
+
+describe('reg_recorded()', function()
+ before_each(clear)
+
+ it('returns the correct value', function()
+ feed [[qqyyq]]
+ eq('q', eval('reg_recorded()'))
+ end)
end)
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index 46ab483036..f03508035d 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -6,7 +6,6 @@ local expect = helpers.expect
local command = helpers.command
local eq = helpers.eq
local eval = helpers.eval
-local meths = helpers.meths
describe('insert-mode', function()
before_each(function()
@@ -75,15 +74,5 @@ describe('insert-mode', function()
feed('ooo')
expect('hello oooworld')
end)
-
- it("doesn't cancel Ctrl-O mode when processing event", function()
- feed('iHello World<c-o>')
- eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('dd')
- eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- expect('') -- executed the command
- end)
end)
end)
diff --git a/test/functional/editor/mode_visual_spec.lua b/test/functional/editor/mode_visual_spec.lua
deleted file mode 100644
index 468ae00e01..0000000000
--- a/test/functional/editor/mode_visual_spec.lua
+++ /dev/null
@@ -1,27 +0,0 @@
--- Visual-mode tests.
-
-local helpers = require('test.functional.helpers')(after_each)
-local clear = helpers.clear
-local eq = helpers.eq
-local eval = helpers.eval
-local expect = helpers.expect
-local feed = helpers.feed
-local meths = helpers.meths
-
-describe('visual-mode', function()
- before_each(clear)
-
- it("select-mode Ctrl-O doesn't cancel Ctrl-O mode when processing event #15688", function()
- feed('iHello World<esc>gh<c-o>')
- eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
- eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('^')
- eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- feed('h')
- eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
- expect('h') -- selection is the whole line and is replaced
- end)
-end)
-
diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua
index 023cdd4ae1..bd14f3bc53 100644
--- a/test/functional/legacy/options_spec.lua
+++ b/test/functional/legacy/options_spec.lua
@@ -83,4 +83,9 @@ describe('set', function()
Press ENTER or type command to continue^ |
]])
end)
+
+ it('foldcolumn and signcolumn to empty string is disallowed', function()
+ matches('E474: Invalid argument: fdc=', exc_exec('set fdc='))
+ matches('E474: Invalid argument: scl=', exc_exec('set scl='))
+ end)
end)
diff --git a/test/functional/lua/spell_spec.lua b/test/functional/lua/spell_spec.lua
new file mode 100644
index 0000000000..7e831f16a7
--- /dev/null
+++ b/test/functional/lua/spell_spec.lua
@@ -0,0 +1,53 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local pcall_err = helpers.pcall_err
+
+describe('vim.spell', function()
+ before_each(function()
+ clear()
+ end)
+
+ describe('.check', function()
+ local check = function(x, exp)
+ return eq(exp, exec_lua("return vim.spell.check(...)", x))
+ end
+
+ it('can handle nil', function()
+ eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'check' (expected string)]],
+ pcall_err(exec_lua, [[vim.spell.check(nil)]]))
+ end)
+
+ it('can check spellings', function()
+ check('hello', {})
+
+ check(
+ 'helloi',
+ {{"helloi", "bad", 1}}
+ )
+
+ check(
+ 'hello therei',
+ {{"therei", "bad", 7}}
+ )
+
+ check(
+ 'hello. there',
+ {{"there", "caps", 8}}
+ )
+
+ check(
+ 'neovim cna chkc spellins. okay?',
+ {
+ {"neovim" , "bad" , 1},
+ {"cna" , "bad" , 8},
+ {"chkc" , "bad" , 12},
+ {"spellins", "bad" , 17},
+ {"okay" , "caps", 27}
+ }
+ )
+ end)
+
+ end)
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 2515b37beb..317f92fcdc 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -131,9 +131,9 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.startswith("123", "2")'))
eq(false, funcs.luaeval('vim.startswith("123", "1234")'))
- eq("Error executing lua: vim/shared.lua:0: prefix: expected string, got nil",
+ matches("prefix: expected string, got nil",
pcall_err(exec_lua, 'return vim.startswith("123", nil)'))
- eq("Error executing lua: vim/shared.lua:0: s: expected string, got nil",
+ matches("s: expected string, got nil",
pcall_err(exec_lua, 'return vim.startswith(nil, "123")'))
end)
@@ -147,9 +147,9 @@ describe('lua stdlib', function()
eq(false, funcs.luaeval('vim.endswith("123", "2")'))
eq(false, funcs.luaeval('vim.endswith("123", "1234")'))
- eq("Error executing lua: vim/shared.lua:0: suffix: expected string, got nil",
+ matches("suffix: expected string, got nil",
pcall_err(exec_lua, 'return vim.endswith("123", nil)'))
- eq("Error executing lua: vim/shared.lua:0: s: expected string, got nil",
+ matches("s: expected string, got nil",
pcall_err(exec_lua, 'return vim.endswith(nil, "123")'))
end)
@@ -220,9 +220,9 @@ describe('lua stdlib', function()
eq({"yy","xx"}, exec_lua("return test_table"))
-- Validates args.
- eq('Error executing lua: vim.schedule: expected function',
+ matches('vim.schedule: expected function',
pcall_err(exec_lua, "vim.schedule('stringly')"))
- eq('Error executing lua: vim.schedule: expected function',
+ matches('vim.schedule: expected function',
pcall_err(exec_lua, "vim.schedule()"))
exec_lua([[
@@ -232,7 +232,7 @@ describe('lua stdlib', function()
]])
feed("<cr>")
- eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', remove_trace(eval("v:errmsg")))
+ matches('big failure\nvery async', remove_trace(eval("v:errmsg")))
local screen = Screen.new(60,5)
screen:set_default_attr_ids({
@@ -300,16 +300,16 @@ describe('lua stdlib', function()
}
for _, t in ipairs(loops) do
- eq("Error executing lua: vim/shared.lua:0: Infinite loop detected", pcall_err(split, t[1], t[2]))
+ matches("Infinite loop detected", pcall_err(split, t[1], t[2]))
end
-- Validates args.
eq(true, pcall(split, 'string', 'string'))
- eq('Error executing lua: vim/shared.lua:0: s: expected string, got number',
+ matches('s: expected string, got number',
pcall_err(split, 1, 'string'))
- eq('Error executing lua: vim/shared.lua:0: sep: expected string, got number',
+ matches('sep: expected string, got number',
pcall_err(split, 'string', 1))
- eq('Error executing lua: vim/shared.lua:0: kwargs: expected table, got number',
+ matches('kwargs: expected table, got number',
pcall_err(split, 'string', 'string', 1))
end)
@@ -330,7 +330,7 @@ describe('lua stdlib', function()
end
-- Validates args.
- eq('Error executing lua: vim/shared.lua:0: s: expected string, got number',
+ matches('s: expected string, got number',
pcall_err(trim, 2))
end)
@@ -410,7 +410,7 @@ describe('lua stdlib', function()
return getmetatable(t2) == mt
]]))
- eq('Error executing lua: vim/shared.lua:0: Cannot deepcopy object of type thread',
+ matches('Cannot deepcopy object of type thread',
pcall_err(exec_lua, [[
local thread = coroutine.create(function () return 0 end)
local t = {thr = thread}
@@ -423,7 +423,7 @@ describe('lua stdlib', function()
eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
-- Validates args.
- eq('Error executing lua: vim/shared.lua:0: s: expected string, got number',
+ matches('s: expected string, got number',
pcall_err(exec_lua, [[return vim.pesc(2)]]))
end)
@@ -548,19 +548,19 @@ describe('lua stdlib', function()
return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1
]]))
- eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil',
+ matches('invalid "behavior": nil',
pcall_err(exec_lua, [[
return vim.tbl_extend()
]])
)
- eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ matches('wrong number of arguments %(given 1, expected at least 3%)',
pcall_err(exec_lua, [[
return vim.tbl_extend("keep")
]])
)
- eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ matches('wrong number of arguments %(given 2, expected at least 3%)',
pcall_err(exec_lua, [[
return vim.tbl_extend("keep", {})
]])
@@ -661,19 +661,19 @@ describe('lua stdlib', function()
return vim.tbl_deep_extend("force", a, b)
]]), {a = 123 })
- eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil',
+ matches('invalid "behavior": nil',
pcall_err(exec_lua, [[
return vim.tbl_deep_extend()
]])
)
- eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
+ matches('wrong number of arguments %(given 1, expected at least 3%)',
pcall_err(exec_lua, [[
return vim.tbl_deep_extend("keep")
]])
)
- eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
+ matches('wrong number of arguments %(given 2, expected at least 3%)',
pcall_err(exec_lua, [[
return vim.tbl_deep_extend("keep", {})
]])
@@ -706,7 +706,7 @@ describe('lua stdlib', function()
it('vim.list_extend', function()
eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]])
- eq('Error executing lua: vim/shared.lua:0: src: expected table, got nil',
+ matches('src: expected table, got nil',
pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]])
eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]])
@@ -730,7 +730,7 @@ describe('lua stdlib', function()
assert(vim.deep_equal(a, { A = 1; [1] = 'A'; }))
vim.tbl_add_reverse_lookup(a)
]]
- matches('^Error executing lua: vim/shared%.lua:0: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$',
+ matches('The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$',
pcall_err(exec_lua, code))
end)
@@ -771,7 +771,7 @@ describe('lua stdlib', function()
end)
it('vim.fn should error when calling API function', function()
- eq('Error executing lua: vim.lua:0: Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
+ matches('Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
pcall_err(exec_lua, "vim.fn.nvim_get_current_line()"))
end)
@@ -907,37 +907,37 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
- eq('Error executing lua: [string "<nvim>"]:0: opt[1]: expected table, got number',
+ matches('expected table, got number',
pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
- eq('Error executing lua: [string "<nvim>"]:0: invalid type name: x',
+ matches('invalid type name: x',
pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
- eq('Error executing lua: [string "<nvim>"]:0: invalid type name: 1',
+ matches('invalid type name: 1',
pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
- eq('Error executing lua: [string "<nvim>"]:0: invalid type name: nil',
+ matches('invalid type name: nil',
pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}"))
-- Validated parameters are required by default.
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil',
+ matches('arg1: expected string, got nil',
pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
-- Explicitly required.
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil',
+ matches('arg1: expected string, got nil',
pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected table, got number',
+ matches('arg1: expected table, got number',
pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg2: expected string, got number',
+ matches('arg2: expected string, got number',
pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil',
+ matches('arg2: expected string, got nil',
pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil',
+ matches('arg2: expected string, got nil',
pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected even number, got 3',
+ matches('arg1: expected even number, got 3',
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3',
+ matches('arg1: expected %?, got 3',
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
-- Pass an additional message back.
- eq('Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3. Info: TEST_MSG',
+ matches('arg1: expected %?, got 3. Info: TEST_MSG',
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1, 'TEST_MSG' end}}"))
end)
@@ -982,7 +982,7 @@ describe('lua stdlib', function()
]]
eq(NIL, funcs.luaeval "vim.g.to_delete")
- matches([[^Error executing lua: .*: attempt to index .* nil value]],
+ matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.g[0].testing'))
end)
@@ -1009,7 +1009,7 @@ describe('lua stdlib', function()
return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL}
]])
- matches([[^Error executing lua: .*: attempt to index .* nil value]],
+ matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.b[BUF][0].testing'))
eq({hello="world"}, funcs.luaeval "vim.b.to_delete")
@@ -1046,7 +1046,7 @@ describe('lua stdlib', function()
eq(NIL, funcs.luaeval "vim.w.nonexistant")
eq(NIL, funcs.luaeval "vim.w[WIN].nonexistant")
- matches([[^Error executing lua: .*: attempt to index .* nil value]],
+ matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.w[WIN][0].testing'))
eq({hello="world"}, funcs.luaeval "vim.w.to_delete")
@@ -1078,7 +1078,7 @@ describe('lua stdlib', function()
eq(123, funcs.luaeval "vim.t[0].other")
eq(NIL, funcs.luaeval "vim.t[0].nonexistant")
- matches([[^Error executing lua: .*: attempt to index .* nil value]],
+ matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.t[0][0].testing'))
eq({hello="world"}, funcs.luaeval "vim.t.to_delete")
@@ -1108,7 +1108,7 @@ describe('lua stdlib', function()
eq(funcs.luaeval "vim.api.nvim_get_vvar('progpath')", funcs.luaeval "vim.v.progpath")
eq(false, funcs.luaeval "vim.v['false']")
eq(NIL, funcs.luaeval "vim.v.null")
- matches([[^Error executing lua: .*: attempt to index .* nil value]],
+ matches([[attempt to index .* nil value]],
pcall_err(exec_lua, 'return vim.v[0].progpath'))
end)
@@ -1128,9 +1128,9 @@ describe('lua stdlib', function()
]]
eq('', funcs.luaeval "vim.bo.filetype")
eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
- matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$",
+ matches("Invalid option name: 'nosuchopt'$",
pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
- matches("^Error executing lua: .*: Expected lua string$",
+ matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
end)
@@ -1147,9 +1147,9 @@ describe('lua stdlib', function()
eq(0, funcs.luaeval "vim.wo.cole")
eq(0, funcs.luaeval "vim.wo[0].cole")
eq(0, funcs.luaeval "vim.wo[1001].cole")
- matches("^Error executing lua: .*: Invalid option name: 'notanopt'$",
+ matches("Invalid option name: 'notanopt'$",
pcall_err(exec_lua, 'return vim.wo.notanopt'))
- matches("^Error executing lua: .*: Expected lua string$",
+ matches("Expected lua string$",
pcall_err(exec_lua, 'return vim.wo[0][0].list'))
eq(2, funcs.luaeval "vim.wo[1000].cole")
exec_lua [[
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index b567b3e20c..37de5d0ce6 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -156,7 +156,7 @@ describe('health.vim', function()
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
========================================================================
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
- function health#check, line 24]])
+ function health#check, line 20]])
eq(expected, received)
end)
@@ -167,7 +167,7 @@ describe('health.vim', function()
broken: health#broken#check
========================================================================
- ERROR: Failed to run healthcheck for "broken" plugin. Exception:
- function health#check[24]..health#broken#check, line 1
+ function health#check[20]..health#broken#check, line 1
caused an error
]])
end)
@@ -186,7 +186,7 @@ describe('health.vim', function()
test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
========================================================================
- ERROR: Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
- function health#check, line 24]])
+ function health#check, line 20]])
eq(expected, received)
end)
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 5dd34e7665..4e3eddb960 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -164,6 +164,201 @@ describe('incremental synchronization', function()
}
test_edit({"a"}, {"rb"}, expected_text_changes, 'utf-16', '\n')
end)
+ it('deleting a line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 0
+ },
+ ['end'] = {
+ character = 0,
+ line = 1
+ }
+ },
+ rangeLength = 12,
+ text = ''
+ }
+ }
+ test_edit({"hello world"}, {"dd"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('deleting an empty line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 0,
+ line = 2
+ }
+ },
+ rangeLength = 1,
+ text = ''
+ }
+ }
+ test_edit({"hello world", ""}, {"jdd"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('adding a line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 0,
+ line = 1
+ }
+ },
+ rangeLength = 0,
+ text = 'hello world\n'
+ }
+ }
+ test_edit({"hello world"}, {"yyp"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('adding an empty line', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 0,
+ line = 1
+ }
+ },
+ rangeLength = 0,
+ text = '\n'
+ }
+ }
+ test_edit({"hello world"}, {"o"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ end)
+ describe('multi line edit', function()
+ it('deletion and insertion', function()
+ local expected_text_changes = {
+ -- delete "_fsda" from end of line 1
+ {
+ range = {
+ ['start'] = {
+ character = 4,
+ line = 1
+ },
+ ['end'] = {
+ character = 9,
+ line = 1
+ }
+ },
+ rangeLength = 5,
+ text = ''
+ },
+ -- delete "hello world\n" from line 2
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 2
+ },
+ ['end'] = {
+ character = 0,
+ line = 3
+ }
+ },
+ rangeLength = 12,
+ text = ''
+ },
+ -- delete "1234" from beginning of line 2
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 2
+ },
+ ['end'] = {
+ character = 4,
+ line = 2
+ }
+ },
+ rangeLength = 4,
+ text = ''
+ },
+ -- add " asdf" to end of line 1
+ {
+ range = {
+ ['start'] = {
+ character = 4,
+ line = 1
+ },
+ ['end'] = {
+ character = 4,
+ line = 1
+ }
+ },
+ rangeLength = 0,
+ text = ' asdf'
+ },
+ -- delete " asdf\n" from line 2
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 2
+ },
+ ['end'] = {
+ character = 0,
+ line = 3
+ }
+ },
+ rangeLength = 6,
+ text = ''
+ },
+ -- undo entire deletion
+ {
+ range = {
+ ['start'] = {
+ character = 4,
+ line = 1
+ },
+ ['end'] = {
+ character = 9,
+ line = 1
+ }
+ },
+ rangeLength = 5,
+ text = "_fdsa\nhello world\n1234 asdf"
+ },
+ -- redo entire deletion
+ {
+ range = {
+ ['start'] = {
+ character = 4,
+ line = 1
+ },
+ ['end'] = {
+ character = 9,
+ line = 3
+ }
+ },
+ rangeLength = 27,
+ text = ' asdf'
+ },
+ }
+ local original_lines = {
+ "\\begin{document}",
+ "test_fdsa",
+ "hello world",
+ "1234 asdf",
+ "\\end{document}"
+ }
+ test_edit(original_lines, {"jf_vejjbhhdu<C-R>"}, expected_text_changes, 'utf-16', '\n')
+ end)
end)
describe('multi-operation edits', function()
@@ -297,6 +492,80 @@ describe('incremental synchronization', function()
}
test_edit({"🔥"}, {"x"}, expected_text_changes, 'utf-16', '\n')
end)
+ it('replacing a multibyte character with matching prefix', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 1,
+ line = 1
+ }
+ },
+ rangeLength = 1,
+ text = '⟩'
+ }
+ }
+ -- ⟨ is e29fa8, ⟩ is e29fa9
+ local original_lines = {
+ "\\begin{document}",
+ "⟨",
+ "\\end{document}",
+ }
+ test_edit(original_lines, {"jr⟩"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('replacing a multibyte character with matching suffix', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 1,
+ line = 1
+ }
+ },
+ rangeLength = 1,
+ text = 'ḟ'
+ }
+ }
+ -- ฟ is e0b89f, ḟ is e1b89f
+ local original_lines = {
+ "\\begin{document}",
+ "ฟ",
+ "\\end{document}",
+ }
+ test_edit(original_lines, {"jrḟ"}, expected_text_changes, 'utf-16', '\n')
+ end)
+ it('inserting before a multibyte character', function()
+ local expected_text_changes = {
+ {
+ range = {
+ ['start'] = {
+ character = 0,
+ line = 1
+ },
+ ['end'] = {
+ character = 0,
+ line = 1
+ }
+ },
+ rangeLength = 0,
+ text = ' '
+ }
+ }
+ local original_lines = {
+ "\\begin{document}",
+ "→",
+ "\\end{document}",
+ }
+ test_edit(original_lines, {"ji "}, expected_text_changes, 'utf-16', '\n')
+ end)
it('deleting a multibyte character from a long line', function()
local expected_text_changes = {
{
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index b12d4227d5..1af31c38f8 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -301,6 +301,43 @@ describe('LSP', function()
}
end)
+ it('should detach buffer in response to nvim_buf_detach', function()
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ }
+ local client
+ test_rpc_server {
+ test_name = "basic_finish";
+ on_setup = function()
+ exec_lua [[
+ BUFFER = vim.api.nvim_create_buf(false, true)
+ ]]
+ eq(true, exec_lua("return lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)"))
+ eq(true, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)"))
+ exec_lua [[
+ vim.api.nvim_command(BUFFER.."bwipeout")
+ ]]
+ end;
+ on_init = function(_client)
+ client = _client
+ client.notify('finish')
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
+ exec_lua("return lsp.buf_detach_client(BUFFER, TEST_RPC_CLIENT_ID)")
+ eq(false, exec_lua("return lsp.buf_is_attached(BUFFER, TEST_RPC_CLIENT_ID)"))
+ client.stop()
+ end
+ end;
+ }
+ end)
+
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
{NIL, {}, {method="shutdown", client_id=1}};
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 7d37dcccc8..7223f5ba61 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local command = helpers.command
-local exc_exec = helpers.exc_exec
+local pcall_err = helpers.pcall_err
local feed = helpers.feed
local sleep = helpers.sleep
local poke_eventloop = helpers.poke_eventloop
@@ -13,24 +13,22 @@ describe('associated channel is closed and later freed for terminal', function()
it('opened by nvim_open_term() and deleted by :bdelete!', function()
command([[let id = nvim_open_term(0, {})]])
-- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", exc_exec([[bdelete! | call chansend(id, 'test')]]))
- -- process free_channel_event
- poke_eventloop()
- -- channel has been freed
- eq("Vim(call):E900: Invalid channel id", exc_exec([[call chansend(id, 'test')]]))
+ eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete! | call chansend(id, 'test')]]))
+ -- channel has been freed after one main loop iteration
+ eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
end)
it('opened by termopen(), exited, and deleted by pressing a key', function()
command([[let id = termopen('echo')]])
sleep(500)
-- process has exited
- eq("Vim(call):Can't send data to closed stream", exc_exec([[call chansend(id, 'test')]]))
+ eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
-- delete terminal
feed('i<CR>')
- -- process term_delayed_free and free_channel_event
+ -- need to first process input
poke_eventloop()
- -- channel has been freed
- eq("Vim(call):E900: Invalid channel id", exc_exec([[call chansend(id, 'test')]]))
+ -- channel has been freed after another main loop iteration
+ eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
end)
-- This indirectly covers #16264
@@ -38,12 +36,10 @@ describe('associated channel is closed and later freed for terminal', function()
command([[let id = termopen('echo')]])
sleep(500)
-- process has exited
- eq("Vim(call):Can't send data to closed stream", exc_exec([[call chansend(id, 'test')]]))
+ eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[call chansend(id, 'test')]]))
-- channel hasn't been freed yet
- eq("Vim(call):Can't send data to closed stream", exc_exec([[bdelete | call chansend(id, 'test')]]))
- -- process term_delayed_free and free_channel_event
- poke_eventloop()
- -- channel has been freed
- eq("Vim(call):E900: Invalid channel id", exc_exec([[call chansend(id, 'test')]]))
+ eq("Vim(call):Can't send data to closed stream", pcall_err(command, [[bdelete | call chansend(id, 'test')]]))
+ -- channel has been freed after one main loop iteration
+ eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
end)
end)
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index b932c58430..11bdc73a47 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -12,6 +12,8 @@ local curbufmeths = helpers.curbufmeths
local nvim = helpers.nvim
local feed_data = thelpers.feed_data
local pcall_err = helpers.pcall_err
+local exec_lua = helpers.exec_lua
+local assert_alive = helpers.assert_alive
describe(':terminal scrollback', function()
local screen
@@ -527,3 +529,71 @@ describe("'scrollback' option", function()
end)
end)
+
+describe("pending scrollback line handling", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(30, 7)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {foreground = Screen.colors.Brown},
+ [2] = {reverse = true},
+ [3] = {bold = true},
+ }
+ end)
+
+ it("does not crash after setting 'number' #14891", function()
+ exec_lua [[
+ local a = vim.api
+ local buf = a.nvim_create_buf(true, true)
+ local chan = a.nvim_open_term(buf, {})
+ a.nvim_win_set_option(0, "number", true)
+ a.nvim_chan_send(chan, ("a\n"):rep(11) .. "a")
+ a.nvim_win_set_buf(0, buf)
+ ]]
+ screen:expect [[
+ {1: 1 }^a |
+ {1: 2 } a |
+ {1: 3 } a |
+ {1: 4 } a |
+ {1: 5 } a |
+ {1: 6 } a |
+ |
+ ]]
+ feed('G')
+ screen:expect [[
+ {1: 7 } a |
+ {1: 8 } a |
+ {1: 9 } a |
+ {1: 10 } a |
+ {1: 11 } a |
+ {1: 12 } ^a |
+ |
+ ]]
+ assert_alive()
+ end)
+
+ it("does not crash after nvim_buf_call #14891", function()
+ exec_lua [[
+ local a = vim.api
+ local bufnr = a.nvim_create_buf(false, true)
+ a.nvim_buf_call(bufnr, function()
+ vim.fn.termopen({"echo", ("hi\n"):rep(11)})
+ end)
+ a.nvim_win_set_buf(0, bufnr)
+ vim.cmd("startinsert")
+ ]]
+ screen:expect [[
+ hi |
+ hi |
+ hi |
+ |
+ |
+ [Process exited 0]{2: } |
+ {3:-- TERMINAL --} |
+ ]]
+ assert_alive()
+ end)
+end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 6b9586b4de..bf57b135cb 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -20,6 +20,7 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
+local exec_lua = helpers.exec_lua
if helpers.pending_win32(pending) then return end
@@ -580,21 +581,34 @@ describe('TUI', function()
end)
it("paste: 'nomodifiable' buffer", function()
+ local has_luajit = exec_lua('return jit ~= nil')
child_session:request('nvim_command', 'set nomodifiable')
child_session:request('nvim_exec_lua', [[
-- Stack traces for this test are non-deterministic, so disable them
_G.debug.traceback = function(msg) return msg end
]], {})
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
- screen:expect{grid=[[
- |
- {4:~ }|
- {5: }|
- {8:paste: Error executing lua: vim.lua:243: Vim:E21: }|
- {8:Cannot make changes, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
- {3:-- TERMINAL --} |
- ]]}
+ if has_luajit then
+ screen:expect{grid=[[
+ |
+ {4:~ }|
+ {5: }|
+ {8:paste: Error executing lua: vim.lua:0: Vim:E21: Ca}|
+ {8:nnot make changes, 'modifiable' is off} |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
+ else
+ screen:expect{grid=[[
+ |
+ {4:~ }|
+ {5: }|
+ {8:paste: Error executing lua: Vim:E21: Cannot make c}|
+ {8:hanges, 'modifiable' is off} |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
+ end
feed_data('\n') -- <Enter>
child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
@@ -677,8 +691,8 @@ describe('TUI', function()
item 2997 |
item 2998 |
item 2999 |
- item 3000 en{1:d} |
- {5:[No Name] [+] 3000,13 Bot}|
+ item 3000 en{1:d}d |
+ {5:[No Name] [+] 5999,13 Bot}|
|
{3:-- TERMINAL --} |
]])
@@ -765,6 +779,44 @@ describe('TUI', function()
]])
end)
+ it('paste: streamed paste with isolated "stop paste" code', function()
+ child_session:request('nvim_exec_lua', [[
+ _G.paste_phases = {}
+ vim.paste = (function(overridden)
+ return function(lines, phase)
+ table.insert(_G.paste_phases, phase)
+ overridden(lines, phase)
+ end
+ end)(vim.paste)
+ ]], {})
+ feed_data('i')
+ feed_data('\027[200~pasted') -- phase 1
+ screen:expect([[
+ pasted{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ feed_data(' from terminal') -- phase 2
+ screen:expect([[
+ pasted from terminal{1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ -- Send isolated "stop paste" sequence.
+ feed_data('\027[201~') -- phase 3
+ screen:expect_unchanged()
+ local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {})
+ eq({1, 2, 3}, rv)
+ end)
+
it('allows termguicolors to be set at runtime', function()
screen:set_option('rgb', true)
screen:set_default_attr_ids({
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index aeba049557..4fc5c389e5 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2213,4 +2213,134 @@ describe('builtin popupmenu', function()
feed('<c-y>')
assert_alive()
end)
+
+ it('truncates double-width character correctly when there is no scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=menuone,noselect')
+ feed('i' .. string.rep(' ', 13))
+ funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
+ screen:expect([[
+ ^ |
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+
+ it('truncates double-width character correctly when there is scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=noselect')
+ command('set pumheight=4')
+ feed('i' .. string.rep(' ', 12))
+ local items = {}
+ for _ = 1, 8 do
+ table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+ end
+ funcs.complete(13, items)
+ screen:expect([[
+ ^ |
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {1:~ }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+end)
+
+describe('builtin popupmenu with ui/ext_multigrid', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(32, 20)
+ screen:attach({ext_multigrid=true})
+ screen:set_default_attr_ids({
+ -- popup selected item / scrollbar track
+ ['s'] = {background = Screen.colors.WebGray},
+ -- popup non-selected item
+ ['n'] = {background = Screen.colors.LightMagenta},
+ -- popup scrollbar knob
+ ['c'] = {background = Screen.colors.Grey0},
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true},
+ [3] = {reverse = true},
+ [4] = {bold = true, reverse = true},
+ [5] = {bold = true, foreground = Screen.colors.SeaGreen},
+ [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ })
+ end)
+
+ it('truncates double-width character correctly when there is no scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=menuone,noselect')
+ feed('i' .. string.rep(' ', 13))
+ funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ {2:-- INSERT --} |
+ ## grid 4
+ {n: 哦哦哦哦哦哦哦哦哦>}|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}})
+ end)
+
+ it('truncates double-width character correctly when there is scrollbar', function()
+ screen:try_resize(32,8)
+ command('set completeopt+=noselect')
+ command('set pumheight=4')
+ feed('i' .. string.rep(' ', 12))
+ local items = {}
+ for _ = 1, 8 do
+ table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+ end
+ funcs.complete(13, items)
+ screen:expect({grid=[[
+ ## grid 1
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [2:--------------------------------]|
+ [3:--------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ {2:-- INSERT --} |
+ ## grid 4
+ {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+ ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
+ end)
end)
diff --git a/test/functional/vimscript/screenpos_spec.lua b/test/functional/vimscript/screenpos_spec.lua
new file mode 100644
index 0000000000..75e5c02298
--- /dev/null
+++ b/test/functional/vimscript/screenpos_spec.lua
@@ -0,0 +1,51 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear, eq, meths = helpers.clear, helpers.eq, helpers.meths
+local command, funcs = helpers.command, helpers.funcs
+
+before_each(clear)
+
+describe('screenpos() function', function()
+ it('works in floating window with border', function()
+ local bufnr = meths.create_buf(false, true)
+ local opts = {
+ relative='editor',
+ height=8,
+ width=12,
+ row=6,
+ col=8,
+ anchor='NW',
+ style='minimal',
+ border='none',
+ focusable=1
+ }
+ local float = meths.open_win(bufnr, false, opts)
+ command('redraw')
+ local pos = funcs.screenpos(bufnr, 1, 1)
+ eq(7, pos.row)
+ eq(9, pos.col)
+
+ -- only left border
+ opts.border = {'', '', '', '', '', '', '', '|'}
+ meths.win_set_config(float, opts)
+ command('redraw')
+ pos = funcs.screenpos(bufnr, 1, 1)
+ eq(7, pos.row)
+ eq(10, pos.col)
+
+ -- only top border
+ opts.border = {'', '_', '', '', '', '', '', ''}
+ meths.win_set_config(float, opts)
+ command('redraw')
+ pos = funcs.screenpos(bufnr, 1, 1)
+ eq(8, pos.row)
+ eq(9, pos.col)
+
+ -- both left and top border
+ opts.border = 'single'
+ meths.win_set_config(float, opts)
+ command('redraw')
+ pos = funcs.screenpos(bufnr, 1, 1)
+ eq(8, pos.row)
+ eq(10, pos.col)
+ end)
+end)
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index 52839d8efa..b0b91df791 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -151,8 +151,8 @@ set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0
set(MSGPACK_SHA256 bfbb71b7c02f806393bc3cbc491b40523b89e64f83860c58e3e54af47de176e4)
# https://github.com/LuaJIT/LuaJIT/tree/v2.1
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/b4b2dce9fc3ffaaaede39b36d06415311e2aa516.tar.gz)
-set(LUAJIT_SHA256 6c9e46877db2df16ca0fa76db4043ed30a1ae60c89d9ba2c3e4d35eb2360cd4d)
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/1d20f33d2905db55fb7191076bbac10f570f9175.tar.gz)
+set(LUAJIT_SHA256 4b6e2fc726ed8bf51fe461d90db9fffbc5c894bbdc862a67d17a70190f1fb07f)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)
@@ -203,8 +203,8 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891
set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz)
set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2)
-set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.1.tar.gz)
-set(TREESITTER_SHA256 12a3f7206af3028dbe8a0de50d8ebd6d7010bf762db918acae76fc7585f1258d)
+set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/25f64e1eb66bb1ab3eccd4f0b7da543005f3ba79.tar.gz)
+set(TREESITTER_SHA256 4f43bad474df494d00a779157f1c437638987d0e7896f9c73492cfeef35366b5)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)
diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake
index c4e5112dce..e02d7fe609 100644
--- a/third-party/cmake/BuildLuajit.cmake
+++ b/third-party/cmake/BuildLuajit.cmake
@@ -124,7 +124,9 @@ elseif(MINGW)
COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/libluajit.a ${DEPS_INSTALL_DIR}/lib
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include/luajit-2.1
COMMAND ${CMAKE_COMMAND} -DFROM_GLOB=${DEPS_BUILD_DIR}/src/luajit/src/*.h -DTO=${DEPS_INSTALL_DIR}/include/luajit-2.1 -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyFilesGlob.cmake
- )
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin/lua/jit
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/luajit/src/jit ${DEPS_INSTALL_DIR}/bin/lua/jit
+ )
elseif(MSVC)
BuildLuaJit(
@@ -138,8 +140,10 @@ elseif(MSVC)
# Luv searches for luajit.lib
COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/lua51.lib ${DEPS_INSTALL_DIR}/lib/luajit.lib
COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include/luajit-2.1
- COMMAND ${CMAKE_COMMAND} -DFROM_GLOB=${DEPS_BUILD_DIR}/src/luajit/src/*.h -DTO=${DEPS_INSTALL_DIR}/include/luajit-2.1 -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyFilesGlob.cmake)
-
+ COMMAND ${CMAKE_COMMAND} -DFROM_GLOB=${DEPS_BUILD_DIR}/src/luajit/src/*.h -DTO=${DEPS_INSTALL_DIR}/include/luajit-2.1 -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CopyFilesGlob.cmake
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin/lua/jit
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/luajit/src/jit ${DEPS_INSTALL_DIR}/bin/lua/jit
+ )
else()
message(FATAL_ERROR "Trying to build luajit in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()