diff --git a/.github/CODEOWNERS_vim b/.github/CODEOWNERS_vim index 970cc942dc..02d6986289 100644 --- a/.github/CODEOWNERS_vim +++ b/.github/CODEOWNERS_vim @@ -31,6 +31,7 @@ runtime/compiler/dartdevc.vim @dkearns runtime/compiler/dartdoc.vim @dkearns runtime/compiler/dartfmt.vim @dkearns runtime/compiler/eruby.vim @dkearns +runtime/compiler/fbc.vim @dkearns runtime/compiler/gawk.vim @dkearns runtime/compiler/gjs.vim @dkearns runtime/compiler/haml.vim @tpope @@ -66,12 +67,14 @@ runtime/doc/pi_tar.txt @cecamp runtime/doc/pi_vimball.txt @cecamp runtime/doc/pi_zip.txt @cecamp runtime/ftplugin/awk.vim @dkearns +runtime/ftplugin/basic.vim @dkearns runtime/ftplugin/bst.vim @tpope runtime/ftplugin/cfg.vim @chrisbra runtime/ftplugin/css.vim @dkearns runtime/ftplugin/cucumber.vim @tpope runtime/ftplugin/eiffel.vim @dkearns runtime/ftplugin/eruby.vim @tpope @dkearns +runtime/ftplugin/freebasic.vim @dkearns runtime/ftplugin/git.vim @tpope runtime/ftplugin/gitcommit.vim @tpope runtime/ftplugin/gitconfig.vim @tpope @@ -93,6 +96,7 @@ runtime/ftplugin/ruby.vim @tpope @dkearns runtime/ftplugin/sass.vim @tpope runtime/ftplugin/scss.vim @tpope runtime/ftplugin/spec.vim @ignatenkobrain +runtime/ftplugin/tidy.vim @dkearns runtime/ftplugin/tmux.vim @ericpruitt runtime/ftplugin/typescript.vim @dkearns runtime/ftplugin/typescriptreact.vim @dkearns @@ -127,6 +131,7 @@ runtime/syntax/amiga.vim @cecamp runtime/syntax/asm.vim @dkearns runtime/syntax/asmh8300.vim @dkearns runtime/syntax/awk.vim @dkearns +runtime/syntax/basic.vim @dkearns runtime/syntax/bst.vim @tpope runtime/syntax/cabal.vim @coot runtime/syntax/cabalconfig.vim @coot diff --git a/runtime/compiler/fbc.vim b/runtime/compiler/fbc.vim new file mode 100644 index 0000000000..1c29392da8 --- /dev/null +++ b/runtime/compiler/fbc.vim @@ -0,0 +1,27 @@ +" Vim compiler file +" Compiler: FreeBASIC Compiler +" Maintainer: Doug Kearns +" Last Change: 2015 Jan 10 + +if exists("current_compiler") + finish +endif +let current_compiler = "fbc" + +if exists(":CompilerSet") != 2 " older Vim always used :setlocal + command -nargs=* CompilerSet setlocal +endif + +let s:cpo_save = &cpo +set cpo&vim + +CompilerSet makeprg=fbc +CompilerSet errorformat=%-G%.%#Too\ many\ errors\\,\ exiting, + \%f(%l)\ %tarning\ %n(%\\d%\\+):\ %m, + \%E%f(%l)\ error\ %n:\ %m, + \%-Z%p^, + \%-C%.%#, + \%-G%.%# + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/compiler/tidy.vim b/runtime/compiler/tidy.vim index 75be8b83d9..3f8e68ebf2 100644 --- a/runtime/compiler/tidy.vim +++ b/runtime/compiler/tidy.vim @@ -1,7 +1,7 @@ " Vim compiler file " Compiler: HTML Tidy " Maintainer: Doug Kearns -" Last Change: 2016 Apr 21 +" Last Change: 2020 Sep 4 if exists("current_compiler") finish @@ -12,8 +12,15 @@ if exists(":CompilerSet") != 2 " older Vim always used :setlocal command -nargs=* CompilerSet setlocal endif -CompilerSet makeprg=tidy\ -quiet\ -errors\ --gnu-emacs\ yes\ %:S +let s:cpo_save = &cpo +set cpo&vim -" foo.html:8:1: Warning: inserting missing 'foobar' element -" foo.html:9:2: Error: is not recognized! -CompilerSet errorformat=%f:%l:%c:\ %trror:%m,%f:%l:%c:\ %tarning:%m,%-G%.%# +CompilerSet makeprg=tidy\ -quiet\ -errors\ --gnu-emacs\ yes +CompilerSet errorformat=%f:%l:%c:\ %trror:\ %m, + \%f:%l:%c:\ %tarning:\ %m, + \%f:%l:%c:\ %tnfo:\ %m, + \%f:%l:%c:\ %m, + \%-G%.%# + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 6e40b516b7..86913e3fa9 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2020 Nov 21 +*change.txt* For Vim version 8.2. Last change: 2021 Jan 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1631,24 +1631,31 @@ default setting is "tcq". You can separate the option letters with commas for readability. letter meaning when present in 'formatoptions' ~ - + *fo-t* t Auto-wrap text using textwidth + *fo-c* c Auto-wrap comments using textwidth, inserting the current comment leader automatically. + *fo-r* r Automatically insert the current comment leader after hitting in Insert mode. + *fo-o* o Automatically insert the current comment leader after hitting 'o' or 'O' in Normal mode. + *fo-q* q Allow formatting of comments with "gq". Note that formatting will not change blank lines or lines containing only the comment leader. A new paragraph starts after such a line, or when the comment leader changes. + *fo-w* w Trailing white space indicates a paragraph continues in the next line. A line that ends in a non-white character ends a paragraph. + *fo-a* a Automatic formatting of paragraphs. Every time text is inserted or deleted the paragraph will be reformatted. See |auto-format|. When the 'c' flag is present this only happens for recognized comments. + *fo-n* n When formatting text, recognize numbered lists. This actually uses the 'formatlistpat' option, thus any kind of list can be used. The indent of the text after the number is used for the next line. The @@ -1659,6 +1666,7 @@ n When formatting text, recognize numbered lists. This actually uses 1. the first item wraps 2. the second item +< *fo-2* 2 When formatting text, use the indent of the second line of a paragraph for the rest of the paragraph, instead of the indent of the first line. This supports paragraphs in which the first line has a @@ -1668,36 +1676,46 @@ n When formatting text, recognize numbered lists. This actually uses second line of the same paragraph third line. < This also works inside comments, ignoring the comment leader. + *fo-v* v Vi-compatible auto-wrapping in insert mode: Only break a line at a blank that you have entered during the current insert command. (Note: this is not 100% Vi compatible. Vi has some "unexpected features" or bugs in this area. It uses the screen column instead of the line column.) + *fo-b* b Like 'v', but only auto-wrap if you enter a blank at or before the wrap margin. If the line was longer than 'textwidth' when you started the insert, or you do not enter a blank in the insert before reaching 'textwidth', Vim does not perform auto-wrapping. + *fo-l* l Long lines are not broken in insert mode: When a line was longer than 'textwidth' when the insert command started, Vim does not automatically format it. + *fo-m* m Also break at a multibyte character above 255. This is useful for Asian text where every character is a word on its own. + *fo-M* M When joining lines, don't insert a space before or after a multibyte character. Overrules the 'B' flag. + *fo-B* B When joining lines, don't insert a space between two multibyte characters. Overruled by the 'M' flag. + *fo-1* 1 Don't break a line after a one-letter word. It's broken before it instead (if possible). + *fo-]* ] Respect textwidth rigorously. With this flag set, no line can be longer than textwidth, unless line-break-prohibition rules make this impossible. Mainly for CJK scripts and works only if 'encoding' is "utf-8". + *fo-j* j Where it makes sense, remove a comment leader when joining lines. For example, joining: int i; // the index ~ // in the list ~ Becomes: int i; // the index in the list ~ + *fo-p* p Don't break lines at single spaces that follow periods. This is intended to complement 'joinspaces' and |cpo-J|, for prose with sentences separated by two spaces. For example, with 'textwidth' set diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 730fb6a190..bf2cc05d7c 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2021 Jan 13 +*eval.txt* For Vim version 8.2. Last change: 2021 Jan 22 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2082,6 +2082,12 @@ v:null An empty String. Used to put "null" in JSON. See That is so that eval() can parse the string back to the same value. Read-only. + *v:numbermax* *numbermax-variable* +v:numbermax Maximum value of a number. + + *v:numbermin* *numbermin-variable* +v:numbermin Minimum value of a number (negative) + *v:numbersize* *numbersize-variable* v:numbersize Number of bits in a Number. This is normally 64, but on some systems it may be 32. @@ -4096,8 +4102,9 @@ delete({fname} [, {flags}]) *delete()* A symbolic link itself is deleted, not what it points to. - The result is a Number, which is 0 if the delete operation was - successful and -1 when the deletion failed or partly failed. + The result is a Number, which is 0/false if the delete + operation was successful and -1/true when the deletion failed + or partly failed. Use |remove()| to delete an item from a |List|. To delete a line from the buffer use |:delete| or @@ -6234,8 +6241,8 @@ has({feature} [, {check}]) has_key({dict}, {key}) *has_key()* - The result is a Number, which is 1 if |Dictionary| {dict} has - an entry with key {key}. Zero otherwise. + The result is a Number, which is TRUE if |Dictionary| {dict} + has an entry with key {key}. FALSE otherwise. Can also be used as a |method|: > mydict->has_key(key) @@ -6278,16 +6285,16 @@ haslocaldir([{winnr} [, {tabnr}]]) *haslocaldir()* GetWinnr()->haslocaldir() hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()* - The result is a Number, which is 1 if there is a mapping that - contains {what} in somewhere in the rhs (what it is mapped to) - and this mapping exists in one of the modes indicated by - {mode}. + The result is a Number, which is TRUE if there is a mapping + that contains {what} in somewhere in the rhs (what it is + mapped to) and this mapping exists in one of the modes + indicated by {mode}. When {abbr} is there and it is |TRUE| use abbreviations instead of mappings. Don't forget to specify Insert and/or Command-line mode. Both the global mappings and the mappings local to the current buffer are checked for a match. - If no matching mapping is found 0 is returned. + If no matching mapping is found FALSE is returned. The following characters are recognized in {mode}: n Normal mode v Visual and Select mode @@ -6323,8 +6330,8 @@ histadd({history}, {item}) *histadd()* character is sufficient. If {item} does already exist in the history, it will be shifted to become the newest entry. - The result is a Number: 1 if the operation was successful, - otherwise 0 is returned. + The result is a Number: TRUE if the operation was successful, + otherwise FALSE is returned. Example: > :call histadd("input", strftime("%Y %b %d")) @@ -6347,8 +6354,8 @@ histdel({history} [, {item}]) *histdel()* an index, see |:history-indexing|. The respective entry will be removed if it exists. - The result is a Number: 1 for a successful operation, - otherwise 0 is returned. + The result is TRUE for a successful operation, otherwise FALSE + is returned. Examples: Clear expression register history: > @@ -6400,7 +6407,7 @@ histnr({history}) *histnr()* GetHistory()->histnr() < hlexists({name}) *hlexists()* - The result is a Number, which is non-zero if a highlight group + The result is a Number, which is TRUE if a highlight group called {name} exists. This is when the group has been defined in some way. Not necessarily when highlighting has been defined for it, it may also have been used for a syntax @@ -6573,7 +6580,7 @@ inputrestore() *inputrestore()* Restore typeahead that was saved with a previous |inputsave()|. Should be called the same number of times inputsave() is called. Calling it more often is harmless though. - Returns 1 when there is nothing to restore, 0 otherwise. + Returns TRUE when there is nothing to restore, FALSE otherwise. inputsave() *inputsave()* Preserve typeahead (also from mappings) and clear it, so that @@ -6581,7 +6588,7 @@ inputsave() *inputsave()* followed by a matching inputrestore() after the prompt. Can be used several times, in which case there must be just as many inputrestore() calls. - Returns 1 when out of memory, 0 otherwise. + Returns TRUE when out of memory, FALSE otherwise. inputsecret({prompt} [, {text}]) *inputsecret()* This function acts much like the |input()| function with but @@ -7057,7 +7064,7 @@ listener_flush([{buf}]) *listener_flush()* listener_remove({id}) *listener_remove()* Remove a listener previously added with listener_add(). - Returns zero when {id} could not be found, one when {id} was + Returns FALSE when {id} could not be found, TRUE when {id} was removed. Can also be used as a |method|: > @@ -7740,8 +7747,8 @@ mkdir({name} [, {path} [, {prot}]]) flag is passed (since patch 8.0.1708). However, without the "p" option the call will fail. - The function result is a Number, which is 1 if the call was - successful or 0 if the directory creation failed or partly + The function result is a Number, which is TRUE if the call was + successful or FALSE if the directory creation failed or partly failed. Not available on all systems. To check use: > @@ -9217,6 +9224,7 @@ server2client({clientid}, {string}) *server2client()* Send a reply string to {clientid}. The most recent {clientid} that sent a string can be retrieved with expand(""). {only available when compiled with the |+clientserver| feature} + Returns zero for success, -1 for failure. Note: This id has to be stored before the next command can be received. I.e. before returning from the received command and @@ -9354,8 +9362,8 @@ setcmdpos({pos}) *setcmdpos()* before inserting the resulting text. When the number is too big the cursor is put at the end of the line. A number smaller than one has undefined results. - Returns 0 when successful, 1 when not editing the command - line. + Returns FALSE when successful, TRUE when not editing the + command line. Can also be used as a |method|: > GetPos()->setcmdpos() @@ -9414,8 +9422,8 @@ setline({lnum}, {text}) *setline()* When {lnum} is just below the last line the {text} will be added below the last line. - If this succeeds, 0 is returned. If this fails (most likely - because {lnum} is invalid) 1 is returned. + If this succeeds, FALSE is returned. If this fails (most likely + because {lnum} is invalid) TRUE is returned. Example: > :call setline(5, strftime("%c")) @@ -11390,7 +11398,7 @@ win_gettype([{nr}]) *win_gettype()* win_gotoid({expr}) *win_gotoid()* Go to window with ID {expr}. This may also change the current tabpage. - Return 1 if successful, 0 if the window cannot be found. + Return TRUE if successful, FALSE if the window cannot be found. Can also be used as a |method|: > GetWinid()->win_gotoid() diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 19720e1841..6a23b2fdb8 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -1,4 +1,4 @@ -*filetype.txt* For Vim version 8.2. Last change: 2020 Sep 28 +*filetype.txt* For Vim version 8.2. Last change: 2021 Jan 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -147,6 +147,7 @@ can be used to overrule the filetype used for certain extensions: *.w g:filetype_w |ft-cweb-syntax| *.i g:filetype_i |ft-progress-syntax| *.p g:filetype_p |ft-pascal-syntax| + *.pp g:filetype_pp |ft-pascal-syntax| *.sh g:bash_is_sh |ft-sh-syntax| *.tex g:tex_flavor |ft-tex-plugin| diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 25f71be1b1..35930e3d5b 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 8.2. Last change: 2020 Oct 05 +*index.txt* For Vim version 8.2. Last change: 2021 Jan 15 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 142bd50e80..f577d87ad8 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3288,7 +3288,7 @@ A jump table for the options with a short description can be found at |Q_op|. See the 'endofline' option. *'fkmap'* *'fk'* *'nofkmap'* *'nofk'* -'fkmap' 'fk' boolean (default off) *E198* +'fkmap' 'fk' boolean (default off) global {only available when compiled with the |+rightleft| feature} @@ -5361,7 +5361,7 @@ A jump table for the options with a short description can be found at |Q_op|. NOTE: This option is set to the Vi default value when 'compatible' is set and to the Vim default value when 'compatible' is reset. - *'mouse'* *E538* + *'mouse'* 'mouse' string (default "", "a" for GUI and Win32, set to "a" or "nvi" in |defaults.vim|) global diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 54302a95d8..6d70cecd54 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2020 Nov 07 +*popup.txt* For Vim version 8.2. Last change: 2021 Jan 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -588,8 +588,6 @@ properties. It is in one of four forms: If you want to create a new buffer yourself use |bufadd()| and pass the buffer number to popup_create(). -It is not possible to use the buffer of a terminal window. *E278* You CAN -create a hidden terminal buffer and use that one in a popup window. The second argument of |popup_create()| is a dictionary with options: line Screen line where to position the popup. Can use a diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index fc699a1d78..195a2025a5 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2021 Jan 02 +*repeat.txt* For Vim version 8.2. Last change: 2021 Jan 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -354,7 +354,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. Vim version, or update Vim to a newer version. See |vimscript-version| for what changed between versions. -:vim9script [noclear] *:vim9* *:vim9script* +:vim9[script] [noclear] *:vim9* *:vim9script* Marks a script file as containing |Vim9-script| commands. Also see |vim9-namespace|. Must be the first command in the file. @@ -899,8 +899,9 @@ matches ".../plugin/explorer.vim", ".../plugin/iexplorer.vim", etc. > matches ".../plugin/explorer.vim" and "explorer.vim" in any other directory. The match for functions is done against the name as it's shown in the output -of ":function". For local functions this means that something like "99_" -is prepended. +of ":function". However, for local functions the script-specific prefix such +as "99_" is ignored to make it easier to match script-local functions +without knowing the ID of the script. Note that functions are first loaded and later executed. When they are loaded the "file" breakpoints are checked, when they are executed the "func" @@ -955,10 +956,10 @@ OBSCURE Profiling means that Vim measures the time that is spent on executing functions and/or scripts. The |+profile| feature is required for this. -It is only included when Vim was compiled with "huge" features. +It is included when Vim was compiled with "huge" features. You can also use the |reltime()| function to measure time. This only requires -the |+reltime| feature, which is present more often. +the |+reltime| feature, which is present in more builds. For profiling syntax highlighting see |:syntime|. @@ -1005,7 +1006,12 @@ For example, to profile the one_script.vim script file: > You must always start with a ":profile start fname" command. The resulting -file is written when Vim exits. Here is an example of the output, with line +file is written when Vim exits. For example, to profile one specific +function: > + profile start /tmp/vimprofile + profile func MyFunc + +Here is an example of the output, with line numbers prepended for the explanation: 1 FUNCTION Test2() ~ diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 33d513c62a..6717e382b1 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -1,4 +1,4 @@ -*syntax.txt* For Vim version 8.2. Last change: 2020 Dec 17 +*syntax.txt* For Vim version 8.2. Last change: 2021 Jan 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2335,11 +2335,12 @@ http://papp.plan9.de. PASCAL *pascal.vim* *ft-pascal-syntax* -Files matching "*.p" could be Progress or Pascal. If the automatic detection -doesn't work for you, or you don't edit Progress at all, use this in your -startup vimrc: > +Files matching "*.p" could be Progress or Pascal and those matching "*.pp" +could be Puppet or Pascal. If the automatic detection doesn't work for you, +or you only edit Pascal files, use this in your startup vimrc: > - :let filetype_p = "pascal" + :let filetype_p = "pascal" + :let filetype_pp = "pascal" The Pascal syntax file has been extended to take into account some extensions provided by Turbo Pascal, Free Pascal Compiler and GNU Pascal Compiler. diff --git a/runtime/doc/tags b/runtime/doc/tags index c000a927ff..f8cac19f19 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -1063,6 +1063,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* 't_da' term.txt /*'t_da'* 't_db' term.txt /*'t_db'* 't_dl' term.txt /*'t_dl'* +'t_fd' term.txt /*'t_fd'* +'t_fe' term.txt /*'t_fe'* 't_fs' term.txt /*'t_fs'* 't_k1' term.txt /*'t_k1'* 't_k2' term.txt /*'t_k2'* @@ -3139,9 +3141,11 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :sip change.txt /*:sip* :sir change.txt /*:sir* :sl various.txt /*:sl* +:sl! various.txt /*:sl!* :sla windows.txt /*:sla* :slast windows.txt /*:slast* :sleep various.txt /*:sleep* +:sleep! various.txt /*:sleep!* :sm change.txt /*:sm* :smagic change.txt /*:smagic* :smap map.txt /*:smap* @@ -4082,7 +4086,6 @@ E194 message.txt /*E194* E195 starting.txt /*E195* E196 various.txt /*E196* E197 mlang.txt /*E197* -E198 options.txt /*E198* E199 cmdline.txt /*E199* E20 motion.txt /*E20* E200 autocmd.txt /*E200* @@ -4168,7 +4171,6 @@ E274 eval.txt /*E274* E275 textprop.txt /*E275* E276 eval.txt /*E276* E277 remote.txt /*E277* -E278 popup.txt /*E278* E279 terminal.txt /*E279* E28 syntax.txt /*E28* E280 if_tcl.txt /*E280* @@ -4234,7 +4236,6 @@ E337 gui.txt /*E337* E338 editing.txt /*E338* E339 message.txt /*E339* E34 various.txt /*E34* -E340 vi_diff.txt /*E340* E341 message.txt /*E341* E342 message.txt /*E342* E343 options.txt /*E343* @@ -4442,7 +4443,6 @@ E534 options.txt /*E534* E535 options.txt /*E535* E536 options.txt /*E536* E537 options.txt /*E537* -E538 options.txt /*E538* E539 options.txt /*E539* E54 pattern.txt /*E54* E540 options.txt /*E540* @@ -6438,6 +6438,7 @@ expression-commands eval.txt /*expression-commands* expression-syntax eval.txt /*expression-syntax* exrc starting.txt /*exrc* extend() eval.txt /*extend()* +extendnew() eval.txt /*extendnew()* extension-removal cmdline.txt /*extension-removal* extensions-improvements todo.txt /*extensions-improvements* external-editor gui_mac.txt /*external-editor* @@ -6518,7 +6519,26 @@ fname_new-variable eval.txt /*fname_new-variable* fname_out-variable eval.txt /*fname_out-variable* fnameescape() eval.txt /*fnameescape()* fnamemodify() eval.txt /*fnamemodify()* +fo-1 change.txt /*fo-1* +fo-2 change.txt /*fo-2* +fo-B change.txt /*fo-B* +fo-M change.txt /*fo-M* +fo-] change.txt /*fo-]* +fo-a change.txt /*fo-a* +fo-b change.txt /*fo-b* +fo-c change.txt /*fo-c* +fo-j change.txt /*fo-j* +fo-l change.txt /*fo-l* +fo-m change.txt /*fo-m* +fo-n change.txt /*fo-n* +fo-o change.txt /*fo-o* +fo-p change.txt /*fo-p* +fo-q change.txt /*fo-q* +fo-r change.txt /*fo-r* +fo-t change.txt /*fo-t* fo-table change.txt /*fo-table* +fo-v change.txt /*fo-v* +fo-w change.txt /*fo-w* fold-behavior fold.txt /*fold-behavior* fold-colors fold.txt /*fold-colors* fold-commands fold.txt /*fold-commands* @@ -8414,6 +8434,8 @@ null vim9.txt /*null* null-variable eval.txt /*null-variable* number_relativenumber options.txt /*number_relativenumber* numbered-function eval.txt /*numbered-function* +numbermax-variable eval.txt /*numbermax-variable* +numbermin-variable eval.txt /*numbermin-variable* numbersize-variable eval.txt /*numbersize-variable* o insert.txt /*o* o_CTRL-V motion.txt /*o_CTRL-V* @@ -8826,6 +8848,7 @@ read-in-close-cb channel.txt /*read-in-close-cb* read-messages insert.txt /*read-messages* read-only-share editing.txt /*read-only-share* read-stdin version5.txt /*read-stdin* +readblob() eval.txt /*readblob()* readdir() eval.txt /*readdir()* readdirex() eval.txt /*readdirex()* readfile() eval.txt /*readfile()* @@ -9091,6 +9114,7 @@ sinh() eval.txt /*sinh()* skeleton autocmd.txt /*skeleton* skip_defaults_vim starting.txt /*skip_defaults_vim* slice eval.txt /*slice* +slice() eval.txt /*slice()* slow-fast-terminal term.txt /*slow-fast-terminal* slow-start starting.txt /*slow-start* slow-terminal term.txt /*slow-terminal* @@ -9486,6 +9510,8 @@ t_f6 version4.txt /*t_f6* t_f7 version4.txt /*t_f7* t_f8 version4.txt /*t_f8* t_f9 version4.txt /*t_f9* +t_fd term.txt /*t_fd* +t_fe term.txt /*t_fe* t_float-variable eval.txt /*t_float-variable* t_fs term.txt /*t_fs* t_func-variable eval.txt /*t_func-variable* @@ -9860,6 +9886,7 @@ type-inference vim9.txt /*type-inference* type-mistakes tips.txt /*type-mistakes* typecorr-settings usr_41.txt /*typecorr-settings* typecorr.txt usr_41.txt /*typecorr.txt* +typename() eval.txt /*typename()* u undo.txt /*u* uganda uganda.txt /*uganda* uganda.txt uganda.txt /*uganda.txt* @@ -9987,6 +10014,8 @@ v:mouse_win eval.txt /*v:mouse_win* v:mouse_winid eval.txt /*v:mouse_winid* v:none eval.txt /*v:none* v:null eval.txt /*v:null* +v:numbermax eval.txt /*v:numbermax* +v:numbermin eval.txt /*v:numbermin* v:numbersize eval.txt /*v:numbersize* v:oldfiles eval.txt /*v:oldfiles* v:operator eval.txt /*v:operator* @@ -10230,6 +10259,7 @@ vim8 version8.txt /*vim8* vim9 vim9.txt /*vim9* vim9-classes vim9.txt /*vim9-classes* vim9-const vim9.txt /*vim9-const* +vim9-curly vim9.txt /*vim9-curly* vim9-declaration vim9.txt /*vim9-declaration* vim9-declarations usr_46.txt /*vim9-declarations* vim9-differences vim9.txt /*vim9-differences* @@ -10462,6 +10492,7 @@ xterm-command-server term.txt /*xterm-command-server* xterm-copy-paste term.txt /*xterm-copy-paste* xterm-cursor-keys term.txt /*xterm-cursor-keys* xterm-end-home-keys term.txt /*xterm-end-home-keys* +xterm-focus-event term.txt /*xterm-focus-event* xterm-function-keys term.txt /*xterm-function-keys* xterm-modifier-keys term.txt /*xterm-modifier-keys* xterm-mouse options.txt /*xterm-mouse* diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 0456a8b89b..8eea4a59e7 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -1,4 +1,4 @@ -*term.txt* For Vim version 8.2. Last change: 2020 Dec 29 +*term.txt* For Vim version 8.2. Last change: 2021 Jan 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -373,9 +373,9 @@ Added by Vim (there are no standard codes for these): t_Ri restore icon text from stack *t_Ri* *'t_Ri'* t_TE end of "raw" mode *t_TE* *'t_TE'* t_TI put terminal into "raw" mode *t_TI* *'t_TI'* - t_fd disable focus-event tracking *t_TI* *'t_TI'* + t_fd disable focus-event tracking *t_fd* *'t_fd'* |xterm-focus-event| - t_fe enable focus-event tracking *t_TI* *'t_TI'* + t_fe enable focus-event tracking *t_fe* *'t_fe'* |xterm-focus-event| Some codes have a start, middle and end part. The start and end are defined diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 6e5fe4cc09..efff0929d7 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 Jan 11 +*todo.txt* For Vim version 8.2. Last change: 2021 Jan 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,17 +38,10 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- -no error for: - echo extend([0], ['a', true]) -like it does for: - echo extend([0], ['a']) -At script level this does not give an error: - echo map([0], (_, v) => []) -Or: - var l: list = [0] - echo map(l, (_, v) => []) +test_autocmd failure in Windows: Something wrong with system()? Vim9 - Make everything work: +- Add a test for profiling with nested function calls and lambda. - Expand `=expr` in :next, :argedit, :argadd, :argdelete, :drop - Expand `=expr` in :vimgrep, :vimgrepadd, :lvimgrep, :lvimgrepadd - Expand `=expr` in :mkspell @@ -58,7 +51,7 @@ Vim9 - Make everything work: - Using a script variable inside a :def function doesn't work if the variable is inside a block, see Test_nested_function(). Should it work? - give error for variable name: - let p = function('NoSuchFunc') + var p = function('NoSuchFunc') - Make closures work better: - Create closure in a loop. Need to make a list of them. - If a :def function is called with a function reference, compile it to get @@ -66,20 +59,16 @@ Vim9 - Make everything work: def Filter(x: string, Cond: func(string): bool) Filter(x, (v) => v =~ '^b') - Make inline function work, to be used as a funcref: - let Ref = (arg: type): type => { + var Ref = (arg: type): type => { statement return expr } - let Ref = (arg: type) => { + var Ref = (arg: type) => { statement statement } -- Does this work already: can use func as reference: - def SomeFunc() ... - map(list, SomeFunc) - For builtin functions using tv_get_string*() use check_for_string() to be more strict about the argument type. -- Possible memory leaks in test_vim9_func - Implement :lockvar and :unlockvar. How about local variables? Perhaps only allow this for global variables. Use :final or :const otherwise. - Allow function names that will be script-local to start with lower case @@ -94,10 +83,10 @@ Vim9 - Make everything work: - Need the equivalent of get_lval() and set_var_lval() to implement assignment to nested list and dict members. - Assignment to dict doesn't work: - let ret: dict = #{} + var ret: dict = #{} ret[i] = string(i) - Appending to dict item doesn't work: - let d[i] ..= value + var d[i] ..= value - Using ".." at script level doesn't convert arguments to a string. - Compile replacement of :s command: s/pat/\=expr/ - Compile redir to local variable: var_redir_start(). @@ -117,6 +106,8 @@ Vim9 - Make everything work: - compile "skip" argument of searchpair() - compile "expr" and "call" expression of a channel in channel_exe_cmd()? - give an error for "echo Func()" if Func() does not return anything. +- Using "windo echo expr" does not accept a line break inside "expr" (in a + :def function and at script level in a not executed block). #7681 Once Vim9 is stable: - Change the help to prefer Vim9 syntax where appropriate @@ -150,7 +141,6 @@ Also for Vim9: - Make debugging work - at least per function. Need to recompile a function to step through it line-by-line? Evaluate the stack and variables on the stack? -- Make profiling work - Add ISN_PROFILE instructions after every line? - List commands when 'verbose' is set or :verbose is used. Further Vim9 improvements, possibly after launch: @@ -193,6 +183,10 @@ Popup windows: - Figure out the size and position better if wrapping inserts indent Text properties: +- Popup attached to text property stays visible when text is no longer + visible. (#7736) +- Popup attached to text property stays visible when text is deleted with + "cc". (#7737) "C" works OK. - :goto does not go to the right place when text properties are present. (#5930) - "cc" does not call inserted_bytes(). (Axel Forsman, #5763) @@ -287,6 +281,9 @@ Have another look at the implementation. Patch to implement the vimtutor with a plugin: #6414 Was originally written by Felipe Morales. +Adding "10" to 'spellsuggest' causes spell suggestions to become very slow. +(#4087) Did patch 8.2.2379 help? + Patch to find Python dll using registry key. (#7540) Remove SPACE_IN_FILENAME ? It is only used for completion. @@ -479,9 +476,6 @@ Help for ":argadd fname" says that if "fname" is already in the argument list that entry is used. But instead it's always added. (#6210) Add flag AL_FIND_ADD, if there is one argument find it in the list. -Adding "10" to 'spellsuggest' causes spell suggestions to become very slow. -(#4087) - behavior of i_CTRl-R_CTRL-R differs from documentation. (Paul Desmond Parker, #5771) @@ -556,14 +550,6 @@ when "qq" is mapped and after the first "q" the mouse is moved outside of the gvim window (with focus follows mouse), then the K_FOCUSLOST key is put in the input buffer. (#5302) -xterm should be able to pass focus changes to Vim, so that Vim can check for -buffers that changed. Perhaps in misc.c, function selectwindow(). -Xterm 224 supports it! -Patch to make FocusGained and FocusLost work in modern terminals. (Hayaki -Saito, 2013 Apr 24) Update 2016 Aug 12. -Also see issue #609. -We could add the enable/disable sequences to t_ti/t_te or t_ks/t_ke. - :buffer completion does not escape "+" properly and results in a regexp error. (#5467) diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 5d4686ae04..965a97732d 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1,4 +1,4 @@ -*usr_41.txt* For Vim version 8.2. Last change: 2021 Jan 08 +*usr_41.txt* For Vim version 8.2. Last change: 2021 Jan 13 VIM USER MANUAL - by Bram Moolenaar diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 868af02b41..7395c0f15f 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -1,4 +1,4 @@ -*various.txt* For Vim version 8.2. Last change: 2020 Nov 16 +*various.txt* For Vim version 8.2. Last change: 2021 Jan 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -412,7 +412,7 @@ N *+mouse_sysmouse* Unix only: *BSD console mouse handling |sysmouse| B *+mouse_sgr* Unix only: sgr mouse handling |sgr-mouse| B *+mouse_urxvt* Unix only: urxvt mouse handling |urxvt-mouse| N *+mouse_xterm* Unix only: xterm mouse handling |xterm-mouse| -N *+multi_byte* 16 and 32 bit characters |multibyte| +T *+multi_byte* Unicode support, 16 and 32 bit characters |multibyte| *+multi_byte_ime* Win32 input method for multibyte chars |multibyte-ime| N *+multi_lang* non-English language support |multi-lang| m *+mzscheme* Mzscheme interface |mzscheme| @@ -725,6 +725,9 @@ K Run a program to lookup the keyword under the available when compiled with the |+netbeans_intg| feature} + *:sl!* *:sleep!* +:[N]sl[eep]! [N] [m] Same as above, but hide the cursor + *:xrestore* *:xr* :xr[estore] [display] Reinitializes the connection to the X11 server. Useful after the X server restarts, e.g. when running Vim for diff --git a/runtime/doc/version6.txt b/runtime/doc/version6.txt index 82405e7f5f..6b9f1d9343 100644 --- a/runtime/doc/version6.txt +++ b/runtime/doc/version6.txt @@ -9661,7 +9661,7 @@ Solution: Check for tcsetattr() to return an error, retry when it does. Files: src/os_unix.c Patch 6.2f.018 -Problem: Mac OS X 10.2: OK is defined to zero in cursus.h while Vim uses +Problem: Mac OS X 10.2: OK is defined to zero in curses.h while Vim uses one. Redefining it causes a warning message. Solution: Undefine OK before defining it to one. (Taro Muraoka) Files: src/vim.h diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt index c7c7f7e38c..89ef4bb71e 100644 --- a/runtime/doc/vi_diff.txt +++ b/runtime/doc/vi_diff.txt @@ -1,4 +1,4 @@ -*vi_diff.txt* For Vim version 8.2. Last change: 2020 Aug 15 +*vi_diff.txt* For Vim version 8.2. Last change: 2021 Jan 21 VIM REFERENCE MANUAL by Bram Moolenaar @@ -73,7 +73,7 @@ edit the termcap entry and try again. Vim has the |terminal-options|. Vim has only a few limits for the files that can be edited {Vi: can not handle characters and characters above 128, has limited line length, many other limits}. - *E340* + Maximum line length 2147483647 characters. Longer lines are split. Maximum number of lines 2147483647 lines. Maximum file size 2147483647 bytes (2 Gbyte) when a long integer is diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index a7b91db0a4..7246ff87a6 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 Jan 10 +*vim9.txt* For Vim version 8.2. Last change: 2021 Jan 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -403,10 +403,16 @@ Additionally, a lambda can contain statements in {}: > } NOT IMPLEMENTED YET + *vim9-curly* To avoid the "{" of a dictionary literal to be recognized as a statement block wrap it in parenthesis: > var Lambda = (arg) => ({key: 42}) +Also when confused with the start of a command block: > + ({ + key: value + })->method() + Automatic line continuation ~ @@ -487,6 +493,9 @@ Now "exit_cb: Func})" is actually a valid command: save any changes to the file "_cb: Func})" and exit. To avoid this kind of mistake in Vim9 script there must be white space between most command names and the argument. +However, the argument of a command that is a command won't be recognized. For +example, after "windo echo expr" a line break inside "expr" will not be seen. + Notes: - "enddef" cannot be used at the start of a continuation line, it ends the @@ -527,17 +536,17 @@ that using a literal key is much more common than using an expression, and considering that JavaScript uses this syntax, using the {} form for dictionary literals is considered a much more useful syntax. In Vim9 script the {} form uses literal keys: > - let dict = {key: value} + var dict = {key: value} This works for alphanumeric characters, underscore and dash. If you want to use another character, use a single or double quoted string: > - let dict = {'key with space': value} - let dict = {"key\twith\ttabs": value} - let dict = {'': value} # empty key + var dict = {'key with space': value} + var dict = {"key\twith\ttabs": value} + var dict = {'': value} # empty key In case the key needs to be an expression, square brackets can be used, just like in JavaScript: > - let dict = {["key" .. nr]: value} + var dict = {["key" .. nr]: value} No :xit, :t, :append, :change or :insert ~ @@ -552,6 +561,29 @@ Comparators ~ The 'ignorecase' option is not used for comparators that use strings. +For loop ~ + +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. +Example legacy script: > + let l = [1, 2, 3, 4] + for i in l + echo i + call remove(l, index(l, i)) + endfor +Would echo: + 1 + 2 + 3 + 4 +In compiled Vim9 script you get: + 1 + 3 +Generally, you should not change the list that is iterated over. Make a copy +first if needed. + + White space ~ Vim9 script enforces proper use of white space. This is no longer allowed: > @@ -576,15 +608,17 @@ the start and end: > White space is not allowed: - Between a function name and the "(": > - call Func (arg) # Error! - call Func + Func (arg) # Error! + Func \ (arg) # Error! - call Func(arg) # OK - call Func( - \ arg) # OK - call Func( - \ arg # OK - \ ) + Func + (arg) # Error! + Func(arg) # OK + Func( + arg) # OK + Func( + arg # OK + ) Conditions and expressions ~ @@ -648,12 +682,13 @@ for v:null. When converting a boolean to a string "false" and "true" are used, not "v:false" and "v:true" like in legacy script. "v:none" is not changed, it is only used in JSON and has no equivalent in other languages. -Indexing a string with [idx] or [idx, idx] uses character indexes instead of +Indexing a string with [idx] or [idx : idx] uses character indexes instead of byte indexes. Example: > echo 'bár'[1] In legacy script this results in the character 0xc3 (an illegal byte), in Vim9 script this results in the string 'á'. A negative index is counting from the end, "[-1]" is the last character. +To exclude the last character use |slice()|. If the index is out of range then an empty string results. In legacy script "++var" and "--var" would be silently accepted and have no @@ -670,21 +705,22 @@ same time tries to support the legacy Vim commands. Some compromises had to be made. Here is a summary of what might be unexpected. Ex command ranges need to be prefixed with a colon. > - -> # legacy Vim: shifts the previous line to the right - ->func() # Vim9: method call in continuation line - :-> # Vim9: shifts the previous line to the right + -> legacy Vim: shifts the previous line to the right + ->func() Vim9: method call in a continuation line + :-> Vim9: shifts the previous line to the right - %s/a/b # legacy Vim: substitute on all lines + %s/a/b legacy Vim: substitute on all lines x = alongname - % another # Vim9: line continuation without a backslash - :%s/a/b # Vim9: substitute on all lines - 'text'->func() # Vim9: method call - :'t # legacy Vim: jump to mark m + % another Vim9: modulo operator in a continuation line + :%s/a/b Vim9: substitute on all lines + 't legacy Vim: jump to mark t + 'text'->func() Vim9: method call + :'t Vim9: jump to mark t Some Ex commands can be confused with assignments in Vim9 script: > - g:name = value # assignment - g:pattern:cmd # invalid command - ERROR - :g:pattern:cmd # :global command + g:name = value # assignment + g:pattern:cmd # invalid command - ERROR + :g:pattern:cmd # :global command Functions defined with `:def` compile the whole function. Legacy functions can bail out, and the following lines are not parsed: > @@ -704,7 +740,7 @@ Vim9 functions are compiled as a whole: > For a workaround, split it in two functions: > func Maybe() if has('feature') - call MaybyInner() + call MaybeInner() endif endfunc if has('feature') @@ -720,7 +756,7 @@ evaluates to false: > endif enddef < *vim9-user-command* -Another side effect of compiling a function is that the precense of a user +Another side effect of compiling a function is that the presence of a user command is checked at compile time. If the user command is defined later an error will result. This works: > command -nargs=1 MyCommand echom @@ -811,6 +847,9 @@ prefix and they do not need to exist (they can be deleted any time). Note that for command line completion of {func} you can prepend "s:" to find script-local functions. +:disa[ssemble]! {func} Like `:disassemble` but with the instructions used for + profiling. + Limitations ~ Local variables will not be visible to string evaluation. For example: > @@ -1090,7 +1129,7 @@ actually needed. A recommended mechanism: 1. In the plugin define user commands, functions and/or mappings that refer to an autoload script. > - command -nargs=1 SearchForStuff call searchfor#Stuff() + command -nargs=1 SearchForStuff searchfor#Stuff() < This goes in .../plugin/anyname.vim. "anyname.vim" can be freely chosen. @@ -1183,12 +1222,12 @@ When compiling lines of Vim commands into instructions as much as possible should be done at compile time. Postponing it to runtime makes the execution slower and means mistakes are found only later. For example, when encountering the "+" character and compiling this into a generic add -instruction, at execution time the instruction would have to inspect the type -of the arguments and decide what kind of addition to do. And when the -type is dictionary throw an error. If the types are known to be numbers then -an "add number" instruction can be used, which is faster. The error can be -given at compile time, no error handling is needed at runtime, since adding -two numbers cannot fail. +instruction, at runtime the instruction would have to inspect the type of the +arguments and decide what kind of addition to do. And when the type is +dictionary throw an error. If the types are known to be numbers then an "add +number" instruction can be used, which is faster. The error can be given at +compile time, no error handling is needed at runtime, since adding two numbers +cannot fail. The syntax for types, using for compound types, is similar to Java. It is easy to understand and widely used. The type names are what were used in diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 4c419ed060..e4910e3719 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: 2020 Dec 24 +" Last Change: 2021 Jan 21 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -589,6 +589,9 @@ au BufNewFile,BufRead *.fan,*.fwt setf fan " Factor au BufNewFile,BufRead *.factor setf factor +" Fennel +autocmd BufRead,BufNewFile *.fnl setf fennel + " Fetchmail RC file au BufNewFile,BufRead .fetchmailrc setf fetchmail @@ -1173,9 +1176,10 @@ au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp " Password file au BufNewFile,BufRead */etc/passwd,*/etc/passwd-,*/etc/passwd.edit,*/etc/shadow,*/etc/shadow-,*/etc/shadow.edit,*/var/backups/passwd.bak,*/var/backups/shadow.bak setf passwd -" Pascal (also *.p) +" Pascal (also *.p, *.pp, *.inc) au BufNewFile,BufRead *.pas setf pascal +" Pascal or Puppet manifest au BufNewFile,BufRead *.pp call dist#ft#FTpp() " Delphi or Lazarus program file @@ -1266,7 +1270,7 @@ au BufNewFile,BufRead *.pov setf pov " Povray configuration au BufNewFile,BufRead .povrayrc setf povini -" Povray, PHP or assembly +" Povray, Pascal, PHP or assembly au BufNewFile,BufRead *.inc call dist#ft#FTinc() " Printcap and Termcap @@ -1275,13 +1279,19 @@ au BufNewFile,BufRead *printcap au BufNewFile,BufRead *termcap \ let b:ptcap_type = "term" | setf ptcap -" PCCTS / ANTRL -"au BufNewFile,BufRead *.g setf antrl +" PCCTS / ANTLR +"au BufNewFile,BufRead *.g setf antlr au BufNewFile,BufRead *.g setf pccts " PPWizard au BufNewFile,BufRead *.it,*.ih setf ppwiz +" Puppet +au BufNewFile,BufRead Puppetfile setf ruby + +" Embedded Puppet +au BufNewFile,BufRead *.epp setf epuppet + " Obj 3D file format " TODO: is there a way to avoid MS-Windows Object files? au BufNewFile,BufRead *.obj setf obj @@ -1424,8 +1434,8 @@ au BufNewFile,BufRead *.rb,*.rbw setf ruby " RubyGems au BufNewFile,BufRead *.gemspec setf ruby -" Rust -au BufNewFile,BufRead *.rs setf rust +" RBS (Ruby Signature) +au BufNewFile,BufRead *.rbs setf rbs " Rackup au BufNewFile,BufRead *.ru setf ruby @@ -1439,6 +1449,9 @@ au BufNewFile,BufRead *.builder,*.rxml,*.rjs setf ruby " Rantfile and Rakefile is like Ruby au BufNewFile,BufRead [rR]antfile,*.rant,[rR]akefile,*.rake setf ruby +" Rust +au BufNewFile,BufRead *.rs setf rust + " S-lang (or shader language, or SmallLisp) au BufNewFile,BufRead *.sl setf slang @@ -1731,8 +1744,13 @@ au BufNewFile,BufRead *.tli setf tli " Telix Salt au BufNewFile,BufRead *.slt setf tsalt -" Tera Term Language -au BufRead,BufNewFile *.ttl setf teraterm +" Tera Term Language or Turtle +au BufRead,BufNewFile *.ttl + \ if getline(1) =~ '^@\?\(prefix\|base\)' | + \ setf turtle | + \ else | + \ setf teraterm | + \ endif " Terminfo au BufNewFile,BufRead *.ti setf terminfo diff --git a/runtime/ftplugin/ada.vim b/runtime/ftplugin/ada.vim index 0809e7b206..a0621e1d13 100644 --- a/runtime/ftplugin/ada.vim +++ b/runtime/ftplugin/ada.vim @@ -159,40 +159,41 @@ if exists("g:ada_abbrev") endif " Section: Commands, Mapping, Menus {{{1 -" -call ada#Map_Popup ( - \ 'Tag.List', - \ 'l', - \ 'call ada#List_Tag ()') -call ada#Map_Popup ( - \'Tag.Jump', - \'j', - \'call ada#Jump_Tag ()') -call ada#Map_Menu ( - \'Tag.Create File', - \':AdaTagFile', - \'call ada#Create_Tags (''file'')') -call ada#Map_Menu ( - \'Tag.Create Dir', - \':AdaTagDir', - \'call ada#Create_Tags (''dir'')') +if !exists(':AdaTagFile') + call ada#Map_Popup ( + \ 'Tag.List', + \ 'l', + \ 'call ada#List_Tag ()') + call ada#Map_Popup ( + \'Tag.Jump', + \'j', + \'call ada#Jump_Tag ()') + call ada#Map_Menu ( + \'Tag.Create File', + \':AdaTagFile', + \'call ada#Create_Tags (''file'')') + call ada#Map_Menu ( + \'Tag.Create Dir', + \':AdaTagDir', + \'call ada#Create_Tags (''dir'')') -call ada#Map_Menu ( - \'Highlight.Toggle Space Errors', - \ ':AdaSpaces', - \'call ada#Switch_Syntax_Option (''space_errors'')') -call ada#Map_Menu ( - \'Highlight.Toggle Lines Errors', - \ ':AdaLines', - \'call ada#Switch_Syntax_Option (''line_errors'')') -call ada#Map_Menu ( - \'Highlight.Toggle Rainbow Color', - \ ':AdaRainbow', - \'call ada#Switch_Syntax_Option (''rainbow_color'')') -call ada#Map_Menu ( - \'Highlight.Toggle Standard Types', - \ ':AdaTypes', - \'call ada#Switch_Syntax_Option (''standard_types'')') + call ada#Map_Menu ( + \'Highlight.Toggle Space Errors', + \ ':AdaSpaces', + \'call ada#Switch_Syntax_Option (''space_errors'')') + call ada#Map_Menu ( + \'Highlight.Toggle Lines Errors', + \ ':AdaLines', + \'call ada#Switch_Syntax_Option (''line_errors'')') + call ada#Map_Menu ( + \'Highlight.Toggle Rainbow Color', + \ ':AdaRainbow', + \'call ada#Switch_Syntax_Option (''rainbow_color'')') + call ada#Map_Menu ( + \'Highlight.Toggle Standard Types', + \ ':AdaTypes', + \'call ada#Switch_Syntax_Option (''standard_types'')') +endif " 1}}} " Reset cpoptions diff --git a/runtime/ftplugin/basic.vim b/runtime/ftplugin/basic.vim new file mode 100644 index 0000000000..c6ec254dfc --- /dev/null +++ b/runtime/ftplugin/basic.vim @@ -0,0 +1,27 @@ +" Vim filetype plugin file +" Language: BASIC +" Maintainer: Doug Kearns +" Last Change: 2015 Jan 10 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +setlocal comments=:REM,:' +setlocal commentstring='\ %s +setlocal formatoptions-=t formatoptions+=croql + +if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") + let b:browsefilter = "BASIC Source Files (*.bas)\t*.bas\n" . + \ "All Files (*.*)\t*.*\n" +endif + +let b:undo_ftplugin = "setl fo< com< cms< sua<" . + \ " | unlet! b:browsefilter" + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/ftplugin/bzl.vim b/runtime/ftplugin/bzl.vim index 0296b0c0b8..8ab876e9d6 100644 --- a/runtime/ftplugin/bzl.vim +++ b/runtime/ftplugin/bzl.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: Bazel (http://bazel.io) " Maintainer: David Barnett (https://github.com/google/vim-ft-bzl) -" Last Change: 2015 Aug 11 +" Last Change: 2021 Jan 19 "" " @section Introduction, intro @@ -51,6 +51,8 @@ if get(g:, 'ft_bzl_fold', 0) endif if exists('*BzlFoldText') + let &cpo = s:save_cpo + unlet s:save_cpo finish endif diff --git a/runtime/ftplugin/framescript.vim b/runtime/ftplugin/framescript.vim index 48fe0ace7c..66802cad0d 100644 --- a/runtime/ftplugin/framescript.vim +++ b/runtime/ftplugin/framescript.vim @@ -3,14 +3,14 @@ " Previous Maintainer: Nikolai Weibull " Latest Revision: 2008-07-19 -let s:cpo_save = &cpo -set cpo&vim - if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 +let s:cpo_save = &cpo +set cpo&vim + let b:undo_ftplugin = "setl com< cms< fo< inc< | unlet! b:matchwords" setlocal comments=s1:/*,mb:*,ex:*/,:// commentstring=/*\ %s\ */ diff --git a/runtime/ftplugin/freebasic.vim b/runtime/ftplugin/freebasic.vim new file mode 100644 index 0000000000..a2bb459f20 --- /dev/null +++ b/runtime/ftplugin/freebasic.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin file +" Language: FreeBasic +" Maintainer: Doug Kearns +" Last Change: 2015 Jan 10 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +runtime! ftplugin/basic.vim + +" vim: ts=8 diff --git a/runtime/ftplugin/hamster.vim b/runtime/ftplugin/hamster.vim index 6c0630fe04..5446e72286 100644 --- a/runtime/ftplugin/hamster.vim +++ b/runtime/ftplugin/hamster.vim @@ -2,7 +2,7 @@ " Language: Hamster Script " Version: 2.0.6.0 " Maintainer: David Fishburn -" Last Change: 2017 Mar 18 +" Last Change: 2021 Jan 19 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -57,6 +57,9 @@ if exists("loaded_matchit") endif setlocal ignorecase + let &cpo = s:cpo_save unlet s:cpo_save -setlocal cpo+=M " makes \%( match \) + +" Disabled, 'cpo' is a global option. +" setlocal cpo+=M " makes \%( match \) diff --git a/runtime/ftplugin/ocaml.vim b/runtime/ftplugin/ocaml.vim index 793b887afc..8a628604fa 100644 --- a/runtime/ftplugin/ocaml.vim +++ b/runtime/ftplugin/ocaml.vim @@ -159,6 +159,8 @@ let b:undo_ftplugin = "setlocal efm< foldmethod< foldexpr<" " - Only definitions below, executed once ------------------------------------- if exists("*OMLetFoldLevel") + let &cpoptions = s:cposet + unlet s:cposet finish endif @@ -635,7 +637,7 @@ endfunction nnoremap OCamlPrintType :call Ocaml_print_type("normal") xnoremap OCamlPrintType :call Ocaml_print_type("visual")`< -let &cpoptions=s:cposet +let &cpoptions = s:cposet unlet s:cposet " vim:sw=2 fdm=indent diff --git a/runtime/ftplugin/tidy.vim b/runtime/ftplugin/tidy.vim new file mode 100644 index 0000000000..470548d83a --- /dev/null +++ b/runtime/ftplugin/tidy.vim @@ -0,0 +1,32 @@ +" Vim filetype plugin file +" Language: HMTL Tidy Configuration +" Maintainer: Doug Kearns +" Last Change: 2020 Sep 4 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +setlocal comments=:#,:// +setlocal commentstring=#\ %s +setlocal formatoptions-=t formatoptions+=croql + +if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") + let b:browsefilter = "HTML Tidy Files (tidyrc, .tidyrc, tidy.conf)\ttidyrc;.tidyrc;tidy.conf\n" . + \ "HTML Files (*.html, *.htm)\t*.html;*.htm\n" . + \ "XHTML Files (*.xhtml, *.xhtm)\t*.xhtml;*.xhtm\n" . + \ "XML Files (*.xml)\t*.xml\n" . + \ "All Files (*.*)\t*.*\n" +endif + +let b:undo_ftplugin = "setl fo< com< cms<" . + \ " | unlet! b:browsefilter" + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: nowrap sw=2 sts=2 ts=8 diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim index 3307de5410..d39ad9579b 100644 --- a/runtime/ftplugin/vim.vim +++ b/runtime/ftplugin/vim.vim @@ -1,7 +1,7 @@ " Vim filetype plugin " Language: Vim " Maintainer: Bram Moolenaar -" Last Change: 2021 Jan 05 +" Last Change: 2021 Jan 23 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -51,12 +51,12 @@ setlocal keywordprg=:help if "\n" .. getline(1, 10)->join("\n") =~# '\n\s*vim9\%[script]\>' " Set 'comments' to format dashed lists in comments setlocal com=sO:#\ -,mO:#\ \ ,eO:##,:# - " Comments start with a double quote in a legacy script; - " with # in a Vim9 script - setlocal commentstring=\"%s + " Comments starts with # in Vim9 script + setlocal commentstring=#%s else setlocal com=sO:\"\ -,mO:\"\ \ ,:\" - setlocal commentstring=#%s + " Comments starts with a double quote in legacy script + setlocal commentstring=\"%s endif @@ -88,8 +88,13 @@ endif " Let the matchit plugin know what items can be matched. if exists("loaded_matchit") let b:match_ignorecase = 0 + " "func" can also be used as a type: + " var Ref: func + " or to list functions: + " func name + " require a parenthesis following, then there can be an "endfunc". let b:match_words = - \ '\<\%(fu\%[nction]\|def\)\>)\@!:\:\<\%(endf\%[unction]\|enddef\)\>,' . + \ '\<\%(fu\%[nction]\|def\)\s\+\S\+(:\:\<\%(endf\%[unction]\|enddef\)\>,' . \ '\<\(wh\%[ile]\|for\)\>:\:\:\,' . \ '\:\:\,' . \ '{:},' . diff --git a/runtime/indent/fortran.vim b/runtime/indent/fortran.vim index 696320288d..26ed33a54d 100644 --- a/runtime/indent/fortran.vim +++ b/runtime/indent/fortran.vim @@ -74,11 +74,15 @@ endif if (b:fortran_fixed_source == 1) setlocal indentexpr=FortranGetFixedIndent() if exists("*FortranGetFixedIndent") + let &cpoptions = s:cposet + unlet s:cposet finish endif else setlocal indentexpr=FortranGetFreeIndent() if exists("*FortranGetFreeIndent") + let &cpoptions = s:cposet + unlet s:cposet finish endif endif @@ -213,7 +217,7 @@ function FortranGetFixedIndent() return ind endfunction -let &cpoptions=s:cposet +let &cpoptions = s:cposet unlet s:cposet " vim:sw=2 tw=130 diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in index 47e692975f..f652dbda79 100644 --- a/runtime/indent/testdir/vim.in +++ b/runtime/indent/testdir/vim.in @@ -10,6 +10,11 @@ let cmd = \ 'some ' \ 'string' +if 1 +let x = [ +\ ] +endif + " END_INDENT " START_INDENT diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok index 3f53c5286c..b8592c18eb 100644 --- a/runtime/indent/testdir/vim.ok +++ b/runtime/indent/testdir/vim.ok @@ -10,6 +10,11 @@ let cmd = \ 'some ' \ 'string' +if 1 + let x = [ + \ ] +endif + " END_INDENT " START_INDENT diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim index 3e502c9adb..b031d1f2ed 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 Jan 06 +" Last Change: 2021 Jan 21 " Only load this indent file when no other was loaded. if exists("b:did_indent") @@ -38,6 +38,9 @@ function GetVimIndentIntern() " Find a non-blank line above the current line. let lnum = prevnonblank(v:lnum - 1) + " The previous line, ignoring line continuation + let prev_text_end = lnum > 0 ? getline(lnum) : '' + " If the current line doesn't start with '\' or '"\ ' and below a line that " starts with '\' or '"\ ', use the indent of the line above it. let cur_text = getline(v:lnum) @@ -51,6 +54,8 @@ function GetVimIndentIntern() if lnum == 0 return 0 endif + + " the start of the previous line, skipping over line continuation let prev_text = getline(lnum) let found_cont = 0 @@ -147,13 +152,13 @@ function GetVimIndentIntern() endif " Below a line starting with "]" we must be below the end of a list. - if prev_text =~ '^\s*]' + if prev_text_end =~ '^\s*]' let ind = ind - shiftwidth() endif " A line ending in "{"/"[} is most likely the start of a dict/list literal, " indent the next line more. Not for a continuation line. - if prev_text =~ '[{[]\s*$' && !found_cont + if prev_text_end =~ '[{[]\s*$' && !found_cont let ind = ind + shiftwidth() endif diff --git a/runtime/indent/yaml.vim b/runtime/indent/yaml.vim index 26e14effb2..8dca5cd763 100644 --- a/runtime/indent/yaml.vim +++ b/runtime/indent/yaml.vim @@ -2,16 +2,13 @@ " Language: YAML " Maintainer: Nikolai Pavlov " Last Update: Lukas Reineke -" Last Change: 2020 Jun 07 +" Last Change: 2021 Jan 19 " Only load this indent file when no other was loaded. if exists('b:did_indent') finish endif -let s:save_cpo = &cpo -set cpo&vim - let b:did_indent = 1 setlocal indentexpr=GetYAMLIndent(v:lnum) @@ -25,6 +22,9 @@ if exists('*GetYAMLIndent') finish endif +let s:save_cpo = &cpo +set cpo&vim + function s:FindPrevLessIndentedLine(lnum, ...) let prevlnum = prevnonblank(a:lnum-1) let curindent = a:0 ? a:1 : indent(a:lnum) diff --git a/runtime/scripts.vim b/runtime/scripts.vim index 9217b4416a..6448c542cb 100644 --- a/runtime/scripts.vim +++ b/runtime/scripts.vim @@ -186,6 +186,10 @@ if s:line1 =~# "^#!" elseif s:name =~# 'instantfpc\>' set ft=pascal + " Fennel + elseif s:name =~# 'fennel\>' + set ft=fennel + endif unlet s:name diff --git a/runtime/syntax/basic.vim b/runtime/syntax/basic.vim index 488ddc0ec4..ad9450b3b8 100644 --- a/runtime/syntax/basic.vim +++ b/runtime/syntax/basic.vim @@ -1,14 +1,16 @@ " Vim syntax file -" Language: BASIC -" Maintainer: Allan Kelly -" Last Change: 2011 Dec 25 by Thilo Six +" Language: BASIC +" Maintainer: Doug Kearns +" Previous Maintainer: Allan Kelly +" Contributors: Thilo Six +" Last Change: 2015 Jan 10 " First version based on Micro$soft QBASIC circa 1989, as documented in " 'Learn BASIC Now' by Halvorson&Rygmyr. Microsoft Press 1989. " This syntax file not a complete implementation yet. Send suggestions to the " maintainer. -" quit when a syntax file was already loaded +" Prelude {{{1 if exists("b:current_syntax") finish endif @@ -16,7 +18,7 @@ endif let s:cpo_save = &cpo set cpo&vim -" A bunch of useful BASIC keywords +" Keywords {{{1 syn keyword basicStatement BEEP beep Beep BLOAD bload Bload BSAVE bsave Bsave syn keyword basicStatement CALL call Call ABSOLUTE absolute Absolute syn keyword basicStatement CHAIN chain Chain CHDIR chdir Chdir @@ -116,32 +118,39 @@ syn keyword basicFunction RIGHT$ right$ Right$ RTRIM$ rtrim$ Rtrim$ syn keyword basicFunction SPACE$ space$ Space$ STR$ str$ Str$ syn keyword basicFunction STRING$ string$ String$ TIME$ time$ Time$ syn keyword basicFunction UCASE$ ucase$ Ucase$ VARPTR$ varptr$ Varptr$ -syn keyword basicTodo contained TODO -"integer number, or floating point number without a dot. +" Numbers {{{1 +" Integer number, or floating point number without a dot. syn match basicNumber "\<\d\+\>" -"floating point number, with dot +" Floating point number, with dot syn match basicNumber "\<\d\+\.\d*\>" -"floating point number, starting with a dot +" Floating point number, starting with a dot syn match basicNumber "\.\d\+\>" -" String and Character contstants -syn match basicSpecial contained "\\\d\d\d\|\\." -syn region basicString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=basicSpecial +" String and Character constants {{{1 +syn match basicSpecial "\\\d\d\d\|\\." contained +syn region basicString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=basicSpecial -syn region basicComment start="REM" end="$" contains=basicTodo -syn region basicComment start="^[ \t]*'" end="$" contains=basicTodo +" Line numbers {{{1 syn region basicLineNumber start="^\d" end="\s" -syn match basicTypeSpecifier "[a-zA-Z0-9][\$%&!#]"ms=s+1 + +" Data-type suffixes {{{1 +syn match basicTypeSpecifier "[a-zA-Z0-9][$%&!#]"ms=s+1 " Used with OPEN statement syn match basicFilenumber "#\d\+" -"syn sync ccomment basicComment + +" Mathematical operators {{{1 " syn match basicMathsOperator "[<>+\*^/\\=-]" -syn match basicMathsOperator "-\|=\|[:<>+\*^/\\]\|AND\|OR" +syn match basicMathsOperator "-\|=\|[:<>+\*^/\\]\|AND\|OR" -" Define the default highlighting. -" Only when an item doesn't have highlighting yet +" Comments {{{1 +syn keyword basicTodo TODO FIXME XXX NOTE contained +syn region basicComment start="^\s*\zsREM\>" start="\%(:\s*\)\@<=REM\>" end="$" contains=basicTodo +syn region basicComment start="'" end="$" contains=basicTodo +"syn sync ccomment basicComment + +" Default Highlighting {{{1 hi def link basicLabel Label hi def link basicConditional Conditional hi def link basicRepeat Repeat @@ -150,17 +159,18 @@ hi def link basicNumber Number hi def link basicError Error hi def link basicStatement Statement hi def link basicString String -hi def link basicComment Comment -hi def link basicSpecial Special +hi def link basicComment Comment +hi def link basicSpecial Special hi def link basicTodo Todo -hi def link basicFunction Identifier -hi def link basicTypeSpecifier Type -hi def link basicFilenumber basicTypeSpecifier +hi def link basicFunction Identifier +hi def link basicTypeSpecifier Type +hi def link basicFilenumber basicTypeSpecifier "hi basicMathsOperator term=bold cterm=bold gui=bold - +" Postscript {{{1 let b:current_syntax = "basic" let &cpo = s:cpo_save unlet s:cpo_save -" vim: ts=8 + +" vim: nowrap sw=2 sts=2 ts=8 noet fdm=marker: diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim index 7925e88aa5..d07aaf2658 100644 --- a/runtime/syntax/c.vim +++ b/runtime/syntax/c.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: C " Maintainer: Bram Moolenaar -" Last Change: 2020 Aug 28 +" Last Change: 2021 Jan 11 " Quit when a (custom) syntax file was already loaded if exists("b:current_syntax") @@ -13,6 +13,9 @@ set cpo&vim let s:ft = matchstr(&ft, '^\([^.]\)\+') +" check if this was included from cpp.vim +let s:in_cpp_family = exists("b:filetype_in_cpp_family") + " Optional embedded Autodoc parsing " To enable it add: let g:c_autodoc = 1 " to your .vimrc @@ -55,7 +58,7 @@ if !exists("c_no_cformat") endif " cCppString: same as cString, but ends at end of line -if s:ft ==# "cpp" && !exists("cpp_no_cpp11") && !exists("c_no_cformat") +if s:in_cpp_family && !exists("cpp_no_cpp11") && !exists("c_no_cformat") " ISO C++11 syn region cString start=+\(L\|u\|u8\|U\|R\|LR\|u8R\|uR\|UR\)\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat,@Spell extend syn region cCppString start=+\(L\|u\|u8\|U\|R\|LR\|u8R\|uR\|UR\)\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial,cFormat,@Spell @@ -87,7 +90,7 @@ syn match cSpecialCharacter display "L\='\\\o\{1,3}'" syn match cSpecialCharacter display "'\\x\x\{1,2}'" syn match cSpecialCharacter display "L'\\x\x\+'" -if (s:ft ==# "c" && !exists("c_no_c11")) || (s:ft ==# "cpp" && !exists("cpp_no_cpp11")) +if (s:ft ==# "c" && !exists("c_no_c11")) || (s:in_cpp_family && !exists("cpp_no_cpp11")) " ISO C11 or ISO C++ 11 if exists("c_no_cformat") syn region cString start=+\%(U\|u8\=\)"+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,@Spell extend @@ -130,7 +133,7 @@ endif " But avoid matching <::. syn cluster cParenGroup contains=cParenError,cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserLabel,cBitField,cOctalZero,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom if exists("c_no_curly_error") - if s:ft ==# 'cpp' && !exists("cpp_no_cpp11") + if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell @@ -144,7 +147,7 @@ if exists("c_no_curly_error") syn match cErrInParen display contained "^[{}]\|^<%\|^%>" endif elseif exists("c_no_bracket_error") - if s:ft ==# 'cpp' && !exists("cpp_no_cpp11") + if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString,@Spell @@ -158,7 +161,7 @@ elseif exists("c_no_bracket_error") syn match cErrInParen display contained "[{}]\|<%\|%>" endif else - if s:ft ==# 'cpp' && !exists("cpp_no_cpp11") + if s:in_cpp_family && !exists("cpp_no_cpp11") syn region cParen transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,cErrInBracket,cCppBracket,@cStringGroup,@Spell " cCppParen: same as cParen but ends at end-of-line; used in cDefine syn region cCppParen transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cErrInBracket,cParen,cBracket,cString,@Spell @@ -278,7 +281,7 @@ syn keyword cStorageClass static register auto volatile extern const if exists("c_gnu") syn keyword cStorageClass inline __attribute__ endif -if !exists("c_no_c99") && s:ft !=# 'cpp' +if !exists("c_no_c99") && !s:in_cpp_family syn keyword cStorageClass inline restrict endif if !exists("c_no_c11") @@ -420,7 +423,7 @@ endif syn cluster cLabelGroup contains=cUserLabel syn match cUserCont display "^\s*\zs\I\i*\s*:$" contains=@cLabelGroup syn match cUserCont display ";\s*\zs\I\i*\s*:$" contains=@cLabelGroup -if s:ft ==# 'cpp' +if s:in_cpp_family syn match cUserCont display "^\s*\zs\%(class\|struct\|enum\)\@!\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup syn match cUserCont display ";\s*\zs\%(class\|struct\|enum\)\@!\I\i*\s*:[^:]"me=e-1 contains=@cLabelGroup else diff --git a/runtime/syntax/cpp.vim b/runtime/syntax/cpp.vim index 53b6a513f2..ed38913f29 100644 --- a/runtime/syntax/cpp.vim +++ b/runtime/syntax/cpp.vim @@ -2,13 +2,16 @@ " Language: C++ " Current Maintainer: vim-jp (https://github.com/vim-jp/vim-cpp) " Previous Maintainer: Ken Shan -" Last Change: 2019 Dec 18 +" Last Change: 2021 Jan 12 " 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 diff --git a/runtime/syntax/tidy.vim b/runtime/syntax/tidy.vim index 6371cb5a86..7ffda90e55 100644 --- a/runtime/syntax/tidy.vim +++ b/runtime/syntax/tidy.vim @@ -1,8 +1,9 @@ " Vim syntax file -" Language: HMTL Tidy configuration file (/etc/tidyrc ~/.tidyrc) +" Language: HMTL Tidy Configuration " Maintainer: Doug Kearns -" Last Change: 2016 Apr 24 +" Last Change: 2020 Sep 4 +" Preamble {{{1 if exists("b:current_syntax") finish endif @@ -12,10 +13,15 @@ set cpo&vim syn iskeyword @,48-57,-,_ +" Values {{{1 +syn match tidyWordSeparator contained ",\|\s" nextgroup=tidyWord skipwhite skipnl +syn match tidyMuteIDSeparator contained ",\|\s" nextgroup=tidyMuteID skipwhite skipnl + syn case ignore syn keyword tidyBoolean contained t[rue] f[alse] y[es] n[o] 1 0 syn keyword tidyAutoBoolean contained t[rue] f[alse] y[es] n[o] 1 0 auto syn case match +syn keyword tidyCustomTags contained no blocklevel empty inline pre syn keyword tidyDoctype contained html5 omit auto strict loose transitional user syn keyword tidyEncoding contained raw ascii latin0 latin1 utf8 iso2022 mac win1252 ibm858 utf16le utf16be utf16 big5 shiftjis syn keyword tidyNewline contained LF CRLF CR @@ -24,36 +30,148 @@ syn keyword tidyRepeat contained keep-first keep-last syn keyword tidySorter contained alpha none syn region tidyString contained start=+"+ skip=+\\\\\|\\"+ end=+"+ oneline syn region tidyString contained start=+'+ skip=+\\\\\|\\'+ end=+'+ oneline -syn match tidyTags contained "\<\w\+\(\s*,\s*\w\+\)*\>" +" Tag and attribute lists +syn match tidyWord contained "\<\k\+\>:\@!" nextgroup=tidyWordSeparator skipwhite skipnl -syn keyword tidyBooleanOption add-xml-decl add-xml-pi add-xml-space - \ anchor-as-name ascii-chars assume-xml-procins bare break-before-br - \ clean coerce-endtags decorate-inferred-ul drop-empty-paras - \ drop-empty-elements drop-font-tags drop-proprietary-attributes - \ enclose-block-text enclose-text escape-cdata escape-scripts - \ fix-backslash fix-bad-comments fix-uri force-output gdoc gnu-emacs - \ hide-comments hide-endtags indent-attributes indent-cdata - \ indent-with-tabs input-xml join-classes join-styles keep-time - \ language literal-attributes logical-emphasis lower-literals markup - \ merge-emphasis ncr numeric-entities omit-optional-tags output-html - \ output-xhtml output-xml preserve-entities punctuation-wrap quiet - \ quote-ampersand quote-marks quote-nbsp raw replace-color show-info - \ show-warnings skip-nested split strict-tags-attributes tidy-mark - \ uppercase-attributes uppercase-tags word-2000 wrap-asp - \ wrap-attributes wrap-jste wrap-php wrap-script-literals - \ wrap-sections write-back +" Mute Message IDs {{{2 +syn keyword tidyMuteID ADDED_MISSING_CHARSET ANCHOR_DUPLICATED + \ ANCHOR_NOT_UNIQUE APOS_UNDEFINED APPLET_MISSING_ALT AREA_MISSING_ALT + \ ASCII_REQUIRES_DESCRIPTION ASSOCIATE_LABELS_EXPLICITLY + \ ASSOCIATE_LABELS_EXPLICITLY_FOR ASSOCIATE_LABELS_EXPLICITLY_ID + \ ATTRIBUTE_IS_NOT_ALLOWED ATTRIBUTE_VALUE_REPLACED + \ ATTR_VALUE_NOT_LCASE AUDIO_MISSING_TEXT_AIFF AUDIO_MISSING_TEXT_AU + \ AUDIO_MISSING_TEXT_RA AUDIO_MISSING_TEXT_RM AUDIO_MISSING_TEXT_SND + \ AUDIO_MISSING_TEXT_WAV BACKSLASH_IN_URI BAD_ATTRIBUTE_VALUE + \ BAD_ATTRIBUTE_VALUE_REPLACED BAD_CDATA_CONTENT BAD_SUMMARY_HTML5 + \ BAD_SURROGATE_LEAD BAD_SURROGATE_PAIR BAD_SURROGATE_TAIL + \ CANT_BE_NESTED COERCE_TO_ENDTAG COLOR_CONTRAST_ACTIVE_LINK + \ COLOR_CONTRAST_LINK COLOR_CONTRAST_TEXT COLOR_CONTRAST_VISITED_LINK + \ CONTENT_AFTER_BODY CUSTOM_TAG_DETECTED DATA_TABLE_MISSING_HEADERS + \ DATA_TABLE_MISSING_HEADERS_COLUMN DATA_TABLE_MISSING_HEADERS_ROW + \ DATA_TABLE_REQUIRE_MARKUP_COLUMN_HEADERS + \ DATA_TABLE_REQUIRE_MARKUP_ROW_HEADERS DISCARDING_UNEXPECTED + \ DOCTYPE_AFTER_TAGS DOCTYPE_MISSING DUPLICATE_FRAMESET + \ ELEMENT_NOT_EMPTY ELEMENT_VERS_MISMATCH_ERROR + \ ELEMENT_VERS_MISMATCH_WARN ENCODING_MISMATCH + \ ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_APPLET + \ ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_EMBED + \ ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_OBJECT + \ ENSURE_PROGRAMMATIC_OBJECTS_ACCESSIBLE_SCRIPT ESCAPED_ILLEGAL_URI + \ FILE_CANT_OPEN FILE_CANT_OPEN_CFG FILE_NOT_FILE FIXED_BACKSLASH + \ FOUND_STYLE_IN_BODY FRAME_MISSING_LONGDESC FRAME_MISSING_NOFRAMES + \ FRAME_MISSING_TITLE FRAME_SRC_INVALID FRAME_TITLE_INVALID_NULL + \ FRAME_TITLE_INVALID_SPACES HEADERS_IMPROPERLY_NESTED + \ HEADER_USED_FORMAT_TEXT ID_NAME_MISMATCH ILLEGAL_NESTING + \ ILLEGAL_URI_CODEPOINT ILLEGAL_URI_REFERENCE + \ IMAGE_MAP_SERVER_SIDE_REQUIRES_CONVERSION + \ IMG_ALT_SUSPICIOUS_FILENAME IMG_ALT_SUSPICIOUS_FILE_SIZE + \ IMG_ALT_SUSPICIOUS_PLACEHOLDER IMG_ALT_SUSPICIOUS_TOO_LONG + \ IMG_BUTTON_MISSING_ALT IMG_MAP_CLIENT_MISSING_TEXT_LINKS + \ IMG_MAP_SERVER_REQUIRES_TEXT_LINKS IMG_MISSING_ALT IMG_MISSING_DLINK + \ IMG_MISSING_LONGDESC IMG_MISSING_LONGDESC_DLINK + \ INFORMATION_NOT_CONVEYED_APPLET INFORMATION_NOT_CONVEYED_IMAGE + \ INFORMATION_NOT_CONVEYED_INPUT INFORMATION_NOT_CONVEYED_OBJECT + \ INFORMATION_NOT_CONVEYED_SCRIPT INSERTING_AUTO_ATTRIBUTE + \ INSERTING_TAG INVALID_ATTRIBUTE INVALID_NCR INVALID_SGML_CHARS + \ INVALID_UTF16 INVALID_UTF8 INVALID_XML_ID JOINING_ATTRIBUTE + \ LANGUAGE_INVALID LANGUAGE_NOT_IDENTIFIED + \ LAYOUT_TABLES_LINEARIZE_PROPERLY LAYOUT_TABLE_INVALID_MARKUP + \ LINK_TEXT_MISSING LINK_TEXT_NOT_MEANINGFUL + \ LINK_TEXT_NOT_MEANINGFUL_CLICK_HERE LINK_TEXT_TOO_LONG + \ LIST_USAGE_INVALID_LI LIST_USAGE_INVALID_OL LIST_USAGE_INVALID_UL + \ MALFORMED_COMMENT MALFORMED_COMMENT_DROPPING MALFORMED_COMMENT_EOS + \ MALFORMED_COMMENT_WARN MALFORMED_DOCTYPE METADATA_MISSING + \ METADATA_MISSING_REDIRECT_AUTOREFRESH MISMATCHED_ATTRIBUTE_ERROR + \ MISMATCHED_ATTRIBUTE_WARN MISSING_ATTRIBUTE MISSING_ATTR_VALUE + \ MISSING_DOCTYPE MISSING_ENDTAG_BEFORE MISSING_ENDTAG_FOR + \ MISSING_ENDTAG_OPTIONAL MISSING_IMAGEMAP MISSING_QUOTEMARK + \ MISSING_QUOTEMARK_OPEN MISSING_SEMICOLON MISSING_SEMICOLON_NCR + \ MISSING_STARTTAG MISSING_TITLE_ELEMENT MOVED_STYLE_TO_HEAD + \ MULTIMEDIA_REQUIRES_TEXT NESTED_EMPHASIS NESTED_QUOTATION + \ NEWLINE_IN_URI NEW_WINDOWS_REQUIRE_WARNING_BLANK + \ NEW_WINDOWS_REQUIRE_WARNING_NEW NOFRAMES_CONTENT + \ NOFRAMES_INVALID_CONTENT NOFRAMES_INVALID_LINK + \ NOFRAMES_INVALID_NO_VALUE NON_MATCHING_ENDTAG OBJECT_MISSING_ALT + \ OBSOLETE_ELEMENT OPTION_REMOVED OPTION_REMOVED_APPLIED + \ OPTION_REMOVED_UNAPPLIED POTENTIAL_HEADER_BOLD + \ POTENTIAL_HEADER_ITALICS POTENTIAL_HEADER_UNDERLINE + \ PREVIOUS_LOCATION PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_APPLET + \ PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_EMBED + \ PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_OBJECT + \ PROGRAMMATIC_OBJECTS_REQUIRE_TESTING_SCRIPT PROPRIETARY_ATTRIBUTE + \ PROPRIETARY_ATTR_VALUE PROPRIETARY_ELEMENT REMOVED_HTML5 + \ REMOVE_AUTO_REDIRECT REMOVE_AUTO_REFRESH REMOVE_BLINK_MARQUEE + \ REMOVE_FLICKER_ANIMATED_GIF REMOVE_FLICKER_APPLET + \ REMOVE_FLICKER_EMBED REMOVE_FLICKER_OBJECT REMOVE_FLICKER_SCRIPT + \ REPEATED_ATTRIBUTE REPLACE_DEPRECATED_HTML_APPLET + \ REPLACE_DEPRECATED_HTML_BASEFONT REPLACE_DEPRECATED_HTML_CENTER + \ REPLACE_DEPRECATED_HTML_DIR REPLACE_DEPRECATED_HTML_FONT + \ REPLACE_DEPRECATED_HTML_ISINDEX REPLACE_DEPRECATED_HTML_MENU + \ REPLACE_DEPRECATED_HTML_S REPLACE_DEPRECATED_HTML_STRIKE + \ REPLACE_DEPRECATED_HTML_U REPLACING_ELEMENT REPLACING_UNEX_ELEMENT + \ SCRIPT_MISSING_NOSCRIPT SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_CLICK + \ SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_DOWN + \ SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_MOVE + \ SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OUT + \ SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_OVER + \ SCRIPT_NOT_KEYBOARD_ACCESSIBLE_ON_MOUSE_UP SKIPOVER_ASCII_ART + \ SPACE_PRECEDING_XMLDECL STRING_ARGUMENT_BAD STRING_CONTENT_LOOKS + \ STRING_DOCTYPE_GIVEN STRING_MISSING_MALFORMED STRING_MUTING_TYPE + \ STRING_NO_SYSID STRING_UNKNOWN_OPTION + \ STYLESHEETS_REQUIRE_TESTING_LINK + \ STYLESHEETS_REQUIRE_TESTING_STYLE_ATTR + \ STYLESHEETS_REQUIRE_TESTING_STYLE_ELEMENT + \ STYLE_SHEET_CONTROL_PRESENTATION SUSPECTED_MISSING_QUOTE + \ TABLE_MAY_REQUIRE_HEADER_ABBR TABLE_MAY_REQUIRE_HEADER_ABBR_NULL + \ TABLE_MAY_REQUIRE_HEADER_ABBR_SPACES TABLE_MISSING_CAPTION + \ TABLE_MISSING_SUMMARY TABLE_SUMMARY_INVALID_NULL + \ TABLE_SUMMARY_INVALID_PLACEHOLDER TABLE_SUMMARY_INVALID_SPACES + \ TAG_NOT_ALLOWED_IN TEXT_EQUIVALENTS_REQUIRE_UPDATING_APPLET + \ TEXT_EQUIVALENTS_REQUIRE_UPDATING_OBJECT + \ TEXT_EQUIVALENTS_REQUIRE_UPDATING_SCRIPT TOO_MANY_ELEMENTS + \ TOO_MANY_ELEMENTS_IN TRIM_EMPTY_ELEMENT UNESCAPED_AMPERSAND + \ UNEXPECTED_ENDTAG UNEXPECTED_ENDTAG_ERR UNEXPECTED_ENDTAG_IN + \ UNEXPECTED_END_OF_FILE UNEXPECTED_END_OF_FILE_ATTR + \ UNEXPECTED_EQUALSIGN UNEXPECTED_GT UNEXPECTED_QUOTEMARK + \ UNKNOWN_ELEMENT UNKNOWN_ELEMENT_LOOKS_CUSTOM UNKNOWN_ENTITY + \ USING_BR_INPLACE_OF VENDOR_SPECIFIC_CHARS WHITE_IN_URI + \ XML_DECLARATION_DETECTED XML_ID_SYNTAX + \ contained nextgroup=tidyMuteIDSeparator skipwhite skipnl + +" Options {{{1 +syn keyword tidyCustomTagsOption custom-tags contained nextgroup=tidyCustomTagsDelimiter +syn match tidyCustomTagsDelimiter ":" nextgroup=tidyCustomTags contained skipwhite + +syn keyword tidyBooleanOption add-meta-charset add-xml-decl + \ add-xml-pi add-xml-space anchor-as-name ascii-chars + \ assume-xml-procins bare break-before-br clean coerce-endtags + \ decorate-inferred-ul drop-empty-paras drop-empty-elements + \ drop-font-tags drop-proprietary-attributes enclose-block-text + \ enclose-text escape-cdata escape-scripts fix-backslash + \ fix-style-tags fix-uri force-output gdoc gnu-emacs hide-comments + \ hide-endtags indent-attributes indent-cdata indent-with-tabs + \ input-xml join-classes join-styles keep-tabs keep-time language + \ literal-attributes logical-emphasis lower-literals markup + \ merge-emphasis mute-id ncr numeric-entities omit-optional-tags + \ output-html output-xhtml output-xml preserve-entities + \ punctuation-wrap quiet quote-ampersand quote-marks quote-nbsp raw + \ replace-color show-filename show-info show-meta-change show-warnings + \ skip-nested split strict-tags-attributes tidy-mark + \ uppercase-attributes uppercase-tags warn-proprietary-attributes + \ word-2000 wrap-asp wrap-attributes wrap-jste wrap-php + \ wrap-script-literals wrap-sections write-back \ contained nextgroup=tidyBooleanDelimiter syn match tidyBooleanDelimiter ":" nextgroup=tidyBoolean contained skipwhite -syn keyword tidyAutoBooleanOption indent merge-divs merge-spans output-bom show-body-only vertical-space contained nextgroup=tidyAutoBooleanDelimiter +syn keyword tidyAutoBooleanOption fix-bad-comments indent merge-divs merge-spans output-bom show-body-only vertical-space contained nextgroup=tidyAutoBooleanDelimiter syn match tidyAutoBooleanDelimiter ":" nextgroup=tidyAutoBoolean contained skipwhite syn keyword tidyCSSSelectorOption css-prefix contained nextgroup=tidyCSSSelectorDelimiter syn match tidyCSSSelectorDelimiter ":" nextgroup=tidyCSSSelector contained skipwhite syn keyword tidyDoctypeOption doctype contained nextgroup=tidyDoctypeDelimiter -syn match tidyDoctypeDelimiter ":" nextgroup=tidyDoctype contained skipwhite +syn match tidyDoctypeDelimiter ":" nextgroup=tidyDoctype,tidyString contained skipwhite syn keyword tidyEncodingOption char-encoding input-encoding output-encoding contained nextgroup=tidyEncodingDelimiter syn match tidyEncodingDelimiter ":" nextgroup=tidyEncoding contained skipwhite @@ -67,8 +185,11 @@ syn match tidyNameDelimiter ":" nextgroup=tidyName contained skipwhite syn keyword tidyNewlineOption newline contained nextgroup=tidyNewlineDelimiter syn match tidyNewlineDelimiter ":" nextgroup=tidyNewline contained skipwhite +syn keyword tidyAttributesOption priority-attributes contained nextgroup=tidyAttributesDelimiter +syn match tidyAttributesDelimiter ":" nextgroup=tidyWord contained skipwhite + syn keyword tidyTagsOption new-blocklevel-tags new-empty-tags new-inline-tags new-pre-tags contained nextgroup=tidyTagsDelimiter -syn match tidyTagsDelimiter ":" nextgroup=tidyTags contained skipwhite +syn match tidyTagsDelimiter ":" nextgroup=tidyWord contained skipwhite syn keyword tidyRepeatOption repeated-attributes contained nextgroup=tidyRepeatDelimiter syn match tidyRepeatDelimiter ":" nextgroup=tidyRepeat contained skipwhite @@ -79,57 +200,77 @@ syn match tidySorterDelimiter ":" nextgroup=tidySorter contained skipwhite syn keyword tidyStringOption alt-text error-file gnu-emacs-file output-file contained nextgroup=tidyStringDelimiter syn match tidyStringDelimiter ":" nextgroup=tidyString contained skipwhite +syn keyword tidyMuteOption mute contained nextgroup=tidyMuteDelimiter +syn match tidyMuteDelimiter ":" nextgroup=tidyMuteID contained skipwhite + syn cluster tidyOptions contains=tidy.*Option +" Option line anchor {{{1 syn match tidyStart "^" nextgroup=@tidyOptions +" Long standing bug - option lines (except the first) with leading whitespace +" are silently ignored. +syn match tidyErrorStart '^\s\+\ze\S' +" Comments {{{1 syn match tidyComment "^\s*//.*$" contains=tidyTodo syn match tidyComment "^\s*#.*$" contains=tidyTodo syn keyword tidyTodo TODO NOTE FIXME XXX contained +" Default highlighting {{{1 +hi def link tidyAttributesOption Identifier hi def link tidyAutoBooleanOption Identifier hi def link tidyBooleanOption Identifier hi def link tidyCSSSelectorOption Identifier +hi def link tidyCustomTagsOption Identifier hi def link tidyDoctypeOption Identifier hi def link tidyEncodingOption Identifier hi def link tidyIntegerOption Identifier +hi def link tidyMuteOption Identifier hi def link tidyNameOption Identifier hi def link tidyNewlineOption Identifier -hi def link tidyTagsOption Identifier hi def link tidyRepeatOption Identifier hi def link tidySorterOption Identifier hi def link tidyStringOption Identifier +hi def link tidyTagsOption Identifier +hi def link tidyAttributesDelimiter Special hi def link tidyAutoBooleanDelimiter Special hi def link tidyBooleanDelimiter Special hi def link tidyCSSSelectorDelimiter Special +hi def link tidyCustomTagsDelimiter Special hi def link tidyDoctypeDelimiter Special hi def link tidyEncodingDelimiter Special hi def link tidyIntegerDelimiter Special +hi def link tidyMuteDelimiter Special hi def link tidyNameDelimiter Special hi def link tidyNewlineDelimiter Special -hi def link tidyTagsDelimiter Special hi def link tidyRepeatDelimiter Special hi def link tidySorterDelimiter Special hi def link tidyStringDelimiter Special +hi def link tidyTagsDelimiter Special hi def link tidyAutoBoolean Boolean hi def link tidyBoolean Boolean +hi def link tidyCustomTags Constant hi def link tidyDoctype Constant hi def link tidyEncoding Constant +hi def link tidyMuteID Constant hi def link tidyNewline Constant -hi def link tidyTags Constant hi def link tidyNumber Number hi def link tidyRepeat Constant hi def link tidySorter Constant hi def link tidyString String +hi def link tidyWord Constant hi def link tidyComment Comment hi def link tidyTodo Todo +hi def link tidyErrorStart Error + +" Postscript {{{1 let b:current_syntax = "tidy" let &cpo = s:cpo_save unlet s:cpo_save -" vim: ts=8 +" vim: ts=8 fdm=marker diff --git a/runtime/tutor/tutor.ko b/runtime/tutor/tutor.ko index 942fdb44a8..f732bbc246 100644 --- a/runtime/tutor/tutor.ko +++ b/runtime/tutor/tutor.ko @@ -907,7 +907,7 @@ ce 는 단어를 치환하는 것 뿐만 아니라, 내용을 삽입할 수 있 5. 을 눌러 ":edit" 명령어를 완성해 봅니다. - 6. 이제 빈칸 하나를 추가한 뒤, 존재 파일 이름을 앞 부분을 입력합니다: :edit FIL + 6. 이제 빈칸 하나를 추가한 뒤, 존재하는 파일 이름의 앞 부분을 입력합니다: :edit FIL 7. 을 눌러 파일 이름을 완성 시킵니다. diff --git a/runtime/tutor/tutor.ko.euc b/runtime/tutor/tutor.ko.euc index 551b9a0ffb..74c81d9444 100644 --- a/runtime/tutor/tutor.ko.euc +++ b/runtime/tutor/tutor.ko.euc @@ -907,7 +907,7 @@ ce 5. ":edit" ɾ ϼ ϴ. - 6. ĭ ϳ ߰ , ̸ κ Էմϴ: :edit FIL + 6. ĭ ϳ ߰ , ϴ ̸ κ Էմϴ: :edit FIL 7. ̸ ϼ ŵϴ. diff --git a/runtime/tutor/tutor.ko.utf-8 b/runtime/tutor/tutor.ko.utf-8 index 942fdb44a8..f732bbc246 100644 --- a/runtime/tutor/tutor.ko.utf-8 +++ b/runtime/tutor/tutor.ko.utf-8 @@ -907,7 +907,7 @@ ce 는 단어를 치환하는 것 뿐만 아니라, 내용을 삽입할 수 있 5. 을 눌러 ":edit" 명령어를 완성해 봅니다. - 6. 이제 빈칸 하나를 추가한 뒤, 존재 파일 이름을 앞 부분을 입력합니다: :edit FIL + 6. 이제 빈칸 하나를 추가한 뒤, 존재하는 파일 이름의 앞 부분을 입력합니다: :edit FIL 7. 을 눌러 파일 이름을 완성 시킵니다. diff --git a/src/GvimExt/Make_ming.mak b/src/GvimExt/Make_ming.mak index a6ab3ae10e..8d17142817 100644 --- a/src/GvimExt/Make_ming.mak +++ b/src/GvimExt/Make_ming.mak @@ -49,8 +49,8 @@ WINVER = 0x0501 endif CXX := $(CROSS_COMPILE)g++ WINDRES := $(CROSS_COMPILE)windres -WINDRES_CXX = $(CXX) -WINDRES_FLAGS = --preprocessor="$(WINDRES_CXX) -E -xc" -DRC_INVOKED +# this used to have --preprocessor, but it's no longer supported +WINDRES_FLAGS = LIBS := -luuid -lgdi32 RES := gvimext.res DEFFILE = gvimext_ming.def diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index b6dd928b12..8895d2797f 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -220,7 +220,6 @@ WINDRES := $(CROSS_COMPILE)windres else WINDRES := windres endif -WINDRES_CC = $(CC) # Get the default ARCH. ifndef ARCH @@ -514,7 +513,8 @@ endif CFLAGS = -I. -Iproto $(DEFINES) -pipe -march=$(ARCH) -Wall CXXFLAGS = -std=gnu++11 -WINDRES_FLAGS = --preprocessor="$(WINDRES_CC) -E -xc" -DRC_INVOKED +# This used to have --preprocessor, but it's no longer supported +WINDRES_FLAGS = EXTRA_LIBS = ifdef GETTEXT diff --git a/src/buffer.c b/src/buffer.c index f071bc729f..5d88d01c04 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2568,12 +2568,15 @@ buflist_findpat( char_u *p; int toggledollar; - if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) + // "%" is current file, "%%" or "#" is alternate file + if ((pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) + || (in_vim9script() && pattern_end == pattern + 2 + && pattern[0] == '%' && pattern[1] == '%')) { - if (*pattern == '%') - match = curbuf->b_fnum; - else + if (*pattern == '#' || pattern_end == pattern + 2) match = curwin->w_alt_fnum; + else + match = curbuf->b_fnum; #ifdef FEAT_DIFF if (diffmode && !diff_mode_buf(buflist_findnr(match))) match = -1; diff --git a/src/debugger.c b/src/debugger.c index f745761f10..4e8a173186 100644 --- a/src/debugger.c +++ b/src/debugger.c @@ -864,7 +864,7 @@ has_profiling( */ static linenr_T debuggy_find( - int file, // TRUE for a file, FALSE for a function + int is_file, // TRUE for a file, FALSE for a function char_u *fname, // file or function name linenr_T after, // after this line number garray_T *gap, // either &dbg_breakp or &prof_ga @@ -873,20 +873,25 @@ debuggy_find( struct debuggy *bp; int i; linenr_T lnum = 0; - char_u *name = fname; + char_u *name = NULL; + char_u *short_name = fname; int prev_got_int; // Return quickly when there are no breakpoints. if (gap->ga_len == 0) return (linenr_T)0; - // Replace K_SNR in function name with "". - if (!file && fname[0] == K_SPECIAL) + // For a script-local function remove the prefix, so that + // "profile func Func" matches "Func" in any script. Otherwise it's very + // difficult to profile/debug a script-local function. It may match a + // function in the wrong script, but that is much better than not being + // able to profile/debug a function in a script with unknown ID. + // Also match a script-specific name. + if (!is_file && fname[0] == K_SPECIAL) { + short_name = vim_strchr(fname, '_') + 1; name = alloc(STRLEN(fname) + 3); - if (name == NULL) - name = fname; - else + if (name != NULL) { STRCPY(name, ""); STRCPY(name + 5, fname + 3); @@ -898,8 +903,8 @@ debuggy_find( // Skip entries that are not useful or are for a line that is beyond // an already found breakpoint. bp = &DEBUGGY(gap, i); - if (((bp->dbg_type == DBG_FILE) == file && - bp->dbg_type != DBG_EXPR && ( + if (((bp->dbg_type == DBG_FILE) == is_file + && bp->dbg_type != DBG_EXPR && ( #ifdef FEAT_PROFILE gap == &prof_ga || #endif @@ -910,7 +915,10 @@ debuggy_find( // while matching should abort it. prev_got_int = got_int; got_int = FALSE; - if (vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0)) + if ((name != NULL + && vim_regexec_prog(&bp->dbg_prog, FALSE, name, (colnr_T)0)) + || vim_regexec_prog(&bp->dbg_prog, FALSE, + short_name, (colnr_T)0)) { lnum = bp->dbg_lnum; if (fp != NULL) diff --git a/src/dict.c b/src/dict.c index fc8756c57b..b267e240db 100644 --- a/src/dict.c +++ b/src/dict.c @@ -1032,7 +1032,8 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal) if (**arg != '}') { - semsg(_(e_missing_dict_end), *arg); + if (evalarg != NULL) + semsg(_(e_missing_dict_end), *arg); failret: if (d != NULL) dict_free(d); diff --git a/src/edit.c b/src/edit.c index 0e7a6792c4..ef8f1ac5d4 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1595,7 +1595,7 @@ decodeModifyOtherKeys(int c) // Recognize: // form 0: {lead}{key};{modifier}u // form 1: {lead}27;{modifier};{key}~ - if ((c == CSI || (c == ESC && *p == '[')) && typebuf.tb_len >= 4) + if (typebuf.tb_len >= 4 && (c == CSI || (c == ESC && *p == '['))) { idx = (*p == '['); if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';') diff --git a/src/errors.h b/src/errors.h index 47e9876f68..4bd4efea69 100644 --- a/src/errors.h +++ b/src/errors.h @@ -84,7 +84,7 @@ EXTERN char e_const_requires_a_value[] EXTERN char e_type_or_initialization_required[] INIT(= N_("E1022: Type or initialization required")); EXTERN char e_using_number_as_bool_nr[] - INIT(= N_("E1023: Using a Number as a Bool: %d")); + INIT(= N_("E1023: Using a Number as a Bool: %lld")); EXTERN char e_using_number_as_string[] INIT(= N_("E1024: Using a Number as a String")); EXTERN char e_using_rcurly_outside_if_block_scope[] @@ -343,3 +343,5 @@ EXTERN char e_mismatched_enddef[] INIT(= N_("E1152: Mismatched enddef")); EXTERN char e_invalid_operation_for_bool[] INIT(= N_("E1153: Invalid operation for bool")); +EXTERN char e_divide_by_zero[] + INIT(= N_("E1154: Divide by zero")); diff --git a/src/eval.c b/src/eval.c index 13ee49aac4..ebd25077c3 100644 --- a/src/eval.c +++ b/src/eval.c @@ -57,14 +57,21 @@ static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u * /* * Return "n1" divided by "n2", taking care of dividing by zero. + * If "failed" is not NULL set it to TRUE when dividing by zero fails. */ varnumber_T -num_divide(varnumber_T n1, varnumber_T n2) +num_divide(varnumber_T n1, varnumber_T n2, int *failed) { varnumber_T result; - if (n2 == 0) // give an error message? + if (n2 == 0) { + if (in_vim9script()) + { + emsg(_(e_divide_by_zero)); + if (failed != NULL) + *failed = TRUE; + } if (n1 == 0) result = VARNUM_MIN; // similar to NaN else if (n1 < 0) @@ -80,11 +87,17 @@ num_divide(varnumber_T n1, varnumber_T n2) /* * Return "n1" modulus "n2", taking care of dividing by zero. + * If "failed" is not NULL set it to TRUE when dividing by zero fails. */ varnumber_T -num_modulus(varnumber_T n1, varnumber_T n2) +num_modulus(varnumber_T n1, varnumber_T n2, int *failed) { - // Give an error when n2 is 0? + if (n2 == 0 && in_vim9script()) + { + emsg(_(e_divide_by_zero)); + if (failed != NULL) + *failed = TRUE; + } return (n2 == 0) ? 0 : (n1 % n2); } @@ -1513,6 +1526,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) varnumber_T n; char_u numbuf[NUMBUFLEN]; char_u *s; + int failed = FALSE; // Can't do anything with a Funcref, Dict, v:true on the right. if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT @@ -1596,8 +1610,10 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) case '+': n += tv_get_number(tv2); break; case '-': n -= tv_get_number(tv2); break; case '*': n *= tv_get_number(tv2); break; - case '/': n = num_divide(n, tv_get_number(tv2)); break; - case '%': n = num_modulus(n, tv_get_number(tv2)); break; + case '/': n = num_divide(n, tv_get_number(tv2), + &failed); break; + case '%': n = num_modulus(n, tv_get_number(tv2), + &failed); break; } clear_tv(tv1); tv1->v_type = VAR_NUMBER; @@ -1616,7 +1632,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op) tv1->v_type = VAR_STRING; tv1->vval.v_string = s; } - return OK; + return failed ? FAIL : OK; case VAR_FLOAT: #ifdef FEAT_FLOAT @@ -3193,12 +3209,16 @@ eval6( else #endif { + int failed = FALSE; + if (op == '*') n1 = n1 * n2; else if (op == '/') - n1 = num_divide(n1, n2); + n1 = num_divide(n1, n2, &failed); else - n1 = num_modulus(n1, n2); + n1 = num_modulus(n1, n2, &failed); + if (failed) + return FAIL; rettv->v_type = VAR_NUMBER; rettv->vval.v_number = n1; @@ -3651,7 +3671,7 @@ call_func_rettv( /* * Evaluate "->method()". - * "*arg" points to the '-'. + * "*arg" points to "method". * Returns FAIL or OK. "*arg" is advanced to after the ')'. */ static int @@ -3666,8 +3686,6 @@ eval_lambda( typval_T base = *rettv; int ret; - // Skip over the ->. - *arg += 2; rettv->v_type = VAR_UNKNOWN; if (**arg == '{') @@ -3715,7 +3733,7 @@ eval_lambda( /* * Evaluate "->method()". - * "*arg" points to the '-'. + * "*arg" points to "method". * Returns FAIL or OK. "*arg" is advanced to after the ')'. */ static int @@ -3733,8 +3751,6 @@ eval_method( int evaluate = evalarg != NULL && (evalarg->eval_flags & EVAL_EVALUATE); - // Skip over the ->. - *arg += 2; rettv->v_type = VAR_UNKNOWN; name = *arg; @@ -5745,10 +5761,10 @@ handle_subscript( } else if (p[0] == '-' && p[1] == '>') { - *arg = p; + *arg = skipwhite(p + 2); if (ret == OK) { - if (((*arg)[2] == '{' && !in_vim9script()) || (*arg)[2] == '(') + if ((**arg == '{' && !in_vim9script()) || **arg == '(') // expr->{lambda}() or expr->(lambda)() ret = eval_lambda(arg, rettv, evalarg, verbose); else diff --git a/src/evalfunc.c b/src/evalfunc.c index a340b3b266..141c145415 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -449,6 +449,11 @@ ret_bool(int argcount UNUSED, type_T **argtypes UNUSED) return &t_bool; } static type_T * +ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_number_bool; +} + static type_T * ret_number(int argcount UNUSED, type_T **argtypes UNUSED) { return &t_number; @@ -690,9 +695,9 @@ static funcentry_T global_functions[] = {"and", 2, 2, FEARG_1, NULL, ret_number, f_and}, {"append", 2, 2, FEARG_2, NULL, - ret_number, f_append}, + ret_number_bool, f_append}, {"appendbufline", 3, 3, FEARG_3, NULL, - ret_number, f_appendbufline}, + ret_number_bool, f_appendbufline}, {"argc", 0, 1, 0, NULL, ret_number, f_argc}, {"argidx", 0, 0, 0, NULL, @@ -704,29 +709,29 @@ static funcentry_T global_functions[] = {"asin", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_asin)}, {"assert_beeps", 1, 2, FEARG_1, NULL, - ret_number, f_assert_beeps}, + ret_number_bool, f_assert_beeps}, {"assert_equal", 2, 3, FEARG_2, NULL, - ret_number, f_assert_equal}, + ret_number_bool, f_assert_equal}, {"assert_equalfile", 2, 3, FEARG_1, NULL, - ret_number, f_assert_equalfile}, + ret_number_bool, f_assert_equalfile}, {"assert_exception", 1, 2, 0, NULL, - ret_number, f_assert_exception}, + ret_number_bool, f_assert_exception}, {"assert_fails", 1, 5, FEARG_1, NULL, - ret_number, f_assert_fails}, + ret_number_bool, f_assert_fails}, {"assert_false", 1, 2, FEARG_1, NULL, - ret_number, f_assert_false}, + ret_number_bool, f_assert_false}, {"assert_inrange", 3, 4, FEARG_3, NULL, - ret_number, f_assert_inrange}, + ret_number_bool, f_assert_inrange}, {"assert_match", 2, 3, FEARG_2, NULL, - ret_number, f_assert_match}, + ret_number_bool, f_assert_match}, {"assert_notequal", 2, 3, FEARG_2, NULL, - ret_number, f_assert_notequal}, + ret_number_bool, f_assert_notequal}, {"assert_notmatch", 2, 3, FEARG_2, NULL, - ret_number, f_assert_notmatch}, + ret_number_bool, f_assert_notmatch}, {"assert_report", 1, 1, FEARG_1, NULL, - ret_number, f_assert_report}, + ret_number_bool, f_assert_report}, {"assert_true", 1, 2, FEARG_1, NULL, - ret_number, f_assert_true}, + ret_number_bool, f_assert_true}, {"atan", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_atan)}, {"atan2", 2, 2, FEARG_1, NULL, @@ -762,19 +767,19 @@ static funcentry_T global_functions[] = {"bufadd", 1, 1, FEARG_1, NULL, ret_number, f_bufadd}, {"bufexists", 1, 1, FEARG_1, NULL, - ret_number, f_bufexists}, + ret_number_bool, f_bufexists}, {"buffer_exists", 1, 1, FEARG_1, NULL, // obsolete - ret_number, f_bufexists}, + ret_number_bool, f_bufexists}, {"buffer_name", 0, 1, FEARG_1, NULL, // obsolete ret_string, f_bufname}, {"buffer_number", 0, 1, FEARG_1, NULL, // obsolete ret_number, f_bufnr}, {"buflisted", 1, 1, FEARG_1, NULL, - ret_number, f_buflisted}, + ret_number_bool, f_buflisted}, {"bufload", 1, 1, FEARG_1, NULL, ret_void, f_bufload}, {"bufloaded", 1, 1, FEARG_1, NULL, - ret_number, f_bufloaded}, + ret_number_bool, f_bufloaded}, {"bufname", 0, 1, FEARG_1, NULL, ret_string, f_bufname}, {"bufnr", 0, 2, FEARG_1, NULL, @@ -794,7 +799,7 @@ static funcentry_T global_functions[] = {"ceil", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_ceil)}, {"ch_canread", 1, 1, FEARG_1, NULL, - ret_number, JOB_FUNC(f_ch_canread)}, + ret_number_bool, JOB_FUNC(f_ch_canread)}, {"ch_close", 1, 1, FEARG_1, NULL, ret_void, JOB_FUNC(f_ch_close)}, {"ch_close_in", 1, 1, FEARG_1, NULL, @@ -852,7 +857,7 @@ static funcentry_T global_functions[] = {"complete_add", 1, 1, FEARG_1, NULL, ret_number, f_complete_add}, {"complete_check", 0, 0, 0, NULL, - ret_number, f_complete_check}, + ret_number_bool, f_complete_check}, {"complete_info", 0, 1, FEARG_1, NULL, ret_dict_any, f_complete_info}, {"confirm", 1, 4, FEARG_1, NULL, @@ -880,19 +885,19 @@ static funcentry_T global_functions[] = {"deepcopy", 1, 2, FEARG_1, NULL, ret_first_arg, f_deepcopy}, {"delete", 1, 2, FEARG_1, NULL, - ret_number, f_delete}, + ret_number_bool, f_delete}, {"deletebufline", 2, 3, FEARG_1, NULL, - ret_number, f_deletebufline}, + ret_number_bool, f_deletebufline}, {"did_filetype", 0, 0, 0, NULL, - ret_number, f_did_filetype}, + ret_number_bool, f_did_filetype}, {"diff_filler", 1, 1, FEARG_1, NULL, ret_number, f_diff_filler}, {"diff_hlID", 2, 2, FEARG_1, NULL, ret_number, f_diff_hlID}, {"echoraw", 1, 1, FEARG_1, NULL, - ret_number, f_echoraw}, + ret_void, f_echoraw}, {"empty", 1, 1, FEARG_1, NULL, - ret_number, f_empty}, + ret_number_bool, f_empty}, {"environ", 0, 0, 0, NULL, ret_dict_string, f_environ}, {"escape", 2, 2, FEARG_1, NULL, @@ -900,7 +905,7 @@ static funcentry_T global_functions[] = {"eval", 1, 1, FEARG_1, NULL, ret_any, f_eval}, {"eventhandler", 0, 0, 0, NULL, - ret_number, f_eventhandler}, + ret_number_bool, f_eventhandler}, {"executable", 1, 1, FEARG_1, NULL, ret_number, f_executable}, {"execute", 1, 2, FEARG_1, NULL, @@ -908,7 +913,7 @@ static funcentry_T global_functions[] = {"exepath", 1, 1, FEARG_1, NULL, ret_string, f_exepath}, {"exists", 1, 1, FEARG_1, NULL, - ret_number, f_exists}, + ret_number_bool, f_exists}, {"exp", 1, 1, FEARG_1, NULL, ret_float, FLOAT_FUNC(f_exp)}, {"expand", 1, 3, FEARG_1, NULL, @@ -922,9 +927,9 @@ static funcentry_T global_functions[] = {"feedkeys", 1, 2, FEARG_1, NULL, ret_void, f_feedkeys}, {"file_readable", 1, 1, FEARG_1, NULL, // obsolete - ret_number, f_filereadable}, + ret_number_bool, f_filereadable}, {"filereadable", 1, 1, FEARG_1, NULL, - ret_number, f_filereadable}, + ret_number_bool, f_filereadable}, {"filewritable", 1, 1, FEARG_1, NULL, ret_number, f_filewritable}, {"filter", 2, 2, FEARG_1, NULL, @@ -1010,7 +1015,7 @@ static funcentry_T global_functions[] = {"getftype", 1, 1, FEARG_1, NULL, ret_string, f_getftype}, {"getimstatus", 0, 0, 0, NULL, - ret_number, f_getimstatus}, + ret_number_bool, f_getimstatus}, {"getjumplist", 0, 2, FEARG_1, NULL, ret_list_any, f_getjumplist}, {"getline", 1, 2, FEARG_1, NULL, @@ -1062,21 +1067,21 @@ static funcentry_T global_functions[] = {"globpath", 2, 5, FEARG_2, NULL, ret_any, f_globpath}, {"has", 1, 2, 0, NULL, - ret_number, f_has}, + ret_number_bool, f_has}, {"has_key", 2, 2, FEARG_1, NULL, - ret_number, f_has_key}, + ret_number_bool, f_has_key}, {"haslocaldir", 0, 2, FEARG_1, NULL, ret_number, f_haslocaldir}, {"hasmapto", 1, 3, FEARG_1, NULL, - ret_number, f_hasmapto}, + ret_number_bool, f_hasmapto}, {"highlightID", 1, 1, FEARG_1, NULL, // obsolete ret_number, f_hlID}, {"highlight_exists",1, 1, FEARG_1, NULL, // obsolete - ret_number, f_hlexists}, + ret_number_bool, f_hlexists}, {"histadd", 2, 2, FEARG_2, NULL, - ret_number, f_histadd}, + ret_number_bool, f_histadd}, {"histdel", 1, 2, FEARG_1, NULL, - ret_number, f_histdel}, + ret_number_bool, f_histdel}, {"histget", 1, 2, FEARG_1, NULL, ret_string, f_histget}, {"histnr", 1, 1, FEARG_1, NULL, @@ -1084,7 +1089,7 @@ static funcentry_T global_functions[] = {"hlID", 1, 1, FEARG_1, NULL, ret_number, f_hlID}, {"hlexists", 1, 1, FEARG_1, NULL, - ret_number, f_hlexists}, + ret_number_bool, f_hlexists}, {"hostname", 0, 0, 0, NULL, ret_string, f_hostname}, {"iconv", 3, 3, FEARG_1, NULL, @@ -1100,9 +1105,9 @@ static funcentry_T global_functions[] = {"inputlist", 1, 1, FEARG_1, NULL, ret_number, f_inputlist}, {"inputrestore", 0, 0, 0, NULL, - ret_number, f_inputrestore}, + ret_number_bool, f_inputrestore}, {"inputsave", 0, 0, 0, NULL, - ret_number, f_inputsave}, + ret_number_bool, f_inputsave}, {"inputsecret", 1, 2, FEARG_1, NULL, ret_string, f_inputsecret}, {"insert", 2, 3, FEARG_1, arg3_insert, @@ -1112,13 +1117,13 @@ static funcentry_T global_functions[] = {"invert", 1, 1, FEARG_1, NULL, ret_number, f_invert}, {"isdirectory", 1, 1, FEARG_1, NULL, - ret_number, f_isdirectory}, + ret_number_bool, f_isdirectory}, {"isinf", 1, 1, FEARG_1, NULL, ret_number, MATH_FUNC(f_isinf)}, {"islocked", 1, 1, FEARG_1, NULL, - ret_number, f_islocked}, + ret_number_bool, f_islocked}, {"isnan", 1, 1, FEARG_1, NULL, - ret_number, MATH_FUNC(f_isnan)}, + ret_number_bool, MATH_FUNC(f_isnan)}, {"items", 1, 1, FEARG_1, NULL, ret_list_any, f_items}, {"job_getchannel", 1, 1, FEARG_1, NULL, @@ -1132,7 +1137,7 @@ static funcentry_T global_functions[] = {"job_status", 1, 1, FEARG_1, NULL, ret_string, JOB_FUNC(f_job_status)}, {"job_stop", 1, 2, FEARG_1, NULL, - ret_number, JOB_FUNC(f_job_stop)}, + ret_number_bool, JOB_FUNC(f_job_stop)}, {"join", 1, 2, FEARG_1, NULL, ret_string, f_join}, {"js_decode", 1, 1, FEARG_1, NULL, @@ -1166,7 +1171,7 @@ static funcentry_T global_functions[] = {"listener_flush", 0, 1, FEARG_1, NULL, ret_void, f_listener_flush}, {"listener_remove", 1, 1, FEARG_1, NULL, - ret_number, f_listener_remove}, + ret_number_bool, f_listener_remove}, {"localtime", 0, 0, 0, NULL, ret_number, f_localtime}, {"log", 1, 1, FEARG_1, NULL, @@ -1200,7 +1205,7 @@ static funcentry_T global_functions[] = {"matcharg", 1, 1, FEARG_1, NULL, ret_list_string, f_matcharg}, {"matchdelete", 1, 2, FEARG_1, NULL, - ret_number, f_matchdelete}, + ret_number_bool, f_matchdelete}, {"matchend", 2, 4, FEARG_1, NULL, ret_number, f_matchend}, {"matchfuzzy", 2, 3, FEARG_1, NULL, @@ -1214,7 +1219,7 @@ static funcentry_T global_functions[] = {"matchstrpos", 2, 4, FEARG_1, NULL, ret_list_any, f_matchstrpos}, {"max", 1, 1, FEARG_1, NULL, - ret_any, f_max}, + ret_number, f_max}, {"menu_info", 1, 2, FEARG_1, NULL, ret_dict_any, #ifdef FEAT_MENU @@ -1224,9 +1229,9 @@ static funcentry_T global_functions[] = #endif }, {"min", 1, 1, FEARG_1, NULL, - ret_any, f_min}, + ret_number, f_min}, {"mkdir", 1, 3, FEARG_1, NULL, - ret_number, f_mkdir}, + ret_number_bool, f_mkdir}, {"mode", 0, 1, FEARG_1, NULL, ret_string, f_mode}, {"mzeval", 1, 1, FEARG_1, NULL, @@ -1332,7 +1337,7 @@ static funcentry_T global_functions[] = {"pum_getpos", 0, 0, 0, NULL, ret_dict_number, f_pum_getpos}, {"pumvisible", 0, 0, 0, NULL, - ret_number, f_pumvisible}, + ret_number_bool, f_pumvisible}, {"py3eval", 1, 1, FEARG_1, NULL, ret_any, #ifdef FEAT_PYTHON3 @@ -1396,7 +1401,7 @@ static funcentry_T global_functions[] = {"remove", 2, 3, FEARG_1, NULL, ret_remove, f_remove}, {"rename", 2, 2, FEARG_1, NULL, - ret_number, f_rename}, + ret_number_bool, f_rename}, {"repeat", 2, 2, FEARG_1, NULL, ret_first_arg, f_repeat}, {"resolve", 1, 1, FEARG_1, NULL, @@ -1432,7 +1437,7 @@ static funcentry_T global_functions[] = {"searchcount", 0, 1, FEARG_1, NULL, ret_dict_any, f_searchcount}, {"searchdecl", 1, 3, FEARG_1, NULL, - ret_number, f_searchdecl}, + ret_number_bool, f_searchdecl}, {"searchpair", 3, 7, 0, NULL, ret_number, f_searchpair}, {"searchpairpos", 3, 7, 0, NULL, @@ -1440,45 +1445,45 @@ static funcentry_T global_functions[] = {"searchpos", 1, 5, FEARG_1, NULL, ret_list_number, f_searchpos}, {"server2client", 2, 2, FEARG_1, NULL, - ret_number, f_server2client}, + ret_number_bool, f_server2client}, {"serverlist", 0, 0, 0, NULL, ret_string, f_serverlist}, {"setbufline", 3, 3, FEARG_3, NULL, - ret_number, f_setbufline}, + ret_number_bool, f_setbufline}, {"setbufvar", 3, 3, FEARG_3, NULL, ret_void, f_setbufvar}, {"setcellwidths", 1, 1, FEARG_1, NULL, ret_void, f_setcellwidths}, {"setcharpos", 2, 2, FEARG_2, NULL, - ret_number, f_setcharpos}, + ret_number_bool, f_setcharpos}, {"setcharsearch", 1, 1, FEARG_1, NULL, ret_void, f_setcharsearch}, {"setcmdpos", 1, 1, FEARG_1, NULL, - ret_number, f_setcmdpos}, - {"setcursorcharpos", 1, 3, FEARG_1, NULL, - ret_number, f_setcursorcharpos}, + ret_number_bool, f_setcmdpos}, + {"setcursorcharpos", 1, 3, FEARG_1, NULL, + ret_number_bool, f_setcursorcharpos}, {"setenv", 2, 2, FEARG_2, NULL, ret_void, f_setenv}, {"setfperm", 2, 2, FEARG_1, NULL, - ret_number, f_setfperm}, + ret_number_bool, f_setfperm}, {"setline", 2, 2, FEARG_2, NULL, - ret_number, f_setline}, + ret_number_bool, f_setline}, {"setloclist", 2, 4, FEARG_2, NULL, - ret_number, f_setloclist}, + ret_number_bool, f_setloclist}, {"setmatches", 1, 2, FEARG_1, NULL, - ret_number, f_setmatches}, + ret_number_bool, f_setmatches}, {"setpos", 2, 2, FEARG_2, NULL, - ret_number, f_setpos}, + ret_number_bool, f_setpos}, {"setqflist", 1, 3, FEARG_1, NULL, - ret_number, f_setqflist}, + ret_number_bool, f_setqflist}, {"setreg", 2, 3, FEARG_2, NULL, - ret_number, f_setreg}, + ret_number_bool, f_setreg}, {"settabvar", 3, 3, FEARG_3, NULL, ret_void, f_settabvar}, {"settabwinvar", 4, 4, FEARG_4, NULL, ret_void, f_settabwinvar}, {"settagstack", 2, 3, FEARG_2, NULL, - ret_number, f_settagstack}, + ret_number_bool, f_settagstack}, {"setwinvar", 3, 3, FEARG_3, NULL, ret_void, f_setwinvar}, {"sha256", 1, 1, FEARG_1, NULL, @@ -1506,9 +1511,9 @@ static funcentry_T global_functions[] = {"sign_placelist", 1, 1, FEARG_1, NULL, ret_list_number, SIGN_FUNC(f_sign_placelist)}, {"sign_undefine", 0, 1, FEARG_1, NULL, - ret_number, SIGN_FUNC(f_sign_undefine)}, + ret_number_bool, SIGN_FUNC(f_sign_undefine)}, {"sign_unplace", 1, 2, FEARG_1, NULL, - ret_number, SIGN_FUNC(f_sign_unplace)}, + ret_number_bool, SIGN_FUNC(f_sign_unplace)}, {"sign_unplacelist", 1, 2, FEARG_1, NULL, ret_list_number, SIGN_FUNC(f_sign_unplacelist)}, {"simplify", 1, 1, FEARG_1, NULL, @@ -1788,7 +1793,7 @@ static funcentry_T global_functions[] = {"win_gettype", 0, 1, FEARG_1, NULL, ret_string, f_win_gettype}, {"win_gotoid", 1, 1, FEARG_1, NULL, - ret_number, f_win_gotoid}, + ret_number_bool, f_win_gotoid}, {"win_id2tabwin", 1, 1, FEARG_1, NULL, ret_list_number, f_win_id2tabwin}, {"win_id2win", 1, 1, FEARG_1, NULL, @@ -1796,7 +1801,7 @@ static funcentry_T global_functions[] = {"win_screenpos", 1, 1, FEARG_1, NULL, ret_list_number, f_win_screenpos}, {"win_splitmove", 2, 3, FEARG_1, NULL, - ret_number, f_win_splitmove}, + ret_number_bool, f_win_splitmove}, {"winbufnr", 1, 1, FEARG_1, NULL, ret_number, f_winbufnr}, {"wincol", 0, 0, 0, NULL, @@ -1822,7 +1827,7 @@ static funcentry_T global_functions[] = {"wordcount", 0, 0, 0, NULL, ret_dict_number, f_wordcount}, {"writefile", 2, 3, FEARG_1, NULL, - ret_number, f_writefile}, + ret_number_bool, f_writefile}, {"xor", 2, 2, FEARG_1, NULL, ret_number, f_xor}, }; @@ -2567,7 +2572,7 @@ f_charidx(typval_T *argvars, typval_T *rettv) { char_u *str; varnumber_T idx; - int countcc = FALSE; + varnumber_T countcc = FALSE; char_u *p; int len; int (*ptr2len)(char_u *); @@ -2588,7 +2593,7 @@ f_charidx(typval_T *argvars, typval_T *rettv) return; if (argvars[2].v_type != VAR_UNKNOWN) - countcc = (int)tv_get_bool(&argvars[2]); + countcc = tv_get_bool(&argvars[2]); if (countcc < 0 || countcc > 1) { semsg(_(e_using_number_as_bool_nr), countcc); @@ -2848,11 +2853,11 @@ f_debugbreak(typval_T *argvars, typval_T *rettv) static void f_deepcopy(typval_T *argvars, typval_T *rettv) { - int noref = 0; + varnumber_T noref = 0; int copyID; if (argvars[1].v_type != VAR_UNKNOWN) - noref = (int)tv_get_bool_chk(&argvars[1], NULL); + noref = tv_get_bool_chk(&argvars[1], NULL); if (noref < 0 || noref > 1) semsg(_(e_using_number_as_bool_nr), noref); else @@ -8345,7 +8350,7 @@ f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED) * "setcursorcharpos" function */ static void -f_setcursorcharpos(typval_T *argvars, typval_T *rettv UNUSED) +f_setcursorcharpos(typval_T *argvars, typval_T *rettv) { set_cursorpos(argvars, rettv, TRUE); } @@ -9220,12 +9225,12 @@ f_strlen(typval_T *argvars, typval_T *rettv) f_strchars(typval_T *argvars, typval_T *rettv) { char_u *s = tv_get_string(&argvars[0]); - int skipcc = FALSE; + varnumber_T skipcc = FALSE; varnumber_T len = 0; int (*func_mb_ptr2char_adv)(char_u **pp); if (argvars[1].v_type != VAR_UNKNOWN) - skipcc = (int)tv_get_bool(&argvars[1]); + skipcc = tv_get_bool(&argvars[1]); if (skipcc < 0 || skipcc > 1) semsg(_(e_using_number_as_bool_nr), skipcc); else diff --git a/src/evalvars.c b/src/evalvars.c index d3470096cd..8a922b9a46 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -122,6 +122,8 @@ static struct vimvar {VV_NAME("true", VAR_BOOL), VV_RO}, {VV_NAME("none", VAR_SPECIAL), VV_RO}, {VV_NAME("null", VAR_SPECIAL), VV_RO}, + {VV_NAME("numbermax", VAR_NUMBER), VV_RO}, + {VV_NAME("numbermin", VAR_NUMBER), VV_RO}, {VV_NAME("numbersize", VAR_NUMBER), VV_RO}, {VV_NAME("vim_did_enter", VAR_NUMBER), VV_RO}, {VV_NAME("testing", VAR_NUMBER), 0}, @@ -230,6 +232,8 @@ evalvars_init(void) set_vim_var_nr(VV_TRUE, VVAL_TRUE); set_vim_var_nr(VV_NONE, VVAL_NONE); set_vim_var_nr(VV_NULL, VVAL_NULL); + set_vim_var_nr(VV_NUMBERMAX, VARNUM_MAX); + set_vim_var_nr(VV_NUMBERMIN, VARNUM_MIN); set_vim_var_nr(VV_NUMBERSIZE, sizeof(varnumber_T) * 8); set_vim_var_nr(VV_TYPE_NUMBER, VAR_TYPE_NUMBER); @@ -836,6 +840,8 @@ ex_let(exarg_T *eap) i = FAIL; if (has_assign || concat) { + int cur_lnum; + op[0] = '='; op[1] = NUL; if (*expr != '=') @@ -880,10 +886,15 @@ ex_let(exarg_T *eap) evalarg.eval_cookie = eap->cookie; } expr = skipwhite_and_linebreak(expr, &evalarg); + cur_lnum = SOURCING_LNUM; i = eval0(expr, &rettv, eap, &evalarg); if (eap->skip) --emsg_skip; clear_evalarg(&evalarg, eap); + + // Restore the line number so that any type error is given for the + // declaration, not the expression. + SOURCING_LNUM = cur_lnum; } if (eap->skip) { @@ -1021,7 +1032,7 @@ skip_var_list( for (;;) { p = skipwhite(p + 1); // skip whites after '[', ';' or ',' - s = skip_var_one(p, FALSE); + s = skip_var_one(p, include_type); if (s == p) { if (!silent) @@ -1063,17 +1074,21 @@ skip_var_list( char_u * skip_var_one(char_u *arg, int include_type) { - char_u *end; + char_u *end; + int vim9 = in_vim9script(); if (*arg == '@' && arg[1] != NUL) return arg + 2; end = find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START); - if (include_type && in_vim9script()) + + // "a: type" is declaring variable "a" with a type, not "a:". + // Same for "s: type". + if (vim9 && end == arg + 2 && end[-1] == ':') + --end; + + if (include_type && vim9) { - // "a: type" is declaring variable "a" with a type, not "a:". - if (end == arg + 2 && end[-1] == ':') - --end; if (*end == ':') end = skip_type(skipwhite(end + 1), FALSE); } @@ -1408,8 +1423,10 @@ ex_let_one( case '+': n = numval + n; break; case '-': n = numval - n; break; case '*': n = numval * n; break; - case '/': n = (long)num_divide(numval, n); break; - case '%': n = (long)num_modulus(numval, n); break; + case '/': n = (long)num_divide(numval, n, + &failed); break; + case '%': n = (long)num_modulus(numval, n, + &failed); break; } } else if (opt_type == gov_string diff --git a/src/ex_cmds.h b/src/ex_cmds.h index acd3120ff4..b530adf174 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -489,7 +489,7 @@ EXCMD(CMD_digraphs, "digraphs", ex_digraphs, EX_BANG|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_disassemble, "disassemble", ex_disassemble, - EX_EXTRA|EX_NEEDARG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + EX_BANG|EX_EXTRA|EX_NEEDARG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), EXCMD(CMD_djump, "djump", ex_findpat, EX_BANG|EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_EXTRA, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index a3c345c943..314d589480 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -872,7 +872,7 @@ do_cmdline( if (do_profiling == PROF_YES) { if (getline_is_func) - func_line_start(real_cookie); + func_line_start(real_cookie, SOURCING_LNUM); else if (getline_equal(fgetline, cookie, getsourceline)) script_line_start(); } @@ -3319,8 +3319,9 @@ find_ex_command( if (vim_strchr((char_u *)"{('[\"@", *p) != NULL || ((p = to_name_const_end(pskip)) > eap->cmd && *p != NUL)) { - int oplen; - int heredoc; + int oplen; + int heredoc; + char_u *swp = skipwhite(p); if ( // "(..." is an expression. @@ -3338,7 +3339,7 @@ find_ex_command( || eap->cmd[1] == ':' ) // "varname->func()" is an expression. - : (*p == '-' && p[1] == '>'))) + : (*swp == '-' && swp[1] == '>'))) { if (*eap->cmd == '{' && ends_excmd(*skipwhite(eap->cmd + 1))) { diff --git a/src/list.c b/src/list.c index d6357f789c..77dd2a3074 100644 --- a/src/list.c +++ b/src/list.c @@ -925,7 +925,7 @@ list_slice_or_index( if (!range) { if (verbose) - semsg(_(e_listidx), n1_arg); + semsg(_(e_listidx), (long)n1_arg); return FAIL; } n1 = n1 < 0 ? 0 : len; @@ -1452,7 +1452,7 @@ list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) listitem_T *item, *item2; listitem_T *li; int error = FALSE; - int idx; + long idx; if ((l = argvars[0].vval.v_list) == NULL || value_check_lock(l->lv_lock, arg_errmsg, TRUE)) @@ -1475,7 +1475,7 @@ list_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) else { // Remove range of items, return list with values. - int end = (long)tv_get_number_chk(&argvars[2], &error); + long end = (long)tv_get_number_chk(&argvars[2], &error); if (error) ; // type error: do nothing diff --git a/src/mark.c b/src/mark.c index 5efda8e0eb..6107c9ac4e 100644 --- a/src/mark.c +++ b/src/mark.c @@ -140,9 +140,6 @@ setpcmark(void) int i; xfmark_T *fm; #endif -#ifdef JUMPLIST_ROTATE - xfmark_T tempmark; -#endif // for :global the mark is set only once if (global_busy || listcmd_busy || (cmdmod.cmod_flags & CMOD_KEEPJUMPS)) @@ -152,24 +149,6 @@ setpcmark(void) curwin->w_pcmark = curwin->w_cursor; #ifdef FEAT_JUMPLIST -# ifdef JUMPLIST_ROTATE - /* - * If last used entry is not at the top, put it at the top by rotating - * the stack until it is (the newer entries will be at the bottom). - * Keep one entry (the last used one) at the top. - */ - if (curwin->w_jumplistidx < curwin->w_jumplistlen) - ++curwin->w_jumplistidx; - while (curwin->w_jumplistidx < curwin->w_jumplistlen) - { - tempmark = curwin->w_jumplist[curwin->w_jumplistlen - 1]; - for (i = curwin->w_jumplistlen - 1; i > 0; --i) - curwin->w_jumplist[i] = curwin->w_jumplist[i - 1]; - curwin->w_jumplist[0] = tempmark; - ++curwin->w_jumplistidx; - } -# endif - // If jumplist is full: remove oldest entry if (++curwin->w_jumplistlen > JUMPLISTSIZE) { diff --git a/src/misc2.c b/src/misc2.c index 7c7c73c779..3a8193d15b 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -2538,6 +2538,8 @@ static struct key_name_entry #endif {K_IGNORE, (char_u *)"Ignore"}, {K_COMMAND, (char_u *)"Cmd"}, + {K_FOCUSGAINED, (char_u *)"FocusGained"}, + {K_FOCUSLOST, (char_u *)"FocusLost"}, {0, NULL} // NOTE: When adding a long name update MAX_KEY_NAME_LEN. }; diff --git a/src/normal.c b/src/normal.c index a869ba11a2..aee5d4570a 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2573,12 +2573,6 @@ nv_screengo(oparg_T *oap, int dir, long dist) else { // to previous line - if (curwin->w_cursor.lnum == 1) - { - retval = FAIL; - break; - } - --curwin->w_cursor.lnum; #ifdef FEAT_FOLDING // Move to the start of a closed fold. Don't do that when // 'foldopen' contains "all": it will open in a moment. @@ -2586,6 +2580,13 @@ nv_screengo(oparg_T *oap, int dir, long dist) (void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); #endif + if (curwin->w_cursor.lnum == 1) + { + retval = FAIL; + break; + } + --curwin->w_cursor.lnum; + linelen = linetabsize(ml_get_curline()); if (linelen > width1) curwin->w_curswant += (((linelen - width1 - 1) / width2) @@ -5969,13 +5970,8 @@ nv_g_cmd(cmdarg_T *cap) */ case 'j': case K_DOWN: - // with 'nowrap' it works just like the normal "j" command; also when - // in a closed fold - if (!curwin->w_p_wrap -#ifdef FEAT_FOLDING - || hasFolding(curwin->w_cursor.lnum, NULL, NULL) -#endif - ) + // with 'nowrap' it works just like the normal "j" command. + if (!curwin->w_p_wrap) { oap->motion_type = MLINE; i = cursor_down(cap->count1, oap->op_type == OP_NOP); @@ -5988,13 +5984,8 @@ nv_g_cmd(cmdarg_T *cap) case 'k': case K_UP: - // with 'nowrap' it works just like the normal "k" command; also when - // in a closed fold - if (!curwin->w_p_wrap -#ifdef FEAT_FOLDING - || hasFolding(curwin->w_cursor.lnum, NULL, NULL) -#endif - ) + // with 'nowrap' it works just like the normal "k" command. + if (!curwin->w_p_wrap) { oap->motion_type = MLINE; i = cursor_up(cap->count1, oap->op_type == OP_NOP); diff --git a/src/profiler.c b/src/profiler.c index 7896897a44..46ab3e3059 100644 --- a/src/profiler.c +++ b/src/profiler.c @@ -554,6 +554,51 @@ func_do_profile(ufunc_T *fp) fp->uf_profiling = TRUE; } +/* + * When calling a function: may initialize for profiling. + */ + void +profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc) +{ + if (do_profiling == PROF_YES) + { + if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) + { + info->pi_started_profiling = TRUE; + func_do_profile(fp); + } + if (fp->uf_profiling + || (fc->caller != NULL && fc->caller->func->uf_profiling)) + { + ++fp->uf_tm_count; + profile_start(&info->pi_call_start); + profile_zero(&fp->uf_tm_children); + } + script_prof_save(&info->pi_wait_start); + } +} + +/* + * After calling a function: may handle profiling. profile_may_start_func() + * must have been called previously. + */ + void +profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc) +{ + profile_end(&info->pi_call_start); + profile_sub_wait(&info->pi_wait_start, &info->pi_call_start); + profile_add(&fp->uf_tm_total, &info->pi_call_start); + profile_self(&fp->uf_tm_self, &info->pi_call_start, &fp->uf_tm_children); + if (fc->caller != NULL && fc->caller->func->uf_profiling) + { + profile_add(&fc->caller->func->uf_tm_children, &info->pi_call_start); + profile_add(&fc->caller->func->uf_tml_children, &info->pi_call_start); + } + if (info->pi_started_profiling) + // make a ":profdel func" stop profiling the function + fp->uf_profiling = FALSE; +} + /* * Prepare profiling for entering a child or something else that is not * counted for the script/function itself. @@ -597,15 +642,14 @@ prof_child_exit( * until later and we need to store the time now. */ void -func_line_start(void *cookie) +func_line_start(void *cookie, long lnum) { funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; - if (fp->uf_profiling && SOURCING_LNUM >= 1 - && SOURCING_LNUM <= fp->uf_lines.ga_len) + if (fp->uf_profiling && lnum >= 1 && lnum <= fp->uf_lines.ga_len) { - fp->uf_tml_idx = SOURCING_LNUM - 1; + fp->uf_tml_idx = lnum - 1; // Skip continuation lines. while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) --fp->uf_tml_idx; diff --git a/src/proto/eval.pro b/src/proto/eval.pro index fbae530306..07b11b25a5 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -1,6 +1,6 @@ /* eval.c */ -varnumber_T num_divide(varnumber_T n1, varnumber_T n2); -varnumber_T num_modulus(varnumber_T n1, varnumber_T n2); +varnumber_T num_divide(varnumber_T n1, varnumber_T n2, int *failed); +varnumber_T num_modulus(varnumber_T n1, varnumber_T n2, int *failed); void eval_init(void); void eval_clear(void); void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip); diff --git a/src/proto/profiler.pro b/src/proto/profiler.pro index 5e0b6a2144..b2070df132 100644 --- a/src/proto/profiler.pro +++ b/src/proto/profiler.pro @@ -19,9 +19,11 @@ void prof_inchar_enter(void); void prof_inchar_exit(void); int prof_def_func(void); void func_do_profile(ufunc_T *fp); +void profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc); +void profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc); void prof_child_enter(proftime_T *tm); void prof_child_exit(proftime_T *tm); -void func_line_start(void *cookie); +void func_line_start(void *cookie, long lnum); void func_line_exec(void *cookie); void func_line_end(void *cookie); void script_do_profile(scriptitem_T *si); diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index d1d1b0c7d0..04c3c5efda 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -3,6 +3,7 @@ int check_defined(char_u *p, size_t len, cctx_T *cctx); int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2); int use_typecheck(type_T *actual, type_T *expected); int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const); +int func_needs_compiling(ufunc_T *ufunc, int profile); int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx); imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); imported_T *find_imported_in_script(char_u *name, size_t len, int sid); @@ -15,7 +16,7 @@ void error_white_both(char_u *op, int len); int assignment_len(char_u *p, int *heredoc); void vim9_declare_error(char_u *name); int check_vim9_unlet(char_u *name); -int compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx); +int compile_def_function(ufunc_T *ufunc, int check_return_type, int profiling, cctx_T *outer_cctx); void set_function_type(ufunc_T *ufunc); void delete_instr(isn_T *isn); void unlink_def_function(ufunc_T *ufunc); diff --git a/src/spellsuggest.c b/src/spellsuggest.c index e2423cd98a..3de9ff2112 100644 --- a/src/spellsuggest.c +++ b/src/spellsuggest.c @@ -770,6 +770,7 @@ spell_find_suggest( int c; int i; langp_T *lp; + int did_intern = FALSE; // Set the info in "*su". CLEAR_POINTER(su); @@ -863,12 +864,13 @@ spell_find_suggest( else if (STRNCMP(buf, "file:", 5) == 0) // Use list of suggestions in a file. spell_suggest_file(su, buf + 5); - else + else if (!did_intern) { - // Use internal method. + // Use internal method once. spell_suggest_intern(su, interactive); if (sps_flags & SPS_DOUBLE) do_combine = TRUE; + did_intern = TRUE; } } diff --git a/src/structs.h b/src/structs.h index 3cfd447cad..a717051b27 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1577,7 +1577,7 @@ typedef struct svar_S svar_T; #if defined(FEAT_EVAL) || defined(PROTO) typedef struct funccall_S funccall_T; -// values used for "uf_dfunc_idx" +// values used for "uf_def_status" typedef enum { UF_NOT_COMPILED, UF_TO_BE_COMPILED, @@ -1899,6 +1899,18 @@ typedef struct sn_prl_S } sn_prl_T; # define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)]) + +typedef struct { + int pi_started_profiling; + proftime_T pi_wait_start; + proftime_T pi_call_start; +} profinfo_T; + +# else +typedef struct +{ + int dummy; +} profinfo_T; # endif #else // dummy typedefs for use in function prototypes diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index e5f521c85c..52e8df9242 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -256,10 +256,13 @@ func Test_execute_cmd_with_null() endif endfunc -func Test_numbersize() - " This will fail on systems without 64 bit int support or when not configured - " correctly. +func Test_number_max_min_size() + " This will fail on systems without 64 bit number support or when not + " configured correctly. call assert_equal(64, v:numbersize) + + call assert_true(v:numbermin < -9999999) + call assert_true(v:numbermax > 9999999) endfunc func Assert_reg(name, type, value, valuestr, expr, exprstr) diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index b05c152dc6..4104ec2b32 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -162,6 +162,7 @@ let s:filename_checks = { \ 'elinks': ['elinks.conf'], \ 'elm': ['file.elm'], \ 'elmfilt': ['filter-rules'], + \ 'epuppet': ['file.epp'], \ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'], \ 'eruby': ['file.erb', 'file.rhtml'], \ 'esmtprc': ['anyesmtprc', 'esmtprc', 'some-esmtprc'], @@ -174,6 +175,7 @@ let s:filename_checks = { \ 'factor': ['file.factor'], \ 'falcon': ['file.fal'], \ 'fan': ['file.fan', 'file.fwt'], + \ 'fennel': ['file.fnl'], \ 'fetchmail': ['.fetchmailrc'], \ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'], \ 'focexec': ['file.fex', 'file.focexec'], @@ -390,6 +392,7 @@ let s:filename_checks = { \ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'], \ 'radiance': ['file.rad', 'file.mat'], \ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'], + \ 'rbs': ['file.rbs'], \ 'rc': ['file.rc', 'file.rch'], \ 'rcs': ['file,v'], \ 'readline': ['.inputrc', 'inputrc'], @@ -406,7 +409,7 @@ let s:filename_checks = { \ 'rpl': ['file.rpl'], \ 'rst': ['file.rst'], \ 'rtf': ['file.rtf'], - \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file'], + \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile'], \ 'rust': ['file.rs'], \ 'samba': ['smb.conf'], \ 'sas': ['file.sas'], @@ -639,6 +642,7 @@ let s:script_checks = { \ ['// -*- C++ -*-']], \ 'yaml': [['%YAML 1.2']], \ 'pascal': [['#!/path/instantfpc']], + \ 'fennel': [['#!/path/fennel']], \ } " Various forms of "env" optional arguments. @@ -733,6 +737,23 @@ func Test_ts_file() filetype off endfunc +func Test_ttl_file() + filetype on + + call writefile(['@base .'], 'Xfile.ttl') + split Xfile.ttl + call assert_equal('turtle', &filetype) + bwipe! + + call writefile(['looks like Tera Term Language'], 'Xfile.ttl') + split Xfile.ttl + call assert_equal('teraterm', &filetype) + bwipe! + + call delete('Xfile.ttl') + filetype off +endfunc + func Test_pp_file() filetype on diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim index b978fc080f..8206193c4a 100644 --- a/src/testdir/test_fold.vim +++ b/src/testdir/test_fold.vim @@ -859,4 +859,39 @@ func Test_fold_create_delete() bwipe! endfunc +func Test_fold_relative_move() + enew! + set fdm=indent sw=2 wrap tw=80 + + let content = [ ' foo', ' bar', ' baz', + \ repeat('x', &columns + 1), + \ ' foo', ' bar', ' baz' + \ ] + call append(0, content) + + normal zM + + call cursor(3, 1) + call assert_true(foldclosed(line('.'))) + normal gj + call assert_equal(2, winline()) + + call cursor(2, 1) + call assert_true(foldclosed(line('.'))) + normal 2gj + call assert_equal(3, winline()) + + call cursor(5, 1) + call assert_true(foldclosed(line('.'))) + normal gk + call assert_equal(3, winline()) + + call cursor(6, 1) + call assert_true(foldclosed(line('.'))) + normal 2gk + call assert_equal(2, winline()) + + set fdm& sw& wrap& tw& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_highlight.vim b/src/testdir/test_highlight.vim index 8bd03e2da1..a4c7a72591 100644 --- a/src/testdir/test_highlight.vim +++ b/src/testdir/test_highlight.vim @@ -781,8 +781,9 @@ func Test_highlight_User() endfunc " Test for using RGB color values in a highlight group -func Test_highlight_RGB_color() - CheckGui +func Test_xxlast_highlight_RGB_color() + CheckCanRunGui + gui -f hi MySearch guifg=#110000 guibg=#001100 guisp=#000011 call assert_equal('#110000', synIDattr(synIDtrans(hlID('MySearch')), 'fg#')) call assert_equal('#001100', synIDattr(synIDtrans(hlID('MySearch')), 'bg#')) diff --git a/src/testdir/test_method.vim b/src/testdir/test_method.vim index 0d55f2a894..262c08c79b 100644 --- a/src/testdir/test_method.vim +++ b/src/testdir/test_method.vim @@ -131,9 +131,11 @@ func Test_method_syntax() eval [1, 2, 3] \ ->sort( \ ) - call assert_fails('eval [1, 2, 3]-> sort()', 'E15:') + eval [1, 2, 3]-> sort() + call assert_fails('eval [1, 2, 3]->sort ()', 'E274:') - call assert_fails('eval [1, 2, 3]-> sort ()', 'E15:') + call assert_fails('eval [1, 2, 3] ->sort ()', 'E274:') + call assert_fails('eval [1, 2, 3]-> sort ()', 'E274:') endfunc func Test_method_lambda() diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index b8aeddd83b..3773aa88cb 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -371,8 +371,14 @@ func Test_set_errors() call assert_fails('set foldmarker=x', 'E536:') call assert_fails('set commentstring=x', 'E537:') call assert_fails('set complete=x', 'E539:') + call assert_fails('set rulerformat=%-', 'E539:') + call assert_fails('set rulerformat=%(', 'E542:') + call assert_fails('set rulerformat=%15(%%', 'E542:') + call assert_fails('set statusline=%$', 'E539:') call assert_fails('set statusline=%{', 'E540:') call assert_fails('set statusline=%(', 'E542:') + call assert_fails('set statusline=%)', 'E542:') + if has('cursorshape') " This invalid value for 'guicursor' used to cause Vim to crash. call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:') @@ -406,11 +412,22 @@ func Test_set_errors() call assert_fails('set wildchar=', 'E474:') call assert_fails('set cmdheight=1a', 'E521:') call assert_fails('set invcmdheight', 'E474:') - if has('python') && has('python3') + if has('python') || has('python3') call assert_fails('set pyxversion=6', 'E474:') endif call assert_fails("let &tabstop='ab'", 'E521:') call assert_fails('set spellcapcheck=%\\(', 'E54:') + call assert_fails('set sessionoptions=curdir,sesdir', 'E474:') + call assert_fails('set foldmarker={{{,', 'E474:') + call assert_fails('set sessionoptions=sesdir,curdir', 'E474:') + call assert_fails('set listchars=trail:· ambiwidth=double', 'E834:') + set listchars& + call assert_fails('set fillchars=stl:· ambiwidth=double', 'E835:') + set fillchars& + call assert_fails('set fileencoding=latin1,utf-8', 'E474:') + set nomodifiable + call assert_fails('set fileencoding=latin1', 'E21:') + set modifiable& endfunc func CheckWasSet(name) diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim index 7bac118aef..c8c877d5c1 100644 --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -5,24 +5,30 @@ CheckFeature profile source shared.vim source screendump.vim +source vim9.vim func Test_profile_func() + call RunProfileFunc('func', 'let', 'let') + call RunProfileFunc('def', 'var', '') +endfunc + +func RunProfileFunc(command, declare, assign) let lines =<< trim [CODE] profile start Xprofile_func.log profile func Foo* - func! Foo1() - endfunc - func! Foo2() - let l:count = 100 - while l:count > 0 - let l:count = l:count - 1 + XXX Foo1() + endXXX + XXX Foo2() + DDD counter = 100 + while counter > 0 + AAA counter = counter - 1 endwhile sleep 1m - endfunc - func! Foo3() - endfunc - func! Bar() - endfunc + endXXX + XXX Foo3() + endXXX + XXX Bar() + endXXX call Foo1() call Foo1() profile pause @@ -37,6 +43,10 @@ func Test_profile_func() delfunc Foo3 [CODE] + call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') }) + call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') }) + call map(lines, {k, v -> substitute(v, 'AAA', a:assign, '') }) + call writefile(lines, 'Xprofile_func.vim') call system(GetVimCommand() \ . ' -es --clean' @@ -69,10 +79,10 @@ func Test_profile_func() call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[12]) call assert_equal('', lines[13]) call assert_equal('count total (s) self (s)', lines[14]) - call assert_match('^\s*1\s\+.*\slet l:count = 100$', lines[15]) - call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[16]) - call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[17]) - call assert_match('^\s*101\s\+.*\sendwhile$', lines[18]) + call assert_match('^\s*1\s\+.*\s\(let\|var\) counter = 100$', lines[15]) + call assert_match('^\s*101\s\+.*\swhile counter > 0$', lines[16]) + call assert_match('^\s*100\s\+.*\s \(let\)\= counter = counter - 1$', lines[17]) + call assert_match('^\s*10[01]\s\+.*\sendwhile$', lines[18]) call assert_match('^\s*1\s\+.\+sleep 1m$', lines[19]) call assert_equal('', lines[20]) call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[21]) @@ -91,39 +101,47 @@ func Test_profile_func() endfunc func Test_profile_func_with_ifelse() + call Run_profile_func_with_ifelse('func', 'let') + call Run_profile_func_with_ifelse('def', 'var') +endfunc + +func Run_profile_func_with_ifelse(command, declare) let lines =<< trim [CODE] - func! Foo1() + XXX Foo1() if 1 - let x = 0 + DDD x = 0 elseif 1 - let x = 1 + DDD x = 1 else - let x = 2 + DDD x = 2 endif - endfunc - func! Foo2() + endXXX + XXX Foo2() if 0 - let x = 0 + DDD x = 0 elseif 1 - let x = 1 + DDD x = 1 else - let x = 2 + DDD x = 2 endif - endfunc - func! Foo3() + endXXX + XXX Foo3() if 0 - let x = 0 + DDD x = 0 elseif 0 - let x = 1 + DDD x = 1 else - let x = 2 + DDD x = 2 endif - endfunc + endXXX call Foo1() call Foo2() call Foo3() [CODE] + call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') }) + call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') }) + call writefile(lines, 'Xprofile_func.vim') call system(GetVimCommand() \ . ' -es -i NONE --noplugin' @@ -148,11 +166,11 @@ func Test_profile_func_with_ifelse() call assert_equal('', lines[5]) call assert_equal('count total (s) self (s)', lines[6]) call assert_match('^\s*1\s\+.*\sif 1$', lines[7]) - call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 0$', lines[8]) call assert_match( '^\s\+elseif 1$', lines[9]) - call assert_match( '^\s\+let x = 1$', lines[10]) + call assert_match( '^\s\+\(let\|var\) x = 1$', lines[10]) call assert_match( '^\s\+else$', lines[11]) - call assert_match( '^\s\+let x = 2$', lines[12]) + call assert_match( '^\s\+\(let\|var\) x = 2$', lines[12]) call assert_match('^\s*1\s\+.*\sendif$', lines[13]) call assert_equal('', lines[14]) call assert_equal('FUNCTION Foo2()', lines[15]) @@ -162,11 +180,11 @@ func Test_profile_func_with_ifelse() call assert_equal('', lines[20]) call assert_equal('count total (s) self (s)', lines[21]) call assert_match('^\s*1\s\+.*\sif 0$', lines[22]) - call assert_match( '^\s\+let x = 0$', lines[23]) + call assert_match( '^\s\+\(let\|var\) x = 0$', lines[23]) call assert_match('^\s*1\s\+.*\selseif 1$', lines[24]) - call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 1$', lines[25]) call assert_match( '^\s\+else$', lines[26]) - call assert_match( '^\s\+let x = 2$', lines[27]) + call assert_match( '^\s\+\(let\|var\) x = 2$', lines[27]) call assert_match('^\s*1\s\+.*\sendif$', lines[28]) call assert_equal('', lines[29]) call assert_equal('FUNCTION Foo3()', lines[30]) @@ -176,11 +194,11 @@ func Test_profile_func_with_ifelse() call assert_equal('', lines[35]) call assert_equal('count total (s) self (s)', lines[36]) call assert_match('^\s*1\s\+.*\sif 0$', lines[37]) - call assert_match( '^\s\+let x = 0$', lines[38]) + call assert_match( '^\s\+\(let\|var\) x = 0$', lines[38]) call assert_match('^\s*1\s\+.*\selseif 0$', lines[39]) - call assert_match( '^\s\+let x = 1$', lines[40]) + call assert_match( '^\s\+\(let\|var\) x = 1$', lines[40]) call assert_match('^\s*1\s\+.*\selse$', lines[41]) - call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[42]) call assert_match('^\s*1\s\+.*\sendif$', lines[43]) call assert_equal('', lines[44]) call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45]) @@ -201,42 +219,56 @@ func Test_profile_func_with_ifelse() endfunc func Test_profile_func_with_trycatch() + call Run_profile_func_with_trycatch('func', 'let') + call Run_profile_func_with_trycatch('def', 'var') +endfunc + +func Run_profile_func_with_trycatch(command, declare) let lines =<< trim [CODE] - func! Foo1() + XXX Foo1() try - let x = 0 + DDD x = 0 catch - let x = 1 + DDD x = 1 finally - let x = 2 + DDD x = 2 endtry - endfunc - func! Foo2() + endXXX + XXX Foo2() try throw 0 catch - let x = 1 + DDD x = 1 finally - let x = 2 + DDD x = 2 endtry - endfunc - func! Foo3() + endXXX + XXX Foo3() try throw 0 catch throw 1 finally - let x = 2 + DDD x = 2 endtry - endfunc + endXXX call Foo1() call Foo2() + let rethrown = 0 try call Foo3() catch + let rethrown = 1 endtry + if rethrown != 1 + " call Foo1 again so that the test fails + call Foo1() + endif [CODE] + call map(lines, {k, v -> substitute(v, 'XXX', a:command, '') }) + call map(lines, {k, v -> substitute(v, 'DDD', a:declare, '') }) + call writefile(lines, 'Xprofile_func.vim') call system(GetVimCommand() \ . ' -es -i NONE --noplugin' @@ -261,11 +293,11 @@ func Test_profile_func_with_trycatch() call assert_equal('', lines[5]) call assert_equal('count total (s) self (s)', lines[6]) call assert_match('^\s*1\s\+.*\stry$', lines[7]) - call assert_match('^\s*1\s\+.*\s let x = 0$', lines[8]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 0$', lines[8]) call assert_match( '^\s\+catch$', lines[9]) - call assert_match( '^\s\+let x = 1$', lines[10]) + call assert_match( '^\s\+\(let\|var\) x = 1$', lines[10]) call assert_match('^\s*1\s\+.*\sfinally$', lines[11]) - call assert_match('^\s*1\s\+.*\s let x = 2$', lines[12]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[12]) call assert_match('^\s*1\s\+.*\sendtry$', lines[13]) call assert_equal('', lines[14]) call assert_equal('FUNCTION Foo2()', lines[15]) @@ -277,9 +309,9 @@ func Test_profile_func_with_trycatch() call assert_match('^\s*1\s\+.*\stry$', lines[22]) call assert_match('^\s*1\s\+.*\s throw 0$', lines[23]) call assert_match('^\s*1\s\+.*\scatch$', lines[24]) - call assert_match('^\s*1\s\+.*\s let x = 1$', lines[25]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 1$', lines[25]) call assert_match('^\s*1\s\+.*\sfinally$', lines[26]) - call assert_match('^\s*1\s\+.*\s let x = 2$', lines[27]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[27]) call assert_match('^\s*1\s\+.*\sendtry$', lines[28]) call assert_equal('', lines[29]) call assert_equal('FUNCTION Foo3()', lines[30]) @@ -293,7 +325,7 @@ func Test_profile_func_with_trycatch() call assert_match('^\s*1\s\+.*\scatch$', lines[39]) call assert_match('^\s*1\s\+.*\s throw 1$', lines[40]) call assert_match('^\s*1\s\+.*\sfinally$', lines[41]) - call assert_match('^\s*1\s\+.*\s let x = 2$', lines[42]) + call assert_match('^\s*1\s\+.*\s \(let\|var\) x = 2$', lines[42]) call assert_match( '^\s\+endtry$', lines[43]) call assert_equal('', lines[44]) call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[45]) @@ -552,4 +584,26 @@ func Test_profile_typed_func() call delete('XtestProfile') endfunc +func Test_vim9_profiling() + " only tests that compiling and calling functions doesn't crash + let lines =<< trim END + vim9script + def Func() + Crash() + enddef + def Crash() + enddef + prof start Xprofile_crash.log + prof func Func + Func() + END + call writefile(lines, 'Xprofile_crash.vim') + call system(GetVimCommandClean() . ' -es -c "so Xprofile_crash.vim" -c q') + call assert_equal(0, v:shell_error) + call CheckScriptSuccess(lines) + call delete('Xprofile_crash.vim') + call delete('Xprofile_crash.log') +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index c035558803..55beffa958 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -55,6 +55,8 @@ def Test_assignment_bool() CheckDefAndScriptFailure(['var x: bool = [1]'], 'E1012:') CheckDefAndScriptFailure(['var x: bool = {}'], 'E1012:') CheckDefAndScriptFailure(['var x: bool = "x"'], 'E1012:') + + CheckDefAndScriptFailure(['var x: bool = "x"', '', 'eval 0'], 'E1012:', 1) enddef def Test_syntax() @@ -350,7 +352,7 @@ def Test_assign_index() var lines: list lines['a'] = 'asdf' END - CheckDefFailure(lines, 'E39:', 2) + CheckDefFailure(lines, 'E1012:', 2) lines =<< trim END var lines: string @@ -561,6 +563,15 @@ def Test_assignment_list() CheckDefExecFailure(lines, 'E1147:', 2) enddef +def Test_assignment_list_any_index() + var l: list = [1, 2] + for [x, y, _] + in [[0, 1, ''], [1, 3, '']] + l[x] = l[x] + y + endfor + assert_equal([2, 5], l) +enddef + def Test_assignment_list_vim9script() var lines =<< trim END vim9script @@ -1405,7 +1416,7 @@ def Test_unlet() CheckDefExecFailure([ 'var ll = [1]', 'unlet ll[g:astring]', - ], 'E39:', 2) + ], 'E1012:', 2) CheckDefExecFailure([ 'var dd = test_null_dict()', 'unlet dd["a"]', @@ -1480,6 +1491,30 @@ def Test_unlet() assert_equal('', $ENVVAR) enddef +def Test_expr_error_no_assign() + var lines =<< trim END + vim9script + var x = invalid + echo x + END + CheckScriptFailureList(lines, ['E121:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 / 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) + + lines =<< trim END + vim9script + var x = 1 % 0 + echo x + END + CheckScriptFailureList(lines, ['E1154:', 'E121:']) +enddef + + def Test_assign_command_modifier() var lines =<< trim END var verbose = 0 diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 61d129ec23..776aec0bde 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -115,6 +115,21 @@ def Test_add_blob() CheckDefExecFailure(lines, 'E1131:', 2) enddef +def Test_append() + new + setline(1, range(3)) + var res1: number = append(1, 'one') + assert_equal(0, res1) + var res2: bool = append(3, 'two') + assert_equal(false, res2) + assert_equal(['0', 'one', '1', 'two', '2'], getline(1, 6)) +enddef + +def Test_buflisted() + var res: bool = buflisted('asdf') + assert_equal(false, res) +enddef + def Test_bufname() split SomeFile bufname('%')->assert_equal('SomeFile') @@ -199,6 +214,11 @@ def Test_cursor() CheckDefExecAndScriptFailure(lines, 'E475:') enddef +def Test_delete() + var res: bool = delete('doesnotexist') + assert_equal(true, res) +enddef + def Test_executable() assert_false(executable("")) assert_false(executable(test_null_string())) @@ -243,7 +263,7 @@ def Test_extend_arg_types() CheckDefFailure(['extend({a: 1}, {b: 2}, 1)'], 'E1013: Argument 3: type mismatch, expected string but got number') CheckDefFailure(['extend([1], ["b"])'], 'E1013: Argument 2: type mismatch, expected list but got list') - CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1012: Type mismatch; expected list but got list') + CheckDefExecFailure(['extend([1], ["b", 1])'], 'E1013: Argument 2: type mismatch, expected list but got list') enddef def Test_extendnew() @@ -635,6 +655,34 @@ def Test_maparg_mapset() nunmap enddef +def Test_max() + g:flag = true + var l1: list = g:flag + ? [1, max([2, 3])] + : [4, 5] + assert_equal([1, 3], l1) + + g:flag = false + var l2: list = g:flag + ? [1, max([2, 3])] + : [4, 5] + assert_equal([4, 5], l2) +enddef + +def Test_min() + g:flag = true + var l1: list = g:flag + ? [1, min([2, 3])] + : [4, 5] + assert_equal([1, 2], l1) + + g:flag = false + var l2: list = g:flag + ? [1, min([2, 3])] + : [4, 5] + assert_equal([4, 5], l2) +enddef + def Test_nr2char() nr2char(97, true)->assert_equal('a') enddef diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 098cded98a..2f8fd71e95 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -68,6 +68,17 @@ def Test_expand_alternate_file() edit Xfiletwo edit %%:r assert_equal('Xfileone', bufname()) + + assert_false(bufexists('altfoo')) + edit altfoo + edit bar + assert_true(bufexists('altfoo')) + assert_true(buflisted('altfoo')) + bdel %% + assert_true(bufexists('altfoo')) + assert_false(buflisted('altfoo')) + bwipe! altfoo + bwipe! bar END CheckDefAndScriptSuccess(lines) enddef @@ -319,6 +330,20 @@ def Test_method_call_linebreak() CheckScriptSuccess(lines) enddef +def Test_method_call_whitespace() + var lines =<< trim END + new + var yank = 'text' + yank->setline(1) + yank ->setline(2) + yank-> setline(3) + yank -> setline(4) + assert_equal(['text', 'text', 'text', 'text'], getline(1, 4)) + bwipe! + END + CheckDefAndScriptSuccess(lines) +enddef + def Test_skipped_expr_linebreak() if 0 var x = [] @@ -750,6 +775,10 @@ def Test_put_command() :+2put! a assert_equal('aaa', getline(4)) + []->mapnew(() => 0) + :$put ='end' + assert_equal('end', getline('$')) + bwipe! CheckDefFailure(['put =xxx'], 'E1001:') diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 83dcda0854..1c57432485 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -762,7 +762,7 @@ def Test_disassemble_const_expr() 'if has("gui_running")\_s*' .. '\d PUSHS "gui_running"\_s*' .. '\d BCALL has(argc 1)\_s*' .. - '\d COND2BOOL\_s*' .. + '\d 2BOOL (!!val)\_s*' .. '\d JUMP_IF_FALSE -> \d\_s*' .. ' echo "yes"\_s*' .. '\d PUSHS "yes"\_s*' .. @@ -934,7 +934,7 @@ def Test_disassemble_lambda_with_type() 'return Ref(g:value)\_s*' .. '\d LOADG g:value\_s*' .. '\d LOAD $0\_s*' .. - '\d CHECKTYPE number stack\[-2\]\_s*' .. + '\d CHECKTYPE number stack\[-2\] arg 1\_s*' .. '\d PCALL (argc 1)\_s*' .. '\d RETURN', instr) @@ -1842,6 +1842,30 @@ def Test_silent() res) enddef +def s:Profiled(): string + echo "profiled" + return "done" +enddef + +def Test_profiled() + if !has('profile') + MissingFeature 'profile' + endif + var res = execute('disass! s:Profiled') + assert_match('\d*_Profiled\_s*' .. + 'echo "profiled"\_s*' .. + '\d PROFILE START line 1\_s*' .. + '\d PUSHS "profiled"\_s*' .. + '\d ECHO 1\_s*' .. + 'return "done"\_s*' .. + '\d PROFILE END\_s*' .. + '\d PROFILE START line 2\_s*' .. + '\d PUSHS "done"\_s*' .. + '\d RETURN\_s*' .. + '\d PROFILE END', + res) +enddef + def s:SilentReturn(): string silent return "done" enddef diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index a45d0eae6e..2239e76df9 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1403,6 +1403,9 @@ def Test_expr6() CheckDefFailure(["var x = 6 * xxx"], 'E1001:', 1) CheckDefFailure(["var d = 6 * "], 'E1097:', 3) + + CheckDefExecAndScriptFailure(['echo 1 / 0'], 'E1154', 1) + CheckDefExecAndScriptFailure(['echo 1 % 0'], 'E1154', 1) enddef def Test_expr6_vim9script() diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 1ea8ac9fc9..a5855adcbc 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -116,6 +116,38 @@ def Test_missing_endfunc_enddef() CheckScriptFailure(lines, 'E126:', 2) enddef +def Test_white_space_before_paren() + var lines =<< trim END + vim9script + def Test () + echo 'test' + enddef + END + CheckScriptFailure(lines, 'E1068:', 2) + + lines =<< trim END + vim9script + func Test () + echo 'test' + endfunc + END + CheckScriptFailure(lines, 'E1068:', 2) + + lines =<< trim END + def Test () + echo 'test' + enddef + END + CheckScriptFailure(lines, 'E1068:', 1) + + lines =<< trim END + func Test () + echo 'test' + endfunc + END + CheckScriptSuccess(lines) +enddef + def Test_enddef_dict_key() var d = { enddef: 'x', @@ -144,6 +176,22 @@ def Test_return_something() assert_fails('ReturnGlobal()', 'E1012: Type mismatch; expected number but got string', '', 1, 'ReturnGlobal') enddef +def Test_check_argument_type() + var lines =<< trim END + vim9script + def Val(a: number, b: number): number + return 0 + enddef + def Func() + var x: any = true + Val(0, x) + enddef + disass Func + Func() + END + CheckScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected number but got bool', 2) +enddef + def Test_missing_return() CheckDefFailure(['def Missing(): number', ' if g:cond', @@ -2184,6 +2232,24 @@ def Test_dict_member_with_silent() CheckScriptSuccess(lines) enddef +def Test_skip_cmds_with_silent() + var lines =<< trim END + vim9script + + def Func(b: bool) + Crash() + enddef + + def Crash() + sil! :/not found/d _ + sil! :/not found/put _ + enddef + + Func(true) + END + CheckScriptSuccess(lines) +enddef + def Test_opfunc() nnoremap set opfunc=Opfuncg@ def g:Opfunc(_: any): string diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 158c64c27c..0d9586d768 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -558,6 +558,43 @@ def Test_try_catch_throw() assert_equal(411, n) enddef +def Test_cnext_works_in_catch() + var lines =<< trim END + vim9script + au BufEnter * eval 0 + writefile(['text'], 'Xfile1') + writefile(['text'], 'Xfile2') + var items = [ + {lnum: 1, filename: 'Xfile1', valid: true}, + {lnum: 1, filename: 'Xfile2', valid: true} + ] + setqflist([], ' ', {items: items}) + cwindow + + def CnextOrCfirst() + # if cnext fails, cfirst is used + try + cnext + catch + cfirst + endtry + enddef + + CnextOrCfirst() + CnextOrCfirst() + writefile([getqflist({idx: 0}).idx], 'Xresult') + qall + END + writefile(lines, 'XCatchCnext') + RunVim([], [], '--clean -S XCatchCnext') + assert_equal(['1'], readfile('Xresult')) + + delete('Xfile1') + delete('Xfile2') + delete('XCatchCnext') + delete('Xresult') +enddef + def Test_throw_skipped() if 0 throw dontgethere @@ -778,6 +815,12 @@ def Test_list_vimscript() # comment 6 END assert_equal(['# comment 1', 'two', '# comment 3', '', 'five', '# comment 6'], lines) + + lines =<< trim END + [{ + a: 0}]->string()->assert_equal("[{'a': 0}]") + END + CheckDefAndScriptSuccess(lines) enddef if has('channel') @@ -1698,7 +1741,7 @@ def Test_if_elseif_else_fails() CheckDefFailure(['elseif true'], 'E582:') CheckDefFailure(['else'], 'E581:') CheckDefFailure(['endif'], 'E580:') - CheckDefFailure(['if true', 'elseif xxx'], 'E1001:') + CheckDefFailure(['if g:abool', 'elseif xxx'], 'E1001:') CheckDefFailure(['if true', 'echo 1'], 'E171:') enddef @@ -2023,6 +2066,12 @@ def Test_for_loop() total += nr endfor assert_equal(6, total) + + var res = "" + for [n: number, s: string] in [[1, 'a'], [2, 'b']] + res ..= n .. s + endfor + assert_equal('1a2b', res) enddef def Test_for_loop_fails() diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index bb522df151..cc0510fe91 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -69,6 +69,19 @@ def CheckScriptFailure(lines: list, error: string, lnum = -3) endtry enddef +def CheckScriptFailureList(lines: list, errors: list, lnum = -3) + var cwd = getcwd() + var fname = 'XScriptFailure' .. s:sequence + s:sequence += 1 + writefile(lines, fname) + try + assert_fails('so ' .. fname, errors, lines, lnum) + finally + chdir(cwd) + delete(fname) + endtry +enddef + def CheckScriptSuccess(lines: list) var cwd = getcwd() var fname = 'XScriptSuccess' .. s:sequence diff --git a/src/time.c b/src/time.c index d1cf21b6bc..c5ab693050 100644 --- a/src/time.c +++ b/src/time.c @@ -478,6 +478,7 @@ check_due_timer(void) int save_must_redraw = must_redraw; int save_trylevel = trylevel; int save_did_throw = did_throw; + int save_need_rethrow = need_rethrow; int save_ex_pressedreturn = get_pressedreturn(); int save_may_garbage_collect = may_garbage_collect; except_T *save_current_exception = current_exception; @@ -493,6 +494,7 @@ check_due_timer(void) must_redraw = 0; trylevel = 0; did_throw = FALSE; + need_rethrow = FALSE; current_exception = NULL; may_garbage_collect = FALSE; save_vimvars(&vvsave); @@ -513,6 +515,7 @@ check_due_timer(void) called_emsg = save_called_emsg; trylevel = save_trylevel; did_throw = save_did_throw; + need_rethrow = save_need_rethrow; current_exception = save_current_exception; restore_vimvars(&vvsave); if (must_redraw != 0) diff --git a/src/userfunc.c b/src/userfunc.c index bf701b42eb..0f28b028e7 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1352,8 +1352,13 @@ func_clear_items(ufunc_T *fp) VIM_CLEAR(fp->uf_block_ids); VIM_CLEAR(fp->uf_va_name); clear_type_list(&fp->uf_type_list); + + // Increment the refcount of this function to avoid it being freed + // recursively when the partial is freed. + fp->uf_refcount += 3; partial_unref(fp->uf_partial); fp->uf_partial = NULL; + fp->uf_refcount -= 3; #ifdef FEAT_LUA if (fp->uf_cb_free != NULL) @@ -1446,10 +1451,10 @@ copy_func(char_u *lambda, char_u *global, ectx_T *ectx) return FAIL; } - // TODO: handle ! to overwrite fp = find_func(global, TRUE, NULL); if (fp != NULL) { + // TODO: handle ! to overwrite semsg(_(e_funcexts), global); return FAIL; } @@ -1501,8 +1506,9 @@ copy_func(char_u *lambda, char_u *global, ectx_T *ectx) // the referenced dfunc_T is now used one more time link_def_function(fp); - // Create a partial to store the context of the function, if not done - // already. + // Create a partial to store the context of the function where it was + // instantiated. Only needs to be done once. Do this on the original + // function, "dfunc->df_ufunc" will point to it. if ((ufunc->uf_flags & FC_CLOSURE) && ufunc->uf_partial == NULL) { partial_T *pt = ALLOC_CLEAR_ONE(partial_T); @@ -1510,14 +1516,12 @@ copy_func(char_u *lambda, char_u *global, ectx_T *ectx) if (pt == NULL) goto failed; if (fill_partial_and_closure(pt, ufunc, ectx) == FAIL) + { + vim_free(pt); goto failed; + } ufunc->uf_partial = pt; - --pt->pt_refcount; // not referenced here yet - } - if (ufunc->uf_partial != NULL) - { - fp->uf_partial = ufunc->uf_partial; - ++fp->uf_partial->pt_refcount; + --pt->pt_refcount; // not actually referenced here } return OK; @@ -1597,12 +1601,14 @@ call_user_func( char_u numbuf[NUMBUFLEN]; char_u *name; #ifdef FEAT_PROFILE - proftime_T wait_start; - proftime_T call_start; - int started_profiling = FALSE; + profinfo_T profile_info; #endif ESTACK_CHECK_DECLARATION +#ifdef FEAT_PROFILE + CLEAR_FIELD(profile_info); +#endif + // If depth of calling is getting too high, don't execute the function. if (funcdepth_increment() == FAIL) { @@ -1631,8 +1637,16 @@ call_user_func( if (fp->uf_def_status != UF_NOT_COMPILED) { // Execute the function, possibly compiling it first. +#ifdef FEAT_PROFILE + profile_may_start_func(&profile_info, fp, fc); +#endif call_def_function(fp, argcount, argvars, funcexe->partial, rettv); funcdepth_decrement(); +#ifdef FEAT_PROFILE + if (do_profiling == PROF_YES && (fp->uf_profiling + || (fc->caller != NULL && fc->caller->func->uf_profiling))) + profile_may_end_func(&profile_info, fp, fc); +#endif current_funccal = fc->caller; free_funccal(fc); return; @@ -1845,22 +1859,7 @@ call_user_func( --no_wait_return; } #ifdef FEAT_PROFILE - if (do_profiling == PROF_YES) - { - if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) - { - started_profiling = TRUE; - func_do_profile(fp); - } - if (fp->uf_profiling - || (fc->caller != NULL && fc->caller->func->uf_profiling)) - { - ++fp->uf_tm_count; - profile_start(&call_start); - profile_zero(&fp->uf_tm_children); - } - script_prof_save(&wait_start); - } + profile_may_start_func(&profile_info, fp, fc); #endif save_current_sctx = current_sctx; @@ -1898,20 +1897,7 @@ call_user_func( #ifdef FEAT_PROFILE if (do_profiling == PROF_YES && (fp->uf_profiling || (fc->caller != NULL && fc->caller->func->uf_profiling))) - { - profile_end(&call_start); - profile_sub_wait(&wait_start, &call_start); - profile_add(&fp->uf_tm_total, &call_start); - profile_self(&fp->uf_tm_self, &call_start, &fp->uf_tm_children); - if (fc->caller != NULL && fc->caller->func->uf_profiling) - { - profile_add(&fc->caller->func->uf_tm_children, &call_start); - profile_add(&fc->caller->func->uf_tml_children, &call_start); - } - if (started_profiling) - // make a ":profdel func" stop profiling the function - fp->uf_profiling = FALSE; - } + profile_may_end_func(&profile_info, fp, fc); #endif // when being verbose, mention the return value @@ -1960,7 +1946,7 @@ call_user_func( current_sctx = save_current_sctx; #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) - script_prof_restore(&wait_start); + script_prof_restore(&profile_info.pi_wait_start); #endif if (using_sandbox) --sandbox; @@ -3213,6 +3199,12 @@ define_function(exarg_T *eap, char_u *name_arg) p = vim_strchr(p, '('); } + if ((vim9script || eap->cmdidx == CMD_def) && VIM_ISWHITE(p[-1])) + { + semsg(_(e_no_white_space_allowed_before_str), "("); + goto ret_free; + } + // In Vim9 script only global functions can be redefined. if (vim9script && eap->forceit && !is_global) { @@ -3978,7 +3970,7 @@ ex_function(exarg_T *eap) /* * :defcompile - compile all :def functions in the current script that need to - * be compiled. Except dead functions. + * be compiled. Except dead functions. Doesn't do profiling. */ void ex_defcompile(exarg_T *eap UNUSED) @@ -3998,7 +3990,7 @@ ex_defcompile(exarg_T *eap UNUSED) && ufunc->uf_def_status == UF_TO_BE_COMPILED && (ufunc->uf_flags & FC_DEAD) == 0) { - compile_def_function(ufunc, FALSE, NULL); + compile_def_function(ufunc, FALSE, FALSE, NULL); if (func_hashtab.ht_changed != changed) { @@ -4243,23 +4235,21 @@ func_unref(char_u *name) #endif internal_error("func_unref()"); } - if (fp != NULL && --fp->uf_refcount <= 0) - { - // Only delete it when it's not being used. Otherwise it's done - // when "uf_calls" becomes zero. - if (fp->uf_calls == 0) - func_clear_free(fp, FALSE); - } + func_ptr_unref(fp); } /* * Unreference a Function: decrement the reference count and free it when it * becomes zero. + * Also when it becomes one and uf_partial points to the function. */ void func_ptr_unref(ufunc_T *fp) { - if (fp != NULL && --fp->uf_refcount <= 0) + if (fp != NULL && (--fp->uf_refcount <= 0 + || (fp->uf_refcount == 1 && fp->uf_partial != NULL + && fp->uf_partial->pt_refcount <= 1 + && fp->uf_partial->pt_func == fp))) { // Only delete it when it's not being used. Otherwise it's done // when "uf_calls" becomes zero. @@ -4696,7 +4686,7 @@ get_func_line( SOURCING_LNUM = fcp->linenr; #ifdef FEAT_PROFILE if (do_profiling == PROF_YES) - func_line_start(cookie); + func_line_start(cookie, SOURCING_LNUM); #endif } } diff --git a/src/version.c b/src/version.c index 6635ae8073..8f037716ff 100644 --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,96 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2411, +/**/ + 2410, +/**/ + 2409, +/**/ + 2408, +/**/ + 2407, +/**/ + 2406, +/**/ + 2405, +/**/ + 2404, +/**/ + 2403, +/**/ + 2402, +/**/ + 2401, +/**/ + 2400, +/**/ + 2399, +/**/ + 2398, +/**/ + 2397, +/**/ + 2396, +/**/ + 2395, +/**/ + 2394, +/**/ + 2393, +/**/ + 2392, +/**/ + 2391, +/**/ + 2390, +/**/ + 2389, +/**/ + 2388, +/**/ + 2387, +/**/ + 2386, +/**/ + 2385, +/**/ + 2384, +/**/ + 2383, +/**/ + 2382, +/**/ + 2381, +/**/ + 2380, +/**/ + 2379, +/**/ + 2378, +/**/ + 2377, +/**/ + 2376, +/**/ + 2375, +/**/ + 2374, +/**/ + 2373, +/**/ + 2372, +/**/ + 2371, +/**/ + 2370, +/**/ + 2369, +/**/ + 2368, +/**/ + 2367, /**/ 2366, /**/ diff --git a/src/vim.h b/src/vim.h index 0657e34b29..89407b032e 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1984,34 +1984,36 @@ typedef int sock_T; #define VV_TRUE 69 #define VV_NONE 70 #define VV_NULL 71 -#define VV_NUMBERSIZE 72 -#define VV_VIM_DID_ENTER 73 -#define VV_TESTING 74 -#define VV_TYPE_NUMBER 75 -#define VV_TYPE_STRING 76 -#define VV_TYPE_FUNC 77 -#define VV_TYPE_LIST 78 -#define VV_TYPE_DICT 79 -#define VV_TYPE_FLOAT 80 -#define VV_TYPE_BOOL 81 -#define VV_TYPE_NONE 82 -#define VV_TYPE_JOB 83 -#define VV_TYPE_CHANNEL 84 -#define VV_TYPE_BLOB 85 -#define VV_TERMRFGRESP 86 -#define VV_TERMRBGRESP 87 -#define VV_TERMU7RESP 88 -#define VV_TERMSTYLERESP 89 -#define VV_TERMBLINKRESP 90 -#define VV_EVENT 91 -#define VV_VERSIONLONG 92 -#define VV_ECHOSPACE 93 -#define VV_ARGV 94 -#define VV_COLLATE 95 -#define VV_EXITING 96 +#define VV_NUMBERMAX 72 +#define VV_NUMBERMIN 73 +#define VV_NUMBERSIZE 74 +#define VV_VIM_DID_ENTER 75 +#define VV_TESTING 76 +#define VV_TYPE_NUMBER 77 +#define VV_TYPE_STRING 78 +#define VV_TYPE_FUNC 79 +#define VV_TYPE_LIST 80 +#define VV_TYPE_DICT 81 +#define VV_TYPE_FLOAT 82 +#define VV_TYPE_BOOL 83 +#define VV_TYPE_NONE 84 +#define VV_TYPE_JOB 85 +#define VV_TYPE_CHANNEL 86 +#define VV_TYPE_BLOB 87 +#define VV_TERMRFGRESP 88 +#define VV_TERMRBGRESP 89 +#define VV_TERMU7RESP 90 +#define VV_TERMSTYLERESP 91 +#define VV_TERMBLINKRESP 92 +#define VV_EVENT 93 +#define VV_VERSIONLONG 94 +#define VV_ECHOSPACE 95 +#define VV_ARGV 96 +#define VV_COLLATE 97 +#define VV_EXITING 98 // MacVim-specific values go here -#define VV_OS_APPEARANCE 97 -#define VV_LEN 98 // number of v: vars +#define VV_OS_APPEARANCE 99 +#define VV_LEN 100 // number of v: vars // used for v_number in VAR_BOOL and VAR_SPECIAL #define VVAL_FALSE 0L // VAR_BOOL diff --git a/src/vim9.h b/src/vim9.h index b0c465deb2..82fdfe6340 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -152,6 +152,9 @@ typedef enum { ISN_CMDMOD, // set cmdmod ISN_CMDMOD_REV, // undo ISN_CMDMOD + ISN_PROF_START, // start a line for profiling + ISN_PROF_END, // end a line for profiling + ISN_UNPACK, // unpack list into items, uses isn_arg.unpack ISN_SHUFFLE, // move item on stack up or down ISN_DROP // pop stack and discard value @@ -224,7 +227,8 @@ typedef struct { // arguments to ISN_CHECKTYPE typedef struct { type_T *ct_type; - int ct_off; // offset in stack, -1 is bottom + int8_T ct_off; // offset in stack, -1 is bottom + int8_T ct_arg_idx; // argument index or zero } checktype_T; // arguments to ISN_STORENR @@ -365,8 +369,14 @@ struct dfunc_S { // was compiled. garray_T df_def_args_isn; // default argument instructions + + // After compiling "df_instr" and/or "df_instr_prof" is not NULL. isn_T *df_instr; // function body to be executed - int df_instr_count; + int df_instr_count; // size of "df_instr" +#ifdef FEAT_PROFILE + isn_T *df_instr_prof; // like "df_instr" with profiling + int df_instr_prof_count; // size of "df_instr_prof" +#endif int df_varcount; // number of local variables int df_has_closure; // one if a closure was created @@ -398,3 +408,13 @@ extern garray_T def_functions; // Used for "lnum" when a range is to be taken from the stack and "!" is used. #define LNUM_VARIABLE_RANGE_ABOVE -888 + +#ifdef FEAT_PROFILE +# define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling) +# define INSTRUCTIONS(dfunc) \ + ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ + ? (dfunc)->df_instr_prof : (dfunc)->df_instr) +#else +# define PROFILING(ufunc) FALSE +# define INSTRUCTIONS(dfunc) ((dfunc)->df_instr) +#endif diff --git a/src/vim9compile.c b/src/vim9compile.c index fb7aeddd49..5b9f7f5184 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -44,6 +44,7 @@ struct endlabel_S { */ typedef struct { int is_seen_else; + int is_seen_skip_not; // a block was unconditionally executed int is_had_return; // every block ends in :return int is_if_label; // instruction idx at IF or ELSEIF endlabel_T *is_end_label; // instructions to set end label @@ -123,6 +124,8 @@ struct cctx_S { char_u *ctx_line_start; // start of current line or NULL garray_T ctx_instr; // generated instructions + int ctx_profiling; // when TRUE generate ISN_PROF_START + garray_T ctx_locals; // currently visible local variables int ctx_locals_count; // total number of local variables @@ -816,7 +819,8 @@ generate_COND2BOOL(cctx_T *cctx) generate_TYPECHECK( cctx_T *cctx, type_T *expected, - int offset) + int offset, + int argidx) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; @@ -825,7 +829,8 @@ generate_TYPECHECK( if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL) return FAIL; isn->isn_arg.type.ct_type = alloc_type(expected); - isn->isn_arg.type.ct_off = offset; + isn->isn_arg.type.ct_off = (int8_T)offset; + isn->isn_arg.type.ct_arg_idx = (int8_T)argidx; // type becomes expected ((type_T **)stack->ga_data)[stack->ga_len + offset] = expected; @@ -904,7 +909,7 @@ need_type( // If it's a constant a runtime check makes no sense. if (!actual_is_const && use_typecheck(actual, expected)) { - generate_TYPECHECK(cctx, expected, offset); + generate_TYPECHECK(cctx, expected, offset, arg_idx); return OK; } @@ -1637,7 +1642,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call) if (maptype != NULL && maptype->tt_member != NULL && maptype->tt_member != &t_any) // Check that map() didn't change the item types. - generate_TYPECHECK(cctx, maptype, -1); + generate_TYPECHECK(cctx, maptype, -1, 1); return OK; } @@ -1690,6 +1695,34 @@ generate_BLOBAPPEND(cctx_T *cctx) return OK; } +/* + * Return TRUE if "ufunc" should be compiled, taking into account whether + * "profile" indicates profiling is to be done. + */ + int +func_needs_compiling(ufunc_T *ufunc, int profile UNUSED) +{ + switch (ufunc->uf_def_status) + { + case UF_NOT_COMPILED: break; + case UF_TO_BE_COMPILED: return TRUE; + case UF_COMPILED: + { +#ifdef FEAT_PROFILE + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + + return profile ? dfunc->df_instr_prof == NULL + : dfunc->df_instr == NULL; +#else + break; +#endif + } + case UF_COMPILING: break; + } + return FALSE; +} + /* * Generate an ISN_DCALL or ISN_UCALL instruction. * Return FAIL if the number of arguments is wrong. @@ -1735,17 +1768,17 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) else expected = ufunc->uf_va_type->tt_member; actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i]; - if (need_type(actual, expected, -argcount + i, 0, cctx, + if (need_type(actual, expected, -argcount + i, i + 1, cctx, TRUE, FALSE) == FAIL) { arg_type_mismatch(expected, actual, i + 1); return FAIL; } } - if (ufunc->uf_def_status == UF_TO_BE_COMPILED) - if (compile_def_function(ufunc, ufunc->uf_ret_type == NULL, NULL) - == FAIL) - return FAIL; + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, ufunc->uf_ret_type == NULL, + PROFILING(ufunc), NULL) == FAIL) + return FAIL; } if ((isn = generate_instr(cctx, @@ -1852,7 +1885,7 @@ generate_PCALL( type->tt_argcount - 1]->tt_member; else expected = type->tt_args[i]; - if (need_type(actual, expected, offset, 0, + if (need_type(actual, expected, offset, i + 1, cctx, TRUE, FALSE) == FAIL) { arg_type_mismatch(expected, actual, i + 1); @@ -2061,6 +2094,15 @@ generate_undo_cmdmods(cctx_T *cctx) return OK; } +#ifdef FEAT_PROFILE + static void +may_generate_prof_end(cctx_T *cctx, int prof_lnum) +{ + if (cctx->ctx_profiling && prof_lnum >= 0) + generate_instr(cctx, ISN_PROF_END); +} +#endif + /* * Reserve space for a local variable. * Return the variable or NULL if it failed. @@ -2573,9 +2615,10 @@ generate_funcref(cctx_T *cctx, char_u *name) return FAIL; // Need to compile any default values to get the argument types. - if (ufunc->uf_def_status == UF_TO_BE_COMPILED) - if (compile_def_function(ufunc, TRUE, NULL) == FAIL) - return FAIL; + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, TRUE, PROFILING(ufunc), NULL) + == FAIL) + return FAIL; return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type); } @@ -3068,7 +3111,7 @@ compile_lambda(char_u **arg, cctx_T *cctx) clear_tv(&rettv); // Compile the function into instructions. - compile_def_function(ufunc, TRUE, cctx); + compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx); clear_evalarg(&evalarg, NULL); @@ -4291,20 +4334,25 @@ compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) && ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER) { - typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; - typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; - varnumber_T res = 0; + typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; + typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; + varnumber_T res = 0; + int failed = FALSE; // both are numbers: compute the result switch (*op) { case '*': res = tv1->vval.v_number * tv2->vval.v_number; break; - case '/': res = tv1->vval.v_number / tv2->vval.v_number; + case '/': res = num_divide(tv1->vval.v_number, + tv2->vval.v_number, &failed); break; - case '%': res = tv1->vval.v_number % tv2->vval.v_number; + case '%': res = num_modulus(tv1->vval.v_number, + tv2->vval.v_number, &failed); break; } + if (failed) + return FAIL; tv1->vval.v_number = res; --ppconst->pp_used; } @@ -5040,8 +5088,9 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) r = eap->skip ? OK : FAIL; goto theend; } - if (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, TRUE, cctx) == FAIL) + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx) + == FAIL) { func_ptr_unref(ufunc); goto theend; @@ -5802,12 +5851,9 @@ compile_assign_unlet( if (dest_type == VAR_DICT && may_generate_2STRING(-1, cctx) == FAIL) return FAIL; if (dest_type == VAR_LIST - && ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type - != VAR_NUMBER) - { - emsg(_(e_number_exp)); + && need_type(((type_T **)stack->ga_data)[stack->ga_len - 1], + &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL) return FAIL; - } } // Load the dict or list. On the stack we then have: @@ -6520,7 +6566,7 @@ compile_jump_to_end(endlabel_T **el, jumpwhen_T when, cctx_T *cctx) } static void -compile_fill_jump_to_end(endlabel_T **el, cctx_T *cctx) +compile_fill_jump_to_end(endlabel_T **el, int jump_where, cctx_T *cctx) { garray_T *instr = &cctx->ctx_instr; @@ -6530,7 +6576,7 @@ compile_fill_jump_to_end(endlabel_T **el, cctx_T *cctx) isn_T *isn; isn = ((isn_T *)instr->ga_data) + cur->el_end_label; - isn->isn_arg.jump.jump_where = instr->ga_len; + isn->isn_arg.jump.jump_where = jump_where; *el = cur->el_next; vim_free(cur); } @@ -6684,6 +6730,18 @@ compile_if(char_u *arg, cctx_T *cctx) else scope->se_u.se_if.is_if_label = -1; +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES + && skip_save != SKIP_YES) + { + // generated a profile start, need to generate a profile end, since it + // won't be done after returning + cctx->ctx_skip = SKIP_NOT; + generate_instr(cctx, ISN_PROF_END); + cctx->ctx_skip = SKIP_YES; + } +#endif + return p; } @@ -6707,6 +6765,25 @@ compile_elseif(char_u *arg, cctx_T *cctx) if (!cctx->ctx_had_return) scope->se_u.se_if.is_had_return = FALSE; + if (cctx->ctx_skip == SKIP_NOT) + { + // previous block was executed, this one and following will not + cctx->ctx_skip = SKIP_YES; + scope->se_u.se_if.is_seen_skip_not = TRUE; + } + if (scope->se_u.se_if.is_seen_skip_not) + { + // A previous block was executed, skip over expression and bail out. + // Do not count the "elseif" for profiling. +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + --instr->ga_len; +#endif + skip_expr_cctx(&p, cctx); + return p; + } + if (cctx->ctx_skip == SKIP_UNKNOWN) { if (compile_jump_to_end(&scope->se_u.se_if.is_end_label, @@ -6720,7 +6797,17 @@ compile_elseif(char_u *arg, cctx_T *cctx) // compile "expr"; if we know it evaluates to FALSE skip the block CLEAR_FIELD(ppconst); if (cctx->ctx_skip == SKIP_YES) + { cctx->ctx_skip = SKIP_UNKNOWN; +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling) + { + // the previous block was skipped, need to profile this line + generate_instr(cctx, ISN_PROF_START); + instr_count = instr->ga_len; + } +#endif + } if (compile_expr1(&p, cctx, &ppconst) == FAIL) { clear_ppconst(&ppconst); @@ -6778,7 +6865,27 @@ compile_else(char_u *arg, cctx_T *cctx) scope->se_u.se_if.is_had_return = FALSE; scope->se_u.se_if.is_seen_else = TRUE; - if (scope->se_skip_save != SKIP_YES) +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling) + { + if (cctx->ctx_skip == SKIP_NOT + && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + // the previous block was executed, do not count "else" for profiling + --instr->ga_len; + if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not) + { + // the previous block was not executed, this one will, do count the + // "else" for profiling + cctx->ctx_skip = SKIP_NOT; + generate_instr(cctx, ISN_PROF_END); + generate_instr(cctx, ISN_PROF_START); + cctx->ctx_skip = SKIP_YES; + } + } +#endif + + if (!scope->se_u.se_if.is_seen_skip_not && scope->se_skip_save != SKIP_YES) { // jump from previous block to the end, unless the else block is empty if (cctx->ctx_skip == SKIP_UNKNOWN) @@ -6832,7 +6939,18 @@ compile_endif(char_u *arg, cctx_T *cctx) isn->isn_arg.jump.jump_where = instr->ga_len; } // Fill in the "end" label in jumps at the end of the blocks. - compile_fill_jump_to_end(&ifscope->is_end_label, cctx); + compile_fill_jump_to_end(&ifscope->is_end_label, instr->ga_len, cctx); + +#ifdef FEAT_PROFILE + // even when skipping we count the endif as executed, unless the block it's + // in is skipped + if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES + && scope->se_skip_save != SKIP_YES) + { + cctx->ctx_skip = SKIP_NOT; + generate_instr(cctx, ISN_PROF_START); + } +#endif cctx->ctx_skip = scope->se_skip_save; // If all the blocks end in :return and there is an :else then the @@ -6884,6 +7002,8 @@ compile_for(char_u *arg_start, cctx_T *cctx) int idx; p = skip_var_list(arg_start, TRUE, &var_count, &semicolon, FALSE); + if (p == NULL) + return NULL; if (var_count == 0) var_count = 1; @@ -7018,6 +7138,8 @@ compile_for(char_u *arg_start, cctx_T *cctx) generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); } + if (*p == ':') + p = skip_type(skipwhite(p + 1), FALSE); if (*p == ',' || *p == ';') ++p; arg = skipwhite(p); @@ -7060,7 +7182,7 @@ compile_endfor(char_u *arg, cctx_T *cctx) isn->isn_arg.forloop.for_end = instr->ga_len; // Fill in the "end" label any BREAK statements - compile_fill_jump_to_end(&forscope->fs_end_label, cctx); + compile_fill_jump_to_end(&forscope->fs_end_label, instr->ga_len, cctx); // Below the ":for" scope drop the "expr" list from the stack. if (generate_instr_drop(cctx, ISN_DROP, 1) == NULL) @@ -7093,7 +7215,13 @@ compile_while(char_u *arg, cctx_T *cctx) if (scope == NULL) return NULL; + // "endwhile" jumps back here, one before when profiling scope->se_u.se_while.ws_top_label = instr->ga_len; +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + --scope->se_u.se_while.ws_top_label; +#endif // compile "expr" if (compile_expr0(&p, cctx) == FAIL) @@ -7117,6 +7245,7 @@ compile_while(char_u *arg, cctx_T *cctx) compile_endwhile(char_u *arg, cctx_T *cctx) { scope_T *scope = cctx->ctx_scope; + garray_T *instr = &cctx->ctx_instr; if (scope == NULL || scope->se_type != WHILE_SCOPE) { @@ -7126,12 +7255,18 @@ compile_endwhile(char_u *arg, cctx_T *cctx) cctx->ctx_scope = scope->se_outer; unwind_locals(cctx, scope->se_local_count); +#ifdef FEAT_PROFILE + // count the endwhile before jumping + may_generate_prof_end(cctx, cctx->ctx_lnum); +#endif + // At end of ":for" scope jump back to the FOR instruction. generate_JUMP(cctx, JUMP_ALWAYS, scope->se_u.se_while.ws_top_label); // Fill in the "end" label in the WHILE statement so it can jump here. // And in any jumps for ":break" - compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label, cctx); + compile_fill_jump_to_end(&scope->se_u.se_while.ws_end_label, + instr->ga_len, cctx); vim_free(scope); @@ -7313,6 +7448,12 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) if (cctx->ctx_skip != SKIP_YES) { +#ifdef FEAT_PROFILE + // the profile-start should be after the jump + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + --instr->ga_len; +#endif // Jump from end of previous block to :finally or :endtry if (compile_jump_to_end(&scope->se_u.se_try.ts_end_label, JUMP_ALWAYS, cctx) == FAIL) @@ -7328,6 +7469,15 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; isn->isn_arg.jump.jump_where = instr->ga_len; } +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling) + { + // a "throw" that jumps here needs to be counted + generate_instr(cctx, ISN_PROF_END); + // the "catch" is also counted + generate_instr(cctx, ISN_PROF_START); + } +#endif } p = skipwhite(arg); @@ -7388,6 +7538,7 @@ compile_finally(char_u *arg, cctx_T *cctx) scope_T *scope = cctx->ctx_scope; garray_T *instr = &cctx->ctx_instr; isn_T *isn; + int this_instr; // end block scope from :try or :catch if (scope != NULL && scope->se_type == BLOCK_SCOPE) @@ -7409,15 +7560,24 @@ compile_finally(char_u *arg, cctx_T *cctx) return NULL; } - // Fill in the "end" label in jumps at the end of the blocks. - compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx); + this_instr = instr->ga_len; +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + // jump to the profile start of the "finally" + --this_instr; +#endif - isn->isn_arg.try.try_finally = instr->ga_len; + // Fill in the "end" label in jumps at the end of the blocks. + compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, + this_instr, cctx); + + isn->isn_arg.try.try_finally = this_instr; if (scope->se_u.se_try.ts_catch_label != 0) { // Previous catch without match jumps here isn = ((isn_T *)instr->ga_data) + scope->se_u.se_try.ts_catch_label; - isn->isn_arg.jump.jump_where = instr->ga_len; + isn->isn_arg.jump.jump_where = this_instr; scope->se_u.se_try.ts_catch_label = 0; } @@ -7462,9 +7622,18 @@ compile_endtry(char_u *arg, cctx_T *cctx) return NULL; } +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + // move the profile start after "endtry" so that it's not counted when + // the exception is rethrown. + --instr->ga_len; +#endif + // Fill in the "end" label in jumps at the end of the blocks, if not // done by ":finally". - compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx); + compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, + instr->ga_len, cctx); // End :catch or :finally scope: set value in ISN_TRY instruction if (isn->isn_arg.try.try_catch == 0) @@ -7484,6 +7653,10 @@ compile_endtry(char_u *arg, cctx_T *cctx) if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL) return NULL; +#ifdef FEAT_PROFILE + if (cctx->ctx_profiling) + generate_instr(cctx, ISN_PROF_START); +#endif return arg; } @@ -7786,13 +7959,18 @@ add_def_function(ufunc_T *ufunc) * When "check_return_type" is set then set ufunc->uf_ret_type to the type of * the return statement (used for lambda). When uf_ret_type is already set * then check that it matches. + * When "profiling" is true add ISN_PROF_START instructions. * "outer_cctx" is set for a nested function. * This can be used recursively through compile_lambda(), which may reallocate * "def_functions". * Returns OK or FAIL. */ int -compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx) +compile_def_function( + ufunc_T *ufunc, + int check_return_type, + int profiling UNUSED, + cctx_T *outer_cctx) { char_u *line = NULL; char_u *p; @@ -7805,6 +7983,9 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx) int save_estack_compiling = estack_compiling; int do_estack_push; int new_def_function = FALSE; +#ifdef FEAT_PROFILE + int prof_lnum = -1; +#endif // When using a function that was compiled before: Free old instructions. // The index is reused. Otherwise add a new entry in "def_functions". @@ -7824,6 +8005,10 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx) ufunc->uf_def_status = UF_COMPILING; CLEAR_FIELD(cctx); + +#ifdef FEAT_PROFILE + cctx.ctx_profiling = profiling; +#endif cctx.ctx_ufunc = ufunc; cctx.ctx_lnum = -1; cctx.ctx_outer = outer_cctx; @@ -7924,22 +8109,41 @@ compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx) { line = next_line_from_context(&cctx, FALSE); if (cctx.ctx_lnum >= ufunc->uf_lines.ga_len) + { // beyond the last line +#ifdef FEAT_PROFILE + if (cctx.ctx_skip != SKIP_YES) + may_generate_prof_end(&cctx, prof_lnum); +#endif break; + } } CLEAR_FIELD(ea); ea.cmdlinep = &line; ea.cmd = skipwhite(line); + if (*ea.cmd == '#') + { + // "#" starts a comment + line = (char_u *)""; + continue; + } + +#ifdef FEAT_PROFILE + if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum && + cctx.ctx_skip != SKIP_YES) + { + may_generate_prof_end(&cctx, prof_lnum); + + prof_lnum = cctx.ctx_lnum; + generate_instr(&cctx, ISN_PROF_START); + } +#endif + // Some things can be recognized by the first character. switch (*ea.cmd) { - case '#': - // "#" starts a comment - line = (char_u *)""; - continue; - case '}': { // "}" ends a block scope @@ -8300,8 +8504,18 @@ nextline: + ufunc->uf_dfunc_idx; dfunc->df_deleted = FALSE; dfunc->df_script_seq = current_sctx.sc_seq; - dfunc->df_instr = instr->ga_data; - dfunc->df_instr_count = instr->ga_len; +#ifdef FEAT_PROFILE + if (cctx.ctx_profiling) + { + dfunc->df_instr_prof = instr->ga_data; + dfunc->df_instr_prof_count = instr->ga_len; + } + else +#endif + { + dfunc->df_instr = instr->ga_data; + dfunc->df_instr_count = instr->ga_len; + } dfunc->df_varcount = cctx.ctx_locals_count; dfunc->df_has_closure = cctx.ctx_has_closure; if (cctx.ctx_outer_used) @@ -8578,6 +8792,8 @@ delete_instr(isn_T *isn) case ISN_OPNR: case ISN_PCALL: case ISN_PCALL_END: + case ISN_PROF_END: + case ISN_PROF_START: case ISN_PUSHBOOL: case ISN_PUSHF: case ISN_PUSHNR: @@ -8621,6 +8837,15 @@ delete_def_function_contents(dfunc_T *dfunc, int mark_deleted) VIM_CLEAR(dfunc->df_instr); dfunc->df_instr = NULL; } +#ifdef FEAT_PROFILE + if (dfunc->df_instr_prof != NULL) + { + for (idx = 0; idx < dfunc->df_instr_prof_count; ++idx) + delete_instr(dfunc->df_instr_prof + idx); + VIM_CLEAR(dfunc->df_instr_prof); + dfunc->df_instr_prof = NULL; + } +#endif if (mark_deleted) dfunc->df_deleted = TRUE; diff --git a/src/vim9execute.c b/src/vim9execute.c index 87a9218ae4..bcdc5d190a 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -181,6 +181,16 @@ call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx) return FAIL; } +#ifdef FEAT_PROFILE + // Profiling might be enabled/disabled along the way. This should not + // fail, since the function was compiled before and toggling profiling + // doesn't change any errors. + if (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) + == FAIL) + return FAIL; +#endif + if (ufunc->uf_va_name != NULL) { // Need to make a list out of the vararg arguments. @@ -263,7 +273,8 @@ call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx) } ectx->ec_stack.ga_len += STACK_FRAME_SIZE + varcount; - if (pt != NULL || ufunc->uf_partial != NULL || ufunc->uf_flags & FC_CLOSURE) + if (pt != NULL || ufunc->uf_partial != NULL + || (ufunc->uf_flags & FC_CLOSURE)) { outer_T *outer = ALLOC_CLEAR_ONE(outer_T); @@ -292,8 +303,8 @@ call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx) // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; - ectx->ec_instr = dfunc->df_instr; - entry = estack_push_ufunc(dfunc->df_ufunc, 1); + ectx->ec_instr = INSTRUCTIONS(dfunc); + entry = estack_push_ufunc(ufunc, 1); if (entry != NULL) { // Set the script context to the script where the function was defined. @@ -541,7 +552,7 @@ func_return(ectx_T *ectx) ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_IDX_OFF)->vval.v_number; dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; - ectx->ec_instr = dfunc->df_instr; + ectx->ec_instr = INSTRUCTIONS(dfunc); if (ret_idx > 0) { @@ -644,9 +655,14 @@ call_ufunc( int error; int idx; int did_emsg_before = did_emsg; +#ifdef FEAT_PROFILE + int profiling = do_profiling == PROF_YES && ufunc->uf_profiling; +#else +# define profiling FALSE +#endif - if (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, FALSE, NULL) == FAIL) + if (func_needs_compiling(ufunc, profiling) + && compile_def_function(ufunc, FALSE, profiling, NULL) == FAIL) return FAIL; if (ufunc->uf_def_status == UF_COMPILED) { @@ -1062,7 +1078,7 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx) pt->pt_func = ufunc; pt->pt_refcount = 1; - if (pt->pt_func->uf_flags & FC_CLOSURE) + if (ufunc->uf_flags & FC_CLOSURE) { dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; @@ -1093,10 +1109,11 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx) ++pt->pt_refcount; ++ectx->ec_funcrefs.ga_len; } - ++pt->pt_func->uf_refcount; + ++ufunc->uf_refcount; return OK; } + /* * Call a "def" function from old Vim script. * Return OK or FAIL. @@ -1124,6 +1141,7 @@ call_def_function( msglist_T *private_msg_list = NULL; cmdmod_T save_cmdmod; int restore_cmdmod = FALSE; + int restore_cmdmod_stacklen = 0; int save_emsg_silent_def = emsg_silent_def; int save_did_emsg_def = did_emsg_def; int trylevel_at_start = trylevel; @@ -1140,8 +1158,9 @@ call_def_function( #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) if (ufunc->uf_def_status == UF_NOT_COMPILED - || (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, FALSE, NULL) == FAIL)) + || (func_needs_compiling(ufunc, PROFILING(ufunc)) + && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) + == FAIL)) { if (did_emsg_cumul + did_emsg == did_emsg_before) semsg(_(e_function_is_not_compiled_str), @@ -1153,7 +1172,7 @@ call_def_function( // Check the function was really compiled. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - if (dfunc->df_instr == NULL) + if (INSTRUCTIONS(dfunc) == NULL) { iemsg("using call_def_function() on not compiled function"); return FAIL; @@ -1242,24 +1261,32 @@ call_def_function( ectx.ec_frame_idx = ectx.ec_stack.ga_len; initial_frame_idx = ectx.ec_frame_idx; - if (partial != NULL || ufunc->uf_partial != NULL) { - ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T); - if (ectx.ec_outer == NULL) - goto failed_early; - if (partial != NULL) + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + ufunc_T *base_ufunc = dfunc->df_ufunc; + + // "uf_partial" is on the ufunc that "df_ufunc" points to, as is done + // by copy_func(). + if (partial != NULL || base_ufunc->uf_partial != NULL) { - if (partial->pt_outer.out_stack == NULL && current_ectx != NULL) + ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T); + if (ectx.ec_outer == NULL) + goto failed_early; + if (partial != NULL) { - if (current_ectx->ec_outer != NULL) - *ectx.ec_outer = *current_ectx->ec_outer; + if (partial->pt_outer.out_stack == NULL && current_ectx != NULL) + { + if (current_ectx->ec_outer != NULL) + *ectx.ec_outer = *current_ectx->ec_outer; + } + else + *ectx.ec_outer = partial->pt_outer; } else - *ectx.ec_outer = partial->pt_outer; + *ectx.ec_outer = base_ufunc->uf_partial->pt_outer; + ectx.ec_outer->out_up_is_copy = TRUE; } - else - *ectx.ec_outer = ufunc->uf_partial->pt_outer; - ectx.ec_outer->out_up_is_copy = TRUE; } // dummy frame entries @@ -1284,7 +1311,7 @@ call_def_function( ++ectx.ec_stack.ga_len; } - ectx.ec_instr = dfunc->df_instr; + ectx.ec_instr = INSTRUCTIONS(dfunc); } // Following errors are in the function, not the caller. @@ -1935,8 +1962,8 @@ call_def_function( if (status == OK && dest_type == VAR_LIST) { - varnumber_T lidx = tv_idx->vval.v_number; - list_T *list = tv_dest->vval.v_list; + long lidx = (long)tv_idx->vval.v_number; + list_T *list = tv_dest->vval.v_list; if (list == NULL) { @@ -2121,7 +2148,7 @@ call_def_function( else { list_T *l = tv_dest->vval.v_list; - varnumber_T n = tv_idx->vval.v_number; + long n = (long)tv_idx->vval.v_number; listitem_T *li = NULL; li = list_find(l, n); @@ -2572,6 +2599,7 @@ call_def_function( trycmd->tcd_caught = TRUE; } did_emsg = got_int = did_throw = FALSE; + force_abort = need_rethrow = FALSE; catch_exception(current_exception); } break; @@ -2583,7 +2611,7 @@ call_def_function( if (trystack->ga_len > 0) { - trycmd_T *trycmd = NULL; + trycmd_T *trycmd; --trystack->ga_len; --trylevel; @@ -2605,34 +2633,54 @@ call_def_function( break; case ISN_THROW: - if (ectx.ec_trystack.ga_len == 0 && trylevel == 0 - && emsg_silent) { - // throwing an exception while using "silent!" causes the - // function to abort but not display an error. - tv = STACK_TV_BOT(-1); - clear_tv(tv); - tv->v_type = VAR_NUMBER; - tv->vval.v_number = 0; - goto done; - } - --ectx.ec_stack.ga_len; - tv = STACK_TV_BOT(0); - if (tv->vval.v_string == NULL - || *skipwhite(tv->vval.v_string) == NUL) - { - vim_free(tv->vval.v_string); - SOURCING_LNUM = iptr->isn_lnum; - emsg(_(e_throw_with_empty_string)); - goto failed; - } + garray_T *trystack = &ectx.ec_trystack; - if (throw_exception(tv->vval.v_string, ET_USER, NULL) == FAIL) - { - vim_free(tv->vval.v_string); - goto failed; + if (trystack->ga_len == 0 && trylevel == 0 && emsg_silent) + { + // throwing an exception while using "silent!" causes + // the function to abort but not display an error. + tv = STACK_TV_BOT(-1); + clear_tv(tv); + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; + goto done; + } + --ectx.ec_stack.ga_len; + tv = STACK_TV_BOT(0); + if (tv->vval.v_string == NULL + || *skipwhite(tv->vval.v_string) == NUL) + { + vim_free(tv->vval.v_string); + SOURCING_LNUM = iptr->isn_lnum; + emsg(_(e_throw_with_empty_string)); + goto failed; + } + + // Inside a "catch" we need to first discard the caught + // exception. + if (trystack->ga_len > 0) + { + trycmd_T *trycmd = ((trycmd_T *)trystack->ga_data) + + trystack->ga_len - 1; + if (trycmd->tcd_caught && current_exception != NULL) + { + // discard the exception + if (caught_stack == current_exception) + caught_stack = caught_stack->caught; + discard_current_exception(); + trycmd->tcd_caught = FALSE; + } + } + + if (throw_exception(tv->vval.v_string, ET_USER, NULL) + == FAIL) + { + vim_free(tv->vval.v_string); + goto failed; + } + did_throw = TRUE; } - did_throw = TRUE; break; // compare with special values @@ -2950,13 +2998,21 @@ call_def_function( else #endif { + int failed = FALSE; + switch (iptr->isn_arg.op.op_type) { case EXPR_MULT: n1 = n1 * n2; break; - case EXPR_DIV: n1 = num_divide(n1, n2); break; + case EXPR_DIV: n1 = num_divide(n1, n2, &failed); + if (failed) + goto on_error; + break; case EXPR_SUB: n1 = n1 - n2; break; case EXPR_ADD: n1 = n1 + n2; break; - default: n1 = num_modulus(n1, n2); break; + default: n1 = num_modulus(n1, n2, &failed); + if (failed) + goto on_error; + break; } clear_tv(tv1); clear_tv(tv2); @@ -3230,9 +3286,10 @@ call_def_function( { checktype_T *ct = &iptr->isn_arg.type; - tv = STACK_TV_BOT(ct->ct_off); + tv = STACK_TV_BOT((int)ct->ct_off); SOURCING_LNUM = iptr->isn_lnum; - if (check_typval_type(ct->ct_type, tv, 0) == FAIL) + if (check_typval_type(ct->ct_type, tv, ct->ct_arg_idx) + == FAIL) goto on_error; // number 0 is FALSE, number 1 is TRUE @@ -3325,10 +3382,6 @@ call_def_function( exarg_T ea; char *errormsg; - if (GA_GROW(&ectx.ec_stack, 1) == FAIL) - goto failed; - ++ectx.ec_stack.ga_len; - tv = STACK_TV_BOT(-1); ea.line2 = 0; ea.addr_count = 0; ea.addr_type = ADDR_LINES; @@ -3336,6 +3389,13 @@ call_def_function( ea.skip = FALSE; if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL) goto on_error; + + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) + goto failed; + ++ectx.ec_stack.ga_len; + tv = STACK_TV_BOT(-1); + tv->v_type = VAR_NUMBER; + tv->v_lock = 0; if (ea.addr_count == 0) tv->vval.v_number = curwin->w_cursor.lnum; else @@ -3350,18 +3410,6 @@ call_def_function( char_u *expr = NULL; int dir = FORWARD; - if (regname == '=') - { - tv = STACK_TV_BOT(-1); - if (tv->v_type == VAR_STRING) - expr = tv->vval.v_string; - else - { - expr = typval2string(tv, TRUE); // allocates value - clear_tv(tv); - } - --ectx.ec_stack.ga_len; - } if (lnum < -2) { // line number was put on the stack by ISN_RANGE @@ -3376,6 +3424,19 @@ call_def_function( dir = BACKWARD; else if (lnum >= 0) curwin->w_cursor.lnum = iptr->isn_arg.put.put_lnum; + + if (regname == '=') + { + tv = STACK_TV_BOT(-1); + if (tv->v_type == VAR_STRING) + expr = tv->vval.v_string; + else + { + expr = typval2string(tv, TRUE); // allocates value + clear_tv(tv); + } + --ectx.ec_stack.ga_len; + } check_cursor(); do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE); vim_free(expr); @@ -3385,6 +3446,7 @@ call_def_function( case ISN_CMDMOD: save_cmdmod = cmdmod; restore_cmdmod = TRUE; + restore_cmdmod_stacklen = ectx.ec_stack.ga_len; cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod; apply_cmdmod(&cmdmod); break; @@ -3470,6 +3532,28 @@ call_def_function( } break; + case ISN_PROF_START: + case ISN_PROF_END: + { +#ifdef FEAT_PROFILE + funccall_T cookie; + ufunc_T *cur_ufunc = + (((dfunc_T *)def_functions.ga_data) + + ectx.ec_dfunc_idx)->df_ufunc; + + cookie.func = cur_ufunc; + if (iptr->isn_type == ISN_PROF_START) + { + func_line_start(&cookie, iptr->isn_lnum); + // if we get here the instruction is executed + func_line_exec(&cookie); + } + else + func_line_end(&cookie); +#endif + } + break; + case ISN_SHUFFLE: { typval_T tmp_tv; @@ -3510,7 +3594,22 @@ on_error: // when calling the function. if (did_emsg_cumul + did_emsg == did_emsg_before && emsg_silent && did_emsg_def == 0) + { + // If a sequence of instructions causes an error while ":silent!" + // was used, restore the stack length and jump ahead to restoring + // the cmdmod. + if (restore_cmdmod) + { + while (ectx.ec_stack.ga_len > restore_cmdmod_stacklen) + { + --ectx.ec_stack.ga_len; + clear_tv(STACK_TV_BOT(0)); + } + while (ectx.ec_instr[ectx.ec_iidx].isn_type != ISN_CMDMOD_REV) + ++ectx.ec_iidx; + } continue; + } on_fatal_error: // Jump here for an error that messes up the stack. // If we are not inside a try-catch started here, abort execution. @@ -3602,6 +3701,7 @@ ex_disassemble(exarg_T *eap) ufunc_T *ufunc; dfunc_T *dfunc; isn_T *instr; + int instr_count; int current; int line_idx = 0; int prev_current = 0; @@ -3637,8 +3737,8 @@ ex_disassemble(exarg_T *eap) semsg(_(e_cannot_find_function_str), eap->arg); return; } - if (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, FALSE, NULL) == FAIL) + if (func_needs_compiling(ufunc, eap->forceit) + && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL) return; if (ufunc->uf_def_status != UF_COMPILED) { @@ -3651,8 +3751,15 @@ ex_disassemble(exarg_T *eap) msg((char *)ufunc->uf_name); dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; +#ifdef FEAT_PROFILE + instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr; + instr_count = eap->forceit ? dfunc->df_instr_prof_count + : dfunc->df_instr_count; +#else instr = dfunc->df_instr; - for (current = 0; current < dfunc->df_instr_count; ++current) + instr_count = dfunc->df_instr_count; +#endif + for (current = 0; current < instr_count; ++current) { isn_T *iptr = &instr[current]; char *line; @@ -4205,11 +4312,18 @@ ex_disassemble(exarg_T *eap) case ISN_CHECKNR: smsg("%4d CHECKNR", current); break; case ISN_CHECKTYPE: { + checktype_T *ct = &iptr->isn_arg.type; char *tofree; - smsg("%4d CHECKTYPE %s stack[%d]", current, - type_name(iptr->isn_arg.type.ct_type, &tofree), - iptr->isn_arg.type.ct_off); + if (ct->ct_arg_idx == 0) + smsg("%4d CHECKTYPE %s stack[%d]", current, + type_name(ct->ct_type, &tofree), + (int)ct->ct_off); + else + smsg("%4d CHECKTYPE %s stack[%d] arg %d", current, + type_name(ct->ct_type, &tofree), + (int)ct->ct_off, + (int)ct->ct_arg_idx); vim_free(tofree); break; } @@ -4272,6 +4386,14 @@ ex_disassemble(exarg_T *eap) } case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break; + case ISN_PROF_START: + smsg("%4d PROFILE START line %d", current, iptr->isn_lnum); + break; + + case ISN_PROF_END: + smsg("%4d PROFILE END", current); + break; + case ISN_UNPACK: smsg("%4d UNPACK %d%s", current, iptr->isn_arg.unpack.unp_count, iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : ""); diff --git a/src/vim9type.c b/src/vim9type.c index 81b0db22df..1374cee1b1 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -336,7 +336,8 @@ typval2type_int(typval_T *tv, garray_T *type_gap) // May need to get the argument types from default values by // compiling the function. if (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, TRUE, NULL) == FAIL) + && compile_def_function(ufunc, TRUE, FALSE, NULL) + == FAIL) return NULL; if (ufunc->uf_func_type == NULL) set_function_type(ufunc);