diff options
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", §) 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(®match, 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() |