diff --git a/README_vim.md b/README_vim.md index 5c8403c3f9..4c00c6b22a 100644 --- a/README_vim.md +++ b/README_vim.md @@ -1,6 +1,6 @@ [![Vim Logo](https://github.com/vim/vim/raw/master/runtime/vimlogo.gif)](https://www.vim.org) -[![Github Build status](https://github.com/vim/vim/workflows/GitHub%20CI/badge.svg)](https://github.com/vim/vim/actions?query=workflow%3A%22GitHub+CI%22) [![Travis Build Status](https://travis-ci.com/vim/vim.svg?branch=master)](https://travis-ci.com/github/vim/vim) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/o2qht2kjm02sgghk?svg=true)](https://ci.appveyor.com/project/chrisbra/vim) [![Cirrus Build Status](https://api.cirrus-ci.com/github/vim/vim.svg)](https://cirrus-ci.com/github/vim/vim) [![Coverage Status](https://codecov.io/gh/vim/vim/coverage.svg?branch=master)](https://codecov.io/gh/vim/vim?branch=master) [![Coverity Scan](https://scan.coverity.com/projects/241/badge.svg)](https://scan.coverity.com/projects/vim) [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/vim/vim.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/vim/vim/context:cpp) [![Debian CI](https://badges.debian.net/badges/debian/testing/vim/version.svg)](https://buildd.debian.org/vim) [![Packages](https://repology.org/badge/tiny-repos/vim.svg)](https://repology.org/metapackage/vim) [![Fossies codespell report](https://fossies.org/linux/test/vim-master.tar.gz/codespell.svg)](https://fossies.org/linux/test/vim-master.tar.gz/codespell.html) +[![Github Build status](https://github.com/vim/vim/workflows/GitHub%20CI/badge.svg)](https://github.com/vim/vim/actions?query=workflow%3A%22GitHub+CI%22) [![Travis Build Status](https://travis-ci.com/vim/vim.svg?branch=master)](https://travis-ci.com/github/vim/vim) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/o2qht2kjm02sgghk?svg=true)](https://ci.appveyor.com/project/chrisbra/vim) [![Cirrus Build Status](https://api.cirrus-ci.com/github/vim/vim.svg)](https://cirrus-ci.com/github/vim/vim) [![Coverage Status](https://codecov.io/gh/vim/vim/coverage.svg?branch=master)](https://codecov.io/gh/vim/vim?branch=master) [![Coverity Scan](https://scan.coverity.com/projects/241/badge.svg)](https://scan.coverity.com/projects/vim) [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/vim/vim.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/vim/vim/context:cpp) [![Debian CI](https://badges.debian.net/badges/debian/testing/vim/version.svg)](https://buildd.debian.org/vim) [![Packages](https://repology.org/badge/tiny-repos/vim.svg)](https://repology.org/metapackage/vim) [![Fossies codespell report](https://fossies.org/linux/test/vim-master.tar.gz/codespell.svg)](https://fossies.org/linux/test/vim-master.tar.gz/codespell.html) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev/bounties/disclose/?utm_campaign=vim%2Fvim&utm_medium=social&utm_source=github&target=https%3A%2F%2Fgithub.com%2Fvim%2Fvim) For translations of this README see the end. diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim index 74df871544..a3db4ae87a 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 -" Last Change: 2020 Aug 17 +" Last Change: 2021 Nov 27 " These functions are moved here from runtime/filetype.vim to make startup " faster. diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt index 39cb43c004..6124a89458 100644 --- a/runtime/doc/channel.txt +++ b/runtime/doc/channel.txt @@ -1,4 +1,4 @@ -*channel.txt* For Vim version 8.2. Last change: 2020 Oct 17 +*channel.txt* For Vim version 8.2. Last change: 2021 Nov 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -101,7 +101,7 @@ Instead of giving a callback with every send call, it can also be specified when opening the channel: > call ch_close(channel) let channel = ch_open('localhost:8765', {'callback': "MyHandler"}) - call ch_sendexpr(channel, 'hello!') + call ch_sendexpr(channel, 'hello channel!') When trying out channels it's useful to see what is going on. You can tell Vim to write lines in log file: > @@ -132,8 +132,9 @@ When using an IPv6 address, enclose it within square brackets. E.g., "raw" - Use raw messages *channel-callback* *E921* "callback" A function that is called when a message is received that is - not handled otherwise. It gets two arguments: the channel - and the received message. Example: > + not handled otherwise (e.g. a JSON message with ID zero). It + gets two arguments: the channel and the received message. + Example: > func Handle(channel, msg) echo 'Received: ' . a:msg endfunc diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index eca741f753..1dc3ebe5d4 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -1,4 +1,4 @@ -*cmdline.txt* For Vim version 8.2. Last change: 2021 Nov 22 +*cmdline.txt* For Vim version 8.2. Last change: 2021 Dec 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -919,9 +919,11 @@ Note: these are typed literally, they are not special keys! *:* ** When executing autocommands, is replaced with the match for which this autocommand was executed. *E497* - It differs from only when the file name isn't used - to match with (for FileType, Syntax and SpellFileMissing + It differs from when the file name isn't used to + match with (for FileType, Syntax and SpellFileMissing events). + When the match is with a file name, it is expanded to the + full path. *:* ** When executing a ":source" command, is replaced with the file name of the sourced file. *E498* diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 8cb2e118ad..d832e9b113 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -539,14 +539,6 @@ Options: For further discussion of fortran_have_tabs and the method used for the detection of source format see |ft-fortran-syntax|. -GPROF *ft-gprof-plugin* - -The gprof filetype plugin defines a mapping to jump from a function -entry in the gprof flat profile or from a function entry in the call graph -to the details of that function in the call graph. - -The mapping can be disabled with: > - let g:no_gprof_maps = 1 GIT COMMIT *ft-gitcommit-plugin* diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt index b50bd65c5e..6e243fda94 100644 --- a/runtime/doc/motion.txt +++ b/runtime/doc/motion.txt @@ -1,4 +1,4 @@ -*motion.txt* For Vim version 8.2. Last change: 2021 Jun 13 +*motion.txt* For Vim version 8.2. Last change: 2021 Dec 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -386,6 +386,8 @@ w [count] words forward. |exclusive| motion. or ** *W* W [count] WORDS forward. |exclusive| motion. + If does not work, check out + |arrow_modifiers|. *e* e Forward to the end of word [count] |inclusive|. @@ -400,6 +402,8 @@ b [count] words backward. |exclusive| motion. or ** *B* B [count] WORDS backward. |exclusive| motion. + If does not work, check out + |arrow_modifiers|. *ge* ge Backward to the end of word [count] |inclusive|. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index c6e5a8357c..f115542aa1 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2021 Nov 24 +*options.txt* For Vim version 8.2. Last change: 2021 Dec 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -35,6 +35,8 @@ achieve special effects. These options come in three forms: internally and can't be changed. Changing the terminal codes in the GUI is not useful either... +:se[t]! termcap Idem, but don't use multiple columns. + *E518* *E519* :se[t] {option}? Show value of {option}. @@ -373,8 +375,9 @@ Note: In the future more global options can be made global-local. Using *option-value-function* Some options ('completefunc', 'imactivatefunc', 'imstatusfunc', 'omnifunc', -'operatorfunc', 'quickfixtextfunc' and 'tagfunc') are set to a function name -or a function reference or a lambda function. Examples: +'operatorfunc', 'quickfixtextfunc', 'tagfunc' and 'thesaurusfunc') are set to +a function name or a function reference or a lambda function. When using a +lambda it will be converted to the name, e.g. "123". Examples: > set opfunc=MyOpFunc set opfunc=function('MyOpFunc') @@ -384,10 +387,10 @@ or a function reference or a lambda function. Examples: let Fn = function('MyTagFunc') let &tagfunc = string(Fn) " set using a lambda expression - let &tagfunc = "{t -> MyTagFunc(t)}" + let &tagfunc = {t -> MyTagFunc(t)} " set using a variable with lambda expression let L = {a, b, c -> MyTagFunc(a, b , c)} - let &tagfunc = string(L) + let &tagfunc = L < Setting the filetype @@ -866,9 +869,12 @@ A jump table for the options with a short description can be found at |Q_op|. 'autowrite' 'aw' boolean (default off) global Write the contents of the file, if it has been modified, on each - :next, :rewind, :last, :first, :previous, :stop, :suspend, :tag, :!, - :make, CTRL-] and CTRL-^ command; and when a :buffer, CTRL-O, CTRL-I, - '{A-Z0-9}, or `{A-Z0-9} command takes one to another file. + `:next`, `:rewind`, `:last`, `:first`, `:previous`, `:stop`, + `:suspend`, `:tag, `:!`, ``:make`, CTRL-] and CTRL-^ command; and when + a :buffer, CTRL-O, CTRL-I, '{A-Z0-9}, or `{A-Z0-9} command takes one + to another file. + A buffer is not written if it becomes hidden, e.g. when 'bufhidden' is + set to "hide" and `:next` is used Note that for some commands the 'autowrite' option is not used, see 'autowriteall' for that. Some buffers will not be written, specifically when 'buftype' is @@ -1954,7 +1960,9 @@ A jump table for the options with a short description can be found at |Q_op|. This option specifies a function to be used for Insert mode completion with CTRL-X CTRL-U. |i_CTRL-X_CTRL-U| See |complete-functions| for an explanation of how the function is - invoked and what it should return. + invoked and what it should return. The value can be the name of a + function, a |lambda| or a |Funcref|. See |option-value-function| for + more information. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. @@ -4335,7 +4343,9 @@ A jump table for the options with a short description can be found at |Q_op|. 'imactivatefunc' 'imaf' string (default "") global This option specifies a function that will be called to - activate or deactivate the Input Method. + activate or deactivate the Input Method. The value can be the name of + a function, a |lambda| or a |Funcref|. See |option-value-function| for + more information. It is not used in the MS-Windows GUI version. The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. @@ -4445,6 +4455,8 @@ A jump table for the options with a short description can be found at |Q_op|. global This option specifies a function that is called to obtain the status of Input Method. It must return a positive number when IME is active. + The value can be the name of a function, a |lambda| or a |Funcref|. + See |option-value-function| for more information. It is not used in the MS-Windows GUI version. Example: > @@ -5748,7 +5760,9 @@ A jump table for the options with a short description can be found at |Q_op|. This option specifies a function to be used for Insert mode omni completion with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| See |complete-functions| for an explanation of how the function is - invoked and what it should return. + invoked and what it should return. The value can be the name of a + function, a |lambda| or a |Funcref|. See |option-value-function| for + more information. This option is usually set by a filetype plugin: |:filetype-plugin-on| This option cannot be set from a |modeline| or in the |sandbox|, for @@ -8208,6 +8222,8 @@ A jump table for the options with a short description can be found at |Q_op|. feature} This option specifies a function to be used for thesaurus completion with CTRL-X CTRL-T. |i_CTRL-X_CTRL-T| See |compl-thesaurusfunc|. + The value can be the name of a function, a |lambda| or a |Funcref|. + See |option-value-function| for more information. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 904abe73b1..b4d770245f 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2021 Aug 15 +*popup.txt* For Vim version 8.2. Last change: 2021 Nov 29 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 9ebefa956d..47ead217f9 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1,4 +1,4 @@ -*quickfix.txt* For Vim version 8.2. Last change: 2021 May 22 +*quickfix.txt* For Vim version 8.2. Last change: 2021 Dec 03 VIM REFERENCE MANUAL by Bram Moolenaar @@ -856,9 +856,9 @@ lists. They set one of the existing error lists as the current one. *:chistory* *:chi* :[count]chi[story] Show the list of error lists. The current list is marked with ">". The output looks like: - error list 1 of 3; 43 errors ~ - > error list 2 of 3; 0 errors ~ - error list 3 of 3; 15 errors ~ + error list 1 of 3; 43 errors :make ~ + > error list 2 of 3; 0 errors :helpgrep tag ~ + error list 3 of 3; 15 errors :grep ex_help *.c ~ When [count] is given, then the count'th quickfix list is made the current list. Example: > diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt index 489f3d8b52..7976cecca8 100644 --- a/runtime/doc/sign.txt +++ b/runtime/doc/sign.txt @@ -1,4 +1,4 @@ -*sign.txt* For Vim version 8.2. Last change: 2021 Mar 07 +*sign.txt* For Vim version 8.2. Last change: 2021 Dec 05 VIM REFERENCE MANUAL by Gordon Prieur @@ -441,14 +441,16 @@ sign_getdefined([{name}]) *sign_getdefined()* following entries: icon full path to the bitmap file of the sign linehl highlight group used for the whole line the - sign is placed in. + sign is placed in; not present if not set name name of the sign text text that is displayed when there is no icon or the GUI is not being used. - texthl highlight group used for the text item + texthl highlight group used for the text item; not + present if not set culhl highlight group used for the text item when the cursor is on the same line as the sign and - 'cursorline' is enabled. + 'cursorline' is enabled; not present if not + set Returns an empty List if there are no signs and when {name} is not found. diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 329bf93e5c..a30c16b3ce 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -3196,6 +3196,14 @@ buffer by buffer basis. For more detailed instructions see |ft_sql.txt|. +SQUIRREL *squirrel.vim* *ft-squirrel-syntax* + +Squirrel is a high level imperative, object-oriented programming language, +designed to be a light-weight scripting language that fits in the size, memory +bandwidth, and real-time requirements of applications like video games. Files +with the following extensions are recognized as squirrel files: .nut. + + TCSH *tcsh.vim* *ft-tcsh-syntax* This covers the shell named "tcsh". It is a superset of csh. See |csh.vim| diff --git a/runtime/doc/tags b/runtime/doc/tags index 858e354599..8883e114ae 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -4005,7 +4005,6 @@ E107 eval.txt /*E107* E108 eval.txt /*E108* E109 eval.txt /*E109* E1091 vim9.txt /*E1091* -E1092 vim9.txt /*E1092* E1094 vim9.txt /*E1094* E11 cmdline.txt /*E11* E110 eval.txt /*E110* @@ -5548,6 +5547,7 @@ arglistid() eval.txt /*arglistid()* argument-list editing.txt /*argument-list* argv() eval.txt /*argv()* argv-variable eval.txt /*argv-variable* +arrow_modifiers term.txt /*arrow_modifiers* as motion.txt /*as* asin() eval.txt /*asin()* asm.vim syntax.txt /*asm.vim* @@ -6651,6 +6651,7 @@ format-bullet-list tips.txt /*format-bullet-list* format-comments change.txt /*format-comments* format-formatexpr change.txt /*format-formatexpr* formatting change.txt /*formatting* +forth.vim syntax.txt /*forth.vim* fortran.vim syntax.txt /*fortran.vim* friendship intro.txt /*friendship* frombook usr_01.txt /*frombook* @@ -6704,6 +6705,7 @@ ft-erlang-syntax syntax.txt /*ft-erlang-syntax* ft-euphoria-syntax syntax.txt /*ft-euphoria-syntax* ft-flexwiki-syntax syntax.txt /*ft-flexwiki-syntax* ft-form-syntax syntax.txt /*ft-form-syntax* +ft-forth-syntax syntax.txt /*ft-forth-syntax* ft-fortran-indent indent.txt /*ft-fortran-indent* ft-fortran-plugin filetype.txt /*ft-fortran-plugin* ft-fortran-syntax syntax.txt /*ft-fortran-syntax* @@ -6795,6 +6797,7 @@ ft-sql-omni insert.txt /*ft-sql-omni* ft-sql-syntax syntax.txt /*ft-sql-syntax* ft-sqlanywhere-syntax syntax.txt /*ft-sqlanywhere-syntax* ft-sqlinformix-syntax syntax.txt /*ft-sqlinformix-syntax* +ft-squirrel-syntax syntax.txt /*ft-squirrel-syntax* ft-syntax-omni insert.txt /*ft-syntax-omni* ft-tcsh-syntax syntax.txt /*ft-tcsh-syntax* ft-termcap-syntax syntax.txt /*ft-termcap-syntax* @@ -9389,6 +9392,7 @@ sqlj ft_sql.txt /*sqlj* sqlserver ft_sql.txt /*sqlserver* sqlsettype ft_sql.txt /*sqlsettype* sqrt() eval.txt /*sqrt()* +squirrel.vim syntax.txt /*squirrel.vim* srand() eval.txt /*srand()* sscanf eval.txt /*sscanf* standard-plugin usr_05.txt /*standard-plugin* diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index d6f31d379c..3333a3ab6f 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -1,4 +1,4 @@ -*term.txt* For Vim version 8.2. Last change: 2021 Aug 29 +*term.txt* For Vim version 8.2. Last change: 2021 Dec 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -151,7 +151,7 @@ terminal that tmux is running in): > let &t_fe = "\[?1004h" let &t_fd = "\[?1004l" - " Enable modified arrow keys, see :help xterm-modifier-keys + " Enable modified arrow keys, see :help arrow_modifiers execute "silent! set =\[@;*A" execute "silent! set =\[@;*B" execute "silent! set =\[@;*C" @@ -252,7 +252,19 @@ another code. That is to avoid that the codes obtained from xterm directly Another special value is a termcap entry ending in "@;*X". This is for cursor keys, which either use "CSI X" or "CSI 1 ; modifier X". Thus the "@" stands for either "1" if a modifier follows, or nothing. - *xterm-scroll-region* + *arrow_modifiers* +Several terminal emulators (alacritty, gnome, konsole, etc.) send special +codes for keys with modifiers, but these do not have an entry in the +termcap/terminfo database. You can make them work by adding a few lines in +your vimrc. For example, to make the Control modifier work with arrow keys +for the gnome terminal: > + if &term =~ 'gnome' + execute "set =\[@;*A" + execute "set =\[@;*B" + execute "set =\[@;*C" + execute "set =\[@;*D" + endif +< *xterm-scroll-region* The default termcap entry for xterm on Sun and other platforms does not contain the entry for scroll regions. Add ":cs=\E[%i%d;%dr:" to the xterm entry in /etc/termcap and everything should work. diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 4793abd832..1772aa1e92 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2021 Nov 26 +*todo.txt* For Vim version 8.2. Last change: 2021 Dec 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,13 +38,7 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- -refactor ex_let_one() to subfunctions. - Vim9 - Make everything work: -- "filter #pat# ls" should work, #pat# is not a comment - vim9script - edit foobar - filter #foobar# ls - Check TODO items in vim9compile.c and vim9execute.c - use CheckLegacyAndVim9Success(lines) in many more places - For builtin functions using tv_get_string*() use check_for_string() to be @@ -263,6 +257,10 @@ test_arglist func Test_all_not_allowed_from_cmdwin() hangs on MS-Windows. Mapping with partial match not executed properly in GTK. (Ingo Karkat, #7082) +Information for a specific terminal (e.g. gnome, tmux, konsole, alacritty) is +spread out. Make a section with copy/paste examples of script and pointers to +more information. + Problem that a previous silent ":throw" causes a following try/catch not to work. (ZyX, 2013 Sep 28) With examples: (Malcolm Rowe, 2015 Dec 24) Also see #8487 for an example. @@ -1470,10 +1468,6 @@ When the CursorMovedI event triggers, and CTRL-X was typed, a script cannot restore the mode properly. (Andrew Stewart, 2016 Apr 20) Do not trigger the event? -Patch to fix display of listchars on the cursorline. (Nayuri Aohime, 2013) -Update suggested by Yasuhiro Matsumoto, 2014 Nov 25: -https://gist.github.com/presuku/d3d6b230b9b6dcfc0477 - Patch to make the behavior of "w" more straightforward, but not Vi compatible. With a 'cpo' flag. (Christian Brabandt, 2016 Feb 8) diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 361cd7fbe6..dbb79a43ec 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -1,4 +1,4 @@ -*various.txt* For Vim version 8.2. Last change: 2021 Sep 06 +*various.txt* For Vim version 8.2. Last change: 2021 Nov 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -369,7 +369,7 @@ N *+digraphs* |digraphs| *E196* *+dnd* Support for DnD into the "~ register |quote_~|. B *+emacs_tags* |emacs-tags| files N *+eval* expression evaluation |eval.txt| -N *+ex_extra* always on now, used to be for Vim's extra Ex commands +T *+ex_extra* always on now, used to be for Vim's extra Ex commands N *+extra_search* |'hlsearch'| and |'incsearch'| options. - *+farsi* Removed: |farsi| language N *+file_in_path* |gf|, |CTRL-W_f| and || @@ -424,7 +424,7 @@ N *+multi_lang* non-English language support |multi-lang| m *+mzscheme* Mzscheme interface |mzscheme| m *+mzscheme/dyn* Mzscheme interface |mzscheme-dynamic| |/dyn| m *+netbeans_intg* |netbeans| - *+num64* 64-bit Number support |Number| +T *+num64* 64-bit Number support |Number| Always enabled since 8.2.0271, use v:numbersize to check the actual size of a Number. m *+odbeditor* MacVim only: ODB Editor Protocol support |odbeditor| @@ -473,16 +473,16 @@ N *+textobjects* |text-objects| selection N *+textprop* |text-properties| *+tgetent* non-Unix only: able to use external termcap N *+timers* the |timer_start()| function -N *+title* Setting the window 'title' and 'icon'; Always enabled +T *+title* Setting the window 'title' and 'icon'; Always enabled N *+toolbar* |gui-toolbar| m *+transparency* MacVim only: window background transparency T *+user_commands* User-defined commands. |user-commands| Always enabled since 8.1.1210. B *+vartabs* Variable-width tabstops. |'vartabstop'| N *+viminfo* |'viminfo'| - *+vertsplit* Vertically split windows |:vsplit|; Always enabled +T *+vertsplit* Vertically split windows |:vsplit|; Always enabled since 8.0.1118. -N *+virtualedit* |'virtualedit'| Always enabled since 8.1.826. +T *+virtualedit* |'virtualedit'| Always enabled since 8.1.826. T *+visual* Visual mode |Visual-mode| Always enabled since 7.4.200. T *+visualextra* extra Visual mode commands |blockwise-operators| T *+vreplace* |gR| and |gr| diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 9329aa9c7c..856ec2f118 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2021 Nov 22 +*vim9.txt* For Vim version 8.2. Last change: 2021 Dec 01 VIM REFERENCE MANUAL by Bram Moolenaar @@ -234,9 +234,10 @@ the "name#" prefix is sufficient. > def scriptname#function() # autoload When using `:function` or `:def` to specify a nested function inside a `:def` -function, this nested function is local to the code block it is defined in. -In a `:def` function it is not possible to define a script-local function. It -is possible to define a global function by using the "g:" prefix. +function and no namespace was given, this nested function is local to the code +block it is defined in. In a `:def` function it is not possible to define a +script-local function. It is possible to define a global function by using +the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function: @@ -820,10 +821,16 @@ error. Example: > For loop ~ -The loop variable must not exist yet: > +The loop variable must not be declared yet: > var i = 1 for i in [1, 2, 3] # Error! +It is possible to use a global variable though: > + g:i = 1 + for g:i in [1, 2, 3] + echo g:i + endfor + Legacy Vim script has some tricks to make a for loop over a list handle deleting items at the current or previous item. In Vim9 script it just uses the index, if items are deleted then items in the list will be skipped. diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index c288377caa..2f608352db 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -1,4 +1,4 @@ -*windows.txt* For Vim version 8.2. Last change: 2021 Sep 09 +*windows.txt* For Vim version 8.2. Last change: 2021 Nov 29 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1203,6 +1203,8 @@ list of buffers. |unlisted-buffer| the current buffer remains being edited. See |:buffer-!| for [!]. This will also edit a buffer that is not in the buffer list, without setting the 'buflisted' flag. + The notation with single quotes does not work here, + `:buf 12'345'` uses 12'345 as a buffer name. Also see |+cmd|. :[N]b[uffer][!] [+cmd] {bufname} *{bufname}* diff --git a/runtime/doc/xxd-fr.1 b/runtime/doc/xxd-fr.1 index a50336e17c..e170df5d77 100644 --- a/runtime/doc/xxd-fr.1 +++ b/runtime/doc/xxd-fr.1 @@ -111,7 +111,7 @@ octets. .TP .IR \-p " | " \-ps " | " \-postscript " | " \-plain Produit une conversion continue dans le style Postscript (postscript continuous -hexdumd style). +hexdump style). Également connu sous le nom de « conversion brute » (plain hexdump style). .TP .IR \-r " | " \-revert diff --git a/runtime/doc/xxd-fr.UTF-8.1 b/runtime/doc/xxd-fr.UTF-8.1 index c00eff88c1..47773a1363 100644 --- a/runtime/doc/xxd-fr.UTF-8.1 +++ b/runtime/doc/xxd-fr.UTF-8.1 @@ -111,7 +111,7 @@ octets. .TP .IR \-p " | " \-ps " | " \-postscript " | " \-plain Produit une conversion continue dans le style Postscript (postscript continuous -hexdumd style). +hexdump style). Également connu sous le nom de « conversion brute » (plain hexdump style). .TP .IR \-r " | " \-revert diff --git a/runtime/filetype.vim b/runtime/filetype.vim index f687cc77af..87d1f48f75 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar -" Last Change: 2021 Nov 16 +" Last Change: 2021 Dec 03 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -123,7 +123,7 @@ au BufNewFile,BufRead *.aml setf aml " APT config file au BufNewFile,BufRead apt.conf setf aptconf au BufNewFile,BufRead */.aptitude/config setf aptconf -au BufNewFile,BufRead */etc/apt/apt.conf.d/{[-_[:alnum:]]\+,[-_.[:alnum:]]\+.conf} setf aptconf +" more generic pattern far down " Arch Inventory file au BufNewFile,BufRead .arch-inventory,=tagging-method setf arch @@ -1123,14 +1123,15 @@ au BufNewFile,BufRead *.msql setf msql " Mysql au BufNewFile,BufRead *.mysql setf mysql -" Mutt setup files (must be before catch *.rc) -au BufNewFile,BufRead */etc/Muttrc.d/* call s:StarSetf('muttrc') - " Tcl Shell RC file au BufNewFile,BufRead tclsh.rc setf tcl " M$ Resource files -au BufNewFile,BufRead *.rc,*.rch setf rc +" /etc/Muttrc.d/file.rc is muttrc +au BufNewFile,BufRead *.rc,*.rch + \ if expand("") !~ "/etc/Muttrc.d/" | + \ setf rc | + \ endif " MuPAD source au BufRead,BufNewFile *.mu setf mupad @@ -1756,6 +1757,9 @@ au BufNewFile,BufRead *.sqlj setf sqlj " SQR au BufNewFile,BufRead *.sqr,*.sqi setf sqr +" Squirrel +au BufNewFile,BufRead *.nut setf squirrel + " OpenSSH configuration au BufNewFile,BufRead ssh_config,*/.ssh/config setf sshconfig au BufNewFile,BufRead */etc/ssh/ssh_config.d/*.conf setf sshconfig @@ -2159,6 +2163,12 @@ au BufNewFile,BufRead * au StdinReadPost * if !did_filetype() | runtime! scripts.vim | endif +" Plain text files, needs to be far down to not override others. This avoids +" the "conf" type being used if there is a line starting with '#'. +" But before patterns matching everything in a directory. +au BufNewFile,BufRead *.text,README,LICENSE,COPYING,AUTHORS setf text + + " Extra checks for when no filetype has been detected now. Mostly used for " patterns that end in "*". E.g., "zsh*" matches "zsh.vim", but that's a Vim " script file. @@ -2173,6 +2183,9 @@ au BufNewFile,BufRead proftpd.conf* call s:StarSetf('apachestyle') au BufNewFile,BufRead access.conf*,apache.conf*,apache2.conf*,httpd.conf*,srm.conf* call s:StarSetf('apache') au BufNewFile,BufRead */etc/apache2/*.conf*,*/etc/apache2/conf.*/*,*/etc/apache2/mods-*/*,*/etc/apache2/sites-*/*,*/etc/httpd/conf.*/*,*/etc/httpd/mods-*/*,*/etc/httpd/sites-*/*,*/etc/httpd/conf.d/*.conf* call s:StarSetf('apache') +" APT config file +au BufNewFile,BufRead */etc/apt/apt.conf.d/{[-_[:alnum:]]\+,[-_.[:alnum:]]\+.conf} call s:StarSetf('aptconf') + " Asterisk config file au BufNewFile,BufRead *asterisk/*.conf* call s:StarSetf('asterisk') au BufNewFile,BufRead *asterisk*/*voicemail.conf* call s:StarSetf('asteriskvm') @@ -2274,6 +2287,9 @@ au BufNewFile,BufRead */etc/modutils/* \|endif au BufNewFile,BufRead */etc/modprobe.* call s:StarSetf('modconf') +" Mutt setup files (must be before catch *.rc) +au BufNewFile,BufRead */etc/Muttrc.d/* call s:StarSetf('muttrc') + " Mutt setup file au BufNewFile,BufRead .mutt{ng,}rc*,*/.mutt{ng,}/mutt{ng,}rc* call s:StarSetf('muttrc') au BufNewFile,BufRead mutt{ng,}rc*,Mutt{ng,}rc* call s:StarSetf('muttrc') @@ -2366,10 +2382,6 @@ au BufNewFile,BufRead .zsh*,.zlog*,.zcompdump* call s:StarSetf('zsh') au BufNewFile,BufRead zsh*,zlog* call s:StarSetf('zsh') -" Plain text files, needs to be far down to not override others. This avoids -" the "conf" type being used if there is a line starting with '#'. -au BufNewFile,BufRead *.text,README setf text - " Help files match *.txt but should have a last line that is a modeline. au BufNewFile,BufRead *.txt \ if getline('$') !~ 'vim:.*ft=help' diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim index d5d0d94b52..733584a67d 100644 --- a/runtime/indent/vim.vim +++ b/runtime/indent/vim.vim @@ -1,7 +1,7 @@ " Vim indent file " Language: Vim script " Maintainer: Bram Moolenaar -" Last Change: 2021 Nov 03 +" Last Change: 2021 Nov 27 " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -12,6 +12,7 @@ let b:did_indent = 1 setlocal indentexpr=GetVimIndent() setlocal indentkeys+==end,=},=else,=cat,=finall,=END,0\\,0=\"\\\ setlocal indentkeys-=0# +setlocal indentkeys-=: let b:undo_indent = "setl indentkeys< indentexpr<" diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 24161d5231..e2d23475eb 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 27 +" Last Change: 2021 Nov 29 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -479,7 +479,7 @@ func s:StartDebugCommon(dict) " Run the command if the bang attribute was given and got to the debug " window. if get(a:dict, 'bang', 0) - call s:SendCommand('-exec-run') + call s:SendResumingCommand('-exec-run') call win_gotoid(s:ptywin) endif endfunc @@ -512,9 +512,14 @@ func TermDebugSendCommand(cmd) endif endfunc -" Send a command only when stopped. Used for :Next and :Step. -func s:SendCommandIfStopped(cmd) +" Send a command that resumes the program. If the program isn't stopped the +" command is not sent (to avoid a repeated command to cause trouble). +" If the command is sent then reset s:stopped. +func s:SendResumingCommand(cmd) if s:stopped + " reset s:stopped here, it may take a bit of time before we get a response + let s:stopped = 0 + call ch_log('assume that program is running after this command') call s:SendCommand(a:cmd) else call ch_log('dropping command, program is running: ' . a:cmd) @@ -808,11 +813,11 @@ func s:InstallCommands() command -nargs=? Break call s:SetBreakpoint() command Clear call s:ClearBreakpoint() - command Step call s:SendCommandIfStopped('-exec-step') - command Over call s:SendCommandIfStopped('-exec-next') - command Finish call s:SendCommandIfStopped('-exec-finish') + command Step call s:SendResumingCommand('-exec-step') + command Over call s:SendResumingCommand('-exec-next') + command Finish call s:SendResumingCommand('-exec-finish') command -nargs=* Run call s:Run() - command -nargs=* Arguments call s:SendCommand('-exec-arguments ' . ) + command -nargs=* Arguments call s:SendResumingCommand('-exec-arguments ' . ) if s:way == 'prompt' command Stop call s:PromptInterrupt() @@ -995,9 +1000,9 @@ endfunc func s:Run(args) if a:args != '' - call s:SendCommand('-exec-arguments ' . a:args) + call s:SendResumingCommand('-exec-arguments ' . a:args) endif - call s:SendCommand('-exec-run') + call s:SendResumingCommand('-exec-run') endfunc func s:SendEval(expr) diff --git a/runtime/syntax/django.vim b/runtime/syntax/django.vim index d3ca4de0e2..76b47d2e59 100644 --- a/runtime/syntax/django.vim +++ b/runtime/syntax/django.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Django template " Maintainer: Dave Hodder -" Last Change: 2014 Jul 13 +" Last Change: 2021 Nov 29 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -31,6 +31,7 @@ syn keyword djangoStatement contained closecomment widthratio url with endwith syn keyword djangoStatement contained get_current_language trans noop blocktrans syn keyword djangoStatement contained endblocktrans get_available_languages syn keyword djangoStatement contained get_current_language_bidi plural +syn keyword djangoStatement contained translate blocktranslate endblocktranslate " Django templete built-in filters syn keyword djangoFilter contained add addslashes capfirst center cut date diff --git a/runtime/syntax/squirrel.vim b/runtime/syntax/squirrel.vim new file mode 100644 index 0000000000..81d59cc986 --- /dev/null +++ b/runtime/syntax/squirrel.vim @@ -0,0 +1,50 @@ +" Vim syntax file +" Language: squirrel +" Current Maintainer: Matt Dunford (zenmatic@gmail.com) +" URL: https://github.com/zenmatic/vim-syntax-squirrel +" Last Change: 2021 Nov 28 + +" http://squirrel-lang.org/ + +" quit when a syntax file was already loaded +if exists("b:current_syntax") + finish +endif + +" inform C syntax that the file was included from cpp.vim +let b:filetype_in_cpp_family = 1 + +" Read the C syntax to start with +runtime! syntax/c.vim +unlet b:current_syntax + +" squirrel extensions +syn keyword squirrelStatement delete this in yield resume base clone +syn keyword squirrelAccess local +syn keyword cConstant null +syn keyword squirrelModifier static +syn keyword squirrelType bool instanceof typeof +syn keyword squirrelExceptions throw try catch +syn keyword squirrelStructure class function extends constructor +syn keyword squirrelBoolean true false +syn keyword squirrelRepeat foreach + +syn region squirrelMultiString start='@"' end='"$' end='";$'me=e-1 + +syn match squirrelShComment "^\s*#.*$" + +" Default highlighting +hi def link squirrelAccess squirrelStatement +hi def link squirrelExceptions Exception +hi def link squirrelStatement Statement +hi def link squirrelModifier Type +hi def link squirrelType Type +hi def link squirrelStructure Structure +hi def link squirrelBoolean Boolean +hi def link squirrelMultiString String +hi def link squirrelRepeat cRepeat +hi def link squirrelShComment Comment + +let b:current_syntax = "squirrel" + +" vim: ts=8 diff --git a/runtime/syntax/vb.vim b/runtime/syntax/vb.vim index 8ddb1efac3..607f6130ba 100644 --- a/runtime/syntax/vb.vim +++ b/runtime/syntax/vb.vim @@ -1,9 +1,11 @@ " Vim syntax file -" Language: Visual Basic -" Maintainer: Tim Chase -" Former Maintainer: Robert M. Cortopassi -" (tried multiple times to contact, but email bounced) +" Language: Visual Basic +" Maintainer: Doug Kearns +" Former Maintainer: Tim Chase +" Former Maintainer: Robert M. Cortopassi +" (tried multiple times to contact, but email bounced) " Last Change: +" 2021 Nov 26 Incorporated additions from Doug Kearns " 2005 May 25 Synched with work by Thomas Barthel " 2004 May 30 Added a few keywords @@ -13,7 +15,7 @@ " quit when a syntax file was already loaded if exists("b:current_syntax") - finish + finish endif " VB is case insensitive @@ -233,7 +235,7 @@ syn keyword vbKeyword Public PublicNotCreateable OnNewProcessSingleUse syn keyword vbKeyword InSameProcessMultiUse GlobalMultiUse Resume Seek syn keyword vbKeyword Set Static Step String Time WithEvents -syn keyword vbTodo contained TODO +syn keyword vbTodo contained TODO "Datatypes syn keyword vbTypes Boolean Byte Currency Date Decimal Double Empty @@ -319,46 +321,54 @@ syn match vbNumber "\<\d\+\>" syn match vbNumber "\<\d\+\.\d*\>" "floating point number, starting with a dot syn match vbNumber "\.\d\+\>" -"syn match vbNumber "{[[:xdigit:]-]\+}\|&[hH][[:xdigit:]]\+&" -"syn match vbNumber ":[[:xdigit:]]\+" -"syn match vbNumber "[-+]\=\<\d\+\>" -syn match vbFloat "[-+]\=\<\d\+[eE][\-+]\=\d\+" -syn match vbFloat "[-+]\=\<\d\+\.\d*\([eE][\-+]\=\d\+\)\=" -syn match vbFloat "[-+]\=\<\.\d\+\([eE][\-+]\=\d\+\)\=" +"syn match vbNumber "{[[:xdigit:]-]\+}\|&[hH][[:xdigit:]]\+&" +"syn match vbNumber ":[[:xdigit:]]\+" +"syn match vbNumber "[-+]\=\<\d\+\>" +syn match vbFloat "[-+]\=\<\d\+[eE][\-+]\=\d\+" +syn match vbFloat "[-+]\=\<\d\+\.\d*\([eE][\-+]\=\d\+\)\=" +syn match vbFloat "[-+]\=\<\.\d\+\([eE][\-+]\=\d\+\)\=" -" String and Character contstants +" String and Character constants syn region vbString start=+"+ end=+"\|$+ syn region vbComment start="\(^\|\s\)REM\s" end="$" contains=vbTodo syn region vbComment start="\(^\|\s\)\'" end="$" contains=vbTodo -syn match vbLineNumber "^\d\+\(\s\|$\)" -syn match vbTypeSpecifier "[a-zA-Z0-9][\$%&!#]"ms=s+1 +syn match vbLineLabel "^\h\w\+:" +syn match vbLineNumber "^\d\+\(:\|\s\|$\)" +syn match vbTypeSpecifier "\<\a\w*[@\$%&!#]"ms=s+1 syn match vbTypeSpecifier "#[a-zA-Z0-9]"me=e-1 +" Conditional Compilation +syn match vbPreProc "^#const\>" +syn region vbPreProc matchgroup=PreProc start="^#if\>" end="\" transparent contains=TOP +syn region vbPreProc matchgroup=PreProc start="^#elseif\>" end="\" transparent contains=TOP +syn match vbPreProc "^#else\>" +syn match vbPreProc "^#end\s*if\>" " Define the default highlighting. " Only when an item doesn't have highlighting yet -hi def link vbBoolean Boolean -hi def link vbLineNumber Comment -hi def link vbComment Comment -hi def link vbConditional Conditional -hi def link vbConst Constant -hi def link vbDefine Constant -hi def link vbError Error -hi def link vbFunction Identifier -hi def link vbIdentifier Identifier -hi def link vbNumber Number -hi def link vbFloat Float -hi def link vbMethods PreProc -hi def link vbOperator Operator -hi def link vbRepeat Repeat -hi def link vbString String -hi def link vbStatement Statement -hi def link vbKeyword Statement -hi def link vbEvents Special -hi def link vbTodo Todo -hi def link vbTypes Type -hi def link vbTypeSpecifier Type - +hi def link vbBoolean Boolean +hi def link vbLineNumber Comment +hi def link vbLineLabel Comment +hi def link vbComment Comment +hi def link vbConditional Conditional +hi def link vbConst Constant +hi def link vbDefine Constant +hi def link vbError Error +hi def link vbFunction Identifier +hi def link vbIdentifier Identifier +hi def link vbNumber Number +hi def link vbFloat Float +hi def link vbMethods PreProc +hi def link vbOperator Operator +hi def link vbRepeat Repeat +hi def link vbString String +hi def link vbStatement Statement +hi def link vbKeyword Statement +hi def link vbEvents Special +hi def link vbTodo Todo +hi def link vbTypes Type +hi def link vbTypeSpecifier Type +hi def link vbPreProc PreProc let b:current_syntax = "vb" diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index ab948d90ac..40e131ef97 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Vim 8.2 script " Maintainer: Charles E. Campbell -" Last Change: Nov 25, 2021 -" Version: 8.2-17 +" Last Change: December 02, 2021 +" Version: 8.2-18 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM " Automatically generated keyword lists: {{{1 @@ -73,7 +73,7 @@ syn keyword vimAutoEvent contained BufCreate BufEnter BufFilePre BufLeave BufNew syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo " Default highlighting groups {{{2 -syn keyword vimHLGroup contained ColorColumn Cursor CursorColumn CursorIM CursorLine CursorLineNr DiffAdd DiffChange DiffDelete DiffText Directory EndOfBuffer ErrorMsg FoldColumn Folded IncSearch LineNr LineNrAbove LineNrBelow MatchParen Menu ModeMsg MoreMsg NonText Normal Pmenu PmenuSbar PmenuSel PmenuThumb Question QuickFixLine Scrollbar Search SignColumn SpecialKey SpellBad SpellCap SpellLocal SpellRare StatusLine StatusLineNC StatusLineTerm TabLine TabLineFill TabLineSel Terminal Title Tooltip VertSplit Visual VisualNOS WarningMsg WildMenu +syn keyword vimHLGroup contained ColorColumn Cursor CursorColumn CursorIM CursorLine CursorLineFold CursorLineNr CursorLineSign DiffAdd DiffChange DiffDelete DiffText Directory EndOfBuffer ErrorMsg FoldColumn Folded IncSearch LineNr LineNrAbove LineNrBelow MatchParen Menu ModeMsg MoreMsg NonText Normal Pmenu PmenuSbar PmenuSel PmenuThumb Question QuickFixLine Scrollbar Search SignColumn SpecialKey SpellBad SpellCap SpellLocal SpellRare StatusLine StatusLineNC StatusLineTerm TabLine TabLineFill TabLineSel Terminal Title Tooltip VertSplit Visual VisualNOS WarningMsg WildMenu syn match vimHLGroup contained "Conceal" syn case match diff --git a/runtime/tools/demoserver.py b/runtime/tools/demoserver.py index 00fe8bfbca..150ddbee7c 100644 --- a/runtime/tools/demoserver.py +++ b/runtime/tools/demoserver.py @@ -62,9 +62,16 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): if decoded[0] >= 0: if decoded[1] == 'hello!': response = "got it" + id = decoded[0] + elif decoded[1] == 'hello channel!': + response = "got that" + # response is not to a specific message callback but to the + # channel callback, need to use ID zero + id = 0 else: response = "what?" - encoded = json.dumps([decoded[0], response]) + id = decoded[0] + encoded = json.dumps([id, response]) print("sending {0}".format(encoded)) self.request.sendall(encoded.encode('utf-8')) thesocket = None diff --git a/src/alloc.c b/src/alloc.c index 42caa41801..84a1124f35 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -440,6 +440,7 @@ free_all_mem(void) free_prev_shellcmd(); free_regexp_stuff(); free_tag_stuff(); + free_xim_stuff(); free_cd_dir(); # ifdef FEAT_SIGNS free_signs(); @@ -572,6 +573,9 @@ free_all_mem(void) # endif # ifdef FEAT_GUI_GTK gui_mch_free_all(); +# endif +# ifdef FEAT_TCL + vim_tcl_finalize(); # endif clear_hl_tables(); diff --git a/src/beval.c b/src/beval.c index dd7bc3cdc7..8e0efb5e2b 100644 --- a/src/beval.c +++ b/src/beval.c @@ -150,18 +150,18 @@ get_beval_info( int row = mouse_row; int col = mouse_col; -# ifdef FEAT_GUI +# ifdef FEAT_BEVAL_GUI if (gui.in_use) { row = Y_2_ROW(beval->y); col = X_2_COL(beval->x); } -#endif +# endif if (find_word_under_cursor(row, col, getword, FIND_IDENT + FIND_STRING + FIND_EVAL, winp, lnump, textp, colp, NULL) == OK) { -#ifdef FEAT_VARTABS +# ifdef FEAT_VARTABS vim_free(beval->vts); beval->vts = tabstop_copy((*winp)->w_buffer->b_p_vts_array); if ((*winp)->w_buffer->b_p_vts_array != NULL && beval->vts == NULL) @@ -170,7 +170,7 @@ get_beval_info( vim_free(*textp); return FAIL; } -#endif +# endif beval->ts = (*winp)->w_buffer->b_p_ts; return OK; } diff --git a/src/blob.c b/src/blob.c index 04319f8b1e..0458571181 100644 --- a/src/blob.c +++ b/src/blob.c @@ -209,7 +209,7 @@ write_blob(FILE *fd, blob_T *blob) if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd) < (size_t)blob->bv_ga.ga_len) { - emsg(_(e_write)); + emsg(_(e_error_while_writing)); return FAIL; } return OK; @@ -526,6 +526,7 @@ f_list2blob(typval_T *argvars, typval_T *rettv) if (l == NULL) return; + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, li) { int error; diff --git a/src/buffer.c b/src/buffer.c index 8d39c5f637..4dbdc7b179 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -193,7 +193,7 @@ open_buffer( // This is OK, since there are no changes to lose. if (curbuf == NULL) { - emsg(_("E82: Cannot allocate any buffer, exiting...")); + emsg(_(e_cannot_allocate_any_buffer_exiting)); // Don't try to do any saving, with "curbuf" NULL almost nothing // will work. @@ -201,7 +201,7 @@ open_buffer( getout(2); } - emsg(_("E83: Cannot allocate buffer, using other one...")); + emsg(_(e_cannot_allocate_buffer_using_other_one)); enter_buffer(curbuf); #ifdef FEAT_SYN_HL if (old_tw != curbuf->b_p_tw) @@ -1186,7 +1186,7 @@ empty_curbuf( if (action == DOBUF_UNLOAD) { - emsg(_("E90: Cannot unload last buffer")); + emsg(_(e_cannot_unload_last_buffer)); return FAIL; } @@ -1259,7 +1259,7 @@ do_buffer_ext( } if (!bufIsChanged(buf)) { - emsg(_("E84: No modified buffer found")); + emsg(_(e_no_modified_buffer_found)); return FAIL; } } @@ -1298,7 +1298,7 @@ do_buffer_ext( if (bp == buf) { // back where we started, didn't find anything. - emsg(_("E85: There is no listed buffer")); + emsg(_(e_there_is_no_listed_buffer)); return FAIL; } } @@ -1310,12 +1310,12 @@ do_buffer_ext( { // don't warn when deleting if (!unload) - semsg(_(e_nobufnr), count); + semsg(_(e_buffer_nr_does_not_exist), count); } else if (dir == FORWARD) - emsg(_("E87: Cannot go beyond last buffer")); + emsg(_(e_cannot_go_beyond_last_buffer)); else - emsg(_("E88: Cannot go before first buffer")); + emsg(_(e_cannot_go_before_first_buffer)); return FAIL; } #ifdef FEAT_PROP_POPUP @@ -1368,7 +1368,7 @@ do_buffer_ext( else #endif { - semsg(_("E89: No write since last change for buffer %d (add ! to override)"), + semsg(_(e_no_write_since_last_change_for_buffer_nr_add_bang_to_override), buf->b_fnum); return FAIL; } @@ -2330,8 +2330,11 @@ free_buf_options( clear_string_option(&buf->b_p_cpt); #ifdef FEAT_COMPL_FUNC clear_string_option(&buf->b_p_cfu); + free_callback(&buf->b_cfu_cb); clear_string_option(&buf->b_p_ofu); + free_callback(&buf->b_ofu_cb); clear_string_option(&buf->b_p_tsrfu); + free_callback(&buf->b_tsrfu_cb); #endif #ifdef FEAT_QUICKFIX clear_string_option(&buf->b_p_gp); diff --git a/src/bufwrite.c b/src/bufwrite.c index b48200492b..02186e6a68 100644 --- a/src/bufwrite.c +++ b/src/bufwrite.c @@ -713,7 +713,7 @@ buf_write( // Avoid a crash for a long name. if (STRLEN(fname) >= MAXPATHL) { - emsg(_(e_longname)); + emsg(_(e_name_too_long)); return FAIL; } diff --git a/src/channel.c b/src/channel.c index 89979c205e..98f6c88b9f 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1229,7 +1229,8 @@ channel_set_options(channel_T *channel, jobopt_T *opt) { buf = buflist_findnr(opt->jo_io_buf[PART_OUT]); if (buf == NULL) - semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]); + semsg(_(e_buffer_nr_does_not_exist), + (long)opt->jo_io_buf[PART_OUT]); } else { @@ -1276,7 +1277,8 @@ channel_set_options(channel_T *channel, jobopt_T *opt) { buf = buflist_findnr(opt->jo_io_buf[PART_ERR]); if (buf == NULL) - semsg(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]); + semsg(_(e_buffer_nr_does_not_exist), + (long)opt->jo_io_buf[PART_ERR]); } else { diff --git a/src/cmdexpand.c b/src/cmdexpand.c index 48511031b4..d79bc6fa74 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -406,7 +406,7 @@ ExpandOne( // together. Don't really want to wait for this message // (and possibly have to hit return to continue!). if (!(options & WILD_SILENT)) - emsg(_(e_toomany)); + emsg(_(e_too_many_file_names)); else if (!(options & WILD_NO_BEEP)) beep_flush(); } diff --git a/src/errors.h b/src/errors.h index 96aef67fcb..a494de3722 100644 --- a/src/errors.h +++ b/src/errors.h @@ -134,6 +134,68 @@ EXTERN char e_invalid_character_after_str_at[] INIT(= N_("E59: invalid character after %s@")); EXTERN char e_too_many_complex_str_curly[] INIT(= N_("E60: Too many complex %s{...}s")); +EXTERN char e_nested_str[] + INIT(= N_("E61: Nested %s*")); +EXTERN char e_nested_str_chr[] + INIT(= N_("E62: Nested %s%c")); +EXTERN char e_invalid_use_of_underscore[] + INIT(= N_("E63: invalid use of \\_")); +EXTERN char e_str_chr_follows_nothing[] + INIT(= N_("E64: %s%c follows nothing")); +EXTERN char e_illegal_back_reference[] + INIT(= N_("E65: Illegal back reference")); +#ifdef FEAT_SYN_HL +EXTERN char e_z_not_allowed_here[] + INIT(= N_("E66: \\z( not allowed here")); +EXTERN char e_z1_z9_not_allowed_here[] + INIT(= N_("E67: \\z1 - \\z9 not allowed here")); +#endif +EXTERN char e_missing_sb_after_str[] + INIT(= N_("E69: Missing ] after %s%%[")); +EXTERN char e_empty_str_brackets[] + INIT(= N_("E70: Empty %s%%[]")); +EXTERN char e_invalid_character_after_str[] + INIT(= N_("E71: Invalid character after %s%%")); +EXTERN char e_close_error_on_swap_file[] + INIT(= N_("E72: Close error on swap file")); +EXTERN char e_tag_stack_empty[] + INIT(= N_("E73: tag stack empty")); +EXTERN char e_command_too_complex[] + INIT(= N_("E74: Command too complex")); +EXTERN char e_name_too_long[] + INIT(= N_("E75: Name too long")); +EXTERN char e_too_many_brackets[] + INIT(= N_("E76: Too many [")); +EXTERN char e_too_many_file_names[] + INIT(= N_("E77: Too many file names")); +EXTERN char e_unknown_mark[] + INIT(= N_("E78: Unknown mark")); +EXTERN char e_cannot_expand_wildcards[] + INIT(= N_("E79: Cannot expand wildcards")); +EXTERN char e_error_while_writing[] + INIT(= N_("E80: Error while writing")); +#ifdef FEAT_EVAL +EXTERN char e_using_sid_not_in_script_context[] + INIT(= N_("E81: Using not in a script context")); +#endif +EXTERN char e_cannot_allocate_any_buffer_exiting[] + INIT(= N_("E82: Cannot allocate any buffer, exiting...")); +EXTERN char e_cannot_allocate_buffer_using_other_one[] + INIT(= N_("E83: Cannot allocate buffer, using other one...")); +EXTERN char e_no_modified_buffer_found[] + INIT(= N_("E84: No modified buffer found")); +EXTERN char e_there_is_no_listed_buffer[] + INIT(= N_("E85: There is no listed buffer")); +EXTERN char e_buffer_nr_does_not_exist[] + INIT(= N_("E86: Buffer %ld does not exist")); +EXTERN char e_cannot_go_beyond_last_buffer[] + INIT(= N_("E87: Cannot go beyond last buffer")); +EXTERN char e_cannot_go_before_first_buffer[] + INIT(= N_("E88: Cannot go before first buffer")); +EXTERN char e_no_write_since_last_change_for_buffer_nr_add_bang_to_override[] + INIT(= N_("E89: No write since last change for buffer %d (add ! to override)")); +EXTERN char e_cannot_unload_last_buffer[] + INIT(= N_("E90: Cannot unload last buffer")); #ifdef FEAT_EVAL EXTERN char e_undefined_variable_str[] diff --git a/src/eval.c b/src/eval.c index bebe2f0ad5..bc4db2906c 100644 --- a/src/eval.c +++ b/src/eval.c @@ -6281,23 +6281,23 @@ ex_execute(exarg_T *eap) * after the option name. */ char_u * -find_option_end(char_u **arg, int *opt_flags) +find_option_end(char_u **arg, int *scope) { char_u *p = *arg; ++p; if (*p == 'g' && p[1] == ':') { - *opt_flags = OPT_GLOBAL; + *scope = OPT_GLOBAL; p += 2; } else if (*p == 'l' && p[1] == ':') { - *opt_flags = OPT_LOCAL; + *scope = OPT_LOCAL; p += 2; } else - *opt_flags = 0; + *scope = 0; if (!ASCII_ISALPHA(*p)) return NULL; diff --git a/src/evalvars.c b/src/evalvars.c index 17d2162d78..1798e529ed 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1369,7 +1369,7 @@ ex_let_option( char_u *op) { char_u *p; - int opt_flags; + int scope; char_u *arg_end = NULL; if ((flags & (ASSIGN_CONST | ASSIGN_FINAL)) @@ -1380,7 +1380,7 @@ ex_let_option( } // Find the end of the name. - p = find_option_end(&arg, &opt_flags); + p = find_option_end(&arg, &scope); if (p == NULL || (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL)) emsg(_(e_unexpected_characters_in_let)); @@ -1393,11 +1393,14 @@ ex_let_option( char_u *stringval = NULL; char_u *s = NULL; int failed = FALSE; + int opt_p_flags; + char_u *tofree = NULL; c1 = *p; *p = NUL; - opt_type = get_option_value(arg, &numval, &stringval, opt_flags); + opt_type = get_option_value(arg, &numval, &stringval, &opt_p_flags, + scope); if ((opt_type == gov_bool || opt_type == gov_number || opt_type == gov_hidden_bool @@ -1412,9 +1415,20 @@ ex_let_option( n = (long)tv_get_number(tv); } + if (opt_p_flags & P_FUNC && (tv->v_type == VAR_PARTIAL + || tv->v_type == VAR_FUNC)) + { + char_u numbuf[NUMBUFLEN]; + + // If the option can be set to a function reference or a lambda + // and the passed value is a function reference, then convert it to + // the name (string) of the function reference. + + s = tv2string(tv, &tofree, numbuf, 0); + } // Avoid setting a string option to the text "v:false" or similar. // In Vim9 script also don't convert a number to string. - if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL + else if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL && (!in_vim9script() || tv->v_type != VAR_NUMBER)) s = tv_get_string_chk(tv); @@ -1460,7 +1474,7 @@ ex_let_option( { if (opt_type != gov_string || s != NULL) { - set_option_value(arg, n, s, opt_flags); + set_option_value(arg, n, s, scope); arg_end = p; } else @@ -1468,6 +1482,7 @@ ex_let_option( } *p = c1; vim_free(stringval); + vim_free(tofree); } return arg_end; } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 6b6aa8a0fa..7b96299891 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -6883,13 +6883,17 @@ ex_open(exarg_T *eap) regmatch.regprog = vim_regcomp(eap->arg, magic_isset() ? RE_MAGIC : 0); if (regmatch.regprog != NULL) { + // make a copy of the line, when searching for a mark it might be + // flushed + char_u *line = vim_strsave(ml_get_curline()); + regmatch.rm_ic = p_ic; - p = ml_get_curline(); - if (vim_regexec(®match, p, (colnr_T)0)) - curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - p); + if (vim_regexec(®match, line, (colnr_T)0)) + curwin->w_cursor.col = (colnr_T)(regmatch.startp[0] - line); else emsg(_(e_nomatch)); vim_regfree(regmatch.regprog); + vim_free(line); } // Move to the NUL, ignore any other arguments. eap->arg += STRLEN(eap->arg); @@ -9179,7 +9183,7 @@ eval_vars( case SPEC_SID: if (current_sctx.sc_sid <= 0) { - *errormsg = _(e_usingsid); + *errormsg = _(e_using_sid_not_in_script_context); return NULL; } sprintf((char *)strbuf, "%d_", current_sctx.sc_sid); diff --git a/src/getchar.c b/src/getchar.c index 2a27db6c02..e3459ff5f3 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -1010,7 +1010,7 @@ ins_typebuf( if (typebuf.tb_len > 2147483647 - extra) { // string is getting too long for a 32 bit int - emsg(_(e_toocompl)); // also calls flush_buffers + emsg(_(e_command_too_complex)); // also calls flush_buffers setcursor(); return FAIL; } diff --git a/src/globals.h b/src/globals.h index 0e121f40c5..9ca0c23653 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1720,22 +1720,12 @@ EXTERN char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); #if defined(FEAT_SIGN_ICONS) && !defined(FEAT_GUI_GTK) EXTERN char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); #endif -EXTERN char e_swapclose[] INIT(= N_("E72: Close error on swap file")); -EXTERN char e_tagstack[] INIT(= N_("E73: tag stack empty")); -EXTERN char e_toocompl[] INIT(= N_("E74: Command too complex")); -EXTERN char e_longname[] INIT(= N_("E75: Name too long")); -EXTERN char e_toomsbra[] INIT(= N_("E76: Too many [")); -EXTERN char e_toomany[] INIT(= N_("E77: Too many file names")); EXTERN char e_trailing[] INIT(= N_("E488: Trailing characters")); EXTERN char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); -EXTERN char e_umark[] INIT(= N_("E78: Unknown mark")); -EXTERN char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); EXTERN char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); EXTERN char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); -EXTERN char e_write[] INIT(= N_("E80: Error while writing")); EXTERN char e_zerocount[] INIT(= N_("E939: Positive count required")); #ifdef FEAT_EVAL -EXTERN char e_usingsid[] INIT(= N_("E81: Using not in a script context")); EXTERN char e_missing_paren[] INIT(= N_("E107: Missing parentheses: %s")); EXTERN char e_missing_close[] INIT(= N_("E110: Missing ')'")); EXTERN char e_missing_dict_colon[] INIT(= N_("E720: Missing colon in Dictionary: %s")); @@ -1752,7 +1742,6 @@ EXTERN char e_nbreadonly[] INIT(= N_("E744: NetBeans does not allow changes in r #endif EXTERN char e_maxmempat[] INIT(= N_("E363: pattern uses more memory than 'maxmempattern'")); EXTERN char e_emptybuf[] INIT(= N_("E749: empty buffer")); -EXTERN char e_nobufnr[] INIT(= N_("E86: Buffer %ld does not exist")); EXTERN char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); EXTERN char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); diff --git a/src/gui_xim.c b/src/gui_xim.c index 9015cafb51..c825a73e2c 100644 --- a/src/gui_xim.c +++ b/src/gui_xim.c @@ -67,8 +67,24 @@ xim_log(char *s, ...) # define USE_IMSTATUSFUNC (*p_imsf != NUL) #endif -#if defined(FEAT_EVAL) && \ - (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL)) +#if (defined(FEAT_EVAL) && \ + (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))) || \ + defined(PROTO) +static callback_T imaf_cb; // 'imactivatefunc' callback function +static callback_T imsf_cb; // 'imstatusfunc' callback function + + int +set_imactivatefunc_option(void) +{ + return option_set_callback_func(p_imaf, &imaf_cb); +} + + int +set_imstatusfunc_option(void) +{ + return option_set_callback_func(p_imsf, &imsf_cb); +} + # ifdef FEAT_GUI_MACVIM void # else @@ -81,7 +97,7 @@ call_imactivatefunc(int active) argv[0].v_type = VAR_NUMBER; argv[0].vval.v_number = active ? 1 : 0; argv[1].v_type = VAR_UNKNOWN; - (void)call_func_retnr(p_imaf, 1, argv); + (void)call_callback_retnr(&imaf_cb, 1, argv); } # ifdef FEAT_GUI_MACVIM @@ -99,12 +115,25 @@ call_imstatusfunc(void) // FIXME: :py print 'xxx' is shown duplicate result. // Use silent to avoid it. ++msg_silent; - is_active = call_func_retnr(p_imsf, 0, NULL); + is_active = call_callback_retnr(&imsf_cb, 0, NULL); --msg_silent; return (is_active > 0); } #endif +#if defined(EXITFREE) || defined(PROTO) + void +free_xim_stuff(void) +{ +#if defined(FEAT_EVAL) && \ + (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL)) + free_callback(&imaf_cb); + free_callback(&imsf_cb); +# endif +} +#endif + + #if defined(FEAT_XIM) || defined(PROTO) # ifdef FEAT_GUI_MACVIM diff --git a/src/if_mzsch.c b/src/if_mzsch.c index 57b593a19e..41b6d0006f 100644 --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -1715,7 +1715,7 @@ get_option(void *data, int argc, Scheme_Object **argv) getoption_T rc; Scheme_Object *rval = NULL; Scheme_Object *name = NULL; - int opt_flags = 0; + int scope = 0; buf_T *save_curb = curbuf; win_T *save_curw = curwin; @@ -1736,11 +1736,11 @@ get_option(void *data, int argc, Scheme_Object **argv) } if (argv[1] == M_global) - opt_flags = OPT_GLOBAL; + scope = OPT_GLOBAL; else if (SCHEME_VIMBUFFERP(argv[1])) { curbuf = get_valid_buffer(argv[1]); - opt_flags = OPT_LOCAL; + scope = OPT_LOCAL; } else if (SCHEME_VIMWINDOWP(argv[1])) { @@ -1748,14 +1748,14 @@ get_option(void *data, int argc, Scheme_Object **argv) curwin = win; curbuf = win->w_buffer; - opt_flags = OPT_LOCAL; + scope = OPT_LOCAL; } else scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv); } rc = get_option_value(BYTE_STRING_VALUE(name), &value, (char_u **)&strval, - opt_flags); + NULL, scope); curbuf = save_curb; curwin = save_curw; @@ -1793,7 +1793,7 @@ get_option(void *data, int argc, Scheme_Object **argv) set_option(void *data, int argc, Scheme_Object **argv) { char_u *command = NULL; - int opt_flags = 0; + int scope = 0; buf_T *save_curb = curbuf; win_T *save_curw = curwin; Vim_Prim *prim = (Vim_Prim *)data; @@ -1814,18 +1814,18 @@ set_option(void *data, int argc, Scheme_Object **argv) } if (argv[1] == M_global) - opt_flags = OPT_GLOBAL; + scope = OPT_GLOBAL; else if (SCHEME_VIMBUFFERP(argv[1])) { curbuf = get_valid_buffer(argv[1]); - opt_flags = OPT_LOCAL; + scope = OPT_LOCAL; } else if (SCHEME_VIMWINDOWP(argv[1])) { win_T *win = get_valid_window(argv[1]); curwin = win; curbuf = win->w_buffer; - opt_flags = OPT_LOCAL; + scope = OPT_LOCAL; } else scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv); @@ -1834,7 +1834,7 @@ set_option(void *data, int argc, Scheme_Object **argv) // do_set can modify cmd, make copy command = vim_strsave(BYTE_STRING_VALUE(cmd)); MZ_GC_UNREG(); - do_set(command, opt_flags); + do_set(command, scope); vim_free(command); update_screen(NOT_VALID); curbuf = save_curb; diff --git a/src/if_ruby.c b/src/if_ruby.c index 5098468e6a..0d7eaf2e89 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -875,7 +875,7 @@ vim_str2rb_enc_str(const char *s) char_u *sval; rb_encoding *enc; - if (get_option_value((char_u *)"enc", &lval, &sval, 0) == gov_string) + if (get_option_value((char_u *)"enc", &lval, &sval, NULL, 0) == gov_string) { enc = rb_enc_find((char *)sval); vim_free(sval); @@ -895,7 +895,7 @@ eval_enc_string_protect(const char *str, int *state) rb_encoding *enc; VALUE v; - if (get_option_value((char_u *)"enc", &lval, &sval, 0) == gov_string) + if (get_option_value((char_u *)"enc", &lval, &sval, NULL, 0) == gov_string) { enc = rb_enc_find((char *)sval); vim_free(sval); diff --git a/src/if_tcl.c b/src/if_tcl.c index f3f4b0798a..75fa858e8e 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -248,6 +248,14 @@ vim_tcl_init(char *arg) #endif } +#if defined(EXITFREE) || defined(PROTO) + void +vim_tcl_finalize(void) +{ + Tcl_Finalize(); +} +#endif + #if defined(DYNAMIC_TCL) || defined(PROTO) static int stubs_initialized = FALSE; @@ -1300,7 +1308,7 @@ tclsetoption( option = (char_u *)Tcl_GetStringFromObj(objv[objn], NULL); ++objn; - gov = get_option_value(option, &lval, &sval, 0); + gov = get_option_value(option, &lval, &sval, NULL, 0); err = TCL_OK; switch (gov) { diff --git a/src/insexpand.c b/src/insexpand.c index bd67a256fe..2bc8778e49 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2242,6 +2242,113 @@ ins_compl_next_buf(buf_T *buf, int flag) } #ifdef FEAT_COMPL_FUNC + +# ifdef FEAT_EVAL +static callback_T cfu_cb; // 'completefunc' callback function +static callback_T ofu_cb; // 'omnifunc' callback function +static callback_T tsrfu_cb; // 'thesaurusfunc' callback function +# endif + +/* + * Copy a global callback function to a buffer local callback. + */ + static void +copy_global_to_buflocal_cb(callback_T *globcb, callback_T *bufcb) +{ + free_callback(bufcb); + if (globcb->cb_name != NULL && *globcb->cb_name != NUL) + copy_callback(bufcb, globcb); +} + +/* + * Parse the 'completefunc' option value and set the callback function. + * Invoked when the 'completefunc' option is set. The option value can be a + * name of a function (string), or function() or funcref() or a + * lambda expression. + */ + int +set_completefunc_option(void) +{ + int retval; + + retval = option_set_callback_func(curbuf->b_p_cfu, &cfu_cb); + if (retval == OK) + set_buflocal_cfu_callback(curbuf); + + return retval; +} + +/* + * Copy the global 'completefunc' callback function to the buffer-local + * 'completefunc' callback for 'buf'. + */ + void +set_buflocal_cfu_callback(buf_T *buf UNUSED) +{ +# ifdef FEAT_EVAL + copy_global_to_buflocal_cb(&cfu_cb, &buf->b_cfu_cb); +# endif +} + +/* + * Parse the 'omnifunc' option value and set the callback function. + * Invoked when the 'omnifunc' option is set. The option value can be a + * name of a function (string), or function() or funcref() or a + * lambda expression. + */ + int +set_omnifunc_option(void) +{ + int retval; + + retval = option_set_callback_func(curbuf->b_p_ofu, &ofu_cb); + if (retval == OK) + set_buflocal_ofu_callback(curbuf); + + return retval; +} + +/* + * Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc' + * callback for 'buf'. + */ + void +set_buflocal_ofu_callback(buf_T *buf UNUSED) +{ +# ifdef FEAT_EVAL + copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb); +# endif +} + +/* + * Parse the 'thesaurusfunc' option value and set the callback function. + * Invoked when the 'thesaurusfunc' option is set. The option value can be a + * name of a function (string), or function() or funcref() or a + * lambda expression. + */ + int +set_thesaurusfunc_option(void) +{ + int retval; + + if (*curbuf->b_p_tsrfu != NUL) + { + // buffer-local option set + free_callback(&curbuf->b_tsrfu_cb); + retval = option_set_callback_func(curbuf->b_p_tsrfu, + &curbuf->b_tsrfu_cb); + } + else + { + // global option set + free_callback(&tsrfu_cb); + retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); + } + + return retval; +} + + /* * Get the user-defined completion function name for completion 'type' */ @@ -2261,6 +2368,20 @@ get_complete_funcname(int type) } } +/* + * Get the callback to use for insert mode completion. + */ + callback_T * +get_insert_callback(int type) +{ + if (type == CTRL_X_FUNCTION) + return &curbuf->b_cfu_cb; + if (type == CTRL_X_OMNI) + return &curbuf->b_ofu_cb; + // CTRL_X_THESAURUS + return (*curbuf->b_p_tsrfu != NUL) ? &curbuf->b_tsrfu_cb : &tsrfu_cb; +} + /* * Execute user defined complete function 'completefunc', 'omnifunc' or * 'thesaurusfunc', and get matches in "matches". @@ -2274,8 +2395,10 @@ expand_by_function(int type, char_u *base) typval_T args[3]; char_u *funcname; pos_T pos; + callback_T *cb; typval_T rettv; int save_State = State; + int retval; funcname = get_complete_funcname(type); if (*funcname == NUL) @@ -2294,8 +2417,11 @@ expand_by_function(int type, char_u *base) // Insert mode in another buffer. ++textwinlock; + cb = get_insert_callback(type); + retval = call_callback(cb, 0, &rettv, 2, args); + // Call a function, which returns a list or dict. - if (call_vim_function(funcname, 2, args, &rettv) == OK) + if (retval == OK) { switch (rettv.v_type) { @@ -3976,6 +4102,7 @@ ins_complete(int c, int enable_pum) char_u *funcname; pos_T pos; int save_State = State; + callback_T *cb; // Call 'completefunc' or 'omnifunc' and get pattern length as a // string @@ -3996,7 +4123,8 @@ ins_complete(int c, int enable_pum) args[2].v_type = VAR_UNKNOWN; pos = curwin->w_cursor; ++textwinlock; - col = call_func_retnr(funcname, 2, args); + cb = get_insert_callback(ctrl_x_mode); + col = call_callback_retnr(cb, 2, args); --textwinlock; State = save_State; @@ -4344,6 +4472,11 @@ quote_meta(char_u *dest, char_u *src, int len) free_insexpand_stuff(void) { VIM_CLEAR(compl_orig_text); +# ifdef FEAT_EVAL + free_callback(&cfu_cb); + free_callback(&ofu_cb); + free_callback(&tsrfu_cb); +# endif } #endif diff --git a/src/job.c b/src/job.c index 8cff231bd0..bd63e10caa 100644 --- a/src/job.c +++ b/src/job.c @@ -225,7 +225,8 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) } if (buflist_findnr(opt->jo_io_buf[part]) == NULL) { - semsg(_(e_nobufnr), (long)opt->jo_io_buf[part]); + semsg(_(e_buffer_nr_does_not_exist), + (long)opt->jo_io_buf[part]); return FAIL; } } @@ -475,7 +476,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) opt->jo_bufnr_buf = buflist_findnr(nr); if (opt->jo_bufnr_buf == NULL) { - semsg(_(e_nobufnr), (long)nr); + semsg(_(e_buffer_nr_does_not_exist), (long)nr); return FAIL; } if (opt->jo_bufnr_buf->b_nwindows == 0 @@ -1344,7 +1345,8 @@ job_start( { buf = buflist_findnr(opt.jo_io_buf[PART_IN]); if (buf == NULL) - semsg(_(e_nobufnr), (long)opt.jo_io_buf[PART_IN]); + semsg(_(e_buffer_nr_does_not_exist), + (long)opt.jo_io_buf[PART_IN]); } else if (!(opt.jo_set & JO_IN_NAME)) { diff --git a/src/list.c b/src/list.c index 16e59837e6..d673447001 100644 --- a/src/list.c +++ b/src/list.c @@ -1603,7 +1603,7 @@ write_list(FILE *fd, list_T *list, int binary) } if (ret == FAIL) { - emsg(_(e_write)); + emsg(_(e_error_while_writing)); break; } } diff --git a/src/mark.c b/src/mark.c index c708e07e48..099214e74f 100644 --- a/src/mark.c +++ b/src/mark.c @@ -578,7 +578,7 @@ check_mark(pos_T *pos) { if (pos == NULL) { - emsg(_(e_umark)); + emsg(_(e_unknown_mark)); return FAIL; } if (pos->lnum <= 0) diff --git a/src/memfile.c b/src/memfile.c index a414d9e5d6..fbffdbe95d 100644 --- a/src/memfile.c +++ b/src/memfile.c @@ -242,7 +242,7 @@ mf_close(memfile_T *mfp, int del_file) if (mfp->mf_fd >= 0) { if (close(mfp->mf_fd) < 0) - emsg(_(e_swapclose)); + emsg(_(e_close_error_on_swap_file)); } if (del_file && mfp->mf_fname != NULL) mch_remove(mfp->mf_fname); @@ -288,7 +288,7 @@ mf_close_file( } if (close(mfp->mf_fd) < 0) // close the file - emsg(_(e_swapclose)); + emsg(_(e_close_error_on_swap_file)); mfp->mf_fd = -1; if (mfp->mf_fname != NULL) diff --git a/src/misc1.c b/src/misc1.c index 27a67526f6..621deac415 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -852,7 +852,8 @@ get_keystroke(void) if (n == KEYLEN_REMOVED) // key code removed { - if (must_redraw != 0 && !need_wait_return && (State & CMDLINE) == 0) + if (must_redraw != 0 && !need_wait_return + && (State & (CMDLINE|HITRETURN|ASKMORE)) == 0) { // Redrawing was postponed, do it now. update_screen(0); @@ -2409,7 +2410,7 @@ get_cmd_output_as_rettv( buf = buflist_findnr(argvars[1].vval.v_number); if (buf == NULL) { - semsg(_(e_nobufnr), argvars[1].vval.v_number); + semsg(_(e_buffer_nr_does_not_exist), argvars[1].vval.v_number); fclose(fd); goto errret; } diff --git a/src/option.c b/src/option.c index fc70503c4e..878f3d0422 100644 --- a/src/option.c +++ b/src/option.c @@ -56,10 +56,10 @@ static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, long_ static int put_setnum(FILE *fd, char *cmd, char *name, long *valuep); static int put_setbool(FILE *fd, char *cmd, char *name, int value); static int istermoption(struct vimoption *p); -static char_u *get_varp_scope(struct vimoption *p, int opt_flags); +static char_u *get_varp_scope(struct vimoption *p, int scope); static char_u *get_varp(struct vimoption *); static void check_win_options(win_T *win); -static void option_value2string(struct vimoption *, int opt_flags); +static void option_value2string(struct vimoption *, int scope); static void check_winopt(winopt_T *wop); static int wc_use_keyname(char_u *varp, long *wcp); static void paste_option_changed(void); @@ -1236,11 +1236,12 @@ ex_set(exarg_T *eap) * does not need to be expanded with option_expand(). * "opt_flags": * 0 for ":set" - * OPT_GLOBAL for ":setglobal" - * OPT_LOCAL for ":setlocal" and a modeline - * OPT_MODELINE for a modeline - * OPT_WINONLY to only set window-local options - * OPT_NOWIN to skip setting window-local options + * OPT_GLOBAL for ":setglobal" + * OPT_LOCAL for ":setlocal" and a modeline + * OPT_MODELINE for a modeline + * OPT_WINONLY to only set window-local options + * OPT_NOWIN to skip setting window-local options + * OPT_ONECOLUMN do not use multiple columns * * returns FAIL if an error is detected, OK otherwise */ @@ -1308,7 +1309,7 @@ do_set( else if (STRNCMP(arg, "termcap", 7) == 0 && !(opt_flags & OPT_MODELINE)) { showoptions(2, opt_flags); - show_termcodes(); + show_termcodes(opt_flags); did_show = TRUE; arg += 7; } @@ -4044,13 +4045,16 @@ findoption(char_u *arg) * Hidden Toggle option: gov_hidden_bool. * Hidden String option: gov_hidden_string. * Unknown option: gov_unknown. + * + * "flagsp" (if not NULL) is set to the option flags (P_xxxx). */ getoption_T get_option_value( char_u *name, long *numval, char_u **stringval, // NULL when only checking existence - int opt_flags) + int *flagsp, + int scope) { int opt_idx; char_u *varp; @@ -4088,7 +4092,11 @@ get_option_value( return gov_unknown; } - varp = get_varp_scope(&(options[opt_idx]), opt_flags); + varp = get_varp_scope(&(options[opt_idx]), scope); + + if (flagsp != NULL) + // Return the P_xxxx option flags. + *flagsp = options[opt_idx].flags; if (options[opt_idx].flags & P_STRING) { @@ -5286,17 +5294,18 @@ unset_global_local_option(char_u *name, void *from) /* * Get pointer to option variable, depending on local or global scope. + * "scope" can be OPT_LOCAL, OPT_GLOBAL or a combination. */ static char_u * -get_varp_scope(struct vimoption *p, int opt_flags) +get_varp_scope(struct vimoption *p, int scope) { - if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) + if ((scope & OPT_GLOBAL) && p->indir != PV_NONE) { if (p->var == VAR_WIN) return (char_u *)GLOBAL_WO(get_varp(p)); return p->var; } - if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) + if ((scope & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) { switch ((int)p->indir) { @@ -5355,9 +5364,9 @@ get_varp_scope(struct vimoption *p, int opt_flags) * scope. */ char_u * -get_option_varp_scope(int opt_idx, int opt_flags) +get_option_varp_scope(int opt_idx, int scope) { - return get_varp_scope(&(options[opt_idx]), opt_flags); + return get_varp_scope(&(options[opt_idx]), scope); } /* @@ -6038,13 +6047,15 @@ buf_copy_options(buf_T *buf, int flags) #ifdef FEAT_COMPL_FUNC buf->b_p_cfu = vim_strsave(p_cfu); COPY_OPT_SCTX(buf, BV_CFU); + set_buflocal_cfu_callback(buf); buf->b_p_ofu = vim_strsave(p_ofu); COPY_OPT_SCTX(buf, BV_OFU); + set_buflocal_ofu_callback(buf); #endif #ifdef FEAT_EVAL buf->b_p_tfu = vim_strsave(p_tfu); COPY_OPT_SCTX(buf, BV_TFU); - buf_set_tfu_callback(buf); + set_buflocal_tfu_callback(buf); #endif buf->b_p_sts = p_sts; COPY_OPT_SCTX(buf, BV_STS); @@ -6729,11 +6740,11 @@ ExpandOldSetting(int *num_file, char_u ***file) static void option_value2string( struct vimoption *opp, - int opt_flags) // OPT_GLOBAL and/or OPT_LOCAL + int scope) // OPT_GLOBAL and/or OPT_LOCAL { char_u *varp; - varp = get_varp_scope(opp, opt_flags); + varp = get_varp_scope(opp, scope); if (opp->flags & P_NUM) { diff --git a/src/option.h b/src/option.h index 81a27ced92..61b10cf769 100644 --- a/src/option.h +++ b/src/option.h @@ -59,6 +59,7 @@ #define P_NDNAME 0x8000000L // only normal dir name chars allowed #define P_RWINONLY 0x10000000L // only redraw current window #define P_MLE 0x20000000L // under control of 'modelineexpr' +#define P_FUNC 0x40000000L // accept a function reference or a lambda // Returned by get_option_value(). typedef enum { diff --git a/src/optiondefs.h b/src/optiondefs.h index c81f0acdeb..6810dc0aec 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -739,7 +739,7 @@ static struct vimoption options[] = #endif {(char_u *)0L, (char_u *)0L} SCTX_INIT}, - {"completefunc", "cfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE, + {"completefunc", "cfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC, #ifdef FEAT_COMPL_FUNC (char_u *)&p_cfu, PV_CFU, {(char_u *)"", (char_u *)0L} @@ -1402,7 +1402,7 @@ static struct vimoption options[] = {"ignorecase", "ic", P_BOOL|P_VI_DEF, (char_u *)&p_ic, PV_NONE, {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, - {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE, + {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE|P_FUNC, #if defined(FEAT_EVAL) (char_u *)&p_imaf, PV_NONE, {(char_u *)"", (char_u *)NULL} @@ -1437,7 +1437,7 @@ static struct vimoption options[] = (char_u *)&p_imsearch, PV_IMS, {(char_u *)B_IMODE_USE_INSERT, (char_u *)0L} SCTX_INIT}, - {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE, + {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE|P_FUNC, #if defined(FEAT_EVAL) (char_u *)&p_imsf, PV_NONE, {(char_u *)"", (char_u *)NULL} @@ -1934,7 +1934,7 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)8L, (char_u *)4L} SCTX_INIT}, - {"omnifunc", "ofu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE, + {"omnifunc", "ofu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC, #ifdef FEAT_COMPL_FUNC (char_u *)&p_ofu, PV_OFU, {(char_u *)"", (char_u *)0L} @@ -1954,7 +1954,7 @@ static struct vimoption options[] = #endif {(char_u *)FALSE, (char_u *)FALSE} SCTX_INIT}, - {"operatorfunc", "opfunc", P_STRING|P_VI_DEF|P_SECURE, + {"operatorfunc", "opfunc", P_STRING|P_VI_DEF|P_SECURE|P_FUNC, (char_u *)&p_opfunc, PV_NONE, {(char_u *)"", (char_u *)0L} SCTX_INIT}, {"optimize", "opt", P_BOOL|P_VI_DEF, @@ -2167,7 +2167,7 @@ static struct vimoption options[] = #endif {(char_u *)DEFAULT_PYTHON_VER, (char_u *)0L} SCTX_INIT}, - {"quickfixtextfunc", "qftf", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE, + {"quickfixtextfunc", "qftf", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE|P_FUNC, #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL) (char_u *)&p_qftf, PV_NONE, {(char_u *)"", (char_u *)0L} @@ -2619,7 +2619,7 @@ static struct vimoption options[] = {"tagcase", "tc", P_STRING|P_VIM, (char_u *)&p_tc, PV_TC, {(char_u *)"followic", (char_u *)"followic"} SCTX_INIT}, - {"tagfunc", "tfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE, + {"tagfunc", "tfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC, #ifdef FEAT_EVAL (char_u *)&p_tfu, PV_TFU, {(char_u *)"", (char_u *)0L} @@ -2736,7 +2736,7 @@ static struct vimoption options[] = {"thesaurus", "tsr", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME, (char_u *)&p_tsr, PV_TSR, {(char_u *)"", (char_u *)0L} SCTX_INIT}, - {"thesaurusfunc", "tsrfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE, + {"thesaurusfunc", "tsrfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC, #ifdef FEAT_COMPL_FUNC (char_u *)&p_tsrfu, PV_TSRFU, {(char_u *)"", (char_u *)0L} diff --git a/src/optionstr.c b/src/optionstr.c index 47248acfdb..03f76c28fe 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -2326,6 +2326,46 @@ ambw_end: # endif #endif +#ifdef FEAT_COMPL_FUNC + // 'completefunc' + else if (gvarp == &p_cfu) + { + if (set_completefunc_option() == FAIL) + errmsg = e_invarg; + } + + // 'omnifunc' + else if (gvarp == &p_ofu) + { + if (set_omnifunc_option() == FAIL) + errmsg = e_invarg; + } + + // 'thesaurusfunc' + else if (gvarp == &p_tsrfu) + { + if (set_thesaurusfunc_option() == FAIL) + errmsg = e_invarg; + } +#endif + +#if defined(FEAT_EVAL) && \ + (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL)) + // 'imactivatefunc' + else if (gvarp == &p_imaf) + { + if (set_imactivatefunc_option() == FAIL) + errmsg = e_invarg; + } + + // 'imstatusfunc' + else if (gvarp == &p_imsf) + { + if (set_imstatusfunc_option() == FAIL) + errmsg = e_invarg; + } +#endif + // 'operatorfunc' else if (varp == &p_opfunc) { diff --git a/src/os_unix.c b/src/os_unix.c index 1ddf7841d6..db9426eae5 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6819,7 +6819,7 @@ mch_expand_wildcards( if (!(flags & EW_SILENT)) #endif { - msg(_(e_wildexpand)); + msg(_(e_cannot_expand_wildcards)); msg_start(); // don't overwrite this message } } @@ -6839,7 +6839,7 @@ mch_expand_wildcards( // Something went wrong, perhaps a file name with a special char. if (!(flags & EW_SILENT)) { - msg(_(e_wildexpand)); + msg(_(e_cannot_expand_wildcards)); msg_start(); // don't overwrite this message } vim_free(tempname); diff --git a/src/popupwin.c b/src/popupwin.c index 4b8b74102c..76418275bd 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1877,7 +1877,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) buf = buflist_findnr(argvars[0].vval.v_number); if (buf == NULL) { - semsg(_(e_nobufnr), argvars[0].vval.v_number); + semsg(_(e_buffer_nr_does_not_exist), argvars[0].vval.v_number); return NULL; } #ifdef FEAT_TERMINAL diff --git a/src/proto/eval.pro b/src/proto/eval.pro index 96a2c6d1e6..45b559de52 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -73,7 +73,7 @@ void ex_echo(exarg_T *eap); void ex_echohl(exarg_T *eap); int get_echo_attr(void); void ex_execute(exarg_T *eap); -char_u *find_option_end(char_u **arg, int *opt_flags); +char_u *find_option_end(char_u **arg, int *scope); void last_set_msg(sctx_T script_ctx); char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr, char_u *flags); /* vim: set ft=c : */ diff --git a/src/proto/gui_xim.pro b/src/proto/gui_xim.pro index 24f43716ed..60f30d7587 100644 --- a/src/proto/gui_xim.pro +++ b/src/proto/gui_xim.pro @@ -1,8 +1,7 @@ /* gui_xim.c */ -#ifdef FEAT_GUI_MACVIM -void call_imactivatefunc(int active); -int call_imstatusfunc(void); -#endif +int set_imactivatefunc_option(void); +int set_imstatusfunc_option(void); +void free_xim_stuff(void); void im_set_active(int active); void xim_set_focus(int focus); void im_set_position(int row, int col); diff --git a/src/proto/if_tcl.pro b/src/proto/if_tcl.pro index b572fb84ca..11ca7a20ea 100644 --- a/src/proto/if_tcl.pro +++ b/src/proto/if_tcl.pro @@ -1,5 +1,6 @@ /* if_tcl.c */ void vim_tcl_init(char *arg); +void vim_tcl_finalize(void); int tcl_enabled(int verbose); void tcl_end(void); void ex_tcl(exarg_T *eap); diff --git a/src/proto/insexpand.pro b/src/proto/insexpand.pro index 90b5a0732c..d455a98fd7 100644 --- a/src/proto/insexpand.pro +++ b/src/proto/insexpand.pro @@ -39,6 +39,12 @@ int ins_compl_bs(void); void ins_compl_addleader(int c); void ins_compl_addfrommatch(void); int ins_compl_prep(int c); +int set_completefunc_option(void); +void set_buflocal_cfu_callback(buf_T *buf); +int set_omnifunc_option(void); +void set_buflocal_ofu_callback(buf_T *buf); +int set_thesaurusfunc_option(void); +callback_T *get_insert_callback(int type); void f_complete(typval_T *argvars, typval_T *rettv); void f_complete_add(typval_T *argvars, typval_T *rettv); void f_complete_check(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/option.pro b/src/proto/option.pro index ea6baa7e4f..2390f58776 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -25,7 +25,7 @@ void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx); void set_term_option_sctx_idx(char *name, int opt_idx); void check_redraw(long_u flags); int findoption(char_u *arg); -getoption_T get_option_value(char_u *name, long *numval, char_u **stringval, int opt_flags); +getoption_T get_option_value(char_u *name, long *numval, char_u **stringval, int *flagsp, int scope); int get_option_value_strict(char_u *name, long *numval, char_u **stringval, int opt_type, void *from); char_u *option_iter_next(void **option, int opt_type); long_u get_option_flags(int opt_idx); @@ -48,7 +48,7 @@ void free_one_termoption(char_u *var); void set_term_defaults(void); int istermoption_idx(int opt_idx); void unset_global_local_option(char_u *name, void *from); -char_u *get_option_varp_scope(int opt_idx, int opt_flags); +char_u *get_option_varp_scope(int opt_idx, int scope); char_u *get_option_var(int opt_idx); char_u *get_option_fullname(int opt_idx); char_u *get_equalprg(void); diff --git a/src/proto/tag.pro b/src/proto/tag.pro index e9827ea7e4..c8ef72101e 100644 --- a/src/proto/tag.pro +++ b/src/proto/tag.pro @@ -1,7 +1,7 @@ /* tag.c */ int set_tagfunc_option(void); void free_tagfunc_option(void); -void buf_set_tfu_callback(buf_T *buf); +void set_buflocal_tfu_callback(buf_T *buf); int do_tag(char_u *tag, int type, int count, int forceit, int verbose); void tag_freematch(void); void do_tags(exarg_T *eap); diff --git a/src/proto/term.pro b/src/proto/term.pro index 949b350006..6f0f08103a 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -80,7 +80,7 @@ int check_termcode(int max_offset, char_u *buf, int bufsize, int *buflen); void term_get_fg_color(char_u *r, char_u *g, char_u *b); void term_get_bg_color(char_u *r, char_u *g, char_u *b); char_u *replace_termcodes(char_u *from, char_u **bufp, int flags, int *did_simplify); -void show_termcodes(void); +void show_termcodes(int flags); int show_one_termcode(char_u *name, char_u *code, int printit); void update_tcap(int attr); void swap_tcap(void); diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index dcc5b34d05..85144482e6 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -12,6 +12,7 @@ ufunc_T *find_func_even_dead(char_u *name, int is_global, cctx_T *cctx); ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); int func_is_global(ufunc_T *ufunc); int func_name_refcount(char_u *name); +void func_clear_free(ufunc_T *fp, int force); int copy_func(char_u *lambda, char_u *global, ectx_T *ectx); int funcdepth_increment(void); void funcdepth_decrement(void); @@ -28,6 +29,7 @@ int builtin_function(char_u *name, int len); int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv); int get_callback_depth(void); int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); +varnumber_T call_callback_retnr(callback_T *callback, int argcount, typval_T *argvars); void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *printable_func_name(ufunc_T *fp); diff --git a/src/regexp.c b/src/regexp.c index 45485f4018..72255c44a3 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -74,12 +74,6 @@ toggle_Magic(int x) static char_u e_missingbracket[] = N_("E769: Missing ] after %s["); static char_u e_reverse_range[] = N_("E944: Reverse range in character class"); static char_u e_large_class[] = N_("E945: Range too large in character class"); -#ifdef FEAT_SYN_HL -static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here"); -static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here"); -#endif -static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%["); -static char_u e_empty_sb[] = N_("E70: Empty %s%%[]"); static char_u e_recursive[] = N_("E956: Cannot use pattern recursively"); #define NOT_MULTI 0 diff --git a/src/regexp_bt.c b/src/regexp_bt.c index 313451ccbc..f631741618 100644 --- a/src/regexp_bt.c +++ b/src/regexp_bt.c @@ -1242,7 +1242,7 @@ seen_endbrace(int refnum) break; if (*p == NUL) { - emsg(_("E65: Illegal back reference")); + emsg(_(e_illegal_back_reference)); rc_did_emsg = TRUE; return FALSE; } @@ -1347,7 +1347,7 @@ regatom(int *flagp) case Magic('U'): p = vim_strchr(classchars, no_Magic(c)); if (p == NULL) - EMSG_RET_NULL(_("E63: invalid use of \\_")); + EMSG_RET_NULL(_(e_invalid_use_of_underscore)); // When '.' is followed by a composing char ignore the dot, so that // the composing char is matched here. @@ -1402,7 +1402,7 @@ regatom(int *flagp) case Magic('{'): case Magic('*'): c = no_Magic(c); - EMSG3_RET_NULL(_("E64: %s%c follows nothing"), + EMSG3_RET_NULL(_(e_str_chr_follows_nothing), (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL), c); // NOTREACHED @@ -1453,7 +1453,7 @@ regatom(int *flagp) { #ifdef FEAT_SYN_HL case '(': if ((reg_do_extmatch & REX_SET) == 0) - EMSG_RET_NULL(_(e_z_not_allowed)); + EMSG_RET_NULL(_(e_z_not_allowed_here)); if (one_exactly) EMSG_ONE_RET_NULL; ret = reg(REG_ZPAREN, &flags); @@ -1472,7 +1472,7 @@ regatom(int *flagp) case '7': case '8': case '9': if ((reg_do_extmatch & REX_USE) == 0) - EMSG_RET_NULL(_(e_z1_not_allowed)); + EMSG_RET_NULL(_(e_z1_z9_not_allowed_here)); ret = regnode(ZREF + c - '0'); re_has_z = REX_USE; break; @@ -1544,7 +1544,7 @@ regatom(int *flagp) while ((c = getchr()) != ']') { if (c == NUL) - EMSG2_RET_NULL(_(e_missing_sb), + EMSG2_RET_NULL(_(e_missing_sb_after_str), reg_magic == MAGIC_ALL); br = regnode(BRANCH); if (ret == NULL) @@ -1564,7 +1564,7 @@ regatom(int *flagp) return NULL; } if (ret == NULL) - EMSG2_RET_NULL(_(e_empty_sb), + EMSG2_RET_NULL(_(e_empty_str_brackets), reg_magic == MAGIC_ALL); lastbranch = regnode(BRANCH); br = regnode(NOTHING); @@ -1712,7 +1712,7 @@ regatom(int *flagp) } } - EMSG2_RET_NULL(_("E71: Invalid character after %s%%"), + EMSG2_RET_NULL(_(e_invalid_character_after_str), reg_magic == MAGIC_ALL); } } @@ -2001,7 +2001,7 @@ collection: regc(NUL); prevchr_len = 1; // last char was the ']' if (*regparse != ']') - EMSG_RET_NULL(_(e_toomsbra)); // Cannot happen? + EMSG_RET_NULL(_(e_too_many_brackets)); // Cannot happen? skipchr(); // let's be friends with the lexer again *flagp |= HASWIDTH | SIMPLE; break; @@ -2215,8 +2215,8 @@ regpiece(int *flagp) { // Can't have a multi follow a multi. if (peekchr() == Magic('*')) - EMSG2_RET_NULL(_("E61: Nested %s*"), reg_magic >= MAGIC_ON); - EMSG3_RET_NULL(_("E62: Nested %s%c"), reg_magic == MAGIC_ALL, + EMSG2_RET_NULL(_(e_nested_str), reg_magic >= MAGIC_ON); + EMSG3_RET_NULL(_(e_nested_str_chr), reg_magic == MAGIC_ALL, no_Magic(peekchr())); } diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index a0f1a960b3..ffe894d4a4 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -1586,7 +1586,7 @@ nfa_regatom(void) case '9': // \z1...\z9 if ((reg_do_extmatch & REX_USE) == 0) - EMSG_RET_FAIL(_(e_z1_not_allowed)); + EMSG_RET_FAIL(_(e_z1_z9_not_allowed_here)); EMIT(NFA_ZREF1 + (no_Magic(c) - '1')); // No need to set rex.nfa_has_backref, the sub-matches don't // change when \z1 .. \z9 matches or not. @@ -1595,7 +1595,7 @@ nfa_regatom(void) case '(': // \z( if ((reg_do_extmatch & REX_SET) == 0) - EMSG_RET_FAIL(_(e_z_not_allowed)); + EMSG_RET_FAIL(_(e_z_not_allowed_here)); if (nfa_reg(REG_ZPAREN) == FAIL) return FAIL; // cascaded error re_has_z = REX_SET; @@ -1677,7 +1677,7 @@ nfa_regatom(void) for (n = 0; (c = peekchr()) != ']'; ++n) { if (c == NUL) - EMSG2_RET_FAIL(_(e_missing_sb), + EMSG2_RET_FAIL(_(e_missing_sb_after_str), reg_magic == MAGIC_ALL); // recursive call! if (nfa_regatom() == FAIL) @@ -1685,7 +1685,7 @@ nfa_regatom(void) } getchr(); // get the ] if (n == 0) - EMSG2_RET_FAIL(_(e_empty_sb), + EMSG2_RET_FAIL(_(e_empty_str_brackets), reg_magic == MAGIC_ALL); EMIT(NFA_OPT_CHARS); EMIT(n); diff --git a/src/register.c b/src/register.c index d225d7789a..6a4bc2cc1a 100644 --- a/src/register.c +++ b/src/register.c @@ -2836,7 +2836,7 @@ write_reg_contents_ex( buf = buflist_findnr(num); if (buf == NULL) - semsg(_(e_nobufnr), (long)num); + semsg(_(e_buffer_nr_does_not_exist), (long)num); } else buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str), diff --git a/src/session.c b/src/session.c index 9d274a9d01..8a6839383a 100644 --- a/src/session.c +++ b/src/session.c @@ -1339,7 +1339,7 @@ ex_mkrc(exarg_T *eap) failed |= fclose(fd); if (failed) - emsg(_(e_write)); + emsg(_(e_error_while_writing)); #if defined(FEAT_SESSION) else if (eap->cmdidx == CMD_mksession) { diff --git a/src/sign.c b/src/sign.c index a4c89679b4..e358ee9752 100644 --- a/src/sign.c +++ b/src/sign.c @@ -1078,13 +1078,28 @@ sign_define_by_name( return FAIL; if (linehl != NULL) - sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl)); + { + if (*linehl == NUL) + sp->sn_line_hl = 0; + else + sp->sn_line_hl = syn_check_group(linehl, (int)STRLEN(linehl)); + } if (texthl != NULL) - sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl)); + { + if (*texthl == NUL) + sp->sn_text_hl = 0; + else + sp->sn_text_hl = syn_check_group(texthl, (int)STRLEN(texthl)); + } if (culhl != NULL) - sp->sn_cul_hl = syn_check_group(culhl, (int)STRLEN(culhl)); + { + if (*culhl == NUL) + sp->sn_cul_hl = 0; + else + sp->sn_cul_hl = syn_check_group(culhl, (int)STRLEN(culhl)); + } return OK; } @@ -1308,7 +1323,7 @@ sign_define_cmd(char_u *sign_name, char_u *cmdline) char_u *linehl = NULL; char_u *texthl = NULL; char_u *culhl = NULL; - int failed = FALSE; + int failed = FALSE; // set values for a defined sign. for (;;) diff --git a/src/spell.c b/src/spell.c index f472f99326..9b2d3e89f6 100644 --- a/src/spell.c +++ b/src/spell.c @@ -3830,7 +3830,7 @@ ex_spelldump(exarg_T *eap) if (no_spell_checking(curwin)) return; - (void)get_option_value((char_u*)"spl", &dummy, &spl, OPT_LOCAL); + (void)get_option_value((char_u*)"spl", &dummy, &spl, NULL, OPT_LOCAL); // Create a new empty buffer in a new window. do_cmdline_cmd((char_u *)"new"); diff --git a/src/spellfile.c b/src/spellfile.c index 0d7b194aa5..6d6c248ab0 100644 --- a/src/spellfile.c +++ b/src/spellfile.c @@ -5259,7 +5259,7 @@ theend: if (fwv != (size_t)1) retval = FAIL; if (retval == FAIL) - emsg(_(e_write)); + emsg(_(e_error_while_writing)); return retval; } @@ -5404,7 +5404,7 @@ put_node( if (fd != NULL) if (putc(np->wn_byte, fd) == EOF) // or { - emsg(_(e_write)); + emsg(_(e_error_while_writing)); return 0; } } @@ -5815,7 +5815,7 @@ sug_write(spellinfo_T *spin, char_u *fname) */ if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) // { - emsg(_(e_write)); + emsg(_(e_error_while_writing)); goto theend; } putc(VIMSUGVERSION, fd); // @@ -5857,7 +5857,7 @@ sug_write(spellinfo_T *spin, char_u *fname) len = (int)STRLEN(line) + 1; if (fwrite(line, (size_t)len, (size_t)1, fd) == 0) { - emsg(_(e_write)); + emsg(_(e_error_while_writing)); goto theend; } spin->si_memtot += len; @@ -5865,7 +5865,7 @@ sug_write(spellinfo_T *spin, char_u *fname) // Write another byte to check for errors. if (putc(0, fd) == EOF) - emsg(_(e_write)); + emsg(_(e_error_while_writing)); vim_snprintf((char *)IObuff, IOSIZE, _("Estimated runtime memory use: %d bytes"), spin->si_memtot); diff --git a/src/structs.h b/src/structs.h index 51eebe38e6..3636131017 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2879,7 +2879,9 @@ struct file_buffer #endif #ifdef FEAT_COMPL_FUNC char_u *b_p_cfu; // 'completefunc' + callback_T b_cfu_cb; // 'completefunc' callback char_u *b_p_ofu; // 'omnifunc' + callback_T b_ofu_cb; // 'omnifunc' callback #endif #ifdef FEAT_EVAL char_u *b_p_tfu; // 'tagfunc' option value @@ -2985,6 +2987,7 @@ struct file_buffer char_u *b_p_tsr; // 'thesaurus' local value #ifdef FEAT_COMPL_FUNC char_u *b_p_tsrfu; // 'thesaurusfunc' local value + callback_T b_tsrfu_cb; // 'thesaurusfunc' callback #endif long b_p_ul; // 'undolevels' local value #ifdef FEAT_PERSISTENT_UNDO diff --git a/src/tag.c b/src/tag.c index c0601e8806..f932934769 100644 --- a/src/tag.c +++ b/src/tag.c @@ -115,7 +115,7 @@ static callback_T tfu_cb; // 'tagfunc' callback function * a function (string), or function() or funcref() or a lambda. */ int -set_tagfunc_option() +set_tagfunc_option(void) { #ifdef FEAT_EVAL free_callback(&tfu_cb); @@ -148,7 +148,7 @@ free_tagfunc_option(void) * callback for 'buf'. */ void -buf_set_tfu_callback(buf_T *buf UNUSED) +set_buflocal_tfu_callback(buf_T *buf UNUSED) { #ifdef FEAT_EVAL free_callback(&buf->b_tfu_cb); @@ -350,7 +350,7 @@ do_tag( tagstacklen == 0) { // empty stack - emsg(_(e_tagstack)); + emsg(_(e_tag_stack_empty)); goto end_do_tag; } diff --git a/src/term.c b/src/term.c index fae5b08a87..349d00a862 100644 --- a/src/term.c +++ b/src/term.c @@ -5418,6 +5418,8 @@ check_termcode( if (STRNCMP(termcodes[idx].code, tp, (size_t)(slen > len ? len : slen)) == 0) { + int looks_like_mouse_start = FALSE; + if (len < slen) // got a partial sequence return -1; // need to get more chars @@ -5440,15 +5442,48 @@ check_termcode( } } - // The mouse termcode "ESC [" is also the prefix of - // "ESC [ I" (focus gained). Only use it when there is - // no other match. Do use it when a digit is following to - // avoid waiting for more bytes. if (slen == 2 && len > 2 && termcodes[idx].code[0] == ESC - && termcodes[idx].code[1] == '[' - && !isdigit(tp[2])) + && termcodes[idx].code[1] == '[') { + // The mouse termcode "ESC [" is also the prefix of + // "ESC [ I" (focus gained) and other keys. Check some + // more bytes to find out. + if (!isdigit(tp[2])) + { + // ESC [ without number following: Only use it when + // there is no other match. + looks_like_mouse_start = TRUE; + } + else if (termcodes[idx].name[0] == KS_DEC_MOUSE) + { + char_u *nr = tp + 2; + int count = 0; + + // If a digit is following it could be a key with + // modifier, e.g., ESC [ 1;2P. Can be confused + // with DEC_MOUSE, which requires four numbers + // following. If not then it can't be a DEC_MOUSE + // code. + for (;;) + { + ++count; + (void)getdigits(&nr); + if (nr >= tp + len) + return -1; // partial sequence + if (*nr != ';') + break; + ++nr; + if (nr >= tp + len) + return -1; // partial sequence + } + if (count < 4) + continue; // no match + } + } + if (looks_like_mouse_start) + { + // Only use it when there is no other match. if (mouse_index_found < 0) mouse_index_found = idx; } @@ -5992,7 +6027,7 @@ replace_termcodes( if (STRNICMP(src, "", 5) == 0) { if (current_sctx.sc_sid <= 0) - emsg(_(e_usingsid)); + emsg(_(e_using_sid_not_in_script_context)); else { src += 5; @@ -6188,9 +6223,10 @@ gather_termleader(void) /* * Show all termcodes (for ":set termcap") * This code looks a lot like showoptions(), but is different. + * "flags" can have OPT_ONECOLUMN. */ void -show_termcodes(void) +show_termcodes(int flags) { int col; int *items; @@ -6215,12 +6251,13 @@ show_termcodes(void) msg_puts_title(_("\n--- Terminal keys ---")); /* - * do the loop two times: + * Do the loop three times: * 1. display the short items (non-strings and short strings) * 2. display the medium items (medium length strings) * 3. display the long items (remaining strings) + * When "flags" has OPT_ONECOLUMN do everything in 3. */ - for (run = 1; run <= 3 && !got_int; ++run) + for (run = (flags & OPT_ONECOLUMN) ? 3 : 1; run <= 3 && !got_int; ++run) { /* * collect the items in items[] @@ -6230,9 +6267,10 @@ show_termcodes(void) { len = show_one_termcode(termcodes[i].name, termcodes[i].code, FALSE); - if (len <= INC3 - GAP ? run == 1 + if ((flags & OPT_ONECOLUMN) || + (len <= INC3 - GAP ? run == 1 : len <= INC2 - GAP ? run == 2 - : run == 3) + : run == 3)) items[item_count++] = i; } diff --git a/src/testdir/test_autochdir.vim b/src/testdir/test_autochdir.vim index f6cc148326..861db7247a 100644 --- a/src/testdir/test_autochdir.vim +++ b/src/testdir/test_autochdir.vim @@ -25,6 +25,32 @@ func Test_set_filename() call delete('samples/Xtest') endfunc +func Test_set_filename_other_window() + let cwd = getcwd() + call test_autochdir() + call mkdir('Xa') + call mkdir('Xb') + call mkdir('Xc') + try + args Xa/aaa.txt Xb/bbb.txt + set acd + let winid = win_getid() + snext + call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', '')) + call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt') + call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', '')) + finally + set noacd + call chdir(cwd) + bwipe! aaa.txt + bwipe! bbb.txt + bwipe! ccc.txt + call delete('Xa', 'rf') + call delete('Xb', 'rf') + call delete('Xc', 'rf') + endtry +endfunc + func Test_verbose_pwd() let cwd = getcwd() call test_autochdir() @@ -53,6 +79,8 @@ func Test_verbose_pwd() set noacd call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd')) wincmd w + call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd')) + execute 'cd' cwd call assert_match('\[global\].*testdir', execute('verbose pwd')) wincmd w call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd')) diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim index 473886d68e..bd816af4a5 100644 --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -675,7 +675,10 @@ func Test_list2blob() let b = range(16)->repeat(64)->list2blob() call assert_equal(1024, b->len()) call assert_equal([4, 8, 15], [b[100], b[1000], b[1023]]) + call assert_equal(0z, list2blob(test_null_list())) + call assert_equal(0z00010203, list2blob(range(4))) endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim index 81ed491ea5..566e9f6ba6 100644 --- a/src/testdir/test_cd.vim +++ b/src/testdir/test_cd.vim @@ -226,6 +226,8 @@ func Test_cd_unknown_dir() endfunc func Test_getcwd_actual_dir() + CheckOption autochdir + let startdir = getcwd() call mkdir('Xactual') call test_autochdir() diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index 1ca5062328..7031115fcb 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -121,6 +121,19 @@ func Test_open_command() close! endfunc +func Test_open_command_flush_line() + " this was accessing freed memory: the regexp match uses a pointer to the + " current line which becomes invalid when searching for the ') mark. + new + call setline(1, ['one', 'two. three']) + s/one/ONE + try + open /\%')/ + catch /E479/ + endtry + bwipe! +endfunc + " Test for :g/pat/visual to run vi commands in Ex mode " This used to hang Vim before 8.2.0274. func Test_Ex_global() diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index f1966f43e6..c47f99d218 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -340,7 +340,7 @@ let s:filename_checks = { \ 'msql': ['file.msql'], \ 'mupad': ['file.mu'], \ 'mush': ['file.mush'], - \ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'], + \ 'muttrc': ['Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'], \ 'mysql': ['file.mysql'], \ 'n1ql': ['file.n1ql', 'file.nql'], \ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'], @@ -477,6 +477,7 @@ let s:filename_checks = { \ 'sqlj': ['file.sqlj'], \ 'sqr': ['file.sqr', 'file.sqi'], \ 'squid': ['squid.conf'], + \ 'squirrel': ['file.nut'], \ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'], \ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config'], \ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'], @@ -502,7 +503,7 @@ let s:filename_checks = { \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'], \ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'], \ 'texmf': ['texmf.cnf'], - \ 'text': ['file.text', 'README', '/usr/share/doc/bash-completion/AUTHORS'], + \ 'text': ['file.text', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'], \ 'tf': ['file.tf', '.tfrc', 'tfrc'], \ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'], \ 'tilde': ['file.t.html'], diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim index ba8f45b980..3077a718e4 100644 --- a/src/testdir/test_iminsert.vim +++ b/src/testdir/test_iminsert.vim @@ -2,6 +2,7 @@ source view_util.vim source check.vim +source vim9.vim let s:imactivatefunc_called = 0 let s:imstatusfunc_called = 0 @@ -109,4 +110,166 @@ func Test_iminsert_toggle() close! endfunc +" Test for different ways of setting the 'imactivatefunc' and 'imstatusfunc' +" options +func Test_imactivatefunc_imstatusfunc_callback() + CheckNotMSWindows + if has('gui_macvim') + CheckNotGui + endif + func IMactivatefunc1(active) + let g:IMactivatefunc_called += 1 + endfunc + func IMstatusfunc1() + let g:IMstatusfunc_called += 1 + return 1 + endfunc + let g:IMactivatefunc_called = 0 + let g:IMstatusfunc_called = 0 + set iminsert=2 + + " Test for using a function() + set imactivatefunc=function('IMactivatefunc1') + set imstatusfunc=function('IMstatusfunc1') + normal! i + + " Using a funcref variable to set 'completefunc' + let Fn1 = function('IMactivatefunc1') + let &imactivatefunc = Fn1 + let Fn2 = function('IMstatusfunc1') + let &imstatusfunc = Fn2 + normal! i + + " Using a string(funcref variable) to set 'completefunc' + let &imactivatefunc = string(Fn1) + let &imstatusfunc = string(Fn2) + normal! i + + " Test for using a funcref() + set imactivatefunc=funcref('IMactivatefunc1') + set imstatusfunc=funcref('IMstatusfunc1') + normal! i + + " Using a funcref variable to set 'imactivatefunc' + let Fn1 = funcref('IMactivatefunc1') + let &imactivatefunc = Fn1 + let Fn2 = funcref('IMstatusfunc1') + let &imstatusfunc = Fn2 + normal! i + + " Using a string(funcref variable) to set 'imactivatefunc' + let &imactivatefunc = string(Fn1) + let &imstatusfunc = string(Fn2) + normal! i + + " Test for using a lambda function + set imactivatefunc={a\ ->\ IMactivatefunc1(a)} + set imstatusfunc={\ ->\ IMstatusfunc1()} + normal! i + + " Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression + let &imactivatefunc = {a -> IMactivatefunc1(a)} + let &imstatusfunc = { -> IMstatusfunc1()} + normal! i + + " Set 'imactivatefunc' and 'imstatusfunc' to a string(lambda expression) + let &imactivatefunc = '{a -> IMactivatefunc1(a)}' + let &imstatusfunc = '{ -> IMstatusfunc1()}' + normal! i + + " Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda expression + let Lambda1 = {a -> IMactivatefunc1(a)} + let Lambda2 = { -> IMstatusfunc1()} + let &imactivatefunc = Lambda1 + let &imstatusfunc = Lambda2 + normal! i + + " Set 'imactivatefunc' 'imstatusfunc' to a string(variable with a lambda + " expression) + let &imactivatefunc = string(Lambda1) + let &imstatusfunc = string(Lambda2) + normal! i + + " Test for clearing the 'completefunc' option + set imactivatefunc='' imstatusfunc='' + set imactivatefunc& imstatusfunc& + + call assert_fails("set imactivatefunc=function('abc')", "E700:") + call assert_fails("set imstatusfunc=function('abc')", "E700:") + call assert_fails("set imactivatefunc=funcref('abc')", "E700:") + call assert_fails("set imstatusfunc=funcref('abc')", "E700:") + + call assert_equal(11, g:IMactivatefunc_called) + call assert_equal(22, g:IMstatusfunc_called) + + " Vim9 tests + let lines =<< trim END + vim9script + + # Test for using function() + def IMactivatefunc1(active: number): any + g:IMactivatefunc_called += 1 + return 1 + enddef + def IMstatusfunc1(): number + g:IMstatusfunc_called += 1 + return 1 + enddef + g:IMactivatefunc_called = 0 + g:IMstatusfunc_called = 0 + set iminsert=2 + set imactivatefunc=function('IMactivatefunc1') + set imstatusfunc=function('IMstatusfunc1') + normal! i + + # Test for using a lambda + &imactivatefunc = '(a) => IMactivatefunc1(a)' + &imstatusfunc = '() => IMstatusfunc1()' + normal! i + + # Test for using a variable with a lambda expression + var Fn1: func = (active) => { + g:IMactivatefunc_called += 1 + return 1 + } + var Fn2: func = () => { + g:IMstatusfunc_called += 1 + return 1 + } + &imactivatefunc = Fn1 + &imstatusfunc = Fn2 + normal! i + + # Test for using a string(variable with a lambda expression) + &imactivatefunc = string(Fn1) + &imstatusfunc = string(Fn2) + normal! i + + assert_equal(4, g:IMactivatefunc_called) + assert_equal(8, g:IMstatusfunc_called) + + set iminsert=0 + set imactivatefunc= + set imstatusfunc= + END + call CheckScriptSuccess(lines) + + " Using Vim9 lambda expression in legacy context should fail + set imactivatefunc=(a)\ =>\ IMactivatefunc1(a) + set imstatusfunc=IMstatusfunc1 + call assert_fails('normal! i', 'E117:') + set imactivatefunc=IMactivatefunc1 + set imstatusfunc=()\ =>\ IMstatusfunc1(a) + call assert_fails('normal! i', 'E117:') + + " cleanup + delfunc IMactivatefunc1 + delfunc IMstatusfunc1 + set iminsert=0 + set imactivatefunc= + set imstatusfunc= + + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_indent.vim b/src/testdir/test_indent.vim index a01b066b23..f96da6969b 100644 --- a/src/testdir/test_indent.vim +++ b/src/testdir/test_indent.vim @@ -172,7 +172,8 @@ func Test_indent_func_with_gq() \ 'metus lectus ultrices odio, sed elementum mi ante at arcu.', '', '\begin{center}', '', \ 'Proin nec risus consequat nunc dapibus consectetur. Mauris lacinia est a augue', \ 'tristique accumsan. Morbi pretium, felis molestie eleifend condimentum, arcu', - \ 'ipsum congue nisl, quis euismod purus libero in ante. Donec id semper purus.', + \ 'ipsum congue nisl, quis euismod purus libero in ante.', '', + \ 'Donec id semper purus.', \ 'Suspendisse eget aliquam nunc. Maecenas fringilla mauris vitae maximus', \ 'condimentum. Cras a quam in mi dictum eleifend at a lorem. Sed convallis', \ 'ante a commodo facilisis. Nam suscipit vulputate odio, vel dapibus nisl', @@ -181,10 +182,10 @@ func Test_indent_func_with_gq() 1d_ call cursor(5, 1) ka - call cursor(15, 1) + call cursor(14, 1) kb norm! 'agqap - norm! 'bgqap + norm! 'bgqG let expected = [ '\documentclass{article}', '', '\begin{document}', '', \ 'Lorem ipsum dolor sit amet, consectetur adipiscing', \ 'elit. Fusce ut enim non libero efficitur aliquet.', @@ -201,9 +202,10 @@ func Test_indent_func_with_gq() \ ' consectetur. Mauris lacinia est a augue', \ ' tristique accumsan. Morbi pretium, felis', \ ' molestie eleifend condimentum, arcu ipsum congue', - \ ' nisl, quis euismod purus libero in ante. Donec', - \ ' id semper purus. Suspendisse eget aliquam nunc.', - \ ' Maecenas fringilla mauris vitae maximus', + \ ' nisl, quis euismod purus libero in ante.', + \ '', + \ ' Donec id semper purus. Suspendisse eget aliquam', + \ ' nunc. Maecenas fringilla mauris vitae maximus', \ ' condimentum. Cras a quam in mi dictum eleifend', \ ' at a lorem. Sed convallis ante a commodo', \ ' facilisis. Nam suscipit vulputate odio, vel', @@ -217,4 +219,28 @@ func Test_indent_func_with_gq() delfunction GetTeXIndent endfu +func Test_formatting_keeps_first_line_indent() + let lines =<< trim END + foo() + { + int x; // manually positioned + // more text that will be formatted + // but not reindented + END + new + call setline(1, lines) + setlocal sw=4 cindent tw=45 et + normal! 4Ggqj + let expected =<< trim END + foo() + { + int x; // manually positioned + // more text that will be + // formatted but not + // reindented + END + call assert_equal(expected, getline(1, '$')) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 3d6271a42c..d508ba087f 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -2,6 +2,7 @@ source screendump.vim source check.vim +source vim9.vim " Test for insert expansion func Test_ins_complete() @@ -867,4 +868,668 @@ func Test_z1_complete_no_history() close! endfunc +" Test for different ways of setting the 'completefunc' option +func Test_completefunc_callback() + " Test for using a function() + func MycompleteFunc1(findstart, base) + call add(g:MycompleteFunc1_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set completefunc=function('MycompleteFunc1') + new | only + call setline(1, 'one') + let g:MycompleteFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'one']], g:MycompleteFunc1_args) + bw! + + " Using a funcref variable to set 'completefunc' + let Fn = function('MycompleteFunc1') + let &completefunc = Fn + new | only + call setline(1, 'two') + let g:MycompleteFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MycompleteFunc1_args) + bw! + + " Using string(funcref_variable) to set 'completefunc' + let Fn = function('MycompleteFunc1') + let &completefunc = string(Fn) + new | only + call setline(1, 'two') + let g:MycompleteFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MycompleteFunc1_args) + bw! + + " Test for using a funcref() + func MycompleteFunc2(findstart, base) + call add(g:MycompleteFunc2_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set completefunc=funcref('MycompleteFunc2') + new | only + call setline(1, 'three') + let g:MycompleteFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'three']], g:MycompleteFunc2_args) + bw! + + " Using a funcref variable to set 'completefunc' + let Fn = funcref('MycompleteFunc2') + let &completefunc = Fn + new | only + call setline(1, 'four') + let g:MycompleteFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MycompleteFunc2_args) + bw! + + " Using a string(funcref_variable) to set 'completefunc' + let Fn = funcref('MycompleteFunc2') + let &completefunc = string(Fn) + new | only + call setline(1, 'four') + let g:MycompleteFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MycompleteFunc2_args) + bw! + + " Test for using a lambda function + func MycompleteFunc3(findstart, base) + call add(g:MycompleteFunc3_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set completefunc={a,\ b\ ->\ MycompleteFunc3(a,\ b)} + new | only + call setline(1, 'five') + let g:MycompleteFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'five']], g:MycompleteFunc3_args) + bw! + + " Set 'completefunc' to a lambda expression + let &completefunc = {a, b -> MycompleteFunc3(a, b)} + new | only + call setline(1, 'six') + let g:MycompleteFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MycompleteFunc3_args) + bw! + + " Set 'completefunc' to string(lambda_expression) + let &completefunc = '{a, b -> MycompleteFunc3(a, b)}' + new | only + call setline(1, 'six') + let g:MycompleteFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MycompleteFunc3_args) + bw! + + " Set 'completefunc' to a variable with a lambda expression + let Lambda = {a, b -> MycompleteFunc3(a, b)} + let &completefunc = Lambda + new | only + call setline(1, 'seven') + let g:MycompleteFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MycompleteFunc3_args) + bw! + + " Set 'completefunc' to a string(variable with a lambda expression) + let Lambda = {a, b -> MycompleteFunc3(a, b)} + let &completefunc = string(Lambda) + new | only + call setline(1, 'seven') + let g:MycompleteFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MycompleteFunc3_args) + bw! + + " Test for using a lambda function with incorrect return value + let Lambda = {s -> strlen(s)} + let &completefunc = Lambda + new | only + call setline(1, 'eight') + call feedkeys("A\\\", 'x') + bw! + + " Test for clearing the 'completefunc' option + set completefunc='' + set completefunc& + + call assert_fails("set completefunc=function('abc')", "E700:") + call assert_fails("set completefunc=funcref('abc')", "E700:") + let &completefunc = {a -> 'abc'} + call feedkeys("A\\\", 'x') + + " Vim9 tests + let lines =<< trim END + vim9script + + # Test for using function() + def MycompleteFunc1(findstart: number, base: string): any + add(g:MycompleteFunc1_args, [findstart, base]) + return findstart ? 0 : [] + enddef + set completefunc=function('MycompleteFunc1') + new | only + setline(1, 'one') + g:MycompleteFunc1_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'one']], g:MycompleteFunc1_args) + bw! + + # Test for using a lambda + def LambdaComplete1(findstart: number, base: string): any + add(g:LambdaComplete1_args, [findstart, base]) + return findstart ? 0 : [] + enddef + &completefunc = (a, b) => LambdaComplete1(a, b) + new | only + setline(1, 'two') + g:LambdaComplete1_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:LambdaComplete1_args) + bw! + + # Test for using a string(lambda) + &completefunc = '(a, b) => LambdaComplete1(a, b)' + new | only + setline(1, 'two') + g:LambdaComplete1_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:LambdaComplete1_args) + bw! + + # Test for using a variable with a lambda expression + var Fn: func = (findstart, base) => { + add(g:LambdaComplete2_args, [findstart, base]) + return findstart ? 0 : [] + } + &completefunc = Fn + new | only + setline(1, 'three') + g:LambdaComplete2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:LambdaComplete2_args) + bw! + + # Test for using a string(variable with a lambda expression) + &completefunc = string(Fn) + new | only + setline(1, 'three') + g:LambdaComplete2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:LambdaComplete2_args) + bw! + END + call CheckScriptSuccess(lines) + + " Using Vim9 lambda expression in legacy context should fail + set completefunc=(a,\ b)\ =>\ g:MycompleteFunc2(a,\ b) + new | only + let g:MycompleteFunc2_args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E117:') + call assert_equal([], g:MycompleteFunc2_args) + + " cleanup + delfunc MycompleteFunc1 + delfunc MycompleteFunc2 + delfunc MycompleteFunc3 + set completefunc& + %bw! +endfunc + +" Test for different ways of setting the 'omnifunc' option +func Test_omnifunc_callback() + " Test for using a function() + func MyomniFunc1(findstart, base) + call add(g:MyomniFunc1_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set omnifunc=function('MyomniFunc1') + new | only + call setline(1, 'one') + let g:MyomniFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'one']], g:MyomniFunc1_args) + bw! + + " Using a funcref variable to set 'omnifunc' + let Fn = function('MyomniFunc1') + let &omnifunc = Fn + new | only + call setline(1, 'two') + let g:MyomniFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MyomniFunc1_args) + bw! + + " Using a string(funcref_variable) to set 'omnifunc' + let Fn = function('MyomniFunc1') + let &omnifunc = string(Fn) + new | only + call setline(1, 'two') + let g:MyomniFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MyomniFunc1_args) + bw! + + " Test for using a funcref() + func MyomniFunc2(findstart, base) + call add(g:MyomniFunc2_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set omnifunc=funcref('MyomniFunc2') + new | only + call setline(1, 'three') + let g:MyomniFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'three']], g:MyomniFunc2_args) + bw! + + " Using a funcref variable to set 'omnifunc' + let Fn = funcref('MyomniFunc2') + let &omnifunc = Fn + new | only + call setline(1, 'four') + let g:MyomniFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MyomniFunc2_args) + bw! + + " Using a string(funcref_variable) to set 'omnifunc' + let Fn = funcref('MyomniFunc2') + let &omnifunc = string(Fn) + new | only + call setline(1, 'four') + let g:MyomniFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MyomniFunc2_args) + bw! + + " Test for using a lambda function + func MyomniFunc3(findstart, base) + call add(g:MyomniFunc3_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set omnifunc={a,\ b\ ->\ MyomniFunc3(a,\ b)} + new | only + call setline(1, 'five') + let g:MyomniFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'five']], g:MyomniFunc3_args) + bw! + + " Set 'omnifunc' to a lambda expression + let &omnifunc = {a, b -> MyomniFunc3(a, b)} + new | only + call setline(1, 'six') + let g:MyomniFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MyomniFunc3_args) + bw! + + " Set 'omnifunc' to a string(lambda_expression) + let &omnifunc = '{a, b -> MyomniFunc3(a, b)}' + new | only + call setline(1, 'six') + let g:MyomniFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MyomniFunc3_args) + bw! + + " Set 'omnifunc' to a variable with a lambda expression + let Lambda = {a, b -> MyomniFunc3(a, b)} + let &omnifunc = Lambda + new | only + call setline(1, 'seven') + let g:MyomniFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MyomniFunc3_args) + bw! + + " Set 'omnifunc' to a string(variable with a lambda expression) + let Lambda = {a, b -> MyomniFunc3(a, b)} + let &omnifunc = string(Lambda) + new | only + call setline(1, 'seven') + let g:MyomniFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MyomniFunc3_args) + bw! + + " Test for using a lambda function with incorrect return value + let Lambda = {s -> strlen(s)} + let &omnifunc = Lambda + new | only + call setline(1, 'eight') + call feedkeys("A\\\", 'x') + bw! + + " Test for clearing the 'omnifunc' option + set omnifunc='' + set omnifunc& + + call assert_fails("set omnifunc=function('abc')", "E700:") + call assert_fails("set omnifunc=funcref('abc')", "E700:") + let &omnifunc = {a -> 'abc'} + call feedkeys("A\\\", 'x') + + " Vim9 tests + let lines =<< trim END + vim9script + + # Test for using function() + def MyomniFunc1(findstart: number, base: string): any + add(g:MyomniFunc1_args, [findstart, base]) + return findstart ? 0 : [] + enddef + set omnifunc=function('MyomniFunc1') + new | only + setline(1, 'one') + g:MyomniFunc1_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'one']], g:MyomniFunc1_args) + bw! + + # Test for using a lambda + def MyomniFunc2(findstart: number, base: string): any + add(g:MyomniFunc2_args, [findstart, base]) + return findstart ? 0 : [] + enddef + &omnifunc = (a, b) => MyomniFunc2(a, b) + new | only + setline(1, 'two') + g:MyomniFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:MyomniFunc2_args) + bw! + + # Test for using a string(lambda) + &omnifunc = '(a, b) => MyomniFunc2(a, b)' + new | only + setline(1, 'two') + g:MyomniFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:MyomniFunc2_args) + bw! + + # Test for using a variable with a lambda expression + var Fn: func = (a, b) => MyomniFunc2(a, b) + &omnifunc = Fn + new | only + setline(1, 'three') + g:MyomniFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:MyomniFunc2_args) + bw! + + # Test for using a string(variable with a lambda expression) + &omnifunc = string(Fn) + new | only + setline(1, 'three') + g:MyomniFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:MyomniFunc2_args) + bw! + END + call CheckScriptSuccess(lines) + + " Using Vim9 lambda expression in legacy context should fail + set omnifunc=(a,\ b)\ =>\ g:MyomniFunc2(a,\ b) + new | only + let g:MyomniFunc2_args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E117:') + call assert_equal([], g:MyomniFunc2_args) + + " cleanup + delfunc MyomniFunc1 + delfunc MyomniFunc2 + delfunc MyomniFunc3 + set omnifunc& + %bw! +endfunc + +" Test for different ways of setting the 'thesaurusfunc' option +func Test_thesaurusfunc_callback() + " Test for using a function() + func MytsrFunc1(findstart, base) + call add(g:MytsrFunc1_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set thesaurusfunc=function('MytsrFunc1') + new | only + call setline(1, 'one') + let g:MytsrFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'one']], g:MytsrFunc1_args) + bw! + + " Using a funcref variable to set 'thesaurusfunc' + let Fn = function('MytsrFunc1') + let &thesaurusfunc = Fn + new | only + call setline(1, 'two') + let g:MytsrFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MytsrFunc1_args) + bw! + + " Using a string(funcref_variable) to set 'thesaurusfunc' + let Fn = function('MytsrFunc1') + let &thesaurusfunc = string(Fn) + new | only + call setline(1, 'two') + let g:MytsrFunc1_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'two']], g:MytsrFunc1_args) + bw! + + " Test for using a funcref() + func MytsrFunc2(findstart, base) + call add(g:MytsrFunc2_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set thesaurusfunc=funcref('MytsrFunc2') + new | only + call setline(1, 'three') + let g:MytsrFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'three']], g:MytsrFunc2_args) + bw! + + " Using a funcref variable to set 'thesaurusfunc' + let Fn = funcref('MytsrFunc2') + let &thesaurusfunc = Fn + new | only + call setline(1, 'four') + let g:MytsrFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MytsrFunc2_args) + bw! + + " Using a string(funcref_variable) to set 'thesaurusfunc' + let Fn = funcref('MytsrFunc2') + let &thesaurusfunc = string(Fn) + new | only + call setline(1, 'four') + let g:MytsrFunc2_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'four']], g:MytsrFunc2_args) + bw! + + " Test for using a lambda function + func MytsrFunc3(findstart, base) + call add(g:MytsrFunc3_args, [a:findstart, a:base]) + return a:findstart ? 0 : [] + endfunc + set thesaurusfunc={a,\ b\ ->\ MytsrFunc3(a,\ b)} + new | only + call setline(1, 'five') + let g:MytsrFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'five']], g:MytsrFunc3_args) + bw! + + " Set 'thesaurusfunc' to a lambda expression + let &thesaurusfunc = {a, b -> MytsrFunc3(a, b)} + new | only + call setline(1, 'six') + let g:MytsrFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MytsrFunc3_args) + bw! + + " Set 'thesaurusfunc' to a string(lambda expression) + let &thesaurusfunc = '{a, b -> MytsrFunc3(a, b)}' + new | only + call setline(1, 'six') + let g:MytsrFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'six']], g:MytsrFunc3_args) + bw! + + " Set 'thesaurusfunc' to a variable with a lambda expression + let Lambda = {a, b -> MytsrFunc3(a, b)} + let &thesaurusfunc = Lambda + new | only + call setline(1, 'seven') + let g:MytsrFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MytsrFunc3_args) + bw! + + " Set 'thesaurusfunc' to a string(variable with a lambda expression) + let Lambda = {a, b -> MytsrFunc3(a, b)} + let &thesaurusfunc = string(Lambda) + new | only + call setline(1, 'seven') + let g:MytsrFunc3_args = [] + call feedkeys("A\\\", 'x') + call assert_equal([[1, ''], [0, 'seven']], g:MytsrFunc3_args) + bw! + + " Test for using a lambda function with incorrect return value + let Lambda = {s -> strlen(s)} + let &thesaurusfunc = Lambda + new | only + call setline(1, 'eight') + call feedkeys("A\\\", 'x') + bw! + + " Test for clearing the 'thesaurusfunc' option + set thesaurusfunc='' + set thesaurusfunc& + + call assert_fails("set thesaurusfunc=function('abc')", "E700:") + call assert_fails("set thesaurusfunc=funcref('abc')", "E700:") + let &thesaurusfunc = {a -> 'abc'} + call feedkeys("A\\\", 'x') + + " Vim9 tests + let lines =<< trim END + vim9script + + # Test for using function() + def MytsrFunc1(findstart: number, base: string): any + add(g:MytsrFunc1_args, [findstart, base]) + return findstart ? 0 : [] + enddef + set thesaurusfunc=function('MytsrFunc1') + new | only + setline(1, 'one') + g:MytsrFunc1_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'one']], g:MytsrFunc1_args) + bw! + + # Test for using a lambda + def MytsrFunc2(findstart: number, base: string): any + add(g:MytsrFunc2_args, [findstart, base]) + return findstart ? 0 : [] + enddef + &thesaurusfunc = (a, b) => MytsrFunc2(a, b) + new | only + setline(1, 'two') + g:MytsrFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:MytsrFunc2_args) + bw! + + # Test for using a string(lambda) + &thesaurusfunc = '(a, b) => MytsrFunc2(a, b)' + new | only + setline(1, 'two') + g:MytsrFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'two']], g:MytsrFunc2_args) + bw! + + # Test for using a variable with a lambda expression + var Fn: func = (a, b) => MytsrFunc2(a, b) + &thesaurusfunc = Fn + new | only + setline(1, 'three') + g:MytsrFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:MytsrFunc2_args) + bw! + + # Test for using a string(variable with a lambda expression) + &thesaurusfunc = string(Fn) + new | only + setline(1, 'three') + g:MytsrFunc2_args = [] + feedkeys("A\\\", 'x') + assert_equal([[1, ''], [0, 'three']], g:MytsrFunc2_args) + bw! + END + call CheckScriptSuccess(lines) + + " Using Vim9 lambda expression in legacy context should fail + set thesaurusfunc=(a,\ b)\ =>\ g:MytsrFunc2(a,\ b) + new | only + let g:MytsrFunc2_args = [] + call assert_fails('call feedkeys("A\\\", "x")', 'E117:') + call assert_equal([], g:MytsrFunc2_args) + bw! + + " Use a buffer-local value and a global value + func MytsrFunc4(findstart, base) + call add(g:MytsrFunc4_args, [a:findstart, a:base]) + return a:findstart ? 0 : ['sunday'] + endfunc + set thesaurusfunc& + setlocal thesaurusfunc=function('MytsrFunc4') + call setline(1, 'sun') + let g:MytsrFunc4_args = [] + call feedkeys("A\\\", "x") + call assert_equal('sunday', getline(1)) + call assert_equal([[1, ''], [0, 'sun']], g:MytsrFunc4_args) + new + call setline(1, 'sun') + let g:MytsrFunc4_args = [] + call feedkeys("A\\\", "x") + call assert_equal('sun', getline(1)) + call assert_equal([], g:MytsrFunc4_args) + set thesaurusfunc=function('MytsrFunc1') + wincmd w + call setline(1, 'sun') + let g:MytsrFunc4_args = [] + call feedkeys("A\\\", "x") + call assert_equal('sunday', getline(1)) + call assert_equal([[1, ''], [0, 'sun']], g:MytsrFunc4_args) + + " cleanup + set thesaurusfunc& + delfunc MytsrFunc1 + delfunc MytsrFunc2 + delfunc MytsrFunc3 + delfunc MytsrFunc4 + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index 2bcdb744ac..1b602dfbe6 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -136,6 +136,12 @@ func Test_path_keep_commas() set path& endfunc +func Test_path_too_long() + exe 'set path=' .. repeat('x', 10000) + call assert_fails('find x', 'E854:') + set path& +endfunc + func Test_signcolumn() CheckFeature signs call assert_equal("auto", &signcolumn) diff --git a/src/testdir/test_set.vim b/src/testdir/test_set.vim index 7215772a00..f38ac334cd 100644 --- a/src/testdir/test_set.vim +++ b/src/testdir/test_set.vim @@ -1,5 +1,7 @@ " Tests for the :set command +source check.vim + function Test_set_backslash() let isk_save = &isk @@ -45,4 +47,32 @@ func Test_set_no_arg() setglobal textwidth& endfunc +func Test_set_termcap() + CheckNotGui + + let lines = split(execute('set termcap'), "\n") + call assert_match('--- Terminal codes ---', lines[0]) + " four columns + call assert_match('t_..=.*t_..=.*t_..=.*t_..=', lines[1]) + + for keys_idx in range(len(lines)) + if lines[keys_idx] =~ '--- Terminal keys ---' + break + endif + endfor + call assert_true(keys_idx < len(lines)) + " three columns + call assert_match('<[^>]*> .*<[^>]*> .*<[^>]*> ', lines[keys_idx + 1]) + + let more_lines = split(execute('set! termcap'), "\n") + for i in range(len(more_lines)) + if more_lines[i] =~ '--- Terminal keys ---' + break + endif + endfor + call assert_true(i < len(more_lines)) + call assert_true(i > keys_idx) + call assert_true(len(more_lines) - i > len(lines) - keys_idx) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim index 80f7160b10..a1ffdf5cfd 100644 --- a/src/testdir/test_signs.vim +++ b/src/testdir/test_signs.vim @@ -126,6 +126,30 @@ func Test_sign() call assert_fails("sign define Sign4 text= linehl=Comment", 'E239:') call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:') + " an empty highlight argument for an existing sign clears it + sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl + let sl = sign_getdefined('SignY')[0] + call assert_equal('TextHl', sl.texthl) + call assert_equal('CulHl', sl.culhl) + call assert_equal('LineHl', sl.linehl) + + sign define SignY texthl= culhl=CulHl linehl=LineHl + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'texthl')) + call assert_equal('CulHl', sl.culhl) + call assert_equal('LineHl', sl.linehl) + + sign define SignY linehl= + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'linehl')) + call assert_equal('CulHl', sl.culhl) + + sign define SignY culhl= + let sl = sign_getdefined('SignY')[0] + call assert_false(has_key(sl, 'culhl')) + + sign undefine SignY + " define sign with whitespace sign define Sign4 text=\ X linehl=Comment sign undefine Sign4 diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim index b7437fd448..3c32450c24 100644 --- a/src/testdir/test_spell.vim +++ b/src/testdir/test_spell.vim @@ -267,6 +267,11 @@ func Test_spellsuggest() call assert_equal(['Third'], spellsuggest('THird', 1)) call assert_equal(['All'], spellsuggest('ALl', 1)) + " Special suggestion for repeated 'the the'. + call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the')) + call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the')) + call assert_inrange(0, 2, index(spellsuggest('The the', 3), 'The')) + call assert_fails("call spellsuggest('maxch', [])", 'E745:') call assert_fails("call spellsuggest('maxch', 2, [])", 'E745:') diff --git a/src/testdir/test_tagfunc.vim b/src/testdir/test_tagfunc.vim index e29e08edc1..7f16fb25e5 100644 --- a/src/testdir/test_tagfunc.vim +++ b/src/testdir/test_tagfunc.vim @@ -119,6 +119,12 @@ func Test_tagfunc_settagstack() delfunc Mytagfunc2 endfunc +" Script local tagfunc callback function +func s:ScriptLocalTagFunc(pat, flags, info) + let g:ScriptLocalFuncArgs = [a:pat, a:flags, a:info] + return v:null +endfunc + " Test for different ways of setting the 'tagfunc' option func Test_tagfunc_callback() " Test for using a function() @@ -134,12 +140,19 @@ func Test_tagfunc_callback() " Using a funcref variable to set 'tagfunc' let Fn = function('MytagFunc1') + let &tagfunc = Fn + new | only + let g:MytagFunc1_args = [] + call assert_fails('tag a12', 'E433:') + call assert_equal(['a12', '', {}], g:MytagFunc1_args) + + " Using a string(funcref_variable) to set 'tagfunc' + let Fn = function('MytagFunc1') let &tagfunc = string(Fn) new | only let g:MytagFunc1_args = [] call assert_fails('tag a12', 'E433:') call assert_equal(['a12', '', {}], g:MytagFunc1_args) - call assert_fails('let &tagfunc = Fn', 'E729:') " Test for using a funcref() func MytagFunc2(pat, flags, info) @@ -154,12 +167,42 @@ func Test_tagfunc_callback() " Using a funcref variable to set 'tagfunc' let Fn = funcref('MytagFunc2') + let &tagfunc = Fn + new | only + let g:MytagFunc2_args = [] + call assert_fails('tag a14', 'E433:') + call assert_equal(['a14', '', {}], g:MytagFunc2_args) + + " Using a string(funcref_variable) to set 'tagfunc' + let Fn = funcref('MytagFunc2') let &tagfunc = string(Fn) new | only let g:MytagFunc2_args = [] call assert_fails('tag a14', 'E433:') call assert_equal(['a14', '', {}], g:MytagFunc2_args) - call assert_fails('let &tagfunc = Fn', 'E729:') + + " Test for using a script local function + set tagfunc=ScriptLocalTagFunc + new | only + let g:ScriptLocalFuncArgs = [] + call assert_fails('tag a15', 'E433:') + call assert_equal(['a15', '', {}], g:ScriptLocalFuncArgs) + + " Test for using a script local funcref variable + let Fn = function("s:ScriptLocalTagFunc") + let &tagfunc= Fn + new | only + let g:ScriptLocalFuncArgs = [] + call assert_fails('tag a16', 'E433:') + call assert_equal(['a16', '', {}], g:ScriptLocalFuncArgs) + + " Test for using a string(script local funcref variable) + let Fn = function("s:ScriptLocalTagFunc") + let &tagfunc= string(Fn) + new | only + let g:ScriptLocalFuncArgs = [] + call assert_fails('tag a16', 'E433:') + call assert_equal(['a16', '', {}], g:ScriptLocalFuncArgs) " Test for using a lambda function func MytagFunc3(pat, flags, info) @@ -169,30 +212,44 @@ func Test_tagfunc_callback() set tagfunc={a,\ b,\ c\ ->\ MytagFunc3(a,\ b,\ c)} new | only let g:MytagFunc3_args = [] - call assert_fails('tag a15', 'E433:') - call assert_equal(['a15', '', {}], g:MytagFunc3_args) + call assert_fails('tag a17', 'E433:') + call assert_equal(['a17', '', {}], g:MytagFunc3_args) " Set 'tagfunc' to a lambda expression + let &tagfunc = {a, b, c -> MytagFunc3(a, b, c)} + new | only + let g:MytagFunc3_args = [] + call assert_fails('tag a18', 'E433:') + call assert_equal(['a18', '', {}], g:MytagFunc3_args) + + " Set 'tagfunc' to a string(lambda expression) let &tagfunc = '{a, b, c -> MytagFunc3(a, b, c)}' new | only let g:MytagFunc3_args = [] - call assert_fails('tag a16', 'E433:') - call assert_equal(['a16', '', {}], g:MytagFunc3_args) + call assert_fails('tag a18', 'E433:') + call assert_equal(['a18', '', {}], g:MytagFunc3_args) " Set 'tagfunc' to a variable with a lambda expression let Lambda = {a, b, c -> MytagFunc3(a, b, c)} + let &tagfunc = Lambda + new | only + let g:MytagFunc3_args = [] + call assert_fails("tag a19", "E433:") + call assert_equal(['a19', '', {}], g:MytagFunc3_args) + + " Set 'tagfunc' to a string(variable with a lambda expression) + let Lambda = {a, b, c -> MytagFunc3(a, b, c)} let &tagfunc = string(Lambda) new | only let g:MytagFunc3_args = [] - call assert_fails("tag a17", "E433:") - call assert_equal(['a17', '', {}], g:MytagFunc3_args) - call assert_fails('let &tagfunc = Lambda', 'E729:') + call assert_fails("tag a19", "E433:") + call assert_equal(['a19', '', {}], g:MytagFunc3_args) " Test for using a lambda function with incorrect return value let Lambda = {s -> strlen(s)} let &tagfunc = string(Lambda) new | only - call assert_fails("tag a17", "E987:") + call assert_fails("tag a20", "E987:") " Test for clearing the 'tagfunc' option set tagfunc='' @@ -223,6 +280,13 @@ func Test_tagfunc_callback() g:MytagFunc2_args = [pat, flags, info] return null enddef + &tagfunc = (a, b, c) => MytagFunc2(a, b, c) + new | only + g:MytagFunc2_args = [] + assert_fails('tag a20', 'E433:') + assert_equal(['a20', '', {}], g:MytagFunc2_args) + + # Test for using a string(lambda) &tagfunc = '(a, b, c) => MytagFunc2(a, b, c)' new | only g:MytagFunc2_args = [] @@ -231,6 +295,13 @@ func Test_tagfunc_callback() # Test for using a variable with a lambda expression var Fn: func = (a, b, c) => MytagFunc2(a, b, c) + &tagfunc = Fn + new | only + g:MytagFunc2_args = [] + assert_fails('tag a30', 'E433:') + assert_equal(['a30', '', {}], g:MytagFunc2_args) + + # Test for using a variable with a lambda expression &tagfunc = string(Fn) new | only g:MytagFunc2_args = [] diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index ba02584572..614c0977d7 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -2039,6 +2039,32 @@ func Test_modifyOtherKeys_no_mapping() set timeoutlen& endfunc +" Check that when DEC mouse codes are recognized a special key is handled. +func Test_ignore_dec_mouse() + silent !infocmp gnome >/dev/null 2>&1 + if v:shell_error != 0 + throw 'Skipped: gnome entry missing in the terminfo db' + endif + + new + let save_mouse = &mouse + let save_term = &term + let save_ttymouse = &ttymouse + call test_override('no_query_mouse', 1) + set mouse=a term=gnome ttymouse= + + execute "set =\[1;*P" + nnoremap agot it + call feedkeys("\[1;2P", 'Lx!') + call assert_equal('got it', getline(1)) + + let &mouse = save_mouse + let &term = save_term + let &ttymouse = save_ttymouse + call test_override('no_query_mouse', 0) + bwipe! +endfunc + func RunTest_mapping_shift(key, func) call setline(1, '') if a:key == '|' diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 22b1896a1d..ffb2bb8138 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1019,6 +1019,11 @@ def Test_range_after_command_modifier() CheckScriptSuccess(['vim9script', 'silent keepjump :1d _']) assert_equal('', getline(1)) bwipe! + + var lines =<< trim END + legacy /pat/ + END + CheckDefExecAndScriptFailure(lines, 'E486: Pattern not found: pat') enddef def Test_silent_pattern() diff --git a/src/testdir/test_vim9_fails.vim b/src/testdir/test_vim9_fails.vim index 216ef0b286..5c3cab545e 100644 --- a/src/testdir/test_vim9_fails.vim +++ b/src/testdir/test_vim9_fails.vim @@ -1,8 +1,12 @@ " Test for Vim9 script with failures, causing memory leaks to be reported. " The leaks happen after a fork() and can be ignored. +source check.vim + def Test_assignment() - if has('channel') + if !has('channel') + CheckFeature channel + else var chan1: channel var job1: job var job2: job = job_start('willfail') diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 40833c51c6..4d83a4e8fb 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -3988,6 +3988,41 @@ def Test_vim9_autoload() &rtp = save_rtp enddef +" test disassembling an auto-loaded function starting with "debug" +def Test_vim9_autoload_disass() + mkdir('Xdir/autoload', 'p') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdir' + + var lines =<< trim END + vim9script + def debugit#test(): string + return 'debug' + enddef + END + writefile(lines, 'Xdir/autoload/debugit.vim') + + lines =<< trim END + vim9script + def profileit#test(): string + return 'profile' + enddef + END + writefile(lines, 'Xdir/autoload/profileit.vim') + + lines =<< trim END + vim9script + assert_equal('debug', debugit#test()) + disass debugit#test + assert_equal('profile', profileit#test()) + disass profileit#test + END + CheckScriptSuccess(lines) + + delete('Xdir', 'rf') + &rtp = save_rtp +enddef + " test using a vim9script that is auto-loaded from an autocmd def Test_vim9_aucmd_autoload() var lines =<< trim END diff --git a/src/textformat.c b/src/textformat.c index 246f06f648..fb2ca950bf 100644 --- a/src/textformat.c +++ b/src/textformat.c @@ -954,6 +954,7 @@ format_lines( int smd_save; long count; int need_set_indent = TRUE; // set indent of next paragraph + linenr_T first_line = curwin->w_cursor.lnum; int force_format = FALSE; int old_State = State; @@ -1073,8 +1074,13 @@ format_lines( { int indent = 0; // amount of indent needed - // replace indent in first line with minimal number of - // tabs and spaces, according to current options + // Replace indent in first line of a paragraph with minimal + // number of tabs and spaces, according to current options. + // For the very first formatted line keep the current + // indent. + if (curwin->w_cursor.lnum == first_line) + indent = get_indent(); + else # ifdef FEAT_LISP if (curbuf->b_p_lisp) indent = get_lisp_indent(); diff --git a/src/typval.c b/src/typval.c index fb945cb135..8dbb939a7c 100644 --- a/src/typval.c +++ b/src/typval.c @@ -1639,10 +1639,10 @@ eval_option( int c; int working = (**arg == '+'); // has("+option") int ret = OK; - int opt_flags; + int scope; // Isolate the option name and find its value. - option_end = find_option_end(arg, &opt_flags); + option_end = find_option_end(arg, &scope); if (option_end == NULL) { if (rettv != NULL) @@ -1659,7 +1659,7 @@ eval_option( c = *option_end; *option_end = NUL; opt_type = get_option_value(*arg, &numval, - rettv == NULL ? NULL : &stringval, opt_flags); + rettv == NULL ? NULL : &stringval, NULL, scope); if (opt_type == gov_unknown) { diff --git a/src/usercmd.c b/src/usercmd.c index 332f995364..16fbb0db36 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -1394,6 +1394,7 @@ produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote) #ifdef HAVE_SANDBOX {CMOD_SANDBOX, "sandbox"}, #endif + {CMOD_LEGACY, "legacy"}, {0, NULL} }; diff --git a/src/userfunc.c b/src/userfunc.c index 3edbf891ef..4f86c07910 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2281,7 +2281,7 @@ func_free(ufunc_T *fp, int force) * Free all things that a function contains and free the function itself. * When "force" is TRUE we are exiting. */ - static void + void func_clear_free(ufunc_T *fp, int force) { func_clear(fp, force); @@ -3168,6 +3168,29 @@ call_callback( return ret; } +/* + * call the 'callback' function and return the result as a number. + * Returns -1 when calling the function fails. Uses argv[0] to argv[argc - 1] + * for the function arguments. argv[argc] should have type VAR_UNKNOWN. + */ + varnumber_T +call_callback_retnr( + callback_T *callback, + int argcount, // number of "argvars" + typval_T *argvars) // vars for arguments, must have "argcount" + // PLUS ONE elements! +{ + typval_T rettv; + varnumber_T retval; + + if (call_callback(callback, 0, &rettv, argcount, argvars) == FAIL) + return -1; + + retval = tv_get_number_chk(&rettv, NULL); + clear_tv(&rettv); + return retval; +} + /* * Give an error message for the result of a function. * Nothing if "error" is FCERR_NONE. @@ -3740,7 +3763,7 @@ trans_function_name( // It's script-local, "s:" or "" if (current_sctx.sc_sid <= 0) { - emsg(_(e_usingsid)); + emsg(_(e_using_sid_not_in_script_context)); goto theend; } sprintf((char *)sid_buf, "%ld_", (long)current_sctx.sc_sid); diff --git a/src/version.c b/src/version.c index e24d1522f3..b4e5d2493b 100644 --- a/src/version.c +++ b/src/version.c @@ -768,6 +768,66 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 3754, +/**/ + 3753, +/**/ + 3752, +/**/ + 3751, +/**/ + 3750, +/**/ + 3749, +/**/ + 3748, +/**/ + 3747, +/**/ + 3746, +/**/ + 3745, +/**/ + 3744, +/**/ + 3743, +/**/ + 3742, +/**/ + 3741, +/**/ + 3740, +/**/ + 3739, +/**/ + 3738, +/**/ + 3737, +/**/ + 3736, +/**/ + 3735, +/**/ + 3734, +/**/ + 3733, +/**/ + 3732, +/**/ + 3731, +/**/ + 3730, +/**/ + 3729, +/**/ + 3728, +/**/ + 3727, +/**/ + 3726, +/**/ + 3725, /**/ 3724, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 70cf0b4e99..31d06b27c2 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6072,7 +6072,7 @@ vim9_declare_error(char_u *name) /* * For one assignment figure out the type of destination. Return it in "dest". * When not recognized "dest" is not set. - * For an option "opt_flags" is set. + * For an option "option_scope" is set. * For a v:var "vimvaridx" is set. * "type" is set to the destination type if known, unchanted otherwise. * Return FAIL if an error message was given. @@ -6082,7 +6082,7 @@ get_var_dest( char_u *name, assign_dest_T *dest, int cmdidx, - int *opt_flags, + int *option_scope, int *vimvaridx, type_T **type, cctx_T *cctx) @@ -6102,7 +6102,7 @@ get_var_dest( return FAIL; } p = name; - p = find_option_end(&p, opt_flags); + p = find_option_end(&p, option_scope); if (p == NULL) { // cannot happen? @@ -6112,7 +6112,7 @@ get_var_dest( cc = *p; *p = NUL; opt_type = get_option_value(skip_option_env_lead(name), - &numval, NULL, *opt_flags); + &numval, NULL, NULL, *option_scope); *p = cc; switch (opt_type) { @@ -9903,15 +9903,15 @@ compile_def_function( * in "$ENV->func()" the "$" is not a range */ cmd = ea.cmd; - if (!(local_cmdmod.cmod_flags & CMOD_LEGACY) - && (*cmd != '$' || starts_with_colon) + if ((*cmd != '$' || starts_with_colon) && (starts_with_colon || !(*cmd == '\'' || (cmd[0] == cmd[1] && (*cmd == '+' || *cmd == '-'))))) { ea.cmd = skip_range(ea.cmd, TRUE, NULL); if (ea.cmd > cmd) { - if (!starts_with_colon) + if (!starts_with_colon + && !(local_cmdmod.cmod_flags & CMOD_LEGACY)) { semsg(_(e_colon_required_before_range_str), cmd); goto erret; @@ -9920,11 +9920,8 @@ compile_def_function( if (ends_excmd2(line, ea.cmd)) { // A range without a command: jump to the line. - line = skipwhite(line); - while (*line == ':') - ++line; generate_EXEC(&cctx, ISN_EXECRANGE, - vim_strnsave(line, ea.cmd - line)); + vim_strnsave(cmd, ea.cmd - cmd)); line = ea.cmd; goto nextline; } diff --git a/src/vim9execute.c b/src/vim9execute.c index bd7f71e686..f805dc0f14 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1785,6 +1785,8 @@ exec_instructions(ectx_T *ectx) ea.addr_type = ADDR_LINES; ea.cmd = iptr->isn_arg.string; parse_cmd_address(&ea, &error, FALSE); + if (ea.cmd == NULL) + goto on_error; if (error == NULL) error = ex_range_without_command(&ea); if (error != NULL) @@ -4986,8 +4988,9 @@ call_def_function( estack_pop(); current_sctx = save_current_sctx; - // TODO: when is it safe to delete the function if it is no longer used? - --ufunc->uf_calls; + if (--ufunc->uf_calls <= 0 && ufunc->uf_refcount <= 0) + // Function was unreferenced while being used, free it now. + func_clear_free(ufunc, FALSE); if (*msg_list != NULL && saved_msg_list != NULL) { @@ -5902,12 +5905,12 @@ ex_disassemble(exarg_T *eap) int is_global = FALSE; compiletype_T compile_type = CT_NONE; - if (STRNCMP(arg, "profile", 7) == 0) + if (STRNCMP(arg, "profile", 7) == 0 && VIM_ISWHITE(arg[7])) { compile_type = CT_PROFILE; arg = skipwhite(arg + 7); } - else if (STRNCMP(arg, "debug", 5) == 0) + else if (STRNCMP(arg, "debug", 5) == 0 && VIM_ISWHITE(arg[5])) { compile_type = CT_DEBUG; arg = skipwhite(arg + 5); diff --git a/src/window.c b/src/window.c index 78f38fcb1b..f7f8d950e4 100644 --- a/src/window.c +++ b/src/window.c @@ -4863,6 +4863,11 @@ win_enter_ext(win_T *wp, int flags) void fix_current_dir(void) { +#ifdef FEAT_AUTOCHDIR + if (p_acd) + do_autochdir(); + else +#endif if (curwin->w_localdir != NULL || curtab->tp_localdir != NULL) { char_u *dirname; diff --git a/src/xdiff/README.txt b/src/xdiff/README.txt index 95b2242b87..9e01a3c679 100644 --- a/src/xdiff/README.txt +++ b/src/xdiff/README.txt @@ -13,4 +13,7 @@ COPYING file. Changes in these files were made to avoid compiler warnings. +The /* */ comments are kept to make syncing to a newer version easier, do not +change them to // comments! + The first work for including xdiff in Vim was done by Christian Brabandt.