diff --git a/Filelist b/Filelist index 25fefc1d12..41eb53f5a3 100644 --- a/Filelist +++ b/Filelist @@ -127,6 +127,7 @@ SRC_ALL = \ src/termlib.c \ src/testing.c \ src/textprop.c \ + src/time.c \ src/ui.c \ src/undo.c \ src/usercmd.c \ @@ -275,6 +276,7 @@ SRC_ALL = \ src/proto/termlib.pro \ src/proto/testing.pro \ src/proto/textprop.pro \ + src/proto/time.pro \ src/proto/ui.pro \ src/proto/undo.pro \ src/proto/usercmd.pro \ @@ -529,7 +531,6 @@ SRC_DOS = \ src/uninstall.c \ src/vim.def \ src/vim.rc \ - src/vimio.h \ src/gvim.exe.mnf \ src/vimrun.c \ src/xpm_w32.c \ diff --git a/nsis/gvim.nsi b/nsis/gvim.nsi index d782e4397a..2b40e4b0db 100644 --- a/nsis/gvim.nsi +++ b/nsis/gvim.nsi @@ -39,7 +39,7 @@ Unicode true # Uncomment the next line if you want to include VisVim extension: #!define HAVE_VIS_VIM -# Comment the following line to create a multilanguage installer: +# Comment the following line to create an English-only installer: !define HAVE_MULTI_LANG # Uncomment the next line if you want to create a 64-bit installer. diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index e76913db7a..1fc6c0a9a3 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2019 Sep 28 +*change.txt* For Vim version 8.2. Last change: 2020 Feb 09 VIM REFERENCE MANUAL by Bram Moolenaar @@ -636,6 +636,8 @@ For other systems the tmpnam() library function is used. |cmdline-ranges|. See |:s_flags| for [flags]. + The delimiter doesn't need to be /, see + |pattern-delimiter|. :[range]s[ubstitute] [flags] [count] :[range]&[&][flags] [count] *:&* @@ -775,7 +777,7 @@ This deletes "TESTING" from all lines, but only one per line. For compatibility with Vi these two exceptions are allowed: "\/{string}/" and "\?{string}?" do the same as "//{string}/r". "\&{string}&" does the same as "//{string}/". - *E146* + *pattern-delimiter* *E146* Instead of the '/' which surrounds the pattern and replacement string, you can use any other single-byte character, but not an alphanumeric character, '\', '"' or '|'. This is useful if you want to include a '/' in the search diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 95dc672af8..fdead993d5 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2020 Feb 03 +*eval.txt* For Vim version 8.2. Last change: 2020 Feb 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2426,6 +2426,7 @@ deletebufline({expr}, {first} [, {last}]) did_filetype() Number |TRUE| if FileType autocmd event used diff_filler({lnum}) Number diff filler lines about {lnum} diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col} +echoraw({expr}) none output {expr} as-is empty({expr}) Number |TRUE| if {expr} is empty environ() Dict return environment variables escape({string}, {chars}) String escape {chars} in {string} with '\' @@ -2860,7 +2861,6 @@ term_wait({buf} [, {time}]) Number wait for screen to be updated test_alloc_fail({id}, {countdown}, {repeat}) none make memory allocation fail test_autochdir() none enable 'autochdir' during startup -test_clear_search_pat() none clears the last used search pattern test_feedinput({string}) none add key sequence to input buffer test_garbagecollect_now() none free memory right now for testing test_garbagecollect_soon() none free memory soon for testing @@ -2879,6 +2879,7 @@ test_refcount({expr}) Number get the reference count of {expr} test_scrollbar({which}, {value}, {dragging}) none scroll in the GUI for testing test_setmouse({row}, {col}) none set the mouse position for testing +test_srand_seed([seed]) none set seed for testing srand() test_settime({expr}) none set current time for testing timer_info([{id}]) List information about timers timer_pause({id}, {pause}) none pause or unpause a timer @@ -2911,6 +2912,7 @@ win_id2win({expr}) Number get window nr from window ID win_screenpos({nr}) List get screen position of window {nr} win_splitmove({nr}, {target} [, {options}]) Number move window {nr} to split of {target} +win_type([{nr}]) String type of window {nr} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight({nr}) Number height of window {nr} @@ -3956,6 +3958,17 @@ diff_hlID({lnum}, {col}) *diff_hlID()* Can also be used as a |method|: > GetLnum()->diff_hlID(col) + +echoraw({expr}) *echoraw()* + Output {expr} as-is, including unprintable characters. This + can be used to output a terminal code. For example, to disable + modifyOtherKeys: > + call echoraw(&t_TE) +< and to enable it again: > + call echoraw(&t_TI) +< Use with care, you can mess up the terminal this way. + + empty({expr}) *empty()* Return the Number 1 if {expr} is empty, zero otherwise. - A |List| or |Dictionary| is empty when it does not have any @@ -10340,6 +10353,23 @@ win_getid([{win} [, {tab}]]) *win_getid()* Can also be used as a |method|: > GetWinnr()->win_getid() + +win_gettype([{nr}]) *win_gettype()* + Return the type of the window: + "popup" popup window |popup| + "command" command-line window |cmdwin| + (empty) normal window + "unknown" window {nr} not found + + When {nr} is omitted return the type of the current window. + When {nr} is given return the type of this window by number or + |window-ID|. + + Also see the 'buftype' option. When running a terminal in a + popup window then 'buftype' is "terminal" and win_gettype() + returns "popup". + + win_gotoid({expr}) *win_gotoid()* Go to window with ID {expr}. This may also change the current tabpage. @@ -10397,6 +10427,7 @@ win_splitmove({nr}, {target} [, {options}]) *win_splitmove()* Can also be used as a |method|: > GetWinid()->win_splitmove(target) < + *winbufnr()* winbufnr({nr}) The result is a Number, which is the number of the buffer associated with window {nr}. {nr} can be the window number or diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 0620b5c43f..d71c71072b 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2020 Jan 24 +*options.txt* For Vim version 8.2. Last change: 2020 Feb 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1393,6 +1393,7 @@ A jump table for the options with a short description can be found at |Q_op|. This option is used together with 'bufhidden' and 'swapfile' to specify special kinds of buffers. See |special-buffers|. + Also see |win_gettype()|, which returns the type of the window. Be careful with changing this option, it can have many side effects! diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 6372e4d80d..55565bc860 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 Feb 03 +*popup.txt* For Vim version 8.2. Last change: 2020 Feb 05 VIM REFERENCE MANUAL by Bram Moolenaar @@ -402,6 +402,7 @@ popup_hide({id}) *popup_hide()* hidden. If window {id} does not exist nothing happens. If window {id} exists but is not a popup window an error is given. *E993* + If popup window {id} contains a terminal an error is given. Can also be used as a |method|: > GetPopup()->popup_hide() diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index e82c16b420..94333d9dba 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1,4 +1,4 @@ -*starting.txt* For Vim version 8.2. Last change: 2020 Jan 20 +*starting.txt* For Vim version 8.2. Last change: 2020 Feb 04 VIM REFERENCE MANUAL by Bram Moolenaar @@ -58,10 +58,12 @@ filename One or more file names. The first one will be the current that is read from stdin. The commands that would normally be read from stdin will now be read from stderr. Example: > find . -name "*.c" -print | vim - -< The buffer will not be marked as modified, so that it's easy - to exit. Be careful to mark it as modified if you don't want - to accidentally lose it. Example: > - ls | view - + +< The buffer will be marked as modified, so that you are + reminded to save the text when trying to exit. If you don't + like that, put this these lines in your vimrc: > + " Don't set 'modified' when reading from stdin + au StdinReadPost * set nomodified < Starting in Ex mode: > ex - diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index 2f6d8e9aad..75070b5fe7 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -1,4 +1,4 @@ -*tabpage.txt* For Vim version 8.2. Last change: 2019 May 05 +*tabpage.txt* For Vim version 8.2. Last change: 2020 Feb 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -138,7 +138,7 @@ something else. :+tabclose " close the next tab page :1tabclose " close the first tab page :$tabclose " close the last tab page - :tabclose -2 " close the two previous tab page + :tabclose -2 " close the 2nd previous tab page :tabclose + " close the next tab page :tabclose 3 " close the third tab page :tabclose $ " close the last tab page diff --git a/runtime/doc/tags b/runtime/doc/tags index 209838bb0b..d4d84e1ea7 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -2364,6 +2364,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :diffupdate diff.txt /*:diffupdate* :dig digraph.txt /*:dig* :digraphs digraph.txt /*:digraphs* +:disa vim9.txt /*:disa* +:disassemble vim9.txt /*:disassemble* :display change.txt /*:display* :dj tagsrch.txt /*:dj* :djump tagsrch.txt /*:djump* @@ -6192,6 +6194,7 @@ dtd2vim insert.txt /*dtd2vim* dying-variable eval.txt /*dying-variable* e motion.txt /*e* easy starting.txt /*easy* +echoraw() eval.txt /*echoraw()* echospace-variable eval.txt /*echospace-variable* edit-a-file editing.txt /*edit-a-file* edit-binary editing.txt /*edit-binary* @@ -8370,6 +8373,7 @@ patches-8.2 version8.txt /*patches-8.2* pathshorten() eval.txt /*pathshorten()* pattern pattern.txt /*pattern* pattern-atoms pattern.txt /*pattern-atoms* +pattern-delimiter change.txt /*pattern-delimiter* pattern-multi-byte pattern.txt /*pattern-multi-byte* pattern-multi-items pattern.txt /*pattern-multi-items* pattern-overview pattern.txt /*pattern-overview* @@ -9612,6 +9616,7 @@ test_refcount() testing.txt /*test_refcount()* test_scrollbar() testing.txt /*test_scrollbar()* test_setmouse() testing.txt /*test_setmouse()* test_settime() testing.txt /*test_settime()* +test_srand_seed() testing.txt /*test_srand_seed()* testing testing.txt /*testing* testing-support testing.txt /*testing-support* testing-variable eval.txt /*testing-variable* @@ -10179,6 +10184,7 @@ win32s os_win32.txt /*win32s* win_execute() eval.txt /*win_execute()* win_findbuf() eval.txt /*win_findbuf()* win_getid() eval.txt /*win_getid()* +win_gettype() eval.txt /*win_gettype()* win_gotoid() eval.txt /*win_gotoid()* win_id2tabwin() eval.txt /*win_id2tabwin()* win_id2win() eval.txt /*win_id2win()* diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt index 7fb24e6307..f48984c9f2 100644 --- a/runtime/doc/testing.txt +++ b/runtime/doc/testing.txt @@ -1,4 +1,4 @@ -*testing.txt* For Vim version 8.2. Last change: 2019 Sep 08 +*testing.txt* For Vim version 8.2. Last change: 2020 Feb 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -52,11 +52,6 @@ test_autochdir() *test_autochdir()* startup has finished. -test_clear_search_pat() *test_clear_search_pat()* - Clears the last used search pattern (|/|) and the substitute - pattern (|:s|). This is useful for testing conditions where - these patterns are not set previously. - test_feedinput({string}) *test_feedinput()* Characters in {string} are queued for processing as if they were typed by the user. This uses a low level input buffer. @@ -210,7 +205,6 @@ test_setmouse({row}, {col}) *test_setmouse()* call test_setmouse(4, 20) call feedkeys("\", "xt") - test_settime({expr}) *test_settime()* Set the time Vim uses internally. Currently only used for timestamps in the history, as they are used in viminfo, and @@ -223,6 +217,10 @@ test_settime({expr}) *test_settime()* Can also be used as a |method|: > GetTime()->test_settime() +test_srand_seed([seed]) *test_srand_seed()* + When [seed] is given this sets the seed value used by + `srand()`. When omitted the test seed is removed. + ============================================================================== 3. Assert functions *assert-functions-details* diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index ad3ac42c0f..e371e4c59d 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 Feb 04 +*todo.txt* For Vim version 8.2. Last change: 2020 Feb 15 VIM REFERENCE MANUAL by Bram Moolenaar @@ -40,15 +40,15 @@ browser use: https://github.com/vim/vim/issues/1234 Include ipv6 syntax changes? (DJ Lucas, #5360) -Add win_type(), which "popup" and "cmdline" as values? +Avoid modifyOtherKeys temporarily: + call modify_other_keys(v:false) " disable modifyOtherKeys +Should fix #5617. Vim9 script: -- test s:var += 'some' - test exported += 'some' -- implement default values for optional arguments - Generate instructions at start of function, skip over if argument provided? +- "echo Func()" is an error if Func() does not return anything. - Disallow unlet for local/script/imported vars - :func inside vim9script must still use a:arg +- Make "++nr" work. - Check that import in legacy script works and puts item in s: - Error in any command in "vim9script" aborts sourcing. - Find a way to test expressions in legacy and Vim9 script without duplication @@ -58,6 +58,7 @@ Vim9 script: Test return inside try/finally jumps to finally and then returns. - call autoload function. - Type checking arguments when calling :def function +- Implement more expressions, e.g. [a:b] - can use func as reference: def SomeFunc() ... map(list, SomeFunc) @@ -164,6 +165,10 @@ Patch to move duplicated code to a function. (Yegappan Lakshmanan, #5330) Patch to use more FOR_ALL_ macros and use them. (Yegappan Lakshmanan, #5339) +Patch to explain use of "%" in :!. (#5591) + +Patch to add "-d" to xxd. (#5616) + Running test_gui and test_gui_init with Motif sometimes kills the window manager. Problem with Motif? Now test_gui crashes in submenu_change(). Athena is OK. @@ -175,6 +180,8 @@ Flag in 'formatoptions' is not used in the tests. Patch to add 'vtp' option. (#5344) Needs better docs. Is there a better name? +Patch for Haiku support. (Emir Sarı, #5605) + undo result wrong: Masato Nishihata, #4798 When 'lazyredraw' is set sometimes the title is not updated. @@ -186,11 +193,21 @@ Patch to add function to return the text used in the quickfix window. Patch for Template string: #4491. New pull: #4634 Implementation is too inefficient, avoid using lambda. +Patch to add readdirex() (Ken Takata, #5619) + +Request to support in mappings, similar to how Neovim does this. +(Daniel Hahler, #4784) + Undo puts cursor in wrong line after "cG" undo. :unmap gives error but does remove the mapping. (Antony Scriven, 2019 Dec 19) +Dos uninstal may delete vim.bat from the wrong directory (e.g., when someone +makes his own wrapper). Add a magic string with the version number to the +.bat file and check for it in the uninstaller. E.g. + # uninstall key: vim8.1* + Patch to fix session file when using multiple tab pages. (Jason Franklin, 2019 May 20) Also put :argadd commands at the start for all buffers, so that their order @@ -216,6 +233,11 @@ ex_next() should pass flag to do_argfile(), then to do_ecmd(). Adding "10" to 'spellsuggest' causes spell suggestions to become very slow. (#4087) +FR: add search_status(), the current values displayed for search (current +match, total matches). (#5631) +Patch to provide search stats in a variable, so that it can be used in the +statusline. (Fujiwara Takuya, #4446) + ":helptags ALL" should skip directories where "tags" cannot be written. (Matěj Cepl, #5026) @@ -225,8 +247,7 @@ unlisted. (#4478) Patch to include reduce() function. (#5481) -Patch to provide search stats in a variable, so that it can be used in the -statusline. (Fujiwara Takuya, #4446) +Statusline highlighting error, off by one. (#5599) Enable 'termbidi' if $VTE_VERSION >= 5703 ? @@ -1109,11 +1130,9 @@ Make a function to check for function-like type? Screen updated delayed when using CTRL-O u in Insert mode. (Barlik, #1191) Perhaps because status message? -Implement optional arguments for functions. +Implement named arguments for functions: func Foo(start, count = 1 all = 1) - call Foo(12) call Foo(12, all = 0) - call Foo(12, 15, 0) Add a command to take a range of lines, filter them and put the output somewhere else. :{range}copy {dest} !cmd @@ -2758,11 +2777,6 @@ argument list or opening each file in a separate tab. Windows installer: licence text should not use indent, causes bad word wrap. (Benjamin Fritz, 2010 Aug 16) -Dos uninstal may delete vim.bat from the wrong directory (e.g., when someone -makes his own wrapper). Add a magic string with the version number to the -.bat file and check for it in the uninstaller. E.g. - # uninstall key: vim8.1* - Changes for Win32 makefile. (Mike Williams, 2007 Jan 22, Alexei Alexandrov, 2007 Feb 8) @@ -4491,8 +4505,6 @@ Vim script language: 8 Pass the command line arguments to Vim scripts in some way. As v:args List? Or extra parameter to argv()? 8 Add command arguments with three dashes, passed on to Vim scripts. -9 Add optional arguments to user functions: - :func myFunc(arg1, arg2, arg3 = "blah", arg4 = 17) 6 User functions: Functions local to buffer "b:func()"? 8 For Strings add ":let var[{expr}] = {expr}". When past the end of "var" just ignore. diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 316eebcaea..1bed01f418 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -963,7 +963,6 @@ Testing: *test-functions* assert_report() report a test failure test_alloc_fail() make memory allocation fail test_autochdir() enable 'autochdir' during startup - test_clear_search_pat() clears the last used search pattern test_override() test with Vim internal overrides test_garbagecollect_now() free memory right now test_getvalue() get value of an internal variable diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index dd2b1b2187..da4f1634b2 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Jan 30 +*vim9.txt* For Vim version 8.2. Last change: 2020 Feb 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -231,11 +231,8 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE the function follows in the next lines, until the matching `:enddef`. - When {return-type} is omitted the return type will be - decided upon by the first encountered `return` - statement in the function. E.g., for: > - return 'message' -< The return type will be "string". + When {return-type} is omitted the function is not + expected to return anything. {arguments} is a sequence of zero or more argument declarations. There are three forms: @@ -257,6 +254,10 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE :enddef End of a function defined with `:def`. + *:disa* *:disassemble* +:disa[ssemble] {func} Show the instructions generated for {func}. + This is for debugging and testing. + ============================================================================== 4. Types *vim9-types* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index e2e48c9976..ddf5fd9c89 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 Jan 22 +" Last Change: 2020 Jan 31 " Listen very carefully, I will say this only once if exists("did_load_filetypes") diff --git a/runtime/syntax/dockerfile.vim b/runtime/syntax/dockerfile.vim index da3a3fc9d2..ce52e697cd 100644 --- a/runtime/syntax/dockerfile.vim +++ b/runtime/syntax/dockerfile.vim @@ -1,6 +1,6 @@ " dockerfile.vim - Syntax highlighting for Dockerfiles " Maintainer: Honza Pokorny -" Last Change: 2020 Jan 27 +" Last Change: 2020 Feb 11 " License: BSD " https://docs.docker.com/engine/reference/builder/ @@ -22,12 +22,12 @@ syntax region dockerfileFrom matchgroup=dockerfileKeyword start=/\v^\s*(FROM)\ze syntax keyword dockerfileKeyword contained ADD ARG CMD COPY ENTRYPOINT ENV EXPOSE HEALTHCHECK LABEL MAINTAINER ONBUILD RUN SHELL STOPSIGNAL USER VOLUME WORKDIR syntax match dockerfileOption contained /\v(^|\s)\zs--\S+/ -syntax match dockerfileInstruction contained /\v(\S+)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileValue -syntax match dockerfileInstruction contained /\v(ADD|COPY)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileJSON -syntax match dockerfileInstruction contained /\v(HEALTHCHECK)(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileInstruction -syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileShell -syntax match dockerfileInstruction contained /\v(CMD|ENTRYPOINT|RUN)\ze\s+\[/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON -syntax match dockerfileInstruction contained /\v(SHELL|VOLUME)/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON +syntax match dockerfileInstruction contained /\v<(\S+)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileValue +syntax match dockerfileInstruction contained /\v<(ADD|COPY)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileJSON +syntax match dockerfileInstruction contained /\v<(HEALTHCHECK)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileInstruction +syntax match dockerfileInstruction contained /\v<(CMD|ENTRYPOINT|RUN)>/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileShell +syntax match dockerfileInstruction contained /\v<(CMD|ENTRYPOINT|RUN)>\ze\s+\[/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON +syntax match dockerfileInstruction contained /\v<(SHELL|VOLUME)>/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON syntax region dockerfileString contained start=/\v"/ skip=/\v\\./ end=/\v"/ syntax region dockerfileJSON contained keepend start=/\v\[/ skip=/\v\\\_./ end=/\v$/ contains=@JSON diff --git a/runtime/syntax/spec.vim b/runtime/syntax/spec.vim index f56a993ae5..4df549e677 100644 --- a/runtime/syntax/spec.vim +++ b/runtime/syntax/spec.vim @@ -3,7 +3,7 @@ " Language: SPEC: Build/install scripts for Linux RPM packages " Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com " Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014) -" Last Change: 2019 Sep 27 +" Last Change: 2020 Feb 07 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -111,7 +111,7 @@ syn region specDescriptionArea matchgroup=specSection start='^%description' end= syn region specPackageArea matchgroup=specSection start='^%package' end='^%'me=e-1 contains=specPackageOpts,specPreAmble,specComment "%% Scripts Section %% -syn region specScriptArea matchgroup=specSection start='^%\(prep\|build\|install\|clean\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2 +syn region specScriptArea matchgroup=specSection start='^%\(prep\|build\|install\|clean\|check\|pre\|postun\|preun\|post\|posttrans\)\>' skip='^%{\|^%\(define\|patch\d*\|configure\|GNUconfigure\|setup\|autosetup\|autopatch\|find_lang\|make_build\|makeinstall\|make_install\)\>' end='^%'me=e-1 contains=specSpecialVariables,specVariables,@specCommands,specVariables,shDo,shFor,shCaseEsac,specNoNumberHilite,specCommandOpts,shComment,shIf,specSpecialChar,specMacroIdentifier,specSectionMacroArea,specSectionMacroBracketArea,shOperator,shQuote1,shQuote2 "%% Changelog Section %% syn region specChangelogArea matchgroup=specSection start='^%changelog' end='^%'me=e-1 contains=specEmail,specURL,specWeekday,specMonth,specNumber,specComment,specLicense diff --git a/runtime/syntax/sshconfig.vim b/runtime/syntax/sshconfig.vim index 6c36f56af8..d0752aebcb 100644 --- a/runtime/syntax/sshconfig.vim +++ b/runtime/syntax/sshconfig.vim @@ -5,8 +5,9 @@ " Contributor: Leonard Ehrenfried " Contributor: Karsten Hopp " Contributor: Dean, Adam Kenneth -" Last Change: 2019 Sep 09 +" Last Change: 2020 Feb 12 " Added RemoteCommand from pull request #4809 +" Included additional keywords from Martin. " SSH Version: 7.4p1 " @@ -131,24 +132,25 @@ syn case ignore " Keywords syn keyword sshconfigHostSect Host -syn keyword sshconfigMatch canonical exec host originalhost user localuser all +syn keyword sshconfigMatch canonical final exec host originalhost user localuser all syn keyword sshconfigKeyword AddressFamily syn keyword sshconfigKeyword AddKeysToAgent syn keyword sshconfigKeyword BatchMode syn keyword sshconfigKeyword BindAddress +syn keyword sshconfigKeyword BindInterface syn keyword sshconfigKeyword CanonicalDomains syn keyword sshconfigKeyword CanonicalizeFallbackLocal syn keyword sshconfigKeyword CanonicalizeHostname syn keyword sshconfigKeyword CanonicalizeMaxDots +syn keyword sshconfigKeyword CanonicalizePermittedCNAMEs +syn keyword sshconfigKeyword CASignatureAlgorithms syn keyword sshconfigKeyword CertificateFile syn keyword sshconfigKeyword ChallengeResponseAuthentication syn keyword sshconfigKeyword CheckHostIP -syn keyword sshconfigKeyword Cipher syn keyword sshconfigKeyword Ciphers syn keyword sshconfigKeyword ClearAllForwardings syn keyword sshconfigKeyword Compression -syn keyword sshconfigKeyword CompressionLevel syn keyword sshconfigKeyword ConnectTimeout syn keyword sshconfigKeyword ConnectionAttempts syn keyword sshconfigKeyword ControlMaster @@ -158,18 +160,13 @@ syn keyword sshconfigKeyword DynamicForward syn keyword sshconfigKeyword EnableSSHKeysign syn keyword sshconfigKeyword EscapeChar syn keyword sshconfigKeyword ExitOnForwardFailure +syn keyword sshconfigKeyword FingerprintHash syn keyword sshconfigKeyword ForwardAgent syn keyword sshconfigKeyword ForwardX11 syn keyword sshconfigKeyword ForwardX11Timeout syn keyword sshconfigKeyword ForwardX11Trusted syn keyword sshconfigKeyword GSSAPIAuthentication -syn keyword sshconfigKeyword GSSAPIClientIdentity syn keyword sshconfigKeyword GSSAPIDelegateCredentials -syn keyword sshconfigKeyword GSSAPIKeyExchange -syn keyword sshconfigKeyword GSSAPIRenewalForcesRekey -syn keyword sshconfigKeyword GSSAPIServerIdentity -syn keyword sshconfigKeyword GSSAPITrustDNS -syn keyword sshconfigKeyword GSSAPITrustDns syn keyword sshconfigKeyword GatewayPorts syn keyword sshconfigKeyword GlobalKnownHostsFile syn keyword sshconfigKeyword HashKnownHosts @@ -180,6 +177,7 @@ syn keyword sshconfigKeyword HostbasedAuthentication syn keyword sshconfigKeyword HostbasedKeyTypes syn keyword sshconfigKeyword IPQoS syn keyword sshconfigKeyword IdentitiesOnly +syn keyword sshconfigKeyword IdentityAgent syn keyword sshconfigKeyword IdentityFile syn keyword sshconfigKeyword IgnoreUnknown syn keyword sshconfigKeyword Include @@ -199,35 +197,53 @@ syn keyword sshconfigKeyword PasswordAuthentication syn keyword sshconfigKeyword PermitLocalCommand syn keyword sshconfigKeyword Port syn keyword sshconfigKeyword PreferredAuthentications -syn keyword sshconfigKeyword Protocol syn keyword sshconfigKeyword ProxyCommand syn keyword sshconfigKeyword ProxyJump syn keyword sshconfigKeyword ProxyUseFDPass syn keyword sshconfigKeyword PubkeyAcceptedKeyTypes syn keyword sshconfigKeyword PubkeyAuthentication -syn keyword sshconfigKeyword RSAAuthentication syn keyword sshconfigKeyword RekeyLimit syn keyword sshconfigKeyword RemoteCommand syn keyword sshconfigKeyword RemoteForward syn keyword sshconfigKeyword RequestTTY -syn keyword sshconfigKeyword RhostsRSAAuthentication +syn keyword sshconfigKeyword RevokedHostKeys +syn keyword sshconfigKeyword SecurityKeyProvider syn keyword sshconfigKeyword SendEnv syn keyword sshconfigKeyword ServerAliveCountMax syn keyword sshconfigKeyword ServerAliveInterval syn keyword sshconfigKeyword SmartcardDevice +syn keyword sshconfigKeyword SetEnv +syn keyword sshconfigKeyword StreamLocalBindMask +syn keyword sshconfigKeyword StreamLocalBindUnlink syn keyword sshconfigKeyword StrictHostKeyChecking +syn keyword sshconfigKeyword SyslogFacility syn keyword sshconfigKeyword TCPKeepAlive syn keyword sshconfigKeyword Tunnel syn keyword sshconfigKeyword TunnelDevice syn keyword sshconfigKeyword UseBlacklistedKeys -syn keyword sshconfigKeyword UsePrivilegedPort +syn keyword sshconfigKeyword UpdateHostKeys syn keyword sshconfigKeyword User syn keyword sshconfigKeyword UserKnownHostsFile -syn keyword sshconfigKeyword UseRoaming syn keyword sshconfigKeyword VerifyHostKeyDNS syn keyword sshconfigKeyword VisualHostKey syn keyword sshconfigKeyword XAuthLocation +" Deprecated/ignored/remove/unsupported keywords + +syn keyword sshConfigDeprecated Cipher +syn keyword sshconfigDeprecated GSSAPIClientIdentity +syn keyword sshconfigDeprecated GSSAPIKeyExchange +syn keyword sshconfigDeprecated GSSAPIRenewalForcesRekey +syn keyword sshconfigDeprecated GSSAPIServerIdentity +syn keyword sshconfigDeprecated GSSAPITrustDNS +syn keyword sshconfigDeprecated GSSAPITrustDns +syn keyword sshconfigDeprecated Protocol +syn keyword sshconfigDeprecated RSAAuthentication +syn keyword sshconfigDeprecated RhostsRSAAuthentication +syn keyword sshconfigDeprecated CompressionLevel +syn keyword sshconfigDeprecated UseRoaming +syn keyword sshconfigDeprecated UsePrivilegedPort + " Define the default highlighting hi def link sshconfigComment Comment @@ -236,17 +252,17 @@ hi def link sshconfigHostPort sshconfigConstant hi def link sshconfigNumber sshconfigConstant hi def link sshconfigConstant Constant hi def link sshconfigYesNo sshconfigEnum -hi def link sshconfigCipher sshconfigEnum -hi def link sshconfigCiphers sshconfigEnum +hi def link sshconfigCipher sshconfigDeprecated +hi def link sshconfigCiphers sshconfigEnum hi def link sshconfigMAC sshconfigEnum hi def link sshconfigHostKeyAlgo sshconfigEnum hi def link sshconfigLogLevel sshconfigEnum hi def link sshconfigSysLogFacility sshconfigEnum hi def link sshconfigAddressFamily sshconfigEnum -hi def link sshconfigIPQoS sshconfigEnum +hi def link sshconfigIPQoS sshconfigEnum hi def link sshconfigKbdInteractive sshconfigEnum -hi def link sshconfigKexAlgo sshconfigEnum -hi def link sshconfigTunnel sshconfigEnum +hi def link sshconfigKexAlgo sshconfigEnum +hi def link sshconfigTunnel sshconfigEnum hi def link sshconfigPreferredAuth sshconfigEnum hi def link sshconfigVar sshconfigEnum hi def link sshconfigEnum Identifier @@ -254,6 +270,7 @@ hi def link sshconfigSpecial Special hi def link sshconfigKeyword Keyword hi def link sshconfigHostSect Type hi def link sshconfigMatch Type +hi def link sshconfigDeprecated Error let b:current_syntax = "sshconfig" diff --git a/runtime/syntax/syncolor.vim b/runtime/syntax/syncolor.vim index 8d0064db15..5b907a3b83 100644 --- a/runtime/syntax/syncolor.vim +++ b/runtime/syntax/syncolor.vim @@ -1,6 +1,6 @@ " Vim syntax support file " Maintainer: Bram Moolenaar -" Last Change: 2001 Sep 12 +" Last Change: 2020 Feb 13 " This file sets up the default methods for highlighting. " It is loaded from "synload.vim" and from Vim for ":syntax reset". @@ -43,10 +43,12 @@ if &background == "dark" else SynColor Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE SynColor Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE - SynColor Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=SlateBlue guibg=NONE + " #6a5acd is SlateBlue + SynColor Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE SynColor Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE SynColor Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE - SynColor PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=Purple guibg=NONE + " #6a0dad is Purple + SynColor PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE SynColor Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE SynColor Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue SynColor Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE diff --git a/src/GvimExt/Makefile b/src/GvimExt/Makefile index 975ba11705..4b83f52dd5 100644 --- a/src/GvimExt/Makefile +++ b/src/GvimExt/Makefile @@ -10,6 +10,9 @@ TARGETOS = WINNT !ifndef APPVER APPVER = 5.01 !endif +!ifndef WINVER +WINVER = 0x0501 +!endif !if "$(DEBUG)" != "yes" NODEBUG = 1 @@ -53,6 +56,13 @@ olelibsdll = ole32.lib uuid.lib oleaut32.lib user32.lib gdi32.lib advapi32.lib # include CPUARG cflags = $(cflags) $(CPUARG) +# set WINVER and _WIN32_WINNT +cflags = $(cflags) -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) + +!if "$(CL)" == "/D_USING_V110_SDK71_" +rcflags = $(rcflags) /D_USING_V110_SDK71_ +!endif + SUBSYSTEM = console !if "$(SUBSYSTEM_VER)" != "" SUBSYSTEM = $(SUBSYSTEM),$(SUBSYSTEM_VER) diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 639f3e5dcb..99c004fc07 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -783,6 +783,7 @@ OBJ = \ $(OUTDIR)/term.o \ $(OUTDIR)/testing.o \ $(OUTDIR)/textprop.o \ + $(OUTDIR)/time.o \ $(OUTDIR)/ui.o \ $(OUTDIR)/undo.o \ $(OUTDIR)/usercmd.o \ diff --git a/src/Make_morph.mak b/src/Make_morph.mak index bb5805c4d2..2c226de298 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -102,6 +102,7 @@ SRC = arabic.c \ term.c \ testing.c \ textprop.c \ + time.c \ ui.c \ undo.c \ usercmd.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index 3e8eae168f..6076dc172e 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -626,6 +626,12 @@ NODEFAULTLIB = NODEFAULTLIB = /nodefaultlib !endif +# Specify source code charset to suppress warning C4819 on non-English +# environment. Only available from MSVC 14. +!if $(MSVC_MAJOR) >= 14 +CFLAGS = $(CFLAGS) /source-charset:utf-8 +!endif + # Use multiprocess build on MSVC 10 !if ("$(USE_MP)" == "yes") && ($(MSVC_MAJOR) >= 10) CFLAGS = $(CFLAGS) /MP @@ -657,6 +663,9 @@ OPTFLAG = /Ox ! if "$(OPTIMIZE)" != "SPACE" OPTFLAG = $(OPTFLAG) /GL ! endif +# Visual Studio 2005 has 'deprecated' many of the standard CRT functions +CFLAGS_DEPR = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE +CFLAGS = $(CFLAGS) $(CFLAGS_DEPR) ! endif # (/Wp64 is deprecated in VC9 and generates an obnoxious warning.) @@ -666,6 +675,9 @@ CFLAGS = $(CFLAGS) $(WP64CHECK) CFLAGS = $(CFLAGS) $(OPTFLAG) -DNDEBUG $(CPUARG) RCFLAGS = $(rcflags) $(rcvars) -DNDEBUG +! if "$(CL)" == "/D_USING_V110_SDK71_" +RCFLAGS = $(RCFLAGS) /D_USING_V110_SDK71_ +! endif ! ifdef USE_MSVCRT CFLAGS = $(CFLAGS) /MD LIBC = msvcrt.lib @@ -787,6 +799,7 @@ OBJ = \ $(OUTDIR)\term.obj \ $(OUTDIR)\testing.obj \ $(OUTDIR)\textprop.obj \ + $(OUTDIR)\time.obj \ $(OUTDIR)\ui.obj \ $(OUTDIR)\undo.obj \ $(OUTDIR)\usercmd.obj \ @@ -1346,15 +1359,17 @@ $(VIM): $(VIM).exe $(OUTDIR): if not exist $(OUTDIR)/nul mkdir $(OUTDIR) +CFLAGS_INST = /nologo /O2 -DNDEBUG -DWIN32 -DWINVER=$(WINVER) -D_WIN32_WINNT=$(WINVER) $(CFLAGS_DEPR) + install.exe: dosinst.c dosinst.h version.h - $(CC) /nologo -DNDEBUG -DWIN32 dosinst.c kernel32.lib shell32.lib \ + $(CC) $(CFLAGS_INST) dosinst.c kernel32.lib shell32.lib \ user32.lib ole32.lib advapi32.lib uuid.lib \ -link -subsystem:$(SUBSYSTEM_TOOLS) - if exist install.exe del install.exe ren dosinst.exe install.exe uninstall.exe: uninstall.c dosinst.h version.h - $(CC) /nologo -DNDEBUG -DWIN32 uninstall.c shell32.lib advapi32.lib \ + $(CC) $(CFLAGS_INST) uninstall.c shell32.lib advapi32.lib \ -link -subsystem:$(SUBSYSTEM_TOOLS) vimrun.exe: vimrun.c @@ -1584,7 +1599,7 @@ $(OUTDIR)/if_lua.obj: $(OUTDIR) if_lua.c $(INCL) $(CC) $(CFLAGS_OUTDIR) $(LUA_INC) if_lua.c auto/if_perl.c : if_perl.xs typemap - -mkdir auto + -if not exist auto/nul mkdir auto $(XSUBPP) -prototypes -typemap $(XSUBPP_TYPEMAP) \ -typemap typemap if_perl.xs -output $@ @@ -1719,6 +1734,8 @@ $(OUTDIR)/term.obj: $(OUTDIR) testing.c $(INCL) $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL) +$(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL) + $(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL) $(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL) @@ -1912,6 +1929,7 @@ proto.h: \ proto/term.pro \ proto/testing.pro \ proto/textprop.pro \ + proto/time.pro \ proto/ui.pro \ proto/undo.pro \ proto/usercmd.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index 6d5db4b6e3..32857decc1 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -381,11 +381,15 @@ SRC = \ termlib.c \ testing.c \ textprop.c \ + time.c \ ui.c \ undo.c \ usercmd.c \ userfunc.c \ version.c \ + vim9compile.c \ + vim9execute.c \ + vim9script.c \ viminfo.c \ window.c \ $(GUI_SRC) \ @@ -484,11 +488,15 @@ OBJ = \ termlib.obj \ testing.obj \ textprop.obj \ + time.obj \ ui.obj \ undo.obj \ usercmd.obj \ userfunc.obj \ version.obj \ + vim9compile.obj \ + vim9execute.obj \ + vim9script.obj \ viminfo.obj \ window.obj \ $(GUI_OBJ) \ @@ -972,6 +980,9 @@ testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \ textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h +time.obj : time.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h @@ -994,6 +1005,18 @@ viminfo.obj : viminfo.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h \ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ globals.h version.h +vim9compile.obj : vim9compile.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + globals.h version.h +vim9execute.obj : vim9execute.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + globals.h version.h +vim9script.obj : vim9script.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h \ + gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ + globals.h version.h window.obj : window.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h \ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \ diff --git a/src/Makefile b/src/Makefile index 309c3e19b9..3ae49154ff 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1678,6 +1678,7 @@ BASIC_SRC = \ terminal.c \ testing.c \ textprop.c \ + time.c \ ui.c \ undo.c \ usercmd.c \ @@ -1817,6 +1818,7 @@ OBJ_COMMON = \ objects/terminal.o \ objects/testing.o \ objects/textprop.o \ + objects/time.o \ objects/ui.o \ objects/undo.o \ objects/usercmd.o \ @@ -1988,6 +1990,7 @@ PRO_AUTO = \ termlib.pro \ testing.pro \ textprop.pro \ + time.pro \ ui.pro \ undo.pro \ usercmd.pro \ @@ -3459,6 +3462,9 @@ objects/testing.o: testing.c objects/textprop.o: textprop.c $(CCC) -o $@ textprop.c +objects/time.o: time.c + $(CCC) -o $@ time.c + objects/ui.o: ui.c $(CCC) -o $@ ui.c @@ -4028,6 +4034,10 @@ objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix. auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h globals.h +objects/time.o: time.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/README.md b/src/README.md index 0262a7a5bd..4412d533ee 100644 --- a/src/README.md +++ b/src/README.md @@ -79,6 +79,7 @@ tag.c | tags term.c | terminal handling, termcap codes testing.c | testing: assert and test functions textprop.c | text properties +time.c | time and timer functions undo.c | undo and redo usercmd.c | user defined commands userfunc.c | user defined functions diff --git a/src/auto/configure b/src/auto/configure index 100af5cd82..2f05f610f0 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -14916,7 +14916,7 @@ DEPEND_CFLAGS_FILTER= if test "$GCC" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC 3 or later" >&5 $as_echo_n "checking for GCC 3 or later... " >&6; } - gccmajor=`echo "$gccversion" | sed -e 's/^\([0-9]\+\)\..*$/\1/g'` + gccmajor=`echo "$gccversion" | sed -e 's/^\([1-9][0-9]*\)\..*$/\1/g'` if test "$gccmajor" -gt "2"; then DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 diff --git a/src/buffer.c b/src/buffer.c index 6027d16227..36cba7b440 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4226,6 +4226,10 @@ build_stl_str_hl( { p = t; l = 0; + // do not use the highlighting from the removed group + for (n = groupitem[groupdepth] + 1; n < curitem; n++) + if (item[n].type == Highlight) + item[n].type = Empty; } } if (l > item[groupitem[groupdepth]].maxwid) diff --git a/src/configure.ac b/src/configure.ac index 09c9abaf91..cddc78201e 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4560,7 +4560,7 @@ dnl the number before the version number. DEPEND_CFLAGS_FILTER= if test "$GCC" = yes; then AC_MSG_CHECKING(for GCC 3 or later) - gccmajor=`echo "$gccversion" | sed -e 's/^\([[0-9]]\+\)\..*$/\1/g'` + gccmajor=`echo "$gccversion" | sed -e 's/^\([[1-9]][[0-9]]*\)\..*$/\1/g'` if test "$gccmajor" -gt "2"; then DEPEND_CFLAGS_FILTER="| sed 's+-I */+-isystem /+g'" AC_MSG_RESULT(yes) diff --git a/src/dosinst.c b/src/dosinst.c index 2ded88ef3b..6ce40439a0 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -841,6 +841,7 @@ install_bat_choice(int idx) fprintf(fd, "@echo off\n"); fprintf(fd, "rem -- Run Vim --\n"); + fprintf(fd, VIMBAT_UNINSTKEY "\n"); fprintf(fd, "\n"); fprintf(fd, "setlocal\n"); diff --git a/src/dosinst.h b/src/dosinst.h index c9d8c929bf..c262c4224b 100644 --- a/src/dosinst.h +++ b/src/dosinst.h @@ -10,12 +10,6 @@ * dosinst.h: Common code for dosinst.c and uninstall.c */ -// Visual Studio 2005 has 'deprecated' many of the standard CRT functions -#if _MSC_VER >= 1400 -# define _CRT_SECURE_NO_DEPRECATE -# define _CRT_NONSTDC_NO_DEPRECATE -#endif - #include #include #include @@ -23,7 +17,7 @@ #include #ifndef UNIX_LINT -# include "vimio.h" +# include # include # include @@ -360,6 +354,9 @@ struct "vimtutor.bat", "vimtutor.bat", ""}, }; +/* Uninstall key for vim.bat, etc. */ +#define VIMBAT_UNINSTKEY "rem # uninstall key: " VIM_VERSION_NODOT " #" + #define ICON_COUNT 3 char *(icon_names[ICON_COUNT]) = {"gVim " VIM_VERSION_SHORT, diff --git a/src/evalfunc.c b/src/evalfunc.c index 14f7ed39d0..74d93b8420 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -20,10 +20,6 @@ # include #endif -#if defined(MACOS_X) -# include // for time_t -#endif - #ifdef FEAT_FLOAT static void f_abs(typval_T *argvars, typval_T *rettv); static void f_acos(typval_T *argvars, typval_T *rettv); @@ -64,6 +60,7 @@ static void f_debugbreak(typval_T *argvars, typval_T *rettv); #endif static void f_deepcopy(typval_T *argvars, typval_T *rettv); static void f_did_filetype(typval_T *argvars, typval_T *rettv); +static void f_echoraw(typval_T *argvars, typval_T *rettv); static void f_empty(typval_T *argvars, typval_T *rettv); static void f_environ(typval_T *argvars, typval_T *rettv); static void f_escape(typval_T *argvars, typval_T *rettv); @@ -90,7 +87,6 @@ static void f_garbagecollect(typval_T *argvars, typval_T *rettv); static void f_get(typval_T *argvars, typval_T *rettv); static void f_getchangelist(typval_T *argvars, typval_T *rettv); static void f_getcharsearch(typval_T *argvars, typval_T *rettv); -static void f_getcmdwintype(typval_T *argvars, typval_T *rettv); static void f_getenv(typval_T *argvars, typval_T *rettv); static void f_getfontname(typval_T *argvars, typval_T *rettv); static void f_getjumplist(typval_T *argvars, typval_T *rettv); @@ -126,7 +122,6 @@ static void f_libcall(typval_T *argvars, typval_T *rettv); static void f_libcallnr(typval_T *argvars, typval_T *rettv); static void f_line(typval_T *argvars, typval_T *rettv); static void f_line2byte(typval_T *argvars, typval_T *rettv); -static void f_localtime(typval_T *argvars, typval_T *rettv); #ifdef FEAT_FLOAT static void f_log(typval_T *argvars, typval_T *rettv); static void f_log10(typval_T *argvars, typval_T *rettv); @@ -168,15 +163,11 @@ static void f_pyeval(typval_T *argvars, typval_T *rettv); #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) static void f_pyxeval(typval_T *argvars, typval_T *rettv); #endif +static void f_test_srand_seed(typval_T *argvars, typval_T *rettv); static void f_rand(typval_T *argvars, typval_T *rettv); static void f_range(typval_T *argvars, typval_T *rettv); static void f_reg_executing(typval_T *argvars, typval_T *rettv); static void f_reg_recording(typval_T *argvars, typval_T *rettv); -static void f_reltime(typval_T *argvars, typval_T *rettv); -#ifdef FEAT_FLOAT -static void f_reltimefloat(typval_T *argvars, typval_T *rettv); -#endif -static void f_reltimestr(typval_T *argvars, typval_T *rettv); static void f_remote_expr(typval_T *argvars, typval_T *rettv); static void f_remote_foreground(typval_T *argvars, typval_T *rettv); static void f_remote_peek(typval_T *argvars, typval_T *rettv); @@ -233,17 +224,11 @@ static void f_str2float(typval_T *argvars, typval_T *rettv); static void f_str2list(typval_T *argvars, typval_T *rettv); static void f_str2nr(typval_T *argvars, typval_T *rettv); static void f_strchars(typval_T *argvars, typval_T *rettv); -#ifdef HAVE_STRFTIME -static void f_strftime(typval_T *argvars, typval_T *rettv); -#endif static void f_strgetchar(typval_T *argvars, typval_T *rettv); static void f_stridx(typval_T *argvars, typval_T *rettv); static void f_strlen(typval_T *argvars, typval_T *rettv); static void f_strcharpart(typval_T *argvars, typval_T *rettv); static void f_strpart(typval_T *argvars, typval_T *rettv); -#ifdef HAVE_STRPTIME -static void f_strptime(typval_T *argvars, typval_T *rettv); -#endif static void f_strridx(typval_T *argvars, typval_T *rettv); static void f_strtrans(typval_T *argvars, typval_T *rettv); static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv); @@ -410,6 +395,7 @@ static funcentry_T global_functions[] = {"did_filetype", 0, 0, 0, &t_number, f_did_filetype}, {"diff_filler", 1, 1, FEARG_1, &t_number, f_diff_filler}, {"diff_hlID", 2, 2, FEARG_1, &t_number, f_diff_hlID}, + {"echoraw", 1, 1, FEARG_1, &t_number, f_echoraw}, {"empty", 1, 1, FEARG_1, &t_number, f_empty}, {"environ", 0, 0, 0, &t_dict_string, f_environ}, {"escape", 2, 2, FEARG_1, &t_string, f_escape}, @@ -568,7 +554,7 @@ static funcentry_T global_functions[] = {"matcharg", 1, 1, FEARG_1, &t_list_string, f_matcharg}, {"matchdelete", 1, 2, FEARG_1, &t_number, f_matchdelete}, {"matchend", 2, 4, FEARG_1, &t_number, f_matchend}, - {"matchlist", 2, 4, FEARG_1, &t_list_any, f_matchlist}, + {"matchlist", 2, 4, FEARG_1, &t_list_string, f_matchlist}, {"matchstr", 2, 4, FEARG_1, &t_string, f_matchstr}, {"matchstrpos", 2, 4, FEARG_1, &t_list_any, f_matchstrpos}, {"max", 1, 1, FEARG_1, &t_any, f_max}, @@ -621,7 +607,7 @@ static funcentry_T global_functions[] = {"prop_add", 3, 3, FEARG_1, &t_void, f_prop_add}, {"prop_clear", 1, 3, FEARG_1, &t_void, f_prop_clear}, {"prop_find", 1, 2, FEARG_1, &t_dict_any, f_prop_find}, - {"prop_list", 1, 2, FEARG_1, &t_list_any, f_prop_list}, + {"prop_list", 1, 2, FEARG_1, &t_list_dict_any, f_prop_list}, {"prop_remove", 1, 3, FEARG_1, &t_number, f_prop_remove}, {"prop_type_add", 2, 2, FEARG_1, &t_void, f_prop_type_add}, {"prop_type_change", 2, 2, FEARG_1, &t_void, f_prop_type_change}, @@ -810,7 +796,6 @@ static funcentry_T global_functions[] = #endif {"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail}, {"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir}, - {"test_clear_search_pat", 0, 0, 0, &t_void, f_test_clear_search_pat}, {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput}, {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now}, {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon}, @@ -835,6 +820,7 @@ static funcentry_T global_functions[] = #endif {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse}, {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime}, + {"test_srand_seed", 0, 1, FEARG_1, &t_void, f_test_srand_seed}, #ifdef FEAT_TIMERS {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info}, {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause}, @@ -860,6 +846,7 @@ static funcentry_T global_functions[] = {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute}, {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf}, {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid}, + {"win_gettype", 0, 1, FEARG_1, &t_string, f_win_gettype}, {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid}, {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin}, {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win}, @@ -1828,6 +1815,21 @@ f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED) rettv->vval.v_number = did_filetype; } +/* + * "echoraw({expr})" function + */ + static void +f_echoraw(typval_T *argvars, typval_T *rettv UNUSED) +{ + char_u *str = tv_get_string_chk(&argvars[0]); + + if (str != NULL && *str != NUL) + { + out_str(str); + out_flush(); + } +} + /* * "empty({expr})" function */ @@ -2934,24 +2936,6 @@ f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv) } } -/* - * "getcmdwintype()" function - */ - static void -f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_CMDWIN - rettv->vval.v_string = alloc(2); - if (rettv->vval.v_string != NULL) - { - rettv->vval.v_string[0] = cmdwin_type; - rettv->vval.v_string[1] = NUL; - } -#endif -} - /* * "getenv()" function */ @@ -3567,9 +3551,7 @@ f_has(typval_T *argvars, typval_T *rettv) "mzscheme", #endif #endif -#ifdef FEAT_NUM64 "num64", -#endif #ifdef FEAT_OLE "ole", #endif @@ -4526,15 +4508,6 @@ f_line2byte(typval_T *argvars UNUSED, typval_T *rettv) #endif } -/* - * "localtime()" function - */ - static void -f_localtime(typval_T *argvars UNUSED, typval_T *rettv) -{ - rettv->vval.v_number = (varnumber_T)time(NULL); -} - #ifdef FEAT_FLOAT /* * "log()" function @@ -5240,6 +5213,83 @@ f_pyxeval(typval_T *argvars, typval_T *rettv) } #endif +static UINT32_T srand_seed_for_testing = 0; +static int srand_seed_for_testing_is_used = FALSE; + + static void +f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED) +{ + if (argvars[0].v_type == VAR_UNKNOWN) + srand_seed_for_testing_is_used = FALSE; + else + { + srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]); + srand_seed_for_testing_is_used = TRUE; + } +} + + static void +init_srand(UINT32_T *x) +{ +#ifndef MSWIN + static int dev_urandom_state = NOTDONE; // FAIL or OK once tried +#endif + + if (srand_seed_for_testing_is_used) + { + *x = srand_seed_for_testing; + return; + } +#ifndef MSWIN + if (dev_urandom_state != FAIL) + { + int fd = open("/dev/urandom", O_RDONLY); + struct { + union { + UINT32_T number; + char bytes[sizeof(UINT32_T)]; + } contents; + } buf; + + // Attempt reading /dev/urandom. + if (fd == -1) + dev_urandom_state = FAIL; + else + { + buf.contents.number = 0; + if (read(fd, buf.contents.bytes, sizeof(UINT32_T)) + != sizeof(UINT32_T)) + dev_urandom_state = FAIL; + else + { + dev_urandom_state = OK; + *x = buf.contents.number; + } + close(fd); + } + } + if (dev_urandom_state != OK) + // Reading /dev/urandom doesn't work, fall back to time(). +#endif + *x = vim_time(); +} + +#define ROTL(x, k) ((x << k) | (x >> (32 - k))) +#define SPLITMIX32(x, z) ( \ + z = (x += 0x9e3779b9), \ + z = (z ^ (z >> 16)) * 0x85ebca6b, \ + z = (z ^ (z >> 13)) * 0xc2b2ae35, \ + z ^ (z >> 16) \ + ) +#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \ + result = ROTL(y * 5, 7) * 9; \ + t = y << 9; \ + z ^= x; \ + w ^= y; \ + y ^= z, x ^= w; \ + z ^= t; \ + w = ROTL(w, 11); + /* * "rand()" function */ @@ -5247,66 +5297,57 @@ f_pyxeval(typval_T *argvars, typval_T *rettv) f_rand(typval_T *argvars, typval_T *rettv) { list_T *l = NULL; - static list_T *globl = NULL; - UINT32_T x, y, z, w, t, result; + static UINT32_T gx, gy, gz, gw; + static int initialized = FALSE; listitem_T *lx, *ly, *lz, *lw; + UINT32_T x, y, z, w, t, result; if (argvars[0].v_type == VAR_UNKNOWN) { // When no argument is given use the global seed list. - if (globl == NULL) + if (initialized == FALSE) { // Initialize the global seed list. - f_srand(argvars, rettv); - l = rettv->vval.v_list; - if (l == NULL || list_len(l) != 4) - { - clear_tv(rettv); - goto theend; - } - globl = l; + init_srand(&x); + + gx = SPLITMIX32(x, z); + gy = SPLITMIX32(x, z); + gz = SPLITMIX32(x, z); + gw = SPLITMIX32(x, z); + initialized = TRUE; } - else - l = globl; + + SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw); } else if (argvars[0].v_type == VAR_LIST) { l = argvars[0].vval.v_list; if (l == NULL || list_len(l) != 4) goto theend; + + lx = list_find(l, 0L); + ly = list_find(l, 1L); + lz = list_find(l, 2L); + lw = list_find(l, 3L); + if (lx->li_tv.v_type != VAR_NUMBER) goto theend; + if (ly->li_tv.v_type != VAR_NUMBER) goto theend; + if (lz->li_tv.v_type != VAR_NUMBER) goto theend; + if (lw->li_tv.v_type != VAR_NUMBER) goto theend; + x = (UINT32_T)lx->li_tv.vval.v_number; + y = (UINT32_T)ly->li_tv.vval.v_number; + z = (UINT32_T)lz->li_tv.vval.v_number; + w = (UINT32_T)lw->li_tv.vval.v_number; + + SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w); + + lx->li_tv.vval.v_number = (varnumber_T)x; + ly->li_tv.vval.v_number = (varnumber_T)y; + lz->li_tv.vval.v_number = (varnumber_T)z; + lw->li_tv.vval.v_number = (varnumber_T)w; } else goto theend; - lx = list_find(l, 0L); - ly = list_find(l, 1L); - lz = list_find(l, 2L); - lw = list_find(l, 3L); - if (lx->li_tv.v_type != VAR_NUMBER) goto theend; - if (ly->li_tv.v_type != VAR_NUMBER) goto theend; - if (lz->li_tv.v_type != VAR_NUMBER) goto theend; - if (lw->li_tv.v_type != VAR_NUMBER) goto theend; - x = (UINT32_T)lx->li_tv.vval.v_number; - y = (UINT32_T)ly->li_tv.vval.v_number; - z = (UINT32_T)lz->li_tv.vval.v_number; - w = (UINT32_T)lw->li_tv.vval.v_number; - - // SHUFFLE_XOSHIRO128STARSTAR -#define ROTL(x, k) ((x << k) | (x >> (32 - k))) - result = ROTL(y * 5, 7) * 9; - t = y << 9; - z ^= x; - w ^= y; - y ^= z, x ^= w; - z ^= t; - w = ROTL(w, 11); -#undef ROTL - - lx->li_tv.vval.v_number = (varnumber_T)x; - ly->li_tv.vval.v_number = (varnumber_T)y; - lz->li_tv.vval.v_number = (varnumber_T)z; - lw->li_tv.vval.v_number = (varnumber_T)w; - rettv->v_type = VAR_NUMBER; rettv->vval.v_number = (varnumber_T)result; return; @@ -5317,6 +5358,39 @@ theend: rettv->vval.v_number = -1; } +/* + * "srand()" function + */ + static void +f_srand(typval_T *argvars, typval_T *rettv) +{ + UINT32_T x = 0, z; + + if (rettv_list_alloc(rettv) == FAIL) + return; + if (argvars[0].v_type == VAR_UNKNOWN) + { + init_srand(&x); + } + else + { + int error = FALSE; + + x = (UINT32_T)tv_get_number_chk(&argvars[0], &error); + if (error) + return; + } + + list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); + list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); + list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); + list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z)); +} + +#undef ROTL +#undef SPLITMIX32 +#undef SHUFFLE_XOSHIRO128STARSTAR + /* * "range()" function */ @@ -5413,118 +5487,6 @@ f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv) return_register(reg_recording, rettv); } -#if defined(FEAT_RELTIME) -/* - * Convert a List to proftime_T. - * Return FAIL when there is something wrong. - */ - static int -list2proftime(typval_T *arg, proftime_T *tm) -{ - long n1, n2; - int error = FALSE; - - if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL - || arg->vval.v_list->lv_len != 2) - return FAIL; - n1 = list_find_nr(arg->vval.v_list, 0L, &error); - n2 = list_find_nr(arg->vval.v_list, 1L, &error); -# ifdef MSWIN - tm->HighPart = n1; - tm->LowPart = n2; -# else - tm->tv_sec = n1; - tm->tv_usec = n2; -# endif - return error ? FAIL : OK; -} -#endif // FEAT_RELTIME - -/* - * "reltime()" function - */ - static void -f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ -#ifdef FEAT_RELTIME - proftime_T res; - proftime_T start; - - if (argvars[0].v_type == VAR_UNKNOWN) - { - // No arguments: get current time. - profile_start(&res); - } - else if (argvars[1].v_type == VAR_UNKNOWN) - { - if (list2proftime(&argvars[0], &res) == FAIL) - return; - profile_end(&res); - } - else - { - // Two arguments: compute the difference. - if (list2proftime(&argvars[0], &start) == FAIL - || list2proftime(&argvars[1], &res) == FAIL) - return; - profile_sub(&res, &start); - } - - if (rettv_list_alloc(rettv) == OK) - { - long n1, n2; - -# ifdef MSWIN - n1 = res.HighPart; - n2 = res.LowPart; -# else - n1 = res.tv_sec; - n2 = res.tv_usec; -# endif - list_append_number(rettv->vval.v_list, (varnumber_T)n1); - list_append_number(rettv->vval.v_list, (varnumber_T)n2); - } -#endif -} - -#ifdef FEAT_FLOAT -/* - * "reltimefloat()" function - */ - static void -f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) -{ -# ifdef FEAT_RELTIME - proftime_T tm; -# endif - - rettv->v_type = VAR_FLOAT; - rettv->vval.v_float = 0; -# ifdef FEAT_RELTIME - if (list2proftime(&argvars[0], &tm) == OK) - rettv->vval.v_float = profile_float(&tm); -# endif -} -#endif - -/* - * "reltimestr()" function - */ - static void -f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) -{ -#ifdef FEAT_RELTIME - proftime_T tm; -#endif - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = NULL; -#ifdef FEAT_RELTIME - if (list2proftime(&argvars[0], &tm) == OK) - rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); -#endif -} - #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11) static void make_connection(void) @@ -7240,73 +7202,6 @@ f_sqrt(typval_T *argvars, typval_T *rettv) } #endif -/* - * "srand()" function - */ - static void -f_srand(typval_T *argvars, typval_T *rettv) -{ - static int dev_urandom_state = -1; // FAIL or OK once tried - UINT32_T x = 0, z; - - if (rettv_list_alloc(rettv) == FAIL) - return; - if (argvars[0].v_type == VAR_UNKNOWN) - { - if (dev_urandom_state != FAIL) - { - int fd = open("/dev/urandom", O_RDONLY); - struct { - union { - UINT32_T number; - char bytes[sizeof(UINT32_T)]; - } cont; - } buf; - - // Attempt reading /dev/urandom. - if (fd == -1) - dev_urandom_state = FAIL; - else - { - buf.cont.number = 0; - if (read(fd, buf.cont.bytes, sizeof(UINT32_T)) - != sizeof(UINT32_T)) - dev_urandom_state = FAIL; - else - { - dev_urandom_state = OK; - x = buf.cont.number; - } - close(fd); - } - - } - if (dev_urandom_state != OK) - // Reading /dev/urandom doesn't work, fall back to time(). - x = vim_time(); - } - else - { - int error = FALSE; - - x = (UINT32_T)tv_get_number_chk(&argvars[0], &error); - if (error) - return; - } - -#define SPLITMIX32 ( \ - z = (x += 0x9e3779b9), \ - z = (z ^ (z >> 16)) * 0x85ebca6b, \ - z = (z ^ (z >> 13)) * 0xc2b2ae35, \ - z ^ (z >> 16) \ - ) - - list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); - list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); - list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); - list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); -} - #ifdef FEAT_FLOAT /* * "str2float()" function @@ -7410,61 +7305,6 @@ f_str2nr(typval_T *argvars, typval_T *rettv) } -#ifdef HAVE_STRFTIME -/* - * "strftime({format}[, {time}])" function - */ - static void -f_strftime(typval_T *argvars, typval_T *rettv) -{ - char_u result_buf[256]; - struct tm tmval; - struct tm *curtime; - time_t seconds; - char_u *p; - - rettv->v_type = VAR_STRING; - - p = tv_get_string(&argvars[0]); - if (argvars[1].v_type == VAR_UNKNOWN) - seconds = time(NULL); - else - seconds = (time_t)tv_get_number(&argvars[1]); - curtime = vim_localtime(&seconds, &tmval); - // MSVC returns NULL for an invalid value of seconds. - if (curtime == NULL) - rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); - else - { - vimconv_T conv; - char_u *enc; - - conv.vc_type = CONV_NONE; - enc = enc_locale(); - convert_setup(&conv, p_enc, enc); - if (conv.vc_type != CONV_NONE) - p = string_convert(&conv, p, NULL); - if (p != NULL) - (void)strftime((char *)result_buf, sizeof(result_buf), - (char *)p, curtime); - else - result_buf[0] = NUL; - - if (conv.vc_type != CONV_NONE) - vim_free(p); - convert_setup(&conv, enc, p_enc); - if (conv.vc_type != CONV_NONE) - rettv->vval.v_string = string_convert(&conv, result_buf, NULL); - else - rettv->vval.v_string = vim_strsave(result_buf); - - // Release conversion descriptors - convert_setup(&conv, NULL, NULL); - vim_free(enc); - } -} -#endif - /* * "strgetchar()" function */ @@ -7722,40 +7562,6 @@ f_strpart(typval_T *argvars, typval_T *rettv) rettv->vval.v_string = vim_strnsave(p + n, len); } -#ifdef HAVE_STRPTIME -/* - * "strptime({format}, {timestring})" function - */ - static void -f_strptime(typval_T *argvars, typval_T *rettv) -{ - struct tm tmval; - char_u *fmt; - char_u *str; - vimconv_T conv; - char_u *enc; - - vim_memset(&tmval, NUL, sizeof(tmval)); - fmt = tv_get_string(&argvars[0]); - str = tv_get_string(&argvars[1]); - - conv.vc_type = CONV_NONE; - enc = enc_locale(); - convert_setup(&conv, p_enc, enc); - if (conv.vc_type != CONV_NONE) - fmt = string_convert(&conv, fmt, NULL); - if (fmt == NULL - || strptime((char *)str, (char *)fmt, &tmval) == NULL - || (rettv->vval.v_number = mktime(&tmval)) == -1) - rettv->vval.v_number = 0; - - if (conv.vc_type != CONV_NONE) - vim_free(fmt); - convert_setup(&conv, NULL, NULL); - vim_free(enc); -} -#endif - /* * "strridx()" function */ diff --git a/src/evalwindow.c b/src/evalwindow.c index be6762a5c6..c7a9f7960e 100644 --- a/src/evalwindow.c +++ b/src/evalwindow.c @@ -839,6 +839,54 @@ f_win_splitmove(typval_T *argvars, typval_T *rettv) win_move_into_split(wp, targetwin, size, flags); } +/* + * "win_gettype(nr)" function + */ + void +f_win_gettype(typval_T *argvars, typval_T *rettv) +{ + win_T *wp = curwin; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + if (argvars[0].v_type != VAR_UNKNOWN) + { + wp = find_win_by_nr_or_id(&argvars[0]); + if (wp == NULL) + { + rettv->vval.v_string = vim_strsave((char_u *)"unknown"); + return; + } + } +#ifdef FEAT_PROP_POPUP + if (WIN_IS_POPUP(wp)) + rettv->vval.v_string = vim_strsave((char_u *)"popup"); + else +#endif +#ifdef FEAT_CMDWIN + if (wp == curwin && cmdwin_type != 0) + rettv->vval.v_string = vim_strsave((char_u *)"command"); +#endif +} + +/* + * "getcmdwintype()" function + */ + void +f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; +#ifdef FEAT_CMDWIN + rettv->vval.v_string = alloc(2); + if (rettv->vval.v_string != NULL) + { + rettv->vval.v_string[0] = cmdwin_type; + rettv->vval.v_string[1] = NUL; + } +#endif +} + /* * "winbufnr(nr)" function */ diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 881e6f9265..f92537862f 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -1678,20 +1678,6 @@ append_redir( (char *)opt, (char *)fname); } -/* - * Return the current time in seconds. Calls time(), unless test_settime() - * was used. - */ - time_T -vim_time(void) -{ -# ifdef FEAT_EVAL - return time_for_testing == 0 ? time(NULL) : time_for_testing; -# else - return time(NULL); -# endif -} - /* * Implementation of ":fixdel", also used by get_stty(). * resulting @@ -5934,7 +5920,8 @@ helptags_one( char_u *dir, // doc directory char_u *ext, // suffix, ".txt", ".itx", ".frx", etc. char_u *tagfname, // "tags" for English, "tags-fr" for French. - int add_help_tags) // add "help-tags" tag + int add_help_tags, // add "help-tags" tag + int ignore_writeerr) // ignore write error { FILE *fd_tags; FILE *fd; @@ -5978,7 +5965,8 @@ helptags_one( fd_tags = mch_fopen((char *)NameBuff, "w"); if (fd_tags == NULL) { - semsg(_("E152: Cannot open %s for writing"), NameBuff); + if (!ignore_writeerr) + semsg(_("E152: Cannot open %s for writing"), NameBuff); FreeWild(filecount, files); return; } @@ -6179,7 +6167,7 @@ helptags_one( * Generate tags in one help directory, taking care of translations. */ static void -do_helptags(char_u *dirname, int add_help_tags) +do_helptags(char_u *dirname, int add_help_tags, int ignore_writeerr) { #ifdef FEAT_MULTI_LANG int len; @@ -6265,7 +6253,7 @@ do_helptags(char_u *dirname, int add_help_tags) ext[1] = fname[5]; ext[2] = fname[6]; } - helptags_one(dirname, ext, fname, add_help_tags); + helptags_one(dirname, ext, fname, add_help_tags, ignore_writeerr); } ga_clear(&ga); @@ -6273,14 +6261,15 @@ do_helptags(char_u *dirname, int add_help_tags) #else // No language support, just use "*.txt" and "tags". - helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags); + helptags_one(dirname, (char_u *)".txt", (char_u *)"tags", add_help_tags, + ignore_writeerr); #endif } static void helptags_cb(char_u *fname, void *cookie) { - do_helptags(fname, *(int *)cookie); + do_helptags(fname, *(int *)cookie, TRUE); } /* @@ -6314,7 +6303,7 @@ ex_helptags(exarg_T *eap) if (dirname == NULL || !mch_isdir(dirname)) semsg(_("E150: Not a directory: %s"), eap->arg); else - do_helptags(dirname, add_help_tags); + do_helptags(dirname, add_help_tags, FALSE); vim_free(dirname); } } diff --git a/src/ex_cmds.h b/src/ex_cmds.h index d002302a94..7f619b651f 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -479,7 +479,7 @@ EXCMD(CMD_digraphs, "digraphs", ex_digraphs, EX_BANG|EX_EXTRA|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_disassemble, "disassemble", ex_disassemble, - EX_EXTRA|EX_TRLBAR|EX_CMDWIN, + EX_EXTRA|EX_NEEDARG|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_djump, "djump", ex_findpat, EX_BANG|EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_EXTRA, diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 53e4e156ec..00104bac7e 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -14,498 +14,6 @@ #include "vim.h" #include "version.h" -#if defined(FEAT_EVAL) || defined(PROTO) -# if defined(FEAT_TIMERS) || defined(PROTO) -static timer_T *first_timer = NULL; -static long last_timer_id = 0; - -/* - * Return time left until "due". Negative if past "due". - */ - long -proftime_time_left(proftime_T *due, proftime_T *now) -{ -# ifdef MSWIN - LARGE_INTEGER fr; - - if (now->QuadPart > due->QuadPart) - return 0; - QueryPerformanceFrequency(&fr); - return (long)(((double)(due->QuadPart - now->QuadPart) - / (double)fr.QuadPart) * 1000); -# else - if (now->tv_sec > due->tv_sec) - return 0; - return (due->tv_sec - now->tv_sec) * 1000 - + (due->tv_usec - now->tv_usec) / 1000; -# endif -} - -/* - * Insert a timer in the list of timers. - */ - static void -insert_timer(timer_T *timer) -{ - timer->tr_next = first_timer; - timer->tr_prev = NULL; - if (first_timer != NULL) - first_timer->tr_prev = timer; - first_timer = timer; - did_add_timer = TRUE; -} - -/* - * Take a timer out of the list of timers. - */ - static void -remove_timer(timer_T *timer) -{ - if (timer->tr_prev == NULL) - first_timer = timer->tr_next; - else - timer->tr_prev->tr_next = timer->tr_next; - if (timer->tr_next != NULL) - timer->tr_next->tr_prev = timer->tr_prev; -} - - static void -free_timer(timer_T *timer) -{ - free_callback(&timer->tr_callback); - vim_free(timer); -} - -/* - * Create a timer and return it. NULL if out of memory. - * Caller should set the callback. - */ - timer_T * -create_timer(long msec, int repeat) -{ - timer_T *timer = ALLOC_CLEAR_ONE(timer_T); - long prev_id = last_timer_id; - - if (timer == NULL) - return NULL; - if (++last_timer_id <= prev_id) - // Overflow! Might cause duplicates... - last_timer_id = 0; - timer->tr_id = last_timer_id; - insert_timer(timer); - if (repeat != 0) - timer->tr_repeat = repeat - 1; - timer->tr_interval = msec; - - profile_setlimit(msec, &timer->tr_due); - return timer; -} - -/* - * Invoke the callback of "timer". - */ - static void -timer_callback(timer_T *timer) -{ - typval_T rettv; - typval_T argv[2]; - - argv[0].v_type = VAR_NUMBER; - argv[0].vval.v_number = (varnumber_T)timer->tr_id; - argv[1].v_type = VAR_UNKNOWN; - - call_callback(&timer->tr_callback, -1, &rettv, 1, argv); - clear_tv(&rettv); -} - -/* - * Call timers that are due. - * Return the time in msec until the next timer is due. - * Returns -1 if there are no pending timers. - */ - long -check_due_timer(void) -{ - timer_T *timer; - timer_T *timer_next; - long this_due; - long next_due = -1; - proftime_T now; - int did_one = FALSE; - int need_update_screen = FALSE; - long current_id = last_timer_id; - - // Don't run any timers while exiting or dealing with an error. - if (exiting || aborting()) - return next_due; - - profile_start(&now); - for (timer = first_timer; timer != NULL && !got_int; timer = timer_next) - { - timer_next = timer->tr_next; - - if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused) - continue; - this_due = proftime_time_left(&timer->tr_due, &now); - if (this_due <= 1) - { - // Save and restore a lot of flags, because the timer fires while - // waiting for a character, which might be halfway a command. - int save_timer_busy = timer_busy; - int save_vgetc_busy = vgetc_busy; - int save_did_emsg = did_emsg; - int save_called_emsg = called_emsg; - int save_must_redraw = must_redraw; - int save_trylevel = trylevel; - int save_did_throw = did_throw; - int save_ex_pressedreturn = get_pressedreturn(); - int save_may_garbage_collect = may_garbage_collect; - except_T *save_current_exception = current_exception; - vimvars_save_T vvsave; - - // Create a scope for running the timer callback, ignoring most of - // the current scope, such as being inside a try/catch. - timer_busy = timer_busy > 0 || vgetc_busy > 0; - vgetc_busy = 0; - called_emsg = 0; - did_emsg = FALSE; - did_uncaught_emsg = FALSE; - must_redraw = 0; - trylevel = 0; - did_throw = FALSE; - current_exception = NULL; - may_garbage_collect = FALSE; - save_vimvars(&vvsave); - - timer->tr_firing = TRUE; - timer_callback(timer); - timer->tr_firing = FALSE; - - timer_next = timer->tr_next; - did_one = TRUE; - timer_busy = save_timer_busy; - vgetc_busy = save_vgetc_busy; - if (did_uncaught_emsg) - ++timer->tr_emsg_count; - did_emsg = save_did_emsg; - called_emsg = save_called_emsg; - trylevel = save_trylevel; - did_throw = save_did_throw; - current_exception = save_current_exception; - restore_vimvars(&vvsave); - if (must_redraw != 0) - need_update_screen = TRUE; - must_redraw = must_redraw > save_must_redraw - ? must_redraw : save_must_redraw; - set_pressedreturn(save_ex_pressedreturn); - may_garbage_collect = save_may_garbage_collect; - - // Only fire the timer again if it repeats and stop_timer() wasn't - // called while inside the callback (tr_id == -1). - if (timer->tr_repeat != 0 && timer->tr_id != -1 - && timer->tr_emsg_count < 3) - { - profile_setlimit(timer->tr_interval, &timer->tr_due); - this_due = proftime_time_left(&timer->tr_due, &now); - if (this_due < 1) - this_due = 1; - if (timer->tr_repeat > 0) - --timer->tr_repeat; - } - else - { - this_due = -1; - remove_timer(timer); - free_timer(timer); - } - } - if (this_due > 0 && (next_due == -1 || next_due > this_due)) - next_due = this_due; - } - - if (did_one) - redraw_after_callback(need_update_screen); - -#ifdef FEAT_BEVAL_TERM - if (bevalexpr_due_set) - { - this_due = proftime_time_left(&bevalexpr_due, &now); - if (this_due <= 1) - { - bevalexpr_due_set = FALSE; - if (balloonEval == NULL) - { - balloonEval = ALLOC_CLEAR_ONE(BalloonEval); - balloonEvalForTerm = TRUE; - } - if (balloonEval != NULL) - { - general_beval_cb(balloonEval, 0); - setcursor(); - out_flush(); - } - } - else if (next_due == -1 || next_due > this_due) - next_due = this_due; - } -#endif -#ifdef FEAT_TERMINAL - // Some terminal windows may need their buffer updated. - next_due = term_check_timers(next_due, &now); -#endif - - return current_id != last_timer_id ? 1 : next_due; -} - -/* - * Find a timer by ID. Returns NULL if not found; - */ - static timer_T * -find_timer(long id) -{ - timer_T *timer; - - if (id >= 0) - { - for (timer = first_timer; timer != NULL; timer = timer->tr_next) - if (timer->tr_id == id) - return timer; - } - return NULL; -} - - -/* - * Stop a timer and delete it. - */ - void -stop_timer(timer_T *timer) -{ - if (timer->tr_firing) - // Free the timer after the callback returns. - timer->tr_id = -1; - else - { - remove_timer(timer); - free_timer(timer); - } -} - - static void -stop_all_timers(void) -{ - timer_T *timer; - timer_T *timer_next; - - for (timer = first_timer; timer != NULL; timer = timer_next) - { - timer_next = timer->tr_next; - stop_timer(timer); - } -} - - static void -add_timer_info(typval_T *rettv, timer_T *timer) -{ - list_T *list = rettv->vval.v_list; - dict_T *dict = dict_alloc(); - dictitem_T *di; - long remaining; - proftime_T now; - - if (dict == NULL) - return; - list_append_dict(list, dict); - - dict_add_number(dict, "id", timer->tr_id); - dict_add_number(dict, "time", (long)timer->tr_interval); - - profile_start(&now); - remaining = proftime_time_left(&timer->tr_due, &now); - dict_add_number(dict, "remaining", (long)remaining); - - dict_add_number(dict, "repeat", - (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1)); - dict_add_number(dict, "paused", (long)(timer->tr_paused)); - - di = dictitem_alloc((char_u *)"callback"); - if (di != NULL) - { - if (dict_add(dict, di) == FAIL) - vim_free(di); - else - put_callback(&timer->tr_callback, &di->di_tv); - } -} - - static void -add_timer_info_all(typval_T *rettv) -{ - timer_T *timer; - - for (timer = first_timer; timer != NULL; timer = timer->tr_next) - if (timer->tr_id != -1) - add_timer_info(rettv, timer); -} - -/* - * Mark references in partials of timers. - */ - int -set_ref_in_timer(int copyID) -{ - int abort = FALSE; - timer_T *timer; - typval_T tv; - - for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next) - { - if (timer->tr_callback.cb_partial != NULL) - { - tv.v_type = VAR_PARTIAL; - tv.vval.v_partial = timer->tr_callback.cb_partial; - } - else - { - tv.v_type = VAR_FUNC; - tv.vval.v_string = timer->tr_callback.cb_name; - } - abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); - } - return abort; -} - -# if defined(EXITFREE) || defined(PROTO) - void -timer_free_all() -{ - timer_T *timer; - - while (first_timer != NULL) - { - timer = first_timer; - remove_timer(timer); - free_timer(timer); - } -} -# endif - -/* - * "timer_info([timer])" function - */ - void -f_timer_info(typval_T *argvars, typval_T *rettv) -{ - timer_T *timer = NULL; - - if (rettv_list_alloc(rettv) != OK) - return; - if (argvars[0].v_type != VAR_UNKNOWN) - { - if (argvars[0].v_type != VAR_NUMBER) - emsg(_(e_number_exp)); - else - { - timer = find_timer((int)tv_get_number(&argvars[0])); - if (timer != NULL) - add_timer_info(rettv, timer); - } - } - else - add_timer_info_all(rettv); -} - -/* - * "timer_pause(timer, paused)" function - */ - void -f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED) -{ - timer_T *timer = NULL; - int paused = (int)tv_get_number(&argvars[1]); - - if (argvars[0].v_type != VAR_NUMBER) - emsg(_(e_number_exp)); - else - { - timer = find_timer((int)tv_get_number(&argvars[0])); - if (timer != NULL) - timer->tr_paused = paused; - } -} - -/* - * "timer_start(time, callback [, options])" function - */ - void -f_timer_start(typval_T *argvars, typval_T *rettv) -{ - long msec = (long)tv_get_number(&argvars[0]); - timer_T *timer; - int repeat = 0; - callback_T callback; - dict_T *dict; - - rettv->vval.v_number = -1; - if (check_secure()) - return; - if (argvars[2].v_type != VAR_UNKNOWN) - { - if (argvars[2].v_type != VAR_DICT - || (dict = argvars[2].vval.v_dict) == NULL) - { - semsg(_(e_invarg2), tv_get_string(&argvars[2])); - return; - } - if (dict_find(dict, (char_u *)"repeat", -1) != NULL) - repeat = dict_get_number(dict, (char_u *)"repeat"); - } - - callback = get_callback(&argvars[1]); - if (callback.cb_name == NULL) - return; - - timer = create_timer(msec, repeat); - if (timer == NULL) - free_callback(&callback); - else - { - set_callback(&timer->tr_callback, &callback); - rettv->vval.v_number = (varnumber_T)timer->tr_id; - } -} - -/* - * "timer_stop(timer)" function - */ - void -f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) -{ - timer_T *timer; - - if (argvars[0].v_type != VAR_NUMBER) - { - emsg(_(e_number_exp)); - return; - } - timer = find_timer((int)tv_get_number(&argvars[0])); - if (timer != NULL) - stop_timer(timer); -} - -/* - * "timer_stopall()" function - */ - void -f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ - stop_all_timers(); -} - -# endif // FEAT_TIMERS - -#endif // FEAT_EVAL - /* * If 'autowrite' option set, try to write the file. * Careful: autocommands may make "buf" invalid! diff --git a/src/ex_docmd.c b/src/ex_docmd.c index b50a085072..3afaf4be3a 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2381,6 +2381,7 @@ do_one_cmd( case CMD_echoerr: case CMD_echomsg: case CMD_echon: + case CMD_eval: case CMD_execute: case CMD_filter: case CMD_help: @@ -2501,7 +2502,8 @@ do_one_cmd( #ifdef FEAT_EVAL // Set flag that any command was executed, used by ex_vim9script(). - if (getline_equal(ea.getline, ea.cookie, getsourceline)) + if (getline_equal(ea.getline, ea.cookie, getsourceline) + && current_sctx.sc_sid > 0) SCRIPT_ITEM(current_sctx.sc_sid)->sn_had_command = TRUE; /* diff --git a/src/feature.h b/src/feature.h index 14cc3a8ff2..dc7c658c00 100644 --- a/src/feature.h +++ b/src/feature.h @@ -285,16 +285,12 @@ * +eval Built-in script language and expression evaluation, * ":let", ":if", etc. * +float Floating point variables. - * +num64 64-bit Number. */ #ifdef FEAT_NORMAL # define FEAT_EVAL # if defined(HAVE_FLOAT_FUNCS) || defined(MSWIN) || defined(MACOS_X) # define FEAT_FLOAT # endif -# if defined(HAVE_STDINT_H) || defined(MSWIN) || (VIM_SIZEOF_LONG >= 8) -# define FEAT_NUM64 -# endif #endif #ifdef FEAT_EVAL diff --git a/src/globals.h b/src/globals.h index 5442837198..1ac0640490 100644 --- a/src/globals.h +++ b/src/globals.h @@ -384,9 +384,9 @@ EXTERN type_T t_void INIT4(VAR_VOID, 0, NULL, NULL); EXTERN type_T t_bool INIT4(VAR_BOOL, 0, NULL, NULL); EXTERN type_T t_special INIT4(VAR_SPECIAL, 0, NULL, NULL); EXTERN type_T t_number INIT4(VAR_NUMBER, 0, NULL, NULL); -#ifdef FEAT_FLOAT +# ifdef FEAT_FLOAT EXTERN type_T t_float INIT4(VAR_FLOAT, 0, NULL, NULL); -#endif +# endif EXTERN type_T t_string INIT4(VAR_STRING, 0, NULL, NULL); EXTERN type_T t_blob INIT4(VAR_BLOB, 0, NULL, NULL); EXTERN type_T t_job INIT4(VAR_JOB, 0, NULL, NULL); diff --git a/src/if_lua.c b/src/if_lua.c index 1eb7a77a14..8c1638a3a2 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -1148,7 +1148,7 @@ luaV_blob_add(lua_State *L) size_t i, l = 0; const char *s = lua_tolstring(L, 2, &l); - if (ga_grow(&b->bv_ga, l) == OK) + if (ga_grow(&b->bv_ga, (int)l) == OK) for (i = 0; i < l; ++i) ga_append(&b->bv_ga, s[i]); } @@ -1781,7 +1781,7 @@ luaV_blob(lua_State *L) size_t i, l = 0; const char *s = lua_tolstring(L, 1, &l); - if (ga_grow(&b->bv_ga, l) == OK) + if (ga_grow(&b->bv_ga, (int)l) == OK) for (i = 0; i < l; ++i) ga_append(&b->bv_ga, s[i]); } diff --git a/src/if_ruby.c b/src/if_ruby.c index 7f2a7d265e..f4e1e12394 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -21,7 +21,7 @@ #ifdef _WIN32 # if !defined(DYNAMIC_RUBY) || (RUBY_VERSION < 18) -# define NT +# define NT # endif # ifndef DYNAMIC_RUBY # define IMPORT // For static dll usage __declspec(dllimport) @@ -300,8 +300,8 @@ static int ruby_convert_to_vim_value(VALUE val, typval_T *rettv); # define rb_float_new dll_rb_float_new # define rb_ary_new dll_rb_ary_new # ifdef rb_ary_new4 -# define RB_ARY_NEW4_MACRO 1 -# undef rb_ary_new4 +# define RB_ARY_NEW4_MACRO 1 +# undef rb_ary_new4 # endif # define rb_ary_new4 dll_rb_ary_new4 # define rb_ary_push dll_rb_ary_push @@ -1071,15 +1071,15 @@ error_print(int state) } attr = syn_name2attr((char_u *)"Error"); -# if RUBY_VERSION >= 21 +#if RUBY_VERSION >= 21 bt = rb_funcallv(error, rb_intern("backtrace"), 0, 0); for (i = 0; i < RARRAY_LEN(bt); i++) msg_attr(RSTRING_PTR(RARRAY_AREF(bt, i)), attr); -# else +#else bt = rb_funcall2(error, rb_intern("backtrace"), 0, 0); for (i = 0; i < RARRAY_LEN(bt); i++) msg_attr(RSTRING_PTR(RARRAY_PTR(bt)[i]), attr); -# endif +#endif break; default: vim_snprintf(buff, BUFSIZ, _("E273: unknown longjmp status %d"), state); diff --git a/src/main.c b/src/main.c index 300d3be3c7..1e328eb1c1 100644 --- a/src/main.c +++ b/src/main.c @@ -3754,110 +3754,6 @@ check_swap_exists_action(void) #endif // NO_VIM_MAIN -#if defined(STARTUPTIME) || defined(PROTO) -static struct timeval prev_timeval; - -# ifdef MSWIN -/* - * Windows doesn't have gettimeofday(), although it does have struct timeval. - */ - static int -gettimeofday(struct timeval *tv, char *dummy UNUSED) -{ - long t = clock(); - tv->tv_sec = t / CLOCKS_PER_SEC; - tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC; - return 0; -} -# endif - -/* - * Save the previous time before doing something that could nest. - * set "*tv_rel" to the time elapsed so far. - */ - void -time_push(void *tv_rel, void *tv_start) -{ - *((struct timeval *)tv_rel) = prev_timeval; - gettimeofday(&prev_timeval, NULL); - ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec - - ((struct timeval *)tv_rel)->tv_usec; - ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec - - ((struct timeval *)tv_rel)->tv_sec; - if (((struct timeval *)tv_rel)->tv_usec < 0) - { - ((struct timeval *)tv_rel)->tv_usec += 1000000; - --((struct timeval *)tv_rel)->tv_sec; - } - *(struct timeval *)tv_start = prev_timeval; -} - -/* - * Compute the previous time after doing something that could nest. - * Subtract "*tp" from prev_timeval; - * Note: The arguments are (void *) to avoid trouble with systems that don't - * have struct timeval. - */ - void -time_pop( - void *tp) // actually (struct timeval *) -{ - prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec; - prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec; - if (prev_timeval.tv_usec < 0) - { - prev_timeval.tv_usec += 1000000; - --prev_timeval.tv_sec; - } -} - - static void -time_diff(struct timeval *then, struct timeval *now) -{ - long usec; - long msec; - - usec = now->tv_usec - then->tv_usec; - msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L, - usec = usec % 1000L; - fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L); -} - - void -time_msg( - char *mesg, - void *tv_start) // only for do_source: start time; actually - // (struct timeval *) -{ - static struct timeval start; - struct timeval now; - - if (time_fd != NULL) - { - if (strstr(mesg, "STARTING") != NULL) - { - gettimeofday(&start, NULL); - prev_timeval = start; - fprintf(time_fd, "\n\ntimes in msec\n"); - fprintf(time_fd, " clock self+sourced self: sourced script\n"); - fprintf(time_fd, " clock elapsed: other lines\n\n"); - } - gettimeofday(&now, NULL); - time_diff(&start, &now); - if (((struct timeval *)tv_start) != NULL) - { - fprintf(time_fd, " "); - time_diff(((struct timeval *)tv_start), &now); - } - fprintf(time_fd, " "); - time_diff(&prev_timeval, &now); - prev_timeval = now; - fprintf(time_fd, ": %s\n", mesg); - } -} - -#endif - #if !defined(NO_VIM_MAIN) && defined(FEAT_EVAL) static void set_progpath(char_u *argv0) diff --git a/src/memline.c b/src/memline.c index c6db9136fe..b409eb5553 100644 --- a/src/memline.c +++ b/src/memline.c @@ -2080,94 +2080,6 @@ get_b0_dict(char_u *fname, dict_T *d) } #endif -/* - * Cache of the current timezone name as retrieved from TZ, or an empty string - * where unset, up to 64 octets long including trailing null byte. - */ -#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET) -static char tz_cache[64]; -#endif - -/* - * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the - * latter version preferred for reentrancy. - * - * If we use localtime_r(3) and we have tzset(3) available, check to see if the - * environment variable TZ has changed since the last run, and call tzset(3) to - * update the global timezone variables if it has. This is because the POSIX - * standard doesn't require localtime_r(3) implementations to do that as it - * does with localtime(3), and we don't want to call tzset(3) every time. - */ - struct tm * -vim_localtime( - const time_t *timep, // timestamp for local representation - struct tm *result UNUSED) // pointer to caller return buffer -{ -#ifdef HAVE_LOCALTIME_R -# ifdef HAVE_TZSET - char *tz; // pointer for TZ environment var - - tz = (char *)mch_getenv((char_u *)"TZ"); - if (tz == NULL) - tz = ""; - if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0) - { - tzset(); - vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1); - } -# endif // HAVE_TZSET - return localtime_r(timep, result); -#else - return localtime(timep); -#endif // HAVE_LOCALTIME_R -} - -/* - * Replacement for ctime(), which is not safe to use. - * Requires strftime(), otherwise returns "(unknown)". - * If "thetime" is invalid returns "(invalid)". Never returns NULL. - * When "add_newline" is TRUE add a newline like ctime() does. - * Uses a static buffer. - */ - char * -get_ctime(time_t thetime, int add_newline) -{ - static char buf[50]; -#ifdef HAVE_STRFTIME - struct tm tmval; - struct tm *curtime; - - curtime = vim_localtime(&thetime, &tmval); - // MSVC returns NULL for an invalid value of seconds. - if (curtime == NULL) - vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1); - else - { - (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"), - curtime); -# ifdef MSWIN - if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) - { - char_u *to_free = NULL; - int len; - - acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len); - if (to_free != NULL) - { - STRCPY(buf, to_free); - vim_free(to_free); - } - } -# endif - } -#else - STRCPY(buf, "(unknown)"); -#endif - if (add_newline) - STRCAT(buf, "\n"); - return buf; -} - /* * Give information about an existing swap file. * Returns timestamp (0 when unknown). diff --git a/src/message.c b/src/message.c index 5420c4f17b..cc6bfd7a7e 100644 --- a/src/message.c +++ b/src/message.c @@ -4251,10 +4251,8 @@ vim_vsnprintf_typval( # define TMP_LEN 350 // On my system 1e308 is the biggest number possible. // That sounds reasonable to use as the maximum // printable. -# elif defined(FEAT_NUM64) -# define TMP_LEN 66 # else -# define TMP_LEN 34 +# define TMP_LEN 66 # endif char tmp[TMP_LEN]; @@ -4379,11 +4377,7 @@ vim_vsnprintf_typval( if (length_modifier == 'l' && *p == 'l') { // double l = long long -# ifdef FEAT_NUM64 length_modifier = 'L'; -# else - length_modifier = 'l'; // treat it as a single 'l' -# endif p++; } } @@ -4399,7 +4393,7 @@ vim_vsnprintf_typval( default: break; } -# if defined(FEAT_EVAL) && defined(FEAT_NUM64) +# if defined(FEAT_EVAL) switch (fmt_spec) { case 'd': case 'u': case 'o': case 'x': case 'X': @@ -4521,11 +4515,9 @@ vim_vsnprintf_typval( long int long_arg = 0; unsigned long int ulong_arg = 0; -# ifdef FEAT_NUM64 // only defined for length modifier ll varnumber_T llong_arg = 0; uvarnumber_T ullong_arg = 0; -# endif // only defined for b conversion uvarnumber_T bin_arg = 0; @@ -4586,19 +4578,17 @@ vim_vsnprintf_typval( else if (long_arg < 0) arg_sign = -1; break; -# ifdef FEAT_NUM64 case 'L': llong_arg = -# if defined(FEAT_EVAL) +# if defined(FEAT_EVAL) tvs != NULL ? tv_nr(tvs, &arg_idx) : -# endif +# endif va_arg(ap, varnumber_T); if (llong_arg > 0) arg_sign = 1; else if (llong_arg < 0) arg_sign = -1; break; -# endif } } else @@ -4627,18 +4617,16 @@ vim_vsnprintf_typval( if (ulong_arg != 0) arg_sign = 1; break; -# ifdef FEAT_NUM64 case 'L': ullong_arg = -# if defined(FEAT_EVAL) +# if defined(FEAT_EVAL) tvs != NULL ? (uvarnumber_T) tv_nr(tvs, &arg_idx) : -# endif +# endif va_arg(ap, uvarnumber_T); if (ullong_arg != 0) arg_sign = 1; break; -# endif } } @@ -4692,17 +4680,13 @@ vim_vsnprintf_typval( ; else if (length_modifier == 'L') { -# ifdef FEAT_NUM64 -# ifdef MSWIN +# ifdef MSWIN f[f_l++] = 'I'; f[f_l++] = '6'; f[f_l++] = '4'; -# else - f[f_l++] = 'l'; - f[f_l++] = 'l'; -# endif # else f[f_l++] = 'l'; + f[f_l++] = 'l'; # endif } else @@ -4740,11 +4724,9 @@ vim_vsnprintf_typval( case 'l': str_arg_l += sprintf( tmp + str_arg_l, f, long_arg); break; -# ifdef FEAT_NUM64 case 'L': str_arg_l += sprintf( tmp + str_arg_l, f, llong_arg); break; -# endif } } else @@ -4759,11 +4741,9 @@ vim_vsnprintf_typval( case 'l': str_arg_l += sprintf( tmp + str_arg_l, f, ulong_arg); break; -# ifdef FEAT_NUM64 case 'L': str_arg_l += sprintf( tmp + str_arg_l, f, ullong_arg); break; -# endif } } diff --git a/src/message_test.c b/src/message_test.c index 3397a9cb47..7f6540b310 100644 --- a/src/message_test.c +++ b/src/message_test.c @@ -240,14 +240,26 @@ test_vim_snprintf(void) // %p format is not tested in vim script tests Test_printf*() // as it only makes sense in C code. + // NOTE: SunOS libc doesn't use the prefix "0x" on %p. +#ifdef SUN_SYSTEM +# define PREFIX_LEN 0 +# define PREFIX_STR1 "" +# define PREFIX_STR2 "00" +#else +# define PREFIX_LEN 2 +# define PREFIX_STR1 "0x" +# define PREFIX_STR2 "0x" +#endif n = vim_snprintf(buf, bsize, "%p", ptr); - assert(n == 10); - assert(bsize == 0 || STRNCMP(buf, "0x87654321", bsize_int) == 0); + assert(n == 8 + PREFIX_LEN); + assert(bsize == 0 + || STRNCMP(buf, PREFIX_STR1 "87654321", bsize_int) == 0); assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); n = vim_snprintf(buf, bsize, fmt_012p, ptr); assert(n == 12); - assert(bsize == 0 || STRNCMP(buf, "0x0087654321", bsize_int) == 0); + assert(bsize == 0 + || STRNCMP(buf, PREFIX_STR2 "0087654321", bsize_int) == 0); assert(bsize == 0 || buf[MIN(n, bsize_int)] == '\0'); free(buf); diff --git a/src/misc1.c b/src/misc1.c index 8d638bddd7..d8ae6485d7 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -2604,34 +2604,3 @@ path_with_url(char_u *fname) ; return path_is_url(p); } - -/* - * Put timestamp "tt" in "buf[buflen]" in a nice format. - */ - void -add_time(char_u *buf, size_t buflen, time_t tt) -{ -#ifdef HAVE_STRFTIME - struct tm tmval; - struct tm *curtime; - - if (vim_time() - tt >= 100) - { - curtime = vim_localtime(&tt, &tmval); - if (vim_time() - tt < (60L * 60L * 12L)) - // within 12 hours - (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime); - else - // longer ago - (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime); - } - else -#endif - { - long seconds = (long)(vim_time() - tt); - - vim_snprintf((char *)buf, buflen, - NGETTEXT("%ld second ago", "%ld seconds ago", seconds), - seconds); - } -} diff --git a/src/misc2.c b/src/misc2.c index 22faaad463..4a856df17d 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -4133,26 +4133,6 @@ get4c(FILE *fd) return (int)n; } -/* - * Read 8 bytes from "fd" and turn them into a time_T, MSB first. - * Returns -1 when encountering EOF. - */ - time_T -get8ctime(FILE *fd) -{ - int c; - time_T n = 0; - int i; - - for (i = 0; i < 8; ++i) - { - c = getc(fd); - if (c == EOF) return -1; - n = (n << 8) + c; - } - return n; -} - /* * Read a string of length "cnt" from "fd" into allocated memory. * Returns NULL when out of memory or unable to read that many bytes. @@ -4198,68 +4178,6 @@ put_bytes(FILE *fd, long_u nr, int len) return OK; } -#ifdef _MSC_VER -# if (_MSC_VER <= 1200) -// This line is required for VC6 without the service pack. Also see the -// matching #pragma below. - # pragma optimize("", off) -# endif -#endif - -/* - * Write time_T to file "fd" in 8 bytes. - * Returns FAIL when the write failed. - */ - int -put_time(FILE *fd, time_T the_time) -{ - char_u buf[8]; - - time_to_bytes(the_time, buf); - return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL; -} - -/* - * Write time_T to "buf[8]". - */ - void -time_to_bytes(time_T the_time, char_u *buf) -{ - int c; - int i; - int bi = 0; - time_T wtime = the_time; - - // time_T can be up to 8 bytes in size, more than long_u, thus we - // can't use put_bytes() here. - // Another problem is that ">>" may do an arithmetic shift that keeps the - // sign. This happens for large values of wtime. A cast to long_u may - // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes, - // it's safe to assume that long_u is 4 bytes or more and when using 8 - // bytes the top bit won't be set. - for (i = 7; i >= 0; --i) - { - if (i + 1 > (int)sizeof(time_T)) - // ">>" doesn't work well when shifting more bits than avail - buf[bi++] = 0; - else - { -#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4 - c = (int)(wtime >> (i * 8)); -#else - c = (int)((long_u)wtime >> (i * 8)); -#endif - buf[bi++] = c; - } - } -} - -#ifdef _MSC_VER -# if (_MSC_VER <= 1200) - # pragma optimize("", on) -# endif -#endif - #endif #if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO) diff --git a/src/option.c b/src/option.c index 6ab743948c..7a33a07614 100644 --- a/src/option.c +++ b/src/option.c @@ -2521,6 +2521,61 @@ set_term_option_sctx_idx(char *name, int opt_idx) } #endif +#if defined(FEAT_EVAL) +/* + * Apply the OptionSet autocommand. + */ + static void +apply_optionset_autocmd( + int opt_idx, + long opt_flags, + long oldval, + long oldval_g, + long newval, + char *errmsg) +{ + char_u buf_old[12], buf_old_global[12], buf_new[12], buf_type[12]; + + // Don't do this while starting up, failure or recursively. + if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL) + return; + + vim_snprintf((char *)buf_old, sizeof(buf_old), "%ld", oldval); + vim_snprintf((char *)buf_old_global, sizeof(buf_old_global), "%ld", + oldval_g); + vim_snprintf((char *)buf_new, sizeof(buf_new), "%ld", newval); + vim_snprintf((char *)buf_type, sizeof(buf_type), "%s", + (opt_flags & OPT_LOCAL) ? "local" : "global"); + set_vim_var_string(VV_OPTION_NEW, buf_new, -1); + set_vim_var_string(VV_OPTION_OLD, buf_old, -1); + set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); + if (opt_flags & OPT_LOCAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + if (opt_flags & OPT_GLOBAL) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); + } + if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); + } + if (opt_flags & OPT_MODELINE) + { + set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); + set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); + } + apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, + NULL, FALSE, NULL); + reset_v_option_vars(); +} +#endif + /* * Set the value of a boolean option, and take care of side effects. * Returns NULL for success, or an error message for an error. @@ -3142,45 +3197,10 @@ set_bool_option( options[opt_idx].flags |= P_WAS_SET; #if defined(FEAT_EVAL) - // Don't do this while starting up or recursively. - if (!starting && *get_vim_var_str(VV_OPTION_TYPE) == NUL) - { - char_u buf_old[2], buf_old_global[2], buf_new[2], buf_type[7]; - - vim_snprintf((char *)buf_old, 2, "%d", old_value ? TRUE: FALSE); - vim_snprintf((char *)buf_old_global, 2, "%d", - old_global_value ? TRUE: FALSE); - vim_snprintf((char *)buf_new, 2, "%d", value ? TRUE: FALSE); - vim_snprintf((char *)buf_type, 7, "%s", - (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_NEW, buf_new, -1); - set_vim_var_string(VV_OPTION_OLD, buf_old, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - if (opt_flags & OPT_GLOBAL) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); - } - if (opt_flags & OPT_MODELINE) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, - NULL, FALSE, NULL); - reset_v_option_vars(); - } + apply_optionset_autocmd(opt_idx, opt_flags, + (long)(old_value ? TRUE : FALSE), + (long)(old_global_value ? TRUE : FALSE), + (long)(value ? TRUE : FALSE), NULL); #endif comp_col(); // in case 'ruler' or 'showcmd' changed @@ -3776,42 +3796,8 @@ set_num_option( options[opt_idx].flags |= P_WAS_SET; #if defined(FEAT_EVAL) - // Don't do this while starting up, failure or recursively. - if (!starting && errmsg == NULL && *get_vim_var_str(VV_OPTION_TYPE) == NUL) - { - char_u buf_old[11], buf_old_global[11], buf_new[11], buf_type[7]; - vim_snprintf((char *)buf_old, 10, "%ld", old_value); - vim_snprintf((char *)buf_old_global, 10, "%ld", old_global_value); - vim_snprintf((char *)buf_new, 10, "%ld", value); - vim_snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" : "global"); - set_vim_var_string(VV_OPTION_NEW, buf_new, -1); - set_vim_var_string(VV_OPTION_OLD, buf_old, -1); - set_vim_var_string(VV_OPTION_TYPE, buf_type, -1); - if (opt_flags & OPT_LOCAL) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setlocal", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - if (opt_flags & OPT_GLOBAL) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"setglobal", -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old, -1); - } - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"set", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - set_vim_var_string(VV_OPTION_OLDGLOBAL, buf_old_global, -1); - } - if (opt_flags & OPT_MODELINE) - { - set_vim_var_string(VV_OPTION_COMMAND, (char_u *)"modeline", -1); - set_vim_var_string(VV_OPTION_OLDLOCAL, buf_old, -1); - } - apply_autocmds(EVENT_OPTIONSET, (char_u *)options[opt_idx].fullname, - NULL, FALSE, NULL); - reset_v_option_vars(); - } + apply_optionset_autocmd(opt_idx, opt_flags, old_value, old_global_value, + value, errmsg); #endif comp_col(); // in case 'columns' or 'ls' changed diff --git a/src/os_unix.c b/src/os_unix.c index d6976c81bb..e8ca456ed3 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4998,29 +4998,7 @@ mch_call_shell_fork( } } - // replace K_BS by and K_DEL by - for (i = ta_len; i < ta_len + len; ++i) - { - if (ta_buf[i] == CSI && len - i > 2) - { - c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]); - if (c == K_DEL || c == K_KDEL || c == K_BS) - { - mch_memmove(ta_buf + i + 1, ta_buf + i + 3, - (size_t)(len - i - 2)); - if (c == K_DEL || c == K_KDEL) - ta_buf[i] = DEL; - else - ta_buf[i] = Ctrl_H; - len -= 2; - } - } - else if (ta_buf[i] == '\r') - ta_buf[i] = '\n'; - if (has_mbyte) - i += (*mb_ptr2len_len)(ta_buf + i, - ta_len + len - i) - 1; - } + term_replace_bs_del_keycode(ta_buf, ta_len, len); /* * For pipes: echo the typed characters. diff --git a/src/os_win32.c b/src/os_win32.c index 7dc37a1114..df63fb7f3e 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -4173,7 +4173,6 @@ mch_system_piped(char *cmd, int options) int ta_len = 0; // valid bytes in ta_buf[] DWORD i; - int c; int noread_cnt = 0; garray_T ga; int delay = 1; @@ -4312,29 +4311,7 @@ mch_system_piped(char *cmd, int options) } } - // replace K_BS by and K_DEL by - for (i = ta_len; i < ta_len + len; ++i) - { - if (ta_buf[i] == CSI && len - i > 2) - { - c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]); - if (c == K_DEL || c == K_KDEL || c == K_BS) - { - mch_memmove(ta_buf + i + 1, ta_buf + i + 3, - (size_t)(len - i - 2)); - if (c == K_DEL || c == K_KDEL) - ta_buf[i] = DEL; - else - ta_buf[i] = Ctrl_H; - len -= 2; - } - } - else if (ta_buf[i] == '\r') - ta_buf[i] = '\n'; - if (has_mbyte) - i += (*mb_ptr2len_len)(ta_buf + i, - ta_len + len - i) - 1; - } + term_replace_bs_del_keycode(ta_buf, ta_len, len); /* * For pipes: echo the typed characters. For a pty this @@ -4948,24 +4925,6 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) if (ga_grow(gap, 1) == FAIL) return; - if (base) - { - WCHAR *p = (WCHAR*) base; - - // for last \0 - if (ga_grow(gap, 1) == FAIL) - return; - - while (*p != 0 || *(p + 1) != 0) - { - if (ga_grow(gap, 1) == OK) - *((WCHAR*)gap->ga_data + gap->ga_len++) = *p; - p++; - } - FreeEnvironmentStrings(base); - *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; - } - if (env != NULL) { for (hi = env->dv_hashtab.ht_array; todo > 0; ++hi) @@ -4997,6 +4956,24 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) } } + if (base) + { + WCHAR *p = (WCHAR*) base; + + // for last \0 + if (ga_grow(gap, 1) == FAIL) + return; + + while (*p != 0 || *(p + 1) != 0) + { + if (ga_grow(gap, 1) == OK) + *((WCHAR*)gap->ga_data + gap->ga_len++) = *p; + p++; + } + FreeEnvironmentStrings(base); + *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; + } + # if defined(FEAT_CLIENTSERVER) || defined(FEAT_TERMINAL) { # ifdef FEAT_CLIENTSERVER @@ -5384,9 +5361,9 @@ mch_signal_job(job_T *job, char_u *how) { if (job->jv_channel != NULL && job->jv_channel->ch_anonymous_pipe) job->jv_channel->ch_killing = TRUE; - return TerminateJobObject(job->jv_job_object, 0) ? OK : FAIL; + return TerminateJobObject(job->jv_job_object, -1) ? OK : FAIL; } - return terminate_all(job->jv_proc_info.hProcess, 0) ? OK : FAIL; + return terminate_all(job->jv_proc_info.hProcess, -1) ? OK : FAIL; } if (!AttachConsole(job->jv_proc_info.dwProcessId)) diff --git a/src/os_win32.h b/src/os_win32.h index f1be8c4411..abe95b5fe3 100644 --- a/src/os_win32.h +++ b/src/os_win32.h @@ -18,12 +18,6 @@ # endif #endif -// Stop the VC2005 compiler from nagging. -#if _MSC_VER >= 1400 -# define _CRT_SECURE_NO_DEPRECATE -# define _CRT_NONSTDC_NO_DEPRECATE -#endif - #define BINARY_FILE_IO #define USE_EXE_NAME // use argv[0] for $VIM #define USE_TERM_CONSOLE diff --git a/src/proto.h b/src/proto.h index 6cb288da0f..15e691b21c 100644 --- a/src/proto.h +++ b/src/proto.h @@ -221,6 +221,7 @@ void mbyte_im_set_active(int active_arg); # include "textprop.pro" # endif # include "testing.pro" +# include "time.pro" # include "ui.pro" # include "undo.pro" # include "usercmd.pro" diff --git a/src/proto/evalwindow.pro b/src/proto/evalwindow.pro index e3faa96eb5..4eb1ced8bc 100644 --- a/src/proto/evalwindow.pro +++ b/src/proto/evalwindow.pro @@ -20,6 +20,8 @@ void f_win_id2tabwin(typval_T *argvars, typval_T *rettv); void f_win_id2win(typval_T *argvars, typval_T *rettv); void f_win_screenpos(typval_T *argvars, typval_T *rettv); void f_win_splitmove(typval_T *argvars, typval_T *rettv); +void f_win_gettype(typval_T *argvars, typval_T *rettv); +void f_getcmdwintype(typval_T *argvars, typval_T *rettv); void f_winbufnr(typval_T *argvars, typval_T *rettv); void f_wincol(typval_T *argvars, typval_T *rettv); void f_winheight(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro index 3693cf4265..92887a6cf7 100644 --- a/src/proto/ex_cmds.pro +++ b/src/proto/ex_cmds.pro @@ -9,7 +9,6 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out); void do_shell(char_u *cmd, int flags); char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp); void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname); -time_T vim_time(void); void do_fixdel(exarg_T *eap); void print_line_no_prefix(linenr_T lnum, int use_number, int list); void print_line(linenr_T lnum, int use_number, int list); diff --git a/src/proto/ex_cmds2.pro b/src/proto/ex_cmds2.pro index 9f694da93b..b9d1929f7d 100644 --- a/src/proto/ex_cmds2.pro +++ b/src/proto/ex_cmds2.pro @@ -1,15 +1,4 @@ /* ex_cmds2.c */ -long proftime_time_left(proftime_T *due, proftime_T *now); -timer_T *create_timer(long msec, int repeat); -long check_due_timer(void); -void stop_timer(timer_T *timer); -int set_ref_in_timer(int copyID); -void timer_free_all(void); -void f_timer_info(typval_T *argvars, typval_T *rettv); -void f_timer_pause(typval_T *argvars, typval_T *rettv); -void f_timer_start(typval_T *argvars, typval_T *rettv); -void f_timer_stop(typval_T *argvars, typval_T *rettv); -void f_timer_stopall(typval_T *argvars, typval_T *rettv); int autowrite(buf_T *buf, int forceit); void autowrite_all(void); int check_changed(buf_T *buf, int flags); diff --git a/src/proto/main.pro b/src/proto/main.pro index c663cd2b15..5fa96c3903 100644 --- a/src/proto/main.pro +++ b/src/proto/main.pro @@ -12,9 +12,6 @@ void getout_preserve_modified(int exitval); void getout(int exitval); int process_env(char_u *env, int is_viminit); void mainerr_arg_missing(char_u *str); -void time_push(void *tv_rel, void *tv_start); -void time_pop(void *tp); -void time_msg(char *mesg, void *tv_start); void server_to_input_buf(char_u *str); char_u *eval_client_expr_to_string(char_u *expr); int sendToLocalVim(char_u *cmd, int asExpr, char_u **result); diff --git a/src/proto/memline.pro b/src/proto/memline.pro index 663930dabd..113417042e 100644 --- a/src/proto/memline.pro +++ b/src/proto/memline.pro @@ -13,8 +13,6 @@ void ml_recover(int checkext); int recover_names(char_u *fname, int list, int nr, char_u **fname_out); char_u *make_percent_swname(char_u *dir, char_u *name); void get_b0_dict(char_u *fname, dict_T *d); -struct tm *vim_localtime(const time_t *timep, struct tm *result); -char *get_ctime(time_t thetime, int add_newline); void ml_sync_all(int check_file, int check_char); void ml_preserve(buf_T *buf, int message); char_u *ml_get(linenr_T lnum); diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro index e4f2c3d8b6..1327701e0a 100644 --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -47,5 +47,4 @@ int goto_im(void); char_u *get_isolated_shell_name(void); int path_is_url(char_u *p); int path_with_url(char_u *fname); -void add_time(char_u *buf, size_t buflen, time_t tt); /* vim: set ft=c : */ diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro index dfc4df7376..6090bb0676 100644 --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -95,11 +95,8 @@ int filewritable(char_u *fname); int get2c(FILE *fd); int get3c(FILE *fd); int get4c(FILE *fd); -time_T get8ctime(FILE *fd); char_u *read_string(FILE *fd, int cnt); int put_bytes(FILE *fd, long_u nr, int len); -int put_time(FILE *fd, time_T the_time); -void time_to_bytes(time_T the_time, char_u *buf); int has_non_ascii(char_u *s); int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc); int build_argv_from_string(char_u *cmd, char ***argv, int *argc); diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro index 5e8e1a58a6..01f1fff0d7 100644 --- a/src/proto/regexp.pro +++ b/src/proto/regexp.pro @@ -12,7 +12,6 @@ int vim_regcomp_had_eol(void); regprog_T *vim_regcomp(char_u *expr_arg, int re_flags); void vim_regfree(regprog_T *prog); void free_regexp_stuff(void); -void free_regexp_prev_sub(void); int regprog_in_use(regprog_T *prog); int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col); int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col); diff --git a/src/proto/search.pro b/src/proto/search.pro index 3b46c0662c..e6ac11b2cb 100644 --- a/src/proto/search.pro +++ b/src/proto/search.pro @@ -9,7 +9,6 @@ void free_search_patterns(void); void save_last_search_pattern(void); void restore_last_search_pattern(void); char_u *last_search_pattern(void); -void free_last_pat(int idx); int ignorecase(char_u *pat); int ignorecase_opt(char_u *pat, int ic_in, int scs); int pat_has_uppercase(char_u *pat); diff --git a/src/proto/term.pro b/src/proto/term.pro index 4b9ee9ca24..2091cbfee8 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -77,4 +77,5 @@ void swap_tcap(void); guicolor_T gui_get_color_cmn(char_u *name); guicolor_T gui_get_rgb_color_cmn(int r, int g, int b); void cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx); +void term_replace_bs_del_keycode(char_u *ta_buf, int ta_len, int len); /* vim: set ft=c : */ diff --git a/src/proto/testing.pro b/src/proto/testing.pro index 209abf3486..2b001a543a 100644 --- a/src/proto/testing.pro +++ b/src/proto/testing.pro @@ -13,7 +13,6 @@ void f_assert_report(typval_T *argvars, typval_T *rettv); void f_assert_true(typval_T *argvars, typval_T *rettv); void f_test_alloc_fail(typval_T *argvars, typval_T *rettv); void f_test_autochdir(typval_T *argvars, typval_T *rettv); -void f_test_clear_search_pat(typval_T *argvars, typval_T *rettv); void f_test_feedinput(typval_T *argvars, typval_T *rettv); void f_test_getvalue(typval_T *argvars, typval_T *rettv); void f_test_option_not_set(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/time.pro b/src/proto/time.pro new file mode 100644 index 0000000000..becafea3b2 --- /dev/null +++ b/src/proto/time.pro @@ -0,0 +1,28 @@ +/* time.c */ +char *get_ctime(time_t thetime, int add_newline); +time_T vim_time(void); +void f_localtime(typval_T *argvars, typval_T *rettv); +void f_reltime(typval_T *argvars, typval_T *rettv); +void f_reltimefloat(typval_T *argvars, typval_T *rettv); +void f_reltimestr(typval_T *argvars, typval_T *rettv); +void f_strftime(typval_T *argvars, typval_T *rettv); +void f_strptime(typval_T *argvars, typval_T *rettv); +long proftime_time_left(proftime_T *due, proftime_T *now); +timer_T *create_timer(long msec, int repeat); +long check_due_timer(void); +void stop_timer(timer_T *timer); +int set_ref_in_timer(int copyID); +void timer_free_all(void); +void f_timer_info(typval_T *argvars, typval_T *rettv); +void f_timer_pause(typval_T *argvars, typval_T *rettv); +void f_timer_start(typval_T *argvars, typval_T *rettv); +void f_timer_stop(typval_T *argvars, typval_T *rettv); +void f_timer_stopall(typval_T *argvars, typval_T *rettv); +void time_push(void *tv_rel, void *tv_start); +void time_pop(void *tp); +void time_msg(char *mesg, void *tv_start); +time_T get8ctime(FILE *fd); +int put_time(FILE *fd, time_T the_time); +void time_to_bytes(time_T the_time, char_u *buf); +void add_time(char_u *buf, size_t buflen, time_t tt); +/* vim: set ft=c : */ diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 74bcabd8ce..165b04b5e4 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -6,6 +6,7 @@ int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); +char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); ufunc_T *find_func(char_u *name, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); @@ -26,7 +27,6 @@ int has_varargs(ufunc_T *ufunc); int function_exists(char_u *name, int no_deref); char_u *get_expanded_name(char_u *name, int check); char_u *get_user_func_name(expand_T *xp, int idx); -void clean_script_functions(int sid); void ex_delfunction(exarg_T *eap); void func_unref(char_u *name); void func_ptr_unref(ufunc_T *fp); diff --git a/src/quickfix.c b/src/quickfix.c index 868b5d910a..f1df111212 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -980,11 +980,11 @@ qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) } /* - * Parse the match for '%+' format pattern. The whole matching line is included - * in the error string. Return the matched line in "fields->errmsg". + * Copy a non-error line into the error string. Return the matched line in + * "fields->errmsg". */ static int -qf_parse_fmt_plus(char_u *linebuf, int linelen, qffields_T *fields) +copy_nonerror_line(char_u *linebuf, int linelen, qffields_T *fields) { char_u *p; @@ -996,7 +996,9 @@ qf_parse_fmt_plus(char_u *linebuf, int linelen, qffields_T *fields) fields->errmsg = p; fields->errmsglen = linelen + 1; } + // copy whole line to error message vim_strncpy(fields->errmsg, linebuf, linelen); + return QF_OK; } @@ -1180,7 +1182,7 @@ qf_parse_match( else if (i == 5) { if (fmt_ptr->flags == '+' && !qf_multiscan) // %+ - status = qf_parse_fmt_plus(linebuf, linelen, fields); + status = copy_nonerror_line(linebuf, linelen, fields); else if (midx > 0) // %m status = qf_parse_fmt_m(regmatch, midx, fields); } @@ -1307,23 +1309,11 @@ qf_parse_file_pfx( static int qf_parse_line_nomatch(char_u *linebuf, int linelen, qffields_T *fields) { - char_u *p; - fields->namebuf[0] = NUL; // no match found, remove file name fields->lnum = 0; // don't jump to this line fields->valid = FALSE; - if (linelen >= fields->errmsglen) - { - // linelen + null terminator - if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL) - return QF_NOMEM; - fields->errmsg = p; - fields->errmsglen = linelen + 1; - } - // copy whole line to error message - vim_strncpy(fields->errmsg, linebuf, linelen); - return QF_OK; + return copy_nonerror_line(linebuf, linelen, fields); } /* @@ -4520,7 +4510,7 @@ qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last) *dirname = NUL; // Add one line for each error - if (old_last == NULL) + if (old_last == NULL || old_last->qf_next == NULL) { qfp = qfl->qf_start; lnum = 0; diff --git a/src/regexp.c b/src/regexp.c index 7aeddb83cd..4e21d44ccf 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -2511,6 +2511,28 @@ reg_submatch_list(int no) } #endif +/* + * Initialize the values used for matching against multiple lines + */ + static void +init_regexec_multi( + regmmatch_T *rmp, + win_T *win, // window in which to search or NULL + buf_T *buf, // buffer in which to search + linenr_T lnum) // nr of line to start looking for match +{ + rex.reg_match = NULL; + rex.reg_mmatch = rmp; + rex.reg_buf = buf; + rex.reg_win = win; + rex.reg_firstlnum = lnum; + rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum; + rex.reg_line_lbr = FALSE; + rex.reg_ic = rmp->rmm_ic; + rex.reg_icombine = FALSE; + rex.reg_maxcol = rmp->rmm_maxcol; +} + #include "regexp_bt.c" static regengine_T bt_regengine = @@ -2663,15 +2685,6 @@ free_regexp_stuff(void) } #endif -/* - * Free the previously used substitute search pattern. - */ - void -free_regexp_prev_sub(void) -{ - VIM_CLEAR(reg_prev_sub); -} - #ifdef FEAT_EVAL static void report_re_switch(char_u *pat) diff --git a/src/regexp_bt.c b/src/regexp_bt.c index 78be2b5f8d..0ed3711363 100644 --- a/src/regexp_bt.c +++ b/src/regexp_bt.c @@ -4854,17 +4854,7 @@ bt_regexec_multi( proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { - rex.reg_match = NULL; - rex.reg_mmatch = rmp; - rex.reg_buf = buf; - rex.reg_win = win; - rex.reg_firstlnum = lnum; - rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum; - rex.reg_line_lbr = FALSE; - rex.reg_ic = rmp->rmm_ic; - rex.reg_icombine = FALSE; - rex.reg_maxcol = rmp->rmm_maxcol; - + init_regexec_multi(rmp, win, buf, lnum); return bt_regexec_both(NULL, col, tm, timed_out); } diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c index a288ea47c8..67d4af2f61 100644 --- a/src/regexp_nfa.c +++ b/src/regexp_nfa.c @@ -7409,17 +7409,7 @@ nfa_regexec_multi( proftime_T *tm, // timeout limit or NULL int *timed_out) // flag set on timeout or NULL { - rex.reg_match = NULL; - rex.reg_mmatch = rmp; - rex.reg_buf = buf; - rex.reg_win = win; - rex.reg_firstlnum = lnum; - rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum; - rex.reg_line_lbr = FALSE; - rex.reg_ic = rmp->rmm_ic; - rex.reg_icombine = FALSE; - rex.reg_maxcol = rmp->rmm_maxcol; - + init_regexec_multi(rmp, win, buf, lnum); return nfa_regexec_both(NULL, col, tm, timed_out); } diff --git a/src/search.c b/src/search.c index 4c2c4ab2a7..5f227cd39c 100644 --- a/src/search.c +++ b/src/search.c @@ -384,12 +384,6 @@ last_search_pattern(void) } #endif - void -free_last_pat(int idx) -{ - VIM_CLEAR(spats[idx].pat); -} - /* * Return TRUE when case should be ignored for search pattern "pat". * Uses the 'ignorecase' and 'smartcase' options. diff --git a/src/structs.h b/src/structs.h index b81068bbf2..e7a006a061 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1245,42 +1245,33 @@ typedef struct hashtable_S typedef long_u hash_T; // Type for hi_hash -#ifdef FEAT_NUM64 // Use 64-bit Number. -# ifdef MSWIN -# ifdef PROTO -typedef long varnumber_T; -typedef unsigned long uvarnumber_T; -# define VARNUM_MIN LONG_MIN -# define VARNUM_MAX LONG_MAX -# define UVARNUM_MAX ULONG_MAX -# else -typedef __int64 varnumber_T; -typedef unsigned __int64 uvarnumber_T; -# define VARNUM_MIN _I64_MIN -# define VARNUM_MAX _I64_MAX -# define UVARNUM_MAX _UI64_MAX -# endif -# elif defined(HAVE_STDINT_H) -typedef int64_t varnumber_T; -typedef uint64_t uvarnumber_T; -# define VARNUM_MIN INT64_MIN -# define VARNUM_MAX INT64_MAX -# define UVARNUM_MAX UINT64_MAX -# else +#ifdef MSWIN +# ifdef PROTO typedef long varnumber_T; typedef unsigned long uvarnumber_T; # define VARNUM_MIN LONG_MIN # define VARNUM_MAX LONG_MAX # define UVARNUM_MAX ULONG_MAX +# else +typedef __int64 varnumber_T; +typedef unsigned __int64 uvarnumber_T; +# define VARNUM_MIN _I64_MIN +# define VARNUM_MAX _I64_MAX +# define UVARNUM_MAX _UI64_MAX # endif +#elif defined(HAVE_STDINT_H) +typedef int64_t varnumber_T; +typedef uint64_t uvarnumber_T; +# define VARNUM_MIN INT64_MIN +# define VARNUM_MAX INT64_MAX +# define UVARNUM_MAX UINT64_MAX #else -// Use 32-bit Number. -typedef int varnumber_T; -typedef unsigned int uvarnumber_T; -# define VARNUM_MIN INT_MIN -# define VARNUM_MAX INT_MAX -# define UVARNUM_MAX UINT_MAX +typedef long varnumber_T; +typedef unsigned long uvarnumber_T; +# define VARNUM_MIN LONG_MIN +# define VARNUM_MAX LONG_MAX +# define UVARNUM_MAX ULONG_MAX #endif typedef double float_T; @@ -1515,6 +1506,8 @@ typedef struct type_T **uf_arg_types; // argument types (count == uf_args.ga_len) type_T *uf_ret_type; // return type garray_T uf_type_list; // types used in arg and return types + int *uf_def_arg_idx; // instruction indexes for evaluating + // uf_def_args; length: uf_def_args.ga_len + 1 char_u *uf_va_name; // name from "...name" or NULL type_T *uf_va_type; // type from "...name: type" or NULL diff --git a/src/term.c b/src/term.c index 93d97345f2..d0428872d2 100644 --- a/src/term.c +++ b/src/term.c @@ -909,8 +909,8 @@ static struct builtin_term builtin_termcaps[] = {(int)KS_KE, IF_EB("\033[?1l\033>", ESC_STR "[?1l" ESC_STR_nc ">")}, # ifdef FEAT_XTERM_SAVE {(int)KS_TI, IF_EB("\0337\033[?47h", ESC_STR "7" ESC_STR_nc "[?47h")}, - {(int)KS_TE, IF_EB("\033[2J\033[?47l\0338", - ESC_STR "[2J" ESC_STR_nc "[?47l" ESC_STR_nc "8")}, + {(int)KS_TE, IF_EB("\033[?47l\0338", + ESC_STR_nc "[?47l" ESC_STR_nc "8")}, # endif {(int)KS_CTI, IF_EB("\033[>4;2m", ESC_STR_nc "[>4;2m")}, {(int)KS_CTE, IF_EB("\033[>4;m", ESC_STR_nc "[>4;m")}, @@ -6396,3 +6396,34 @@ cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx) } #endif +/* + * Replace K_BS by and K_DEL by + */ + void +term_replace_bs_del_keycode(char_u *ta_buf, int ta_len, int len) +{ + int i; + int c; + + for (i = ta_len; i < ta_len + len; ++i) + { + if (ta_buf[i] == CSI && len - i > 2) + { + c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]); + if (c == K_DEL || c == K_KDEL || c == K_BS) + { + mch_memmove(ta_buf + i + 1, ta_buf + i + 3, + (size_t)(len - i - 2)); + if (c == K_DEL || c == K_KDEL) + ta_buf[i] = DEL; + else + ta_buf[i] = Ctrl_H; + len -= 2; + } + } + else if (ta_buf[i] == '\r') + ta_buf[i] = '\n'; + if (has_mbyte) + i += (*mb_ptr2len_len)(ta_buf + i, ta_len + len - i) - 1; + } +} diff --git a/src/terminal.c b/src/terminal.c index f986376abf..d9bbf66c03 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -4281,6 +4281,8 @@ term_update_colors(void) { term_T *term = curwin->w_buffer->b_term; + if (term->tl_vterm == NULL) + return; init_default_colors(term, curwin); vterm_state_set_default_colors( vterm_obtain_state(term->tl_vterm), diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index ec2f1d2321..423be0b570 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -60,6 +60,7 @@ NEW_TESTS = \ test_blob \ test_blockedit \ test_breakindent \ + test_buffer \ test_bufline \ test_bufwintabinfo \ test_cd \ @@ -269,6 +270,7 @@ NEW_TESTS = \ test_utf8 \ test_utf8_comparisons \ test_vartabs \ + test_vim9_disassemble \ test_vim9_expr \ test_vim9_script \ test_viminfo \ @@ -305,6 +307,7 @@ NEW_TESTS_RES = \ test_blob.res \ test_blockedit.res \ test_breakindent.res \ + test_buffer.res \ test_bufline.res \ test_bufwintabinfo.res \ test_cd.res \ @@ -472,6 +475,7 @@ NEW_TESTS_RES = \ test_user_func.res \ test_usercommands.res \ test_vartabs.res \ + test_vim9_disassemble.res \ test_vim9_expr.res \ test_vim9_script.res \ test_viminfo.res \ diff --git a/src/testdir/dumps/Test_functions_echoraw.dump b/src/testdir/dumps/Test_functions_echoraw.dump new file mode 100644 index 0000000000..f27cd03257 --- /dev/null +++ b/src/testdir/dumps/Test_functions_echoraw.dump @@ -0,0 +1,5 @@ +>x+0&#ffffff0|e|l@1|o| @34 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +| +0#0000000&@21|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_statusline_1.dump b/src/testdir/dumps/Test_statusline_1.dump new file mode 100644 index 0000000000..f9816857af --- /dev/null +++ b/src/testdir/dumps/Test_statusline_1.dump @@ -0,0 +1,10 @@ +> +0&#ffffff0@49 +|~+0#4040ff13&| @48 +|~| @48 +|~| @48 +|~| @48 +|~| @48 +|~| @48 +|~| @48 +| +3#0000000&|Q|≡| @46 +| +0&&@49 diff --git a/src/testdir/dumps/Test_terminal_popup_1.dump b/src/testdir/dumps/Test_terminal_popup_1.dump index 0628eb08fe..a03d589811 100644 --- a/src/testdir/dumps/Test_terminal_popup_1.dump +++ b/src/testdir/dumps/Test_terminal_popup_1.dump @@ -8,8 +8,8 @@ |7| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 |8| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 |9| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 -|1|0| @11|║+0#0000001#ffd7ff255|"+0#0000000#ffffff0|X|t|e|x|t|"| |3|L|,| |3|6|C| @11|1|,|1| @10|A|l@1| |║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|1|0| @11|║+0#0000001#ffd7ff255|:+0#0000000#ffffff0| @25|1|,|1| @10|A|l@1| |║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 |1@1| @11|╚+0#0000001#ffd7ff255|═@44|⇲| +0#0000000#ffffff0@13 |1|2| @72 |1|3| @72 -@57|0|,|0|-|1| @8|A|l@1| +|t|e|r|m|i|n|a|l| |p|o|p|u|p| @42|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim index c486b18e2f..9513ad334c 100644 --- a/src/testdir/test_arglist.vim +++ b/src/testdir/test_arglist.vim @@ -1,5 +1,8 @@ " Test argument list commands +source shared.vim +source term_util.vim + func Test_argidx() args a b c last @@ -505,3 +508,17 @@ func Test_argdo() call assert_equal(['Xa.c', 'Xb.c', 'Xc.c'], l) bwipe Xa.c Xb.c Xc.c endfunc + +" Test for quiting Vim with unedited files in the argument list +func Test_quit_with_arglist() + if !CanRunVimInTerminal() + throw 'Skipped: cannot run vim in terminal' + endif + let buf = RunVimInTerminal('', {'rows': 6}) + call term_sendkeys(buf, ":args a b c\n") + call term_sendkeys(buf, ":quit\n") + call WaitForAssert({-> assert_match('^E173:', term_getline(buf, 6))}) + call StopVimInTerminal(buf) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index f538cbb8fe..00df5b276e 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -2357,3 +2357,5 @@ func Test_FileType_spell() au! crash setglobal spellfile= endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim new file mode 100644 index 0000000000..3266adc275 --- /dev/null +++ b/src/testdir/test_buffer.vim @@ -0,0 +1,157 @@ +" Tests for Vim buffer + +" Test for the :bunload command with an offset +func Test_bunload_with_offset() + %bwipe! + call writefile(['B1'], 'b1') + call writefile(['B2'], 'b2') + call writefile(['B3'], 'b3') + call writefile(['B4'], 'b4') + + " Load four buffers. Unload the second and third buffers and then + " execute .+3bunload to unload the last buffer. + edit b1 + new b2 + new b3 + new b4 + + bunload b2 + bunload b3 + exe bufwinnr('b1') . 'wincmd w' + .+3bunload + call assert_equal(0, getbufinfo('b4')[0].loaded) + call assert_equal('b1', + \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t')) + + " Load four buffers. Unload the third and fourth buffers. Execute .+3bunload + " and check whether the second buffer is unloaded. + ball + bunload b3 + bunload b4 + exe bufwinnr('b1') . 'wincmd w' + .+3bunload + call assert_equal(0, getbufinfo('b2')[0].loaded) + call assert_equal('b1', + \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t')) + + " Load four buffers. Unload the second and third buffers and from the last + " buffer execute .-3bunload to unload the first buffer. + ball + bunload b2 + bunload b3 + exe bufwinnr('b4') . 'wincmd w' + .-3bunload + call assert_equal(0, getbufinfo('b1')[0].loaded) + call assert_equal('b4', + \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t')) + + " Load four buffers. Unload the first and second buffers. Execute .-3bunload + " from the last buffer and check whether the third buffer is unloaded. + ball + bunload b1 + bunload b2 + exe bufwinnr('b4') . 'wincmd w' + .-3bunload + call assert_equal(0, getbufinfo('b3')[0].loaded) + call assert_equal('b4', + \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t')) + + %bwipe! + call delete('b1') + call delete('b2') + call delete('b3') + call delete('b4') + + call assert_fails('1,4bunload', 'E16:') + call assert_fails(',100bunload', 'E16:') + + " Use a try-catch for this test. When assert_fails() is used for this + " test, the command fails with E515: instead of E90: + let caught_E90 = 0 + try + $bunload + catch /E90:/ + let caught_E90 = 1 + endtry + call assert_equal(1, caught_E90) + call assert_fails('$bunload', 'E515:') +endfunc + +" Test for :buffer, :bnext, :bprevious, :brewind, :blast and :bmodified +" commands +func Test_buflist_browse() + %bwipe! + call assert_fails('buffer 1000', 'E86:') + + call writefile(['foo1', 'foo2', 'foo3', 'foo4'], 'Xfile1') + call writefile(['bar1', 'bar2', 'bar3', 'bar4'], 'Xfile2') + call writefile(['baz1', 'baz2', 'baz3', 'baz4'], 'Xfile3') + edit Xfile1 + let b1 = bufnr() + edit Xfile2 + let b2 = bufnr() + edit +/baz4 Xfile3 + let b3 = bufnr() + + call assert_fails('buffer ' .. b1 .. ' abc', 'E488:') + call assert_equal(b3, bufnr()) + call assert_equal(4, line('.')) + exe 'buffer +/bar2 ' .. b2 + call assert_equal(b2, bufnr()) + call assert_equal(2, line('.')) + exe 'buffer +/bar1' + call assert_equal(b2, bufnr()) + call assert_equal(1, line('.')) + + brewind + + call assert_equal(b1, bufnr()) + call assert_equal(4, line('.')) + + blast +/baz2 + call assert_equal(b3, bufnr()) + call assert_equal(2, line('.')) + + bprevious +/bar4 + call assert_equal(b2, bufnr()) + call assert_equal(4, line('.')) + + bnext +/baz3 + call assert_equal(b3, bufnr()) + call assert_equal(3, line('.')) + + call assert_fails('bmodified', 'E84:') + call setbufvar(b2, '&modified', 1) + exe 'bmodified +/bar3' + call assert_equal(b2, bufnr()) + call assert_equal(3, line('.')) + + " With no listed buffers in the list, :bnext and :bprev should fail + %bwipe! + set nobuflisted + call assert_fails('bnext', 'E85:') + call assert_fails('bprev', 'E85:') + set buflisted + + call assert_fails('sandbox bnext', 'E48:') + + call delete('Xfile1') + call delete('Xfile2') + call delete('Xfile3') + %bwipe! +endfunc + +" Test for :bdelete +func Test_bdelete_cmd() + %bwipe! + call assert_fails('bdelete 5', 'E516:') + + " Deleting a unlisted and unloaded buffer + edit Xfile1 + let bnr = bufnr() + set nobuflisted + enew + call assert_fails('bdelete ' .. bnr, 'E516:') + %bwipe! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim index e44b25f0fa..e5c119e22e 100644 --- a/src/testdir/test_cd.vim +++ b/src/testdir/test_cd.vim @@ -1,5 +1,7 @@ " Test for :cd and chdir() +source shared.vim + func Test_cd_large_path() " This used to crash with a heap write overflow. call assert_fails('cd ' . repeat('x', 5000), 'E472:') @@ -40,6 +42,20 @@ func Test_cd_minus() call assert_equal(path_dotdot, getcwd()) cd - call assert_equal(path, getcwd()) + + " Test for :cd - without a previous directory + let lines =<< trim [SCRIPT] + call assert_fails('cd -', 'E186:') + call assert_fails('call chdir("-")', 'E186:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') endfunc func Test_cd_with_cpo_chdir() diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index c2068105bf..16fe5c7829 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1991,3 +1991,27 @@ func Test_job_start_fails() " this was leaking memory call assert_fails("call job_start([''])", "E474:") endfunc + +func Test_issue_5150() + let g:job = job_start('grep foo', {}) + call job_stop(g:job) + sleep 10m + call assert_equal(-1, job_info(g:job).exitval) + let g:job = job_start('grep foo', {}) + call job_stop(g:job, 'term') + sleep 10m + call assert_equal(-1, job_info(g:job).exitval) + let g:job = job_start('grep foo', {}) + call job_stop(g:job, 'kill') + sleep 10m + call assert_equal(-1, job_info(g:job).exitval) +endfunc + +func Test_issue_5485() + let $VAR1 = 'global' + let g:Ch_reply = "" + let l:job = job_start([&shell, &shellcmdflag, has('win32') ? 'echo %VAR1% %VAR2%' : 'echo $VAR1 $VAR2'], {'env': {'VAR1': 'local', 'VAR2': 'local'}, 'callback': 'Ch_handler'}) + let g:Ch_job = l:job + call WaitForAssert({-> assert_equal("local local", trim(g:Ch_reply))}) + unlet $VAR1 +endfunc diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 36067d1d9f..ff15cbbe3b 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -632,9 +632,32 @@ func Test_cmdline_search_range() 1,\&s/b/B/ call assert_equal('B', getline(2)) + let @/ = 'apple' + call assert_fails('\/print', 'E486:') + bwipe! endfunc +" Test for the tick mark (') in an excmd range +func Test_tick_mark_in_range() + " If only the tick is passed as a range and no command is specified, there + " should not be an error + call feedkeys(":'\", 'xt') + call assert_equal("'", getreg(':')) + call assert_fails("',print", 'E78:') +endfunc + +" Test for using a line number followed by a search pattern as range +func Test_lnum_and_pattern_as_range() + new + call setline(1, ['foo 1', 'foo 2', 'foo 3']) + let @" = '' + 2/foo/yank + call assert_equal("foo 3\n", @") + call assert_equal(1, line('.')) + close! +endfunc + " Tests for getcmdline(), getcmdpos() and getcmdtype() func Check_cmdline(cmdtype) call assert_equal('MyCmd a', getcmdline()) @@ -894,12 +917,14 @@ func Test_cmdwin_cedit() let g:cmd_wintype = '' func CmdWinType() let g:cmd_wintype = getcmdwintype() + let g:wintype = win_gettype() return '' endfunc call feedkeys("\a\=CmdWinType()\\") echo input('') call assert_equal('@', g:cmd_wintype) + call assert_equal('command', g:wintype) set cedit&vim delfunc CmdWinType @@ -923,4 +948,33 @@ func Test_cmdlineclear_tabenter() call delete('XtestCmdlineClearTabenter') endfunc +" Test for failure in expanding special keywords in cmdline +func Test_cmdline_expand_special() + %bwipe! + call assert_fails('e #', 'E499:') + call assert_fails('e ', 'E495:') + call assert_fails('e ', 'E496:') + call assert_fails('e ', 'E497:') +endfunc + +func Test_cmdwin_jump_to_win() + call assert_fails('call feedkeys("q:\\\", "xt")', 'E11:') + new + set modified + call assert_fails('call feedkeys("q/:qall\", "xt")', 'E162:') + close! + call feedkeys("q/:close\", "xt") + call assert_equal(1, winnr('$')) + call feedkeys("q/:exit\", "xt") + call assert_equal(1, winnr('$')) +endfunc + +" Test for backtick expression in the command line +func Test_cmd_backtick() + %argd + argadd `=['a', 'b', 'c']` + call assert_equal(['a', 'b', 'c'], argv()) + %argd +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_compiler.vim b/src/testdir/test_compiler.vim index 4f02cf1c2f..464dd9bcb5 100644 --- a/src/testdir/test_compiler.vim +++ b/src/testdir/test_compiler.vim @@ -1,6 +1,7 @@ " Test the :compiler command source check.vim +source shared.vim func Test_compiler() if !executable('perl') @@ -48,6 +49,15 @@ func Test_compiler_without_arg() call assert_match(runtime .. '/compiler/xmlwf.vim$', a[-1]) endfunc +" Test executing :compiler from the command line, not from a script +func Test_compiler_commandline() + call system(GetVimCommandClean() .. ' --not-a-term -c "compiler gcc" -c "call writefile([b:current_compiler], ''XcompilerOut'')" -c "quit"') + call assert_equal(0, v:shell_error) + call assert_equal(["gcc"], readfile('XcompilerOut')) + + call delete('XcompilerOut') +endfunc + func Test_compiler_completion() call feedkeys(":compiler \\\"\", 'tx') call assert_match('^"compiler ant bcc .* xmlwf$', @:) diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index f6779eb51e..4f43854b56 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -1500,6 +1500,22 @@ func Test_edit_startinsert() bwipe! endfunc +" Test for :startreplace and :startgreplace +func Test_edit_startreplace() + new + call setline(1, 'abc') + call feedkeys("l:startreplace\xyz\e", 'xt') + call assert_equal('axyz', getline(1)) + call feedkeys("0:startreplace!\abc\e", 'xt') + call assert_equal('axyzabc', getline(1)) + call setline(1, "a\tb") + call feedkeys("0l:startgreplace\xyz\e", 'xt') + call assert_equal("axyz\tb", getline(1)) + call feedkeys("0i\=execute('startreplace')\12\e", 'xt') + call assert_equal("12axyz\tb", getline(1)) + close! +endfunc + func Test_edit_noesckeys() CheckNotGui new @@ -1519,3 +1535,5 @@ func Test_edit_noesckeys() bwipe! set esckeys endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index 5899571a97..bf10104984 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -55,7 +55,7 @@ func Test_ex_mode() let &encoding = encoding_save endfunc -" Test subsittute confirmation prompt :%s/pat/str/c in Ex mode +" Test substitute confirmation prompt :%s/pat/str/c in Ex mode func Test_Ex_substitute() CheckRunVimInTerminal let buf = RunVimInTerminal('', {'rows': 6}) @@ -77,6 +77,11 @@ func Test_Ex_substitute() call term_sendkeys(buf, "q\") call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000) + " Pressing enter in ex mode should print the current line + call term_sendkeys(buf, "\") + call WaitForAssert({-> assert_match(' 3 foo foo', + \ term_getline(buf, 5))}, 1000) + call term_sendkeys(buf, ":vi\") call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000) @@ -84,4 +89,26 @@ func Test_Ex_substitute() call StopVimInTerminal(buf) endfunc +" Test for displaying lines from an empty buffer in Ex mode +func Test_Ex_emptybuf() + new + call assert_fails('call feedkeys("Q\", "xt")', 'E749:') + call setline(1, "abc") + call assert_fails('call feedkeys("Q\", "xt")', 'E501:') + call assert_fails('call feedkeys("Q%d\", "xt")', 'E749:') + close! +endfunc + +" Test for the :open command +func Test_open_command() + new + call setline(1, ['foo foo', 'foo bar', 'foo baz']) + call feedkeys("Qopen\j", 'xt') + call assert_equal('foo bar', getline('.')) + call feedkeys("Qopen /bar/\", 'xt') + call assert_equal(5, col('.')) + call assert_fails('call feedkeys("Qopen /baz/\", "xt")', 'E479:') + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 6174e660be..2407f8eb1e 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -20,6 +20,7 @@ func Test_range_error() call assert_fails(':\/echo 1', 'E481:') normal vv call assert_fails(":'<,'>echo 1", 'E481:') + call assert_fails(":\\xcenter", 'E10:') endfunc func Test_buffers_lastused() @@ -241,4 +242,97 @@ func Test_confirm_cmd() call delete('bar') endfunc +" Test for the :print command +func Test_print_cmd() + call assert_fails('print', 'E749:') +endfunc + +" Test for the :winsize command +func Test_winsize_cmd() + call assert_fails('winsize 1', 'E465:') +endfunc + +" Test for the :redir command +func Test_redir_cmd() + call assert_fails('redir @@', 'E475:') + call assert_fails('redir abc', 'E475:') + if has('unix') + call mkdir('Xdir') + call assert_fails('redir > Xdir', 'E17:') + call delete('Xdir', 'd') + endif + if !has('bsd') + call writefile([], 'Xfile') + call setfperm('Xfile', 'r--r--r--') + call assert_fails('redir! > Xfile', 'E190:') + call delete('Xfile') + endif + + " Test for redirecting to a register + redir @q> | echon 'clean ' | redir END + redir @q>> | echon 'water' | redir END + call assert_equal('clean water', @q) + + " Test for redirecting to a variable + redir => color | echon 'blue ' | redir END + redir =>> color | echon 'sky' | redir END + call assert_equal('blue sky', color) +endfunc + +" Test for the :filetype command +func Test_filetype_cmd() + call assert_fails('filetype abc', 'E475:') +endfunc + +" Test for the :mode command +func Test_mode_cmd() + call assert_fails('mode abc', 'E359:') +endfunc + +" Test for the :sleep command +func Test_sleep_cmd() + call assert_fails('sleep x', 'E475:') +endfunc + +" Test for the :read command +func Test_read_cmd() + call writefile(['one'], 'Xfile') + new + call assert_fails('read', 'E32:') + edit Xfile + read + call assert_equal(['one', 'one'], getline(1, '$')) + close! + new + read Xfile + call assert_equal(['', 'one'], getline(1, '$')) + call deletebufline('', 1, '$') + call feedkeys("Qr Xfile\visual\", 'xt') + call assert_equal(['one'], getline(1, '$')) + close! + call delete('Xfile') +endfunc + +" Test for running Ex commands when text is locked. +" e in the command line is used to lock the text +func Test_run_excmd_with_text_locked() + " :quit + let cmd = ":\eexecute('quit')\\" + call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + + " :qall + let cmd = ":\eexecute('qall')\\" + call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + + " :exit + let cmd = ":\eexecute('exit')\\" + call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + + " :close - should be ignored + new + let cmd = ":\eexecute('close')\\" + call assert_equal(2, winnr('$')) + close +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_exists.vim b/src/testdir/test_exists.vim index fd34be83b0..471c77853d 100644 --- a/src/testdir/test_exists.vim +++ b/src/testdir/test_exists.vim @@ -94,8 +94,12 @@ func Test_exists() call assert_equal(0, exists(':edit/a')) " Valid internal command (partial match) call assert_equal(1, exists(':q')) + " Valid internal command with a digit + call assert_equal(2, exists(':2match')) " Non-existing internal command call assert_equal(0, exists(':invalidcmd')) + " Internal command with a count + call assert_equal(0, exists(':3buffer')) " User defined command (full match) command! MyCmd :echo 'My command' diff --git a/src/testdir/test_expand.vim b/src/testdir/test_expand.vim index 48dce25bb3..5a51903712 100644 --- a/src/testdir/test_expand.vim +++ b/src/testdir/test_expand.vim @@ -1,5 +1,7 @@ " Test for expanding file names +source shared.vim + func Test_with_directories() call mkdir('Xdir1') call mkdir('Xdir2') @@ -81,3 +83,30 @@ func Test_expandcmd() call assert_fails('call expandcmd("make %")', 'E499:') close endfunc + +" Test for expanding , and outside of sourcing a script +func Test_source_sfile() + let lines =<< trim [SCRIPT] + :call assert_fails('echo expandcmd("")', 'E498:') + :call assert_fails('echo expandcmd("")', 'E842:') + :call assert_fails('echo expandcmd("")', 'E961:') + :call assert_fails('call expandcmd("edit ")', 'E446:') + :call assert_fails('call expandcmd("edit #")', 'E194:') + :call assert_fails('call expandcmd("edit #<2")', 'E684:') + :call assert_fails('call expandcmd("edit ")', 'E348:') + :call assert_fails('call expandcmd("edit ")', 'E348:') + :call assert_fails('autocmd User MyCmd echo ""', 'E498:') + :call writefile(v:errors, 'Xresult') + :qall! + + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -s Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') +endfunc + + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index bd9cacafa2..7601c4fa71 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -382,9 +382,7 @@ function Test_max_min_errors() endfunc function Test_printf_64bit() - if has('num64') - call assert_equal("123456789012345", printf('%d', 123456789012345)) - endif + call assert_equal("123456789012345", printf('%d', 123456789012345)) endfunc function Test_printf_spec_s() @@ -423,12 +421,8 @@ function Test_printf_spec_b() call assert_equal(" 0b1111011", printf('%#10b', 123)) call assert_equal("0B01111011", printf('%#010B', 123)) call assert_equal("1001001100101100000001011010010", printf('%b', 1234567890)) - if has('num64') - call assert_equal("11100000100100010000110000011011101111101111001", printf('%b', 123456789012345)) - call assert_equal("1111111111111111111111111111111111111111111111111111111111111111", printf('%b', -1)) - else - call assert_equal("11111111111111111111111111111111", printf('%b', -1)) - endif + call assert_equal("11100000100100010000110000011011101111101111001", printf('%b', 123456789012345)) + call assert_equal("1111111111111111111111111111111111111111111111111111111111111111", printf('%b', -1)) endfunc func Test_substitute_expr() @@ -530,3 +524,12 @@ func Test_broken_number() call assert_equal(2, str2nr('2a')) call assert_fails('inoremap b', 'E474:') endfunc + +func Test_eval_after_if() + let s:val = '' + func SetVal(x) + let s:val ..= a:x + endfunc + if 0 | eval SetVal('a') | endif | call SetVal('b') + call assert_equal('b', s:val) +endfunc diff --git a/src/testdir/test_filechanged.vim b/src/testdir/test_filechanged.vim index 6d17d9586d..6192b9e66d 100644 --- a/src/testdir/test_filechanged.vim +++ b/src/testdir/test_filechanged.vim @@ -146,3 +146,18 @@ func Test_file_changed_dialog() bwipe! call delete('Xchanged_d') endfunc + +" Test for editing a new buffer from a FileChangedShell autocmd +func Test_FileChangedShell_newbuf() + call writefile(['one', 'two'], 'Xfile') + new Xfile + augroup testnewbuf + autocmd FileChangedShell * enew + augroup END + call writefile(['red'], 'Xfile') + call assert_fails('checktime', 'E811:') + au! testnewbuf + call delete('Xfile') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_fileformat.vim b/src/testdir/test_fileformat.vim index 394c274753..efc3b2252e 100644 --- a/src/testdir/test_fileformat.vim +++ b/src/testdir/test_fileformat.vim @@ -276,3 +276,26 @@ func Test_fileformats() call delete('XXUxDsMc') call delete('Xtest') endfunc + +" Test for changing the fileformat using ++read +func Test_fileformat_plusplus_read() + new + call setline(1, ['one', 'two', 'three']) + w ++ff=dos Xfile1 + enew! + set ff=unix + " A :read doesn't change the fileformat, but does apply to the read lines. + r ++fileformat=unix Xfile1 + call assert_equal('unix', &fileformat) + call assert_equal("three\r", getline('$')) + 3r ++edit Xfile1 + call assert_equal('dos', &fileformat) + close! + call delete('Xfile1') + set fileformat& + call assert_fails('e ++fileformat Xfile1', 'E474:') + call assert_fails('e ++ff=abc Xfile1', 'E474:') + call assert_fails('e ++abc1 Xfile1', 'E474:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 3868e73c5d..213f2de1c9 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -621,3 +621,25 @@ func Test_setfiletype_completion() call feedkeys(":setfiletype java\\\"\", 'tx') call assert_equal('"setfiletype java javacc javascript javascriptreact', @:) endfunc + +" Test for ':filetype detect' command for a buffer without a file +func Test_emptybuf_ftdetect() + new + call setline(1, '#!/bin/sh') + call assert_equal('', &filetype) + filetype detect + call assert_equal('sh', &filetype) + close! +endfunc + +" Test for ':filetype indent on' and ':filetype indent off' commands +func Test_filetype_indent_off() + new Xtest.vim + filetype indent on + call assert_equal(1, g:did_indent_on) + filetype indent off + call assert_equal(0, exists('g:did_indent_on')) + close +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim index 2e6f888896..ac6d8637b8 100644 --- a/src/testdir/test_findfile.vim +++ b/src/testdir/test_findfile.vim @@ -183,3 +183,43 @@ func Test_finddir_error() call assert_fails('call finddir("x", "**x")', 'E343:') call assert_fails('call finddir("x", repeat("x", 5000))', 'E854:') endfunc + +" Test for the :find, :sfind and :tabfind commands +func Test_find_cmd() + new + let save_path = &path + let save_dir = getcwd() + set path=.,./**/* + call CreateFiles() + cd Xdir1 + + " Test for :find + find foo + call assert_equal('foo', expand('%:.')) + 2find foo + call assert_equal('Xdir2/foo', expand('%:.')) + call assert_fails('3find foo', 'E347:') + + " Test for :sfind + enew + sfind barfoo + call assert_equal('Xdir2/Xdir3/barfoo', expand('%:.')) + call assert_equal(3, winnr('$')) + close + call assert_fails('sfind baz', 'E345:') + call assert_equal(2, winnr('$')) + + " Test for :tabfind + enew + tabfind foobar + call assert_equal('Xdir2/foobar', expand('%:.')) + call assert_equal(2, tabpagenr('$')) + tabclose + call assert_fails('tabfind baz', 'E345:') + call assert_equal(1, tabpagenr('$')) + + call chdir(save_dir) + call CleanFiles() + let &path = save_path + close +endfunc diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 9173e8547c..c748854769 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2,6 +2,7 @@ source shared.vim source check.vim source term_util.vim +source screendump.vim " Must be done first, since the alternate buffer must be unset. func Test_00_bufexists() @@ -2017,3 +2018,19 @@ func Test_range() " uniq() call assert_equal([0, 1, 2, 3, 4], uniq(range(5))) endfunc + +func Test_echoraw() + CheckScreendump + + " Normally used for escape codes, but let's test with a CR. + let lines =<< trim END + call echoraw("hello\x") + END + call writefile(lines, 'XTest_echoraw') + let buf = RunVimInTerminal('-S XTest_echoraw', {'rows': 5, 'cols': 40}) + call VerifyScreenDump(buf, 'Test_functions_echoraw', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XTest_echoraw') +endfunc diff --git a/src/testdir/test_help.vim b/src/testdir/test_help.vim index 3b6ad3923b..219689bde5 100644 --- a/src/testdir/test_help.vim +++ b/src/testdir/test_help.vim @@ -90,10 +90,18 @@ func Test_helptag_cmd() " The following tests fail on FreeBSD for some reason if has('unix') && !has('bsd') " Read-only tags file - call writefile([''], 'Xdir/tags') - call setfperm('Xdir/tags', 'r-xr--r--') - call assert_fails('helptags Xdir', 'E152:', getfperm('Xdir/tags')) - call delete('Xdir/tags') + call mkdir('Xdir/doc', 'p') + call writefile([''], 'Xdir/doc/tags') + call writefile([], 'Xdir/doc/sample.txt') + call setfperm('Xdir/doc/tags', 'r-xr--r--') + call assert_fails('helptags Xdir/doc', 'E152:', getfperm('Xdir/doc/tags')) + + let rtp = &rtp + let &rtp = 'Xdir' + helptags ALL + let &rtp = rtp + + call delete('Xdir/doc/tags') " No permission to read the help file call setfperm('Xdir/a/doc/sample.txt', '-w-------') diff --git a/src/testdir/test_join.vim b/src/testdir/test_join.vim index 377edab1e9..fdd9e05ebc 100644 --- a/src/testdir/test_join.vim +++ b/src/testdir/test_join.vim @@ -436,5 +436,11 @@ func Test_join_lines() call setline(1, ['a', 'b', '', 'c', 'd']) normal 5J call assert_equal('a b c d', getline(1)) + call setline(1, ['a', 'b', 'c']) + 2,2join + call assert_equal(['a', 'b', 'c'], getline(1, '$')) + call assert_equal(2, line('.')) + 2join + call assert_equal(['a', 'b c'], getline(1, '$')) bwipe! endfunc diff --git a/src/testdir/test_largefile.vim b/src/testdir/test_largefile.vim index 1b3e02a0c8..68d6ec9eb0 100644 --- a/src/testdir/test_largefile.vim +++ b/src/testdir/test_largefile.vim @@ -24,11 +24,6 @@ func Test_largefile() w " Check if the file size is 4,000,000,000 bytes. let fsize=getfsize(fname) - if has('num64') - call assert_true(fsize == 4000000000) - else - " getfsize() returns -2 if a Number is 32 bits. - call assert_true(fsize == -2) - endif + call assert_true(fsize == 4000000000) call delete(fname) endfunc diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim index 7aeb23c14d..71f254a780 100644 --- a/src/testdir/test_mapping.vim +++ b/src/testdir/test_mapping.vim @@ -38,6 +38,7 @@ func Test_abclear() abclear call assert_equal("\n\nNo abbreviation found", execute('abbrev')) + call assert_fails('%abclear', 'E481:') endfunc func Test_abclear_buffer() @@ -552,6 +553,13 @@ func Test_map_error() map ,f abc call assert_fails('normal ,f', 'E121:') unmap ,f + + " Recursive use of :normal in a map + set maxmapdepth=100 + map gq :normal gq + call assert_fails('normal gq', 'E192:') + unmap gq + set maxmapdepth& endfunc " Test for key mapping diff --git a/src/testdir/test_marks.vim b/src/testdir/test_marks.vim index 829f40dcbd..24c8a41711 100644 --- a/src/testdir/test_marks.vim +++ b/src/testdir/test_marks.vim @@ -212,4 +212,13 @@ func Test_lockmarks_with_put() bwipe! endfunc +" Test for :k command to set a mark +func Test_marks_k_cmd() + new + call setline(1, ['foo', 'bar', 'baz', 'qux']) + 1,3kr + call assert_equal([0, 3, 1, 0], getpos("'r")) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_move.vim b/src/testdir/test_move.vim index f666a904b0..8c40369dbd 100644 --- a/src/testdir/test_move.vim +++ b/src/testdir/test_move.vim @@ -38,6 +38,7 @@ func Test_move() call assert_fails("move -100", 'E16:') call assert_fails("move +100", 'E16:') call assert_fails('move', 'E16:') + call assert_fails("move 'r", 'E20:') %bwipeout! endfunc diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index d45cf41592..843374d26e 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -2006,7 +2006,7 @@ fun! Test_normal37_g_cmd6() tabclose endfor " clean up - call assert_fails(':tabclose', 'E784') + call assert_fails(':tabclose', 'E784:') endfunc fun! Test_normal38_nvhome() @@ -2705,3 +2705,19 @@ func Test_normal_gk() bw! set cpoptions& number& numberwidth& endfunc + +" Test for cursor movement with '-' in 'cpoptions' +func Test_normal_cpo_minus() + new + call setline(1, ['foo', 'bar', 'baz']) + let save_cpo = &cpo + set cpo+=- + call assert_beeps('normal 10j') + call assert_equal(1, line('.')) + normal G + call assert_beeps('normal 10k') + call assert_equal(3, line('.')) + call assert_fails(10, 'E16:') + let &cpo = save_cpo + close! +endfunc diff --git a/src/testdir/test_plus_arg_edit.vim b/src/testdir/test_plus_arg_edit.vim index e31680e7b6..64533e71cf 100644 --- a/src/testdir/test_plus_arg_edit.vim +++ b/src/testdir/test_plus_arg_edit.vim @@ -32,3 +32,16 @@ func Test_edit_bad() bw! call delete('Xfile') endfunc + +" Test for ++bin and ++nobin arguments +func Test_binary_arg() + new + edit ++bin Xfile1 + call assert_equal(1, &binary) + edit ++nobin Xfile2 + call assert_equal(0, &binary) + call assert_fails('edit ++binabc Xfile3', 'E474:') + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index ad5a808611..d331263e3f 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2821,9 +2821,9 @@ func Test_previewpopup() call term_sendkeys(buf, "/another\\}") call VerifyScreenDump(buf, 'Test_popupwin_previewpopup_4', {}) - call term_sendkeys(buf, ":cd ..\:\") + call term_sendkeys(buf, ":silent cd ..\:\") call VerifyScreenDump(buf, 'Test_popupwin_previewpopup_5', {}) - call term_sendkeys(buf, ":cd testdir\") + call term_sendkeys(buf, ":silent cd testdir\") call term_sendkeys(buf, ":pclose\") call term_sendkeys(buf, ":\") diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 79ad82d2d6..d3f2e3abd7 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -538,6 +538,15 @@ func Xtest_browse(cchar) 10Xcc call assert_equal(11, line('.')) call assert_equal('Xqftestfile2', bufname('%')) + Xopen + call cursor(2, 1) + if a:cchar == 'c' + .cc + else + .ll + endif + call assert_equal(6, line('.')) + call assert_equal('Xqftestfile1', bufname('%')) " Jumping to an error from the error window (when only the error window is " present) @@ -1628,6 +1637,13 @@ func Test_setqflist_invalid_nr() eval []->setqflist(' ', {'nr' : $XXX_DOES_NOT_EXIST}) endfunc +func Test_setqflist_user_sets_buftype() + call setqflist([{'text': 'foo'}, {'text': 'bar'}]) + set buftype=quickfix + call setqflist([], 'a') + enew +endfunc + func Test_quickfix_set_list_with_act() call XquickfixSetListWithAct('c') call XquickfixSetListWithAct('l') @@ -2718,10 +2734,6 @@ func XvimgrepTests(cchar) call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded) call assert_equal([], getbufinfo('Xtestfile2')) - " Test with the last search pattern not set - call test_clear_search_pat() - call assert_fails('Xvimgrep // *', 'E35:') - call delete('Xtestfile1') call delete('Xtestfile2') endfunc @@ -2747,6 +2759,21 @@ func Test_vimgrep_incsearch() set noincsearch endfunc +" Test vimgrep with the last search pattern not set +func Test_vimgrep_with_no_last_search_pat() + let lines =<< trim [SCRIPT] + call assert_fails('vimgrep // *', 'E35:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') +endfunc + func XfreeTests(cchar) call s:setup_commands(a:cchar) diff --git a/src/testdir/test_random.vim b/src/testdir/test_random.vim index 747e438486..bdb7e1db0e 100644 --- a/src/testdir/test_random.vim +++ b/src/testdir/test_random.vim @@ -11,7 +11,7 @@ func Test_Rand() call test_settime(12341234) let s = srand() - if filereadable('/dev/urandom') + if !has('win32') && filereadable('/dev/urandom') " using /dev/urandom call assert_notequal(s, srand()) else @@ -21,9 +21,10 @@ func Test_Rand() call assert_notequal(s, srand()) endif - call srand() - let v = rand() - call assert_notequal(v, rand()) + call test_srand_seed(123456789) + call assert_equal(4284103975, rand()) + call assert_equal(1001954530, rand()) + call test_srand_seed() if has('float') call assert_fails('echo srand(1.2)', 'E805:') @@ -38,3 +39,9 @@ func Test_Rand() call test_settime(0) endfunc + +func Test_issue_5587() + call rand() + call garbagecollect() + call rand() +endfunc diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim index 45cf02a59c..b8f0a1012f 100644 --- a/src/testdir/test_registers.vim +++ b/src/testdir/test_registers.vim @@ -386,4 +386,15 @@ func Test_put_reg_restart_mode() bwipe! endfunc +" Test for executing a register using :@ command +func Test_execute_register() + call setreg('r', []) + call assert_beeps('@r') + let i = 1 + let @q = 'let i+= 1' + @q + @ + call assert_equal(3, i) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 69d007354e..9567aa468b 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -1457,42 +1457,62 @@ func Test_search_special() endfunc " Test for command failures when the last search pattern is not set. +" Need to run this in a new vim instance where last search pattern is not set. func Test_search_with_no_last_pat() - call test_clear_search_pat() - call assert_fails("normal i\/\e", 'E35:') - call assert_fails("exe '/'", 'E35:') - call assert_fails("exe '?'", 'E35:') - call assert_fails("/", 'E35:') - call assert_fails("?", 'E35:') - call assert_fails("normal n", 'E35:') - call assert_fails("normal N", 'E35:') - call assert_fails("normal gn", 'E35:') - call assert_fails("normal gN", 'E35:') - call assert_fails("normal cgn", 'E35:') - call assert_fails("normal cgN", 'E35:') - let p = [] - let p = @/ - call assert_equal('', p) - call assert_fails("normal :\/", 'E35:') - call assert_fails("//p", 'E35:') - call assert_fails(";//p", 'E35:') - call assert_fails("??p", 'E35:') - call assert_fails(";??p", 'E35:') - call assert_fails('g//p', 'E476:') - call assert_fails('v//p', 'E476:') + let lines =<< trim [SCRIPT] + call assert_fails("normal i\/\e", 'E35:') + call assert_fails("exe '/'", 'E35:') + call assert_fails("exe '?'", 'E35:') + call assert_fails("/", 'E35:') + call assert_fails("?", 'E35:') + call assert_fails("normal n", 'E35:') + call assert_fails("normal N", 'E35:') + call assert_fails("normal gn", 'E35:') + call assert_fails("normal gN", 'E35:') + call assert_fails("normal cgn", 'E35:') + call assert_fails("normal cgN", 'E35:') + let p = [] + let p = @/ + call assert_equal('', p) + call assert_fails("normal :\/", 'E35:') + call assert_fails("//p", 'E35:') + call assert_fails(";//p", 'E35:') + call assert_fails("??p", 'E35:') + call assert_fails(";??p", 'E35:') + call assert_fails('g//p', 'E476:') + call assert_fails('v//p', 'E476:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') endfunc " Test for using tilde (~) atom in search. This should use the last used " substitute pattern func Test_search_tilde_pat() - call test_clear_search_pat() - set regexpengine=1 - call assert_fails('exe "normal /~\"', 'E33:') - call assert_fails('exe "normal ?~\"', 'E33:') - set regexpengine=2 - call assert_fails('exe "normal /~\"', 'E383:') - call assert_fails('exe "normal ?~\"', 'E383:') - set regexpengine& + let lines =<< trim [SCRIPT] + set regexpengine=1 + call assert_fails('exe "normal /~\"', 'E33:') + call assert_fails('exe "normal ?~\"', 'E33:') + set regexpengine=2 + call assert_fails('exe "normal /~\"', 'E383:') + call assert_fails('exe "normal ?~\"', 'E383:') + set regexpengine& + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index f6ad87af18..8299db4ef8 100644 --- a/src/testdir/test_sort.vim +++ b/src/testdir/test_sort.vim @@ -1295,9 +1295,8 @@ abc \ '2147483647'], getline(1, '$')) bwipe! - if has('num64') - new - a + new + a -9223372036854775808 -9223372036854775807 @@ -1312,22 +1311,21 @@ abc abc . - sort n - call assert_equal(['', - \ 'abc', - \ '', - \ '-9223372036854775808', - \ '-9223372036854775808', - \ '-9223372036854775807', - \ '-9223372036854775806', - \ '-1', - \ '0', - \ '1', - \ '9223372036854775806', - \ '9223372036854775807', - \ '9223372036854775807'], getline(1, '$')) - bwipe! - endif + sort n + call assert_equal(['', + \ 'abc', + \ '', + \ '-9223372036854775808', + \ '-9223372036854775808', + \ '-9223372036854775807', + \ '-9223372036854775806', + \ '-1', + \ '0', + \ '1', + \ '9223372036854775806', + \ '9223372036854775807', + \ '9223372036854775807'], getline(1, '$')) + bwipe! endfunc @@ -1383,11 +1381,25 @@ func Test_sort_last_search_pat() call setline(1, ['3b', '1c', '2a']) sort // call assert_equal(['2a', '3b', '1c'], getline(1, '$')) - call test_clear_search_pat() - call assert_fails('sort //', 'E35:') close! endfunc +" Test for :sort with no last search pattern +func Test_sort_with_no_last_search_pat() + let lines =<< trim [SCRIPT] + call setline(1, ['3b', '1c', '2a']) + call assert_fails('sort //', 'E35:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + call delete('Xscript') + call delete('Xresult') +endfunc + " Test for retaining marks across a :sort func Test_sort_with_marks() new diff --git a/src/testdir/test_source.vim b/src/testdir/test_source.vim index b8fe8422b3..ba6fd5ad95 100644 --- a/src/testdir/test_source.vim +++ b/src/testdir/test_source.vim @@ -57,3 +57,34 @@ func Test_different_script() call assert_fails('source XtwoScript', 'E121:') call delete('XtwoScript') endfunc + +" When sourcing a vim script, shebang should be ignored. +func Test_source_ignore_shebang() + call writefile(['#!./xyzabc', 'let g:val=369'], 'Xfile.vim') + source Xfile.vim + call assert_equal(g:val, 369) + call delete('Xfile.vim') +endfunc + +" Test for expanding in a autocmd and for and +func Test_source_autocmd_sfile() + let code =<< trim [CODE] + let g:SfileName = '' + augroup sfiletest + au! + autocmd User UserAutoCmd let g:Sfile = ':t' + augroup END + doautocmd User UserAutoCmd + let g:Slnum = expand('') + let g:Sflnum = expand('') + augroup! sfiletest + [CODE] + call writefile(code, 'Xscript.vim') + source Xscript.vim + call assert_equal('Xscript.vim', g:Sfile) + call assert_equal('7', g:Slnum) + call assert_equal('8', g:Sflnum) + call delete('Xscript.vim') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim index 1f705b847f..ebfe8aac66 100644 --- a/src/testdir/test_statusline.vim +++ b/src/testdir/test_statusline.vim @@ -8,6 +8,7 @@ source view_util.vim source check.vim +source screendump.vim func s:get_statusline() return ScreenLines(&lines - 1, &columns)[0] @@ -393,3 +394,22 @@ func Test_statusline_visual() bwipe! x1 bwipe! x2 endfunc + +func Test_statusline_removed_group() + CheckScreendump + + let lines =<< trim END + scriptencoding utf-8 + set laststatus=2 + let &statusline = '%#StatColorHi2#%(✓%#StatColorHi2#%) Q≡' + END + call writefile(lines, 'XTest_statusline') + + let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 10, 'cols': 50}) + call term_wait(buf, 100) + call VerifyScreenDump(buf, 'Test_statusline_1', {}) + + " clean up + call StopVimInTerminal(buf) + call delete('XTest_statusline') +endfunc diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim index acc59cf564..2ac6f45419 100644 --- a/src/testdir/test_substitute.vim +++ b/src/testdir/test_substitute.vim @@ -1,5 +1,7 @@ " Tests for multi-line regexps with ":s". +source shared.vim + func Test_multiline_subst() enew! call append(0, ["1 aa", @@ -805,17 +807,32 @@ endfunc " Test for command failures when the last substitute pattern is not set. func Test_sub_with_no_last_pat() - call test_clear_search_pat() - call assert_fails('~', 'E33:') - call assert_fails('s//abc/g', 'E476:') - call assert_fails('s\/bar', 'E476:') - call assert_fails('s\&bar&', 'E476:') + let lines =<< trim [SCRIPT] + call assert_fails('~', 'E33:') + call assert_fails('s//abc/g', 'E476:') + call assert_fails('s\/bar', 'E476:') + call assert_fails('s\&bar&', 'E476:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif - call test_clear_search_pat() - let save_cpo = &cpo - set cpo+=/ - call assert_fails('s/abc/%/', 'E33:') - let &cpo = save_cpo + let lines =<< trim [SCRIPT] + set cpo+=/ + call assert_fails('s/abc/%/', 'E33:') + call writefile(v:errors, 'Xresult') + qall! + [SCRIPT] + call writefile(lines, 'Xscript') + if RunVim([], [], '--clean -S Xscript') + call assert_equal([], readfile('Xresult')) + endif + + call delete('Xscript') + call delete('Xresult') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim index bf721a0b61..35c9fd0eab 100644 --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -139,7 +139,11 @@ function Test_tabpage() call assert_fails("tabmove -99", 'E474:') call assert_fails("tabmove -3+", 'E474:') call assert_fails("tabmove $3", 'E474:') + call assert_fails("%tabonly", 'E16:') 1tabonly! + tabnew + call assert_fails("-2tabmove", 'E474:') + tabonly! endfunc " Test autocommands @@ -609,4 +613,14 @@ func Test_tabpage_cmdheight() call delete('XTest_tabpage_cmdheight') endfunc +" Test for closing the tab page from a command window +func Test_tabpage_close_cmdwin() + tabnew + call feedkeys("q/:tabclose\\", 'xt') + call assert_equal(2, tabpagenr('$')) + call feedkeys("q/:tabonly\\", 'xt') + call assert_equal(2, tabpagenr('$')) + tabonly +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim index 47b9ffb459..29c3840597 100644 --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -893,6 +893,11 @@ func Test_tag_multimatch() tag FIRST tnext call assert_equal(2, line('.')) + tlast + tprev + call assert_equal(2, line('.')) + tNext + call assert_equal(1, line('.')) set ignorecase& call delete('Xtags') @@ -1035,4 +1040,200 @@ Type number and (empty cancels): %bwipe endfunc +" Test for :isearch, :ilist, :ijump and :isplit commands +" Test for [i, ]i, [I, ]I, [ CTRL-I, ] CTRL-I and CTRL-W i commands +func Test_inc_search() + new + call setline(1, ['1:foo', '2:foo', 'foo', '3:foo', '4:foo']) + call cursor(3, 1) + + " Test for [i and ]i + call assert_equal('1:foo', execute('normal [i')) + call assert_equal('2:foo', execute('normal 2[i')) + call assert_fails('normal 3[i', 'E387:') + call assert_equal('3:foo', execute('normal ]i')) + call assert_equal('4:foo', execute('normal 2]i')) + call assert_fails('normal 3]i', 'E389:') + + " Test for :isearch + call assert_equal('1:foo', execute('isearch foo')) + call assert_equal('3:foo', execute('isearch 4 /foo/')) + call assert_fails('isearch 3 foo', 'E387:') + call assert_equal('3:foo', execute('+1,$isearch foo')) + call assert_fails('1,.-1isearch 3 foo', 'E389:') + call assert_fails('isearch bar', 'E389:') + call assert_fails('isearch /foo/3', 'E488:') + + " Test for [I and ]I + call assert_equal([ + \ ' 1: 1 1:foo', + \ ' 2: 2 2:foo', + \ ' 3: 3 foo', + \ ' 4: 4 3:foo', + \ ' 5: 5 4:foo'], split(execute('normal [I'), "\n")) + call assert_equal([ + \ ' 1: 4 3:foo', + \ ' 2: 5 4:foo'], split(execute('normal ]I'), "\n")) + + " Test for :ilist + call assert_equal([ + \ ' 1: 1 1:foo', + \ ' 2: 2 2:foo', + \ ' 3: 3 foo', + \ ' 4: 4 3:foo', + \ ' 5: 5 4:foo'], split(execute('ilist foo'), "\n")) + call assert_equal([ + \ ' 1: 4 3:foo', + \ ' 2: 5 4:foo'], split(execute('+1,$ilist /foo/'), "\n")) + call assert_fails('ilist bar', 'E389:') + + " Test for [ CTRL-I and ] CTRL-I + exe "normal [\t" + call assert_equal([1, 3], [line('.'), col('.')]) + exe "normal 2j4[\t" + call assert_equal([4, 3], [line('.'), col('.')]) + call assert_fails("normal k3[\t", 'E387:') + call assert_fails("normal 6[\t", 'E389:') + exe "normal ]\t" + call assert_equal([4, 3], [line('.'), col('.')]) + exe "normal k2]\t" + call assert_equal([5, 3], [line('.'), col('.')]) + call assert_fails("normal 2k3]\t", 'E389:') + + " Test for :ijump + call cursor(3, 1) + ijump foo + call assert_equal([1, 3], [line('.'), col('.')]) + call cursor(3, 1) + ijump 4 /foo/ + call assert_equal([4, 3], [line('.'), col('.')]) + call cursor(3, 1) + call assert_fails('ijump 3 foo', 'E387:') + +,$ijump 2 foo + call assert_equal([5, 3], [line('.'), col('.')]) + call assert_fails('ijump bar', 'E389:') + + " Test for CTRL-W i + call cursor(3, 1) + wincmd i + call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')]) + close + 5wincmd i + call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')]) + close + call assert_fails('3wincmd i', 'E387:') + call assert_fails('6wincmd i', 'E389:') + + " Test for :isplit + isplit foo + call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')]) + close + isplit 5 /foo/ + call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')]) + close + call assert_fails('isplit 3 foo', 'E387:') + call assert_fails('isplit 6 foo', 'E389:') + call assert_fails('isplit bar', 'E389:') + + close! +endfunc + +" Test for :dsearch, :dlist, :djump and :dsplit commands +" Test for [d, ]d, [D, ]D, [ CTRL-D, ] CTRL-D and CTRL-W d commands +func Test_def_search() + new + call setline(1, ['#define FOO 1', '#define FOO 2', '#define FOO 3', + \ '#define FOO 4', '#define FOO 5']) + call cursor(3, 9) + + " Test for [d and ]d + call assert_equal('#define FOO 1', execute('normal [d')) + call assert_equal('#define FOO 2', execute('normal 2[d')) + call assert_fails('normal 3[d', 'E387:') + call assert_equal('#define FOO 4', execute('normal ]d')) + call assert_equal('#define FOO 5', execute('normal 2]d')) + call assert_fails('normal 3]d', 'E388:') + + " Test for :dsearch + call assert_equal('#define FOO 1', execute('dsearch FOO')) + call assert_equal('#define FOO 5', execute('dsearch 5 /FOO/')) + call assert_fails('dsearch 3 FOO', 'E387:') + call assert_equal('#define FOO 4', execute('+1,$dsearch FOO')) + call assert_fails('1,.-1dsearch 3 FOO', 'E388:') + call assert_fails('dsearch BAR', 'E388:') + + " Test for [D and ]D + call assert_equal([ + \ ' 1: 1 #define FOO 1', + \ ' 2: 2 #define FOO 2', + \ ' 3: 3 #define FOO 3', + \ ' 4: 4 #define FOO 4', + \ ' 5: 5 #define FOO 5'], split(execute('normal [D'), "\n")) + call assert_equal([ + \ ' 1: 4 #define FOO 4', + \ ' 2: 5 #define FOO 5'], split(execute('normal ]D'), "\n")) + + " Test for :dlist + call assert_equal([ + \ ' 1: 1 #define FOO 1', + \ ' 2: 2 #define FOO 2', + \ ' 3: 3 #define FOO 3', + \ ' 4: 4 #define FOO 4', + \ ' 5: 5 #define FOO 5'], split(execute('dlist FOO'), "\n")) + call assert_equal([ + \ ' 1: 4 #define FOO 4', + \ ' 2: 5 #define FOO 5'], split(execute('+1,$dlist /FOO/'), "\n")) + call assert_fails('dlist BAR', 'E388:') + + " Test for [ CTRL-D and ] CTRL-D + exe "normal [\" + call assert_equal([1, 9], [line('.'), col('.')]) + exe "normal 2j4[\" + call assert_equal([4, 9], [line('.'), col('.')]) + call assert_fails("normal k3[\", 'E387:') + call assert_fails("normal 6[\", 'E388:') + exe "normal ]\" + call assert_equal([4, 9], [line('.'), col('.')]) + exe "normal k2]\" + call assert_equal([5, 9], [line('.'), col('.')]) + call assert_fails("normal 2k3]\", 'E388:') + + " Test for :djump + call cursor(3, 9) + djump FOO + call assert_equal([1, 9], [line('.'), col('.')]) + call cursor(3, 9) + djump 4 /FOO/ + call assert_equal([4, 9], [line('.'), col('.')]) + call cursor(3, 9) + call assert_fails('djump 3 FOO', 'E387:') + +,$djump 2 FOO + call assert_equal([5, 9], [line('.'), col('.')]) + call assert_fails('djump BAR', 'E388:') + + " Test for CTRL-W d + call cursor(3, 9) + wincmd d + call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')]) + close + 5wincmd d + call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')]) + close + call assert_fails('3wincmd d', 'E387:') + call assert_fails('6wincmd d', 'E388:') + + " Test for :dsplit + dsplit FOO + call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')]) + close + dsplit 5 /FOO/ + call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')]) + close + call assert_fails('dsplit 3 FOO', 'E387:') + call assert_fails('dsplit 6 FOO', 'E388:') + call assert_fails('dsplit BAR', 'E388:') + + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index c44999887a..bca0339e54 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2338,6 +2338,7 @@ func Test_terminal_in_popup() call writefile(text, 'Xtext') let cmd = GetVimCommandCleanTerm() let lines = [ + \ 'set t_u7=', \ 'call setline(1, range(20))', \ 'hi PopTerm ctermbg=grey', \ 'func OpenTerm(setColor)', @@ -2351,9 +2352,14 @@ func Test_terminal_in_popup() \ 'func HidePopup()', \ ' call popup_hide(s:winid)', \ 'endfunc', + \ 'sleep 10m', + \ 'redraw', + \ 'echo getwinvar(s:winid, "&buftype") win_gettype(s:winid)', \ ] call writefile(lines, 'XtermPopup') let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15}) + call term_wait(buf, 100) + call term_sendkeys(buf, ":\") call VerifyScreenDump(buf, 'Test_terminal_popup_1', {}) call term_sendkeys(buf, ":q\") @@ -2364,12 +2370,10 @@ func Test_terminal_in_popup() call term_sendkeys(buf, "/edit\") call VerifyScreenDump(buf, 'Test_terminal_popup_3', {}) - " TODO: somehow this causes the job to keep running on Mac - if !has('mac') - call term_sendkeys(buf, "\:call HidePopup()\") - call VerifyScreenDump(buf, 'Test_terminal_popup_4', {}) - call term_sendkeys(buf, "\") - endif + call term_sendkeys(buf, "\:call HidePopup()\") + call VerifyScreenDump(buf, 'Test_terminal_popup_4', {}) + call term_sendkeys(buf, "\") + call term_wait(buf, 100) call term_sendkeys(buf, ":q\") call term_wait(buf, 100) " wait for terminal to vanish @@ -2377,3 +2381,18 @@ func Test_terminal_in_popup() call StopVimInTerminal(buf) call delete('XtermPopup') endfunc + +func Test_issue_5607() + let wincount = winnr('$') + exe 'terminal' &shell &shellcmdflag 'exit' + let job = term_getjob(bufnr()) + call WaitForAssert({-> assert_equal("dead", job_status(job))}) + + let old_wincolor = &wincolor + try + set wincolor= + finally + let &wincolor = old_wincolor + bw! + endtry +endfunc diff --git a/src/testdir/test_undo.vim b/src/testdir/test_undo.vim index e858d72747..2ecc52082e 100644 --- a/src/testdir/test_undo.vim +++ b/src/testdir/test_undo.vim @@ -295,6 +295,8 @@ func Test_undo_write() close! call delete('Xtest') bwipe! Xtest + + call assert_fails('earlier xyz', 'E475:') endfunc func Test_insert_expr() diff --git a/src/testdir/test_user_func.vim b/src/testdir/test_user_func.vim index d10a110848..872b87343d 100644 --- a/src/testdir/test_user_func.vim +++ b/src/testdir/test_user_func.vim @@ -162,3 +162,7 @@ endfunc func Test_user_method() eval 'bar'->s:addFoo()->assert_equal('barfoo') endfunc + +func Test_failed_call_in_try() + try | call UnknownFunc() | catch | endtry +endfunc diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim new file mode 100644 index 0000000000..a873c86571 --- /dev/null +++ b/src/testdir/test_vim9_disassemble.vim @@ -0,0 +1,537 @@ +" Test the :disassemble command, and compilation as a side effect + +func NotCompiled() + echo "not" +endfunc + +let s:scriptvar = 4 +let g:globalvar = 'g' + +def s:ScriptFuncLoad(arg: string) + let local = 1 + buffers + echo arg + echo local + echo v:version + echo s:scriptvar + echo g:globalvar + echo &tabstop + echo $ENVVAR + echo @z +enddef + +def Test_disassemble_load() + assert_fails('disass NoFunc', 'E1061:') + assert_fails('disass NotCompiled', 'E1062:') + assert_fails('disass', 'E471:') + assert_fails('disass [', 'E475:') + assert_fails('disass 234', 'E475:') + assert_fails('disass foo', 'E475:') + + let res = execute('disass s:ScriptFuncLoad') + assert_match('\d*_ScriptFuncLoad.*' + \ .. 'buffers.*' + \ .. ' EXEC \+buffers.*' + \ .. ' LOAD arg\[-1\].*' + \ .. ' LOAD $0.*' + \ .. ' LOADV v:version.*' + \ .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' + \ .. ' LOADG g:globalvar.*' + \ .. ' LOADENV $ENVVAR.*' + \ .. ' LOADREG @z.*' + \, res) +enddef + +def s:ScriptFuncPush() + let localbool = true + let localspec = v:none + let localblob = 0z1234 + if has('float') + let localfloat = 1.234 + endif +enddef + +def Test_disassemble_push() + let res = execute('disass s:ScriptFuncPush') + assert_match('\d*_ScriptFuncPush.*' + \ .. 'localbool = true.*' + \ .. ' PUSH v:true.*' + \ .. 'localspec = v:none.*' + \ .. ' PUSH v:none.*' + \ .. 'localblob = 0z1234.*' + \ .. ' PUSHBLOB 0z1234.*' + \, res) + if has('float') + assert_match('\d*_ScriptFuncPush.*' + \ .. 'localfloat = 1.234.*' + \ .. ' PUSHF 1.234.*' + \, res) + endif +enddef + +def s:ScriptFuncStore() + let localnr = 1 + localnr = 2 + let localstr = 'abc' + localstr = 'xyz' + v:char = 'abc' + s:scriptvar = 'sv' + g:globalvar = 'gv' + &tabstop = 8 + $ENVVAR = 'ev' + @z = 'rv' +enddef + +def Test_disassemble_store() + let res = execute('disass s:ScriptFuncStore') + assert_match('\d*_ScriptFuncStore.*' + \ .. 'localnr = 2.*' + \ .. ' STORE 2 in $0.*' + \ .. 'localstr = ''xyz''.*' + \ .. ' STORE $1.*' + \ .. 'v:char = ''abc''.*' + \ .. 'STOREV v:char.*' + \ .. 's:scriptvar = ''sv''.*' + \ .. ' STORES s:scriptvar in .*test_vim9_disassemble.vim.*' + \ .. 'g:globalvar = ''gv''.*' + \ .. ' STOREG g:globalvar.*' + \ .. '&tabstop = 8.*' + \ .. ' STOREOPT &tabstop.*' + \ .. '$ENVVAR = ''ev''.*' + \ .. ' STOREENV $ENVVAR.*' + \ .. '@z = ''rv''.*' + \ .. ' STOREREG @z.*' + \, res) +enddef + +def s:ScriptFuncTry() + try + echo 'yes' + catch /fail/ + echo 'no' + finally + throw 'end' + endtry +enddef + +def Test_disassemble_try() + let res = execute('disass s:ScriptFuncTry') + assert_match('\d*_ScriptFuncTry.*' + \ .. 'try.*' + \ .. 'TRY catch -> \d\+, finally -> \d\+.*' + \ .. 'catch /fail/.*' + \ .. ' JUMP -> \d\+.*' + \ .. ' PUSH v:exception.*' + \ .. ' PUSHS "fail".*' + \ .. ' COMPARESTRING =\~.*' + \ .. ' JUMP_IF_FALSE -> \d\+.*' + \ .. ' CATCH.*' + \ .. 'finally.*' + \ .. ' PUSHS "end".*' + \ .. ' THROW.*' + \ .. 'endtry.*' + \ .. ' ENDTRY.*' + \, res) +enddef + +def s:ScriptFuncNew() + let ll = [1, "two", 333] + let dd = #{one: 1, two: "val"} +enddef + +def Test_disassemble_new() + let res = execute('disass s:ScriptFuncNew') + assert_match('\d*_ScriptFuncNew.*' + \ .. 'let ll = \[1, "two", 333].*' + \ .. 'PUSHNR 1.*' + \ .. 'PUSHS "two".*' + \ .. 'PUSHNR 333.*' + \ .. 'NEWLIST size 3.*' + \ .. 'let dd = #{one: 1, two: "val"}.*' + \ .. 'PUSHS "one".*' + \ .. 'PUSHNR 1.*' + \ .. 'PUSHS "two".*' + \ .. 'PUSHS "val".*' + \ .. 'NEWDICT size 2.*' + \, res) +enddef + +def FuncWithArg(arg) + echo arg +enddef + +func UserFunc() + echo 'nothing' +endfunc + +func UserFuncWithArg(arg) + echo a:arg +endfunc + +def s:ScriptFuncCall(): string + changenr() + char2nr("abc") + Test_disassemble_new() + FuncWithArg(343) + ScriptFuncNew() + s:ScriptFuncNew() + UserFunc() + UserFuncWithArg("foo") + let FuncRef = function("UserFunc") + FuncRef() + let FuncRefWithArg = function("UserFuncWithArg") + FuncRefWithArg("bar") + return "yes" +enddef + +def Test_disassemble_call() + let res = execute('disass s:ScriptFuncCall') + assert_match('\d\+_ScriptFuncCall.*' + \ .. 'changenr().*' + \ .. ' BCALL changenr(argc 0).*' + \ .. 'char2nr("abc").*' + \ .. ' PUSHS "abc".*' + \ .. ' BCALL char2nr(argc 1).*' + \ .. 'Test_disassemble_new().*' + \ .. ' DCALL Test_disassemble_new(argc 0).*' + \ .. 'FuncWithArg(343).*' + \ .. ' PUSHNR 343.*' + \ .. ' DCALL FuncWithArg(argc 1).*' + \ .. 'ScriptFuncNew().*' + \ .. ' DCALL \d\+_ScriptFuncNew(argc 0).*' + \ .. 's:ScriptFuncNew().*' + \ .. ' DCALL \d\+_ScriptFuncNew(argc 0).*' + \ .. 'UserFunc().*' + \ .. ' UCALL UserFunc(argc 0).*' + \ .. 'UserFuncWithArg("foo").*' + \ .. ' PUSHS "foo".*' + \ .. ' UCALL UserFuncWithArg(argc 1).*' + \ .. 'let FuncRef = function("UserFunc").*' + \ .. 'FuncRef().*' + \ .. ' LOAD $\d.*' + \ .. ' PCALL (argc 0).*' + \ .. 'let FuncRefWithArg = function("UserFuncWithArg").*' + \ .. 'FuncRefWithArg("bar").*' + \ .. ' PUSHS "bar".*' + \ .. ' LOAD $\d.*' + \ .. ' PCALL (argc 1).*' + \ .. 'return "yes".*' + \ .. ' PUSHS "yes".*' + \ .. ' RETURN.*' + \, res) +enddef + +def HasEval() + if has("eval") + echo "yes" + else + echo "no" + endif +enddef + +def HasNothing() + if has("nothing") + echo "yes" + else + echo "no" + endif +enddef + +def HasSomething() + if has("nothing") + echo "nothing" + elseif has("something") + echo "something" + elseif has("eval") + echo "eval" + elseif has("less") + echo "less" + endif +enddef + +def Test_disassemble_const_expr() + assert_equal("\nyes", execute('call HasEval()')) + let instr = execute('disassemble HasEval') + assert_match('HasEval.*' + \ .. 'if has("eval").*' + \ .. ' PUSHS "yes".*' + \, instr) + assert_notmatch('JUMP', instr) + + assert_equal("\nno", execute('call HasNothing()')) + instr = execute('disassemble HasNothing') + assert_match('HasNothing.*' + \ .. 'if has("nothing").*' + \ .. 'else.*' + \ .. ' PUSHS "no".*' + \, instr) + assert_notmatch('PUSHS "yes"', instr) + assert_notmatch('JUMP', instr) + + assert_equal("\neval", execute('call HasSomething()')) + instr = execute('disassemble HasSomething') + assert_match('HasSomething.*' + \ .. 'if has("nothing").*' + \ .. 'elseif has("something").*' + \ .. 'elseif has("eval").*' + \ .. ' PUSHS "eval".*' + \ .. 'elseif has("less").*' + \, instr) + assert_notmatch('PUSHS "nothing"', instr) + assert_notmatch('PUSHS "something"', instr) + assert_notmatch('PUSHS "less"', instr) + assert_notmatch('JUMP', instr) +enddef + +def WithLambda(): string + let F = {a -> "X" .. a .. "X"} + return F("x") +enddef + +def Test_disassemble_lambda() + assert_equal("XxX", WithLambda()) + let instr = execute('disassemble WithLambda') + assert_match('WithLambda.*' + \ .. 'let F = {a -> "X" .. a .. "X"}.*' + \ .. ' FUNCREF \d\+.*' + \ .. 'PUSHS "x".*' + \ .. ' LOAD $0.*' + \ .. ' PCALL (argc 1).*' + \ .. ' CHECKTYPE string stack\[-1].*' + \, instr) +enddef + +def AndOr(arg): string + if arg == 1 && arg != 2 || arg == 4 + return 'yes' + endif + return 'no' +enddef + +def Test_disassemble_and_or() + assert_equal("yes", AndOr(1)) + assert_equal("no", AndOr(2)) + assert_equal("yes", AndOr(4)) + let instr = execute('disassemble AndOr') + assert_match('AndOr.*' + \ .. 'if arg == 1 && arg != 2 || arg == 4.*' + \ .. '\d LOAD arg\[-1].*' + \ .. '\d PUSHNR 1.*' + \ .. '\d COMPAREANY ==.*' + \ .. '\d JUMP_AND_KEEP_IF_FALSE -> \d\+.*' + \ .. '\d LOAD arg\[-1].*' + \ .. '\d PUSHNR 2.*' + \ .. '\d COMPAREANY !=.*' + \ .. '\d JUMP_AND_KEEP_IF_TRUE -> \d\+.*' + \ .. '\d LOAD arg\[-1].*' + \ .. '\d PUSHNR 4.*' + \ .. '\d COMPAREANY ==.*' + \ .. '\d JUMP_IF_FALSE -> \d\+.*' + \, instr) +enddef + +def ForLoop(): list + let res: list + for i in range(3) + res->add(i) + endfor + return res +enddef + +def Test_disassemble_for_loop() + assert_equal([0, 1, 2], ForLoop()) + let instr = execute('disassemble ForLoop') + assert_match('ForLoop.*' + \ .. 'let res: list.*' + \ .. ' NEWLIST size 0.*' + \ .. '\d STORE $0.*' + \ .. 'for i in range(3).*' + \ .. '\d STORE -1 in $1.*' + \ .. '\d PUSHNR 3.*' + \ .. '\d BCALL range(argc 1).*' + \ .. '\d FOR $1 -> \d\+.*' + \ .. '\d STORE $2.*' + \ .. 'res->add(i).*' + \ .. '\d LOAD $0.*' + \ .. '\d LOAD $2.*' + \ .. '\d BCALL add(argc 2).*' + \ .. '\d DROP.*' + \ .. 'endfor.*' + \ .. '\d JUMP -> \d\+.*' + \ .. '\d DROP.*' + \, instr) +enddef + +let g:number = 42 + +def Computing() + let nr = 3 + let nrres = nr + 7 + nrres = nr - 7 + nrres = nr * 7 + nrres = nr / 7 + nrres = nr % 7 + + let anyres = g:number + 7 + anyres = g:number - 7 + anyres = g:number * 7 + anyres = g:number / 7 + anyres = g:number % 7 + + if has('float') + let fl = 3.0 + let flres = fl + 7.0 + flres = fl - 7.0 + flres = fl * 7.0 + flres = fl / 7.0 + endif +enddef + +def Test_disassemble_computing() + let instr = execute('disassemble Computing') + assert_match('Computing.*' + \ .. 'let nr = 3.*' + \ .. '\d STORE 3 in $0.*' + \ .. 'let nrres = nr + 7.*' + \ .. '\d LOAD $0.*' + \ .. '\d PUSHNR 7.*' + \ .. '\d OPNR +.*' + \ .. '\d STORE $1.*' + \ .. 'nrres = nr - 7.*' + \ .. '\d OPNR -.*' + \ .. 'nrres = nr \* 7.*' + \ .. '\d OPNR \*.*' + \ .. 'nrres = nr / 7.*' + \ .. '\d OPNR /.*' + \ .. 'nrres = nr % 7.*' + \ .. '\d OPNR %.*' + \ .. 'let anyres = g:number + 7.*' + \ .. '\d LOADG g:number.*' + \ .. '\d PUSHNR 7.*' + \ .. '\d OPANY +.*' + \ .. '\d STORE $2.*' + \ .. 'anyres = g:number - 7.*' + \ .. '\d OPANY -.*' + \ .. 'anyres = g:number \* 7.*' + \ .. '\d OPANY \*.*' + \ .. 'anyres = g:number / 7.*' + \ .. '\d OPANY /.*' + \ .. 'anyres = g:number % 7.*' + \ .. '\d OPANY %.*' + \, instr) + if has('float') + assert_match('Computing.*' + \ .. 'let fl = 3.0.*' + \ .. '\d PUSHF 3.0.*' + \ .. '\d STORE $3.*' + \ .. 'let flres = fl + 7.0.*' + \ .. '\d LOAD $3.*' + \ .. '\d PUSHF 7.0.*' + \ .. '\d OPFLOAT +.*' + \ .. '\d STORE $4.*' + \ .. 'flres = fl - 7.0.*' + \ .. '\d OPFLOAT -.*' + \ .. 'flres = fl \* 7.0.*' + \ .. '\d OPFLOAT \*.*' + \ .. 'flres = fl / 7.0.*' + \ .. '\d OPFLOAT /.*' + \, instr) + endif +enddef + +def Test_disassemble_compare() + " TODO: COMPAREFUNC + let cases = [ + \ ['true == false', 'COMPAREBOOL =='], + \ ['true != false', 'COMPAREBOOL !='], + \ ['v:none == v:null', 'COMPARESPECIAL =='], + \ ['v:none != v:null', 'COMPARESPECIAL !='], + \ + \ ['111 == 222', 'COMPARENR =='], + \ ['111 != 222', 'COMPARENR !='], + \ ['111 > 222', 'COMPARENR >'], + \ ['111 < 222', 'COMPARENR <'], + \ ['111 >= 222', 'COMPARENR >='], + \ ['111 <= 222', 'COMPARENR <='], + \ ['111 =~ 222', 'COMPARENR =\~'], + \ ['111 !~ 222', 'COMPARENR !\~'], + \ + \ ['"xx" == "yy"', 'COMPARESTRING =='], + \ ['"xx" != "yy"', 'COMPARESTRING !='], + \ ['"xx" > "yy"', 'COMPARESTRING >'], + \ ['"xx" < "yy"', 'COMPARESTRING <'], + \ ['"xx" >= "yy"', 'COMPARESTRING >='], + \ ['"xx" <= "yy"', 'COMPARESTRING <='], + \ ['"xx" =~ "yy"', 'COMPARESTRING =\~'], + \ ['"xx" !~ "yy"', 'COMPARESTRING !\~'], + \ ['"xx" is "yy"', 'COMPARESTRING is'], + \ ['"xx" isnot "yy"', 'COMPARESTRING isnot'], + \ + \ ['0z11 == 0z22', 'COMPAREBLOB =='], + \ ['0z11 != 0z22', 'COMPAREBLOB !='], + \ ['0z11 is 0z22', 'COMPAREBLOB is'], + \ ['0z11 isnot 0z22', 'COMPAREBLOB isnot'], + \ + \ ['[1,2] == [3,4]', 'COMPARELIST =='], + \ ['[1,2] != [3,4]', 'COMPARELIST !='], + \ ['[1,2] is [3,4]', 'COMPARELIST is'], + \ ['[1,2] isnot [3,4]', 'COMPARELIST isnot'], + \ + \ ['#{a:1} == #{x:2}', 'COMPAREDICT =='], + \ ['#{a:1} != #{x:2}', 'COMPAREDICT !='], + \ ['#{a:1} is #{x:2}', 'COMPAREDICT is'], + \ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'], + \ + \ ['{->33} == {->44}', 'COMPAREPARTIAL =='], + \ ['{->33} != {->44}', 'COMPAREPARTIAL !='], + \ ['{->33} is {->44}', 'COMPAREPARTIAL is'], + \ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'], + \ + \ ['77 == g:xx', 'COMPAREANY =='], + \ ['77 != g:xx', 'COMPAREANY !='], + \ ['77 > g:xx', 'COMPAREANY >'], + \ ['77 < g:xx', 'COMPAREANY <'], + \ ['77 >= g:xx', 'COMPAREANY >='], + \ ['77 <= g:xx', 'COMPAREANY <='], + \ ['77 =~ g:xx', 'COMPAREANY =\~'], + \ ['77 !~ g:xx', 'COMPAREANY !\~'], + \ ['77 is g:xx', 'COMPAREANY is'], + \ ['77 isnot g:xx', 'COMPAREANY isnot'], + \ ] + if has('float') + cases->extend([ + \ ['1.1 == 2.2', 'COMPAREFLOAT =='], + \ ['1.1 != 2.2', 'COMPAREFLOAT !='], + \ ['1.1 > 2.2', 'COMPAREFLOAT >'], + \ ['1.1 < 2.2', 'COMPAREFLOAT <'], + \ ['1.1 >= 2.2', 'COMPAREFLOAT >='], + \ ['1.1 <= 2.2', 'COMPAREFLOAT <='], + \ ['1.1 =~ 2.2', 'COMPAREFLOAT =\~'], + \ ['1.1 !~ 2.2', 'COMPAREFLOAT !\~'], + \ ]) + endif + + let nr = 1 + for case in cases + writefile(['def TestCase' .. nr .. '()', + \ ' if ' .. case[0], + \ ' echo 42' + \ ' endif', + \ 'enddef'], 'Xdisassemble') + source Xdisassemble + let instr = execute('disassemble TestCase' .. nr) + assert_match('TestCase' .. nr .. '.*' + \ .. 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' + \ .. '\d \(PUSH\|FUNCREF\).*' + \ .. '\d \(PUSH\|FUNCREF\|LOADG\).*' + \ .. '\d ' .. case[1] .. '.*' + \ .. '\d JUMP_IF_FALSE -> \d\+.*' + \, instr) + + nr += 1 + endfor + + " delete('Xdisassemble') +enddef + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 1ff713126b..c0767f517b 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -478,6 +478,17 @@ def Test_expr6() assert_equal(2, g:anint % g:alsoint) assert_equal(4, 6 * 4 / 6) + + let x = [2] + let y = [3] + assert_equal(5, x[0] + y[0]) + assert_equal(6, x[0] * y[0]) + if has('float') + let xf = [2.0] + let yf = [3.0] + assert_equal(5.0, xf[0] + yf[0]) + assert_equal(6.0, xf[0] * yf[0]) + endif enddef def Test_expr6_float() @@ -538,6 +549,10 @@ func Test_expr6_fails() call CheckDefFailure("let x = #{one: 1} / #{two: 2}", 'E1036:') call CheckDefFailure("let x = #{one: 1} % #{two: 2}", 'E1035:') + call CheckDefFailure("let x = 0xff[1]", 'E714:') + if has('float') + call CheckDefFailure("let x = 0.7[1]", 'E714:') + endif endfunc func Test_expr6_float_fails() diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 1cff3b61b2..892806f39a 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -27,6 +27,9 @@ func Test_def_basic() call assert_equal('yes', SomeFunc()) endfunc +let s:appendToMe = 'xxx' +let s:addToMe = 111 + def Test_assignment() let bool1: bool = true assert_equal(v:true, bool1) @@ -44,11 +47,16 @@ def Test_assignment() let dict2: dict = #{one: 1, two: 2} v:char = 'abc' - call assert_equal('abc', v:char) + assert_equal('abc', v:char) $ENVVAR = 'foobar' - call assert_equal('foobar', $ENVVAR) + assert_equal('foobar', $ENVVAR) $ENVVAR = '' + + appendToMe ..= 'yyy' + assert_equal('xxxyyy', appendToMe) + addToMe += 222 + assert_equal(333, addToMe) enddef func Test_assignment_failure() @@ -131,6 +139,39 @@ def Test_call_varargs() assert_equal('one,two,three', MyVarargs('one', 'two', 'three')) enddef +def MyDefaultArgs(name = 'string'): string + return name +enddef + +def Test_call_default_args() + assert_equal('string', MyDefaultArgs()) + assert_equal('one', MyDefaultArgs('one')) + assert_fails('call MyDefaultArgs("one", "two")', 'E118:') +enddef + +func Test_call_default_args_from_func() + call assert_equal('string', MyDefaultArgs()) + call assert_equal('one', MyDefaultArgs('one')) + call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') +endfunc + +" Default arg and varargs +def MyDefVarargs(one: string, two = 'foo', ...rest: list): string + let res = one .. ',' .. two + for s in rest + res ..= ',' .. s + endfor + return res +enddef + +def Test_call_def_varargs() + call assert_fails('call MyDefVarargs()', 'E119:') + assert_equal('one,foo', MyDefVarargs('one')) + assert_equal('one,two', MyDefVarargs('one', 'two')) + assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) +enddef + + "def Test_call_func_defined_later() " call assert_equal('one', DefineLater('one')) " call assert_fails('call NotDefined("one")', 'E99:') @@ -140,25 +181,6 @@ func DefineLater(arg) return a:arg endfunc -def MyDefaultArgs(name = 'string'): string - return name -enddef - -func Test_call_default_args_from_func() - " TODO: implement using default value for optional argument - "call assert_equal('string', MyDefaultArgs()) - call assert_fails('call MyDefaultArgs()', 'optional arguments not implemented yet') - call assert_equal('one', MyDefaultArgs('one')) - call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') -endfunc - -def Test_call_default_args() - " TODO: implement using default value for optional argument - "assert_equal('string', MyDefaultArgs()) - assert_equal('one', MyDefaultArgs('one')) - assert_fails('call MyDefaultArgs("one", "two")', 'E118:') -enddef - def Test_return_type_wrong() CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') @@ -195,6 +217,7 @@ let s:export_script_lines =<< trim END export const CONST = 1234 export let exported = 9876 + export let exp_name = 'John' export def Exported(): string return 'Exported' enddef @@ -205,7 +228,14 @@ def Test_vim9script() vim9script import {exported, Exported} from './Xexport.vim' g:imported = exported + exported += 3 + g:imported_added = exported g:imported_func = Exported() + + import {exp_name} from './Xexport.vim' + g:imported_name = exp_name + exp_name ..= ' Doe' + g:imported_name_appended = exp_name END writefile(import_script_lines, 'Ximport.vim') @@ -216,13 +246,18 @@ def Test_vim9script() assert_equal('bobbie', g:result) assert_equal('bob', g:localname) assert_equal(9876, g:imported) + assert_equal(9879, g:imported_added) assert_equal('Exported', g:imported_func) + assert_equal('John', g:imported_name) + assert_equal('John Doe', g:imported_name_appended) assert_false(exists('g:name')) unlet g:result unlet g:localname unlet g:imported + unlet g:imported_added unlet g:imported_func + unlet g:imported_name g:imported_name_appended delete('Ximport.vim') delete('Xexport.vim') @@ -424,244 +459,22 @@ def do_something(): EOF endfunc -def HasEval() - if has('eval') - echo 'yes' +def IfElse(what: number): string + let res = '' + if what == 1 + res = "one" + elseif what == 2 + res = "two" else - echo 'no' + res = "three" endif + return res enddef -def HasNothing() - if has('nothing') - echo 'yes' - else - echo 'no' - endif -enddef - -def Test_compile_const_expr() - assert_equal("\nyes", execute('call HasEval()')) - let instr = execute('disassemble HasEval') - assert_match('PUSHS "yes"', instr) - assert_notmatch('PUSHS "no"', instr) - assert_notmatch('JUMP', instr) - - assert_equal("\nno", execute('call HasNothing()')) - instr = execute('disassemble HasNothing') - assert_notmatch('PUSHS "yes"', instr) - assert_match('PUSHS "no"', instr) - assert_notmatch('JUMP', instr) -enddef - -func NotCompiled() - echo "not" -endfunc - -let s:scriptvar = 4 -let g:globalvar = 'g' - -def s:ScriptFuncLoad(arg: string) - let local = 1 - buffers - echo arg - echo local - echo v:version - echo s:scriptvar - echo g:globalvar - echo &tabstop - echo $ENVVAR - echo @z -enddef - -def Test_disassembleLoad() - assert_fails('disass NoFunc', 'E1061:') - assert_fails('disass NotCompiled', 'E1062:') - - let res = execute('disass s:ScriptFuncLoad') - assert_match('\d*_ScriptFuncLoad.*' - \ .. 'buffers.*' - \ .. ' EXEC \+buffers.*' - \ .. ' LOAD arg\[-1\].*' - \ .. ' LOAD $0.*' - \ .. ' LOADV v:version.*' - \ .. ' LOADS s:scriptvar from .*test_vim9_script.vim.*' - \ .. ' LOADG g:globalvar.*' - \ .. ' LOADENV $ENVVAR.*' - \ .. ' LOADREG @z.*' - \, res) -enddef - -def s:ScriptFuncPush() - let localbool = true - let localspec = v:none - let localblob = 0z1234 - if has('float') - let localfloat = 1.234 - endif -enddef - -def Test_disassemblePush() - let res = execute('disass s:ScriptFuncPush') - assert_match('\d*_ScriptFuncPush.*' - \ .. 'localbool = true.*' - \ .. ' PUSH v:true.*' - \ .. 'localspec = v:none.*' - \ .. ' PUSH v:none.*' - \ .. 'localblob = 0z1234.*' - \ .. ' PUSHBLOB 0z1234.*' - \, res) - if has('float') - assert_match('\d*_ScriptFuncPush.*' - \ .. 'localfloat = 1.234.*' - \ .. ' PUSHF 1.234.*' - \, res) - endif -enddef - -def s:ScriptFuncStore() - let localnr = 1 - localnr = 2 - let localstr = 'abc' - localstr = 'xyz' - v:char = 'abc' - s:scriptvar = 'sv' - g:globalvar = 'gv' - &tabstop = 8 - $ENVVAR = 'ev' - @z = 'rv' -enddef - -def Test_disassembleStore() - let res = execute('disass s:ScriptFuncStore') - assert_match('\d*_ScriptFuncStore.*' - \ .. 'localnr = 2.*' - \ .. ' STORE 2 in $0.*' - \ .. 'localstr = ''xyz''.*' - \ .. ' STORE $1.*' - \ .. 'v:char = ''abc''.*' - \ .. 'STOREV v:char.*' - \ .. 's:scriptvar = ''sv''.*' - \ .. ' STORES s:scriptvar in .*test_vim9_script.vim.*' - \ .. 'g:globalvar = ''gv''.*' - \ .. ' STOREG g:globalvar.*' - \ .. '&tabstop = 8.*' - \ .. ' STOREOPT &tabstop.*' - \ .. '$ENVVAR = ''ev''.*' - \ .. ' STOREENV $ENVVAR.*' - \ .. '@z = ''rv''.*' - \ .. ' STOREREG @z.*' - \, res) -enddef - -def s:ScriptFuncTry() - try - echo 'yes' - catch /fail/ - echo 'no' - finally - echo 'end' - endtry -enddef - -def Test_disassembleTry() - let res = execute('disass s:ScriptFuncTry') - assert_match('\d*_ScriptFuncTry.*' - \ .. 'try.*' - \ .. 'TRY catch -> \d\+, finally -> \d\+.*' - \ .. 'catch /fail/.*' - \ .. ' JUMP -> \d\+.*' - \ .. ' PUSH v:exception.*' - \ .. ' PUSHS "fail".*' - \ .. ' COMPARESTRING =\~.*' - \ .. ' JUMP_IF_FALSE -> \d\+.*' - \ .. ' CATCH.*' - \ .. 'finally.*' - \ .. ' PUSHS "end".*' - \ .. 'endtry.*' - \ .. ' ENDTRY.*' - \, res) -enddef - -def s:ScriptFuncNew() - let ll = [1, "two", 333] - let dd = #{one: 1, two: "val"} -enddef - -def Test_disassembleNew() - let res = execute('disass s:ScriptFuncNew') - assert_match('\d*_ScriptFuncNew.*' - \ .. 'let ll = \[1, "two", 333].*' - \ .. 'PUSHNR 1.*' - \ .. 'PUSHS "two".*' - \ .. 'PUSHNR 333.*' - \ .. 'NEWLIST size 3.*' - \ .. 'let dd = #{one: 1, two: "val"}.*' - \ .. 'PUSHS "one".*' - \ .. 'PUSHNR 1.*' - \ .. 'PUSHS "two".*' - \ .. 'PUSHS "val".*' - \ .. 'NEWDICT size 2.*' - \, res) -enddef - -def FuncWithArg(arg) - echo arg -enddef - -func UserFunc() - echo 'nothing' -endfunc - -func UserFuncWithArg(arg) - echo a:arg -endfunc - -def s:ScriptFuncCall(): string - changenr() - char2nr("abc") - Test_disassembleNew() - FuncWithArg(343) - UserFunc() - UserFuncWithArg("foo") - let FuncRef = function("UserFunc") - FuncRef() - let FuncRefWithArg = function("UserFuncWithArg") - FuncRefWithArg("bar") - return "yes" -enddef - -def Test_disassembleCall() - let res = execute('disass s:ScriptFuncCall') - assert_match('\d*_ScriptFuncCall.*' - \ .. 'changenr().*' - \ .. ' BCALL changenr(argc 0).*' - \ .. 'char2nr("abc").*' - \ .. ' PUSHS "abc".*' - \ .. ' BCALL char2nr(argc 1).*' - \ .. 'Test_disassembleNew().*' - \ .. ' DCALL Test_disassembleNew(argc 0).*' - \ .. 'FuncWithArg(343).*' - \ .. ' PUSHNR 343.*' - \ .. ' DCALL FuncWithArg(argc 1).*' - \ .. 'UserFunc().*' - \ .. ' UCALL UserFunc(argc 0).*' - \ .. 'UserFuncWithArg("foo").*' - \ .. ' PUSHS "foo".*' - \ .. ' UCALL UserFuncWithArg(argc 1).*' - \ .. 'let FuncRef = function("UserFunc").*' - \ .. 'FuncRef().*' - \ .. ' LOAD $\d.*' - \ .. ' PCALL (argc 0).*' - \ .. 'let FuncRefWithArg = function("UserFuncWithArg").*' - \ .. 'FuncRefWithArg("bar").*' - \ .. ' PUSHS "bar".*' - \ .. ' LOAD $\d.*' - \ .. ' PCALL (argc 1).*' - \ .. 'return "yes".*' - \ .. ' PUSHS "yes".*' - \ .. ' RETURN.*' - \, res) +def Test_if_elseif_else() + assert_equal('one', IfElse(1)) + assert_equal('two', IfElse(2)) + assert_equal('three', IfElse(3)) enddef diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index d7a3fe23f3..b16b05b02c 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1416,10 +1416,6 @@ endfunc "------------------------------------------------------------------------------- func Test_num64() - if !has('num64') - return - endif - call assert_notequal( 4294967296, 0) call assert_notequal(-4294967296, 0) call assert_equal( 4294967296, 0xFFFFffff + 1) @@ -1692,27 +1688,15 @@ func Test_compound_assignment_operators() " Test special cases: division or modulus with 0. let x = 1 let x /= 0 - if has('num64') - call assert_equal(0x7FFFFFFFFFFFFFFF, x) - else - call assert_equal(0x7fffffff, x) - endif + call assert_equal(0x7FFFFFFFFFFFFFFF, x) let x = -1 let x /= 0 - if has('num64') - call assert_equal(-0x7FFFFFFFFFFFFFFF, x) - else - call assert_equal(-0x7fffffff, x) - endif + call assert_equal(-0x7FFFFFFFFFFFFFFF, x) let x = 0 let x /= 0 - if has('num64') - call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x) - else - call assert_equal(-0x7FFFFFFF - 1, x) - endif + call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x) let x = 1 let x %= 0 @@ -1975,6 +1959,102 @@ func Test_function_defined_line() call delete('Xtest.vim') endfunc +" Test for missing :endif, :endfor, :endwhile and :endtry {{{1 +func Test_missing_end() + call writefile(['if 2 > 1', 'echo ">"'], 'Xscript') + call assert_fails('source Xscript', 'E171:') + call writefile(['for i in range(5)', 'echo i'], 'Xscript') + call assert_fails('source Xscript', 'E170:') + call writefile(['while v:true', 'echo "."'], 'Xscript') + call assert_fails('source Xscript', 'E170:') + call writefile(['try', 'echo "."'], 'Xscript') + call assert_fails('source Xscript', 'E600:') + call delete('Xscript') +endfunc + +" Test for deep nesting of if/for/while/try statements {{{1 +func Test_deep_nest() + if !CanRunVimInTerminal() + throw 'Skipped: cannot run vim in terminal' + endif + + let lines =<< trim [SCRIPT] + " Deep nesting of if ... endif + func Test1() + let @a = join(repeat(['if v:true'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endif'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of for ... endfor + func Test2() + let @a = join(repeat(['for i in [1]'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endfor'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of while ... endwhile + func Test3() + let @a = join(repeat(['while v:true'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endwhile'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of try ... endtry + func Test4() + let @a = join(repeat(['try'], 51), "\n") + let @a ..= "\necho v:true\n" + let @a ..= join(repeat(['endtry'], 51), "\n") + @a + let @a = '' + endfunc + [SCRIPT] + call writefile(lines, 'Xscript') + + let buf = RunVimInTerminal('-S Xscript', {'rows': 6}) + + " Deep nesting of if ... endif + call term_sendkeys(buf, ":call Test1()\n") + call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))}) + + " Deep nesting of for ... endfor + call term_sendkeys(buf, ":call Test2()\n") + call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))}) + + " Deep nesting of while ... endwhile + call term_sendkeys(buf, ":call Test3()\n") + call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))}) + + " Deep nesting of try ... endtry + call term_sendkeys(buf, ":call Test4()\n") + call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))}) + + "let l = '' + "for i in range(1, 6) + " let l ..= term_getline(buf, i) . "\n" + "endfor + "call assert_report(l) + + call StopVimInTerminal(buf) + call delete('Xscript') +endfunc + +" Test for , in a function {{{1 +func Test_sfile_in_function() + func Xfunc() + call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('')) + call assert_equal('2', expand('')) + endfunc + call Xfunc() + delfunc Xfunc +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index ae281238e9..601ad0fbe2 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -894,4 +894,18 @@ func Test_block_insert_replace_tabs() bwipe! endfunc +" Test for * register in : +func Test_star_register() + call assert_fails('*bfirst', 'E16:') + new + call setline(1, ['foo', 'bar', 'baz', 'qux']) + exe "normal jVj\" + *yank r + call assert_equal("bar\nbaz\n", @r) + + delmarks < > + call assert_fails('*yank', 'E20:') + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index cbd08c9741..362b0eb02a 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -940,6 +940,29 @@ func Test_window_only() new call assert_fails('only', 'E445:') only! + " Test for :only with a count + let wid = win_getid() + new + new + 3only + call assert_equal(1, winnr('$')) + call assert_equal(wid, win_getid()) + call assert_fails('close', 'E444:') + call assert_fails('%close', 'E16:') +endfunc + +" Test for errors with :wincmd +func Test_wincmd_errors() + call assert_fails('wincmd g', 'E474:') + call assert_fails('wincmd ab', 'E474:') +endfunc + +" Test for errors with :winpos +func Test_winpos_errors() + if !has("gui_running") && !has('win32') + call assert_fails('winpos', 'E188:') + endif + call assert_fails('winpos 10', 'E466:') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim index 98a06eb011..5449071229 100644 --- a/src/testdir/test_writefile.vim +++ b/src/testdir/test_writefile.vim @@ -214,6 +214,8 @@ func Test_write_errors() call assert_fails('1,2write', 'E140:') close! + call assert_fails('w > Xtest', 'E494:') + " Try to overwrite a directory if has('unix') call mkdir('Xdir1') diff --git a/src/testing.c b/src/testing.c index c2b382b8b6..5dacf073b3 100644 --- a/src/testing.c +++ b/src/testing.c @@ -631,19 +631,6 @@ f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED) #endif } -/* - * "test_clear_search_pat()" - * Free the last search and substitute patterns - */ - void -f_test_clear_search_pat(typval_T *argvars UNUSED, typval_T *rettv UNUSED) -{ - free_last_pat(RE_SUBST); - free_last_pat(RE_SEARCH); - set_old_sub(NULL); - free_regexp_prev_sub(); -} - /* * "test_feedinput()" */ diff --git a/src/time.c b/src/time.c new file mode 100644 index 0000000000..2706ac22da --- /dev/null +++ b/src/time.c @@ -0,0 +1,1041 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * time.c: functions related to time and timers + */ + +#include "vim.h" + +/* + * Cache of the current timezone name as retrieved from TZ, or an empty string + * where unset, up to 64 octets long including trailing null byte. + */ +#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET) +static char tz_cache[64]; +#endif + +/* + * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the + * latter version preferred for reentrancy. + * + * If we use localtime_r(3) and we have tzset(3) available, check to see if the + * environment variable TZ has changed since the last run, and call tzset(3) to + * update the global timezone variables if it has. This is because the POSIX + * standard doesn't require localtime_r(3) implementations to do that as it + * does with localtime(3), and we don't want to call tzset(3) every time. + */ + static struct tm * +vim_localtime( + const time_t *timep, // timestamp for local representation + struct tm *result UNUSED) // pointer to caller return buffer +{ +#ifdef HAVE_LOCALTIME_R +# ifdef HAVE_TZSET + char *tz; // pointer for TZ environment var + + tz = (char *)mch_getenv((char_u *)"TZ"); + if (tz == NULL) + tz = ""; + if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0) + { + tzset(); + vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1); + } +# endif // HAVE_TZSET + return localtime_r(timep, result); +#else + return localtime(timep); +#endif // HAVE_LOCALTIME_R +} + +/* + * Return the current time in seconds. Calls time(), unless test_settime() + * was used. + */ + time_T +vim_time(void) +{ +# ifdef FEAT_EVAL + return time_for_testing == 0 ? time(NULL) : time_for_testing; +# else + return time(NULL); +# endif +} + +/* + * Replacement for ctime(), which is not safe to use. + * Requires strftime(), otherwise returns "(unknown)". + * If "thetime" is invalid returns "(invalid)". Never returns NULL. + * When "add_newline" is TRUE add a newline like ctime() does. + * Uses a static buffer. + */ + char * +get_ctime(time_t thetime, int add_newline) +{ + static char buf[50]; +#ifdef HAVE_STRFTIME + struct tm tmval; + struct tm *curtime; + + curtime = vim_localtime(&thetime, &tmval); + // MSVC returns NULL for an invalid value of seconds. + if (curtime == NULL) + vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1); + else + { + (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"), + curtime); +# ifdef MSWIN + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + { + char_u *to_free = NULL; + int len; + + acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len); + if (to_free != NULL) + { + STRCPY(buf, to_free); + vim_free(to_free); + } + } +# endif + } +#else + STRCPY(buf, "(unknown)"); +#endif + if (add_newline) + STRCAT(buf, "\n"); + return buf; +} + +#if defined(FEAT_EVAL) || defined(PROTO) + +#if defined(MACOS_X) +# include // for time_t +#endif + +/* + * "localtime()" function + */ + void +f_localtime(typval_T *argvars UNUSED, typval_T *rettv) +{ + rettv->vval.v_number = (varnumber_T)time(NULL); +} + +# if defined(FEAT_RELTIME) +/* + * Convert a List to proftime_T. + * Return FAIL when there is something wrong. + */ + static int +list2proftime(typval_T *arg, proftime_T *tm) +{ + long n1, n2; + int error = FALSE; + + if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL + || arg->vval.v_list->lv_len != 2) + return FAIL; + n1 = list_find_nr(arg->vval.v_list, 0L, &error); + n2 = list_find_nr(arg->vval.v_list, 1L, &error); +# ifdef MSWIN + tm->HighPart = n1; + tm->LowPart = n2; +# else + tm->tv_sec = n1; + tm->tv_usec = n2; +# endif + return error ? FAIL : OK; +} +# endif // FEAT_RELTIME + +/* + * "reltime()" function + */ + void +f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ +# ifdef FEAT_RELTIME + proftime_T res; + proftime_T start; + + if (argvars[0].v_type == VAR_UNKNOWN) + { + // No arguments: get current time. + profile_start(&res); + } + else if (argvars[1].v_type == VAR_UNKNOWN) + { + if (list2proftime(&argvars[0], &res) == FAIL) + return; + profile_end(&res); + } + else + { + // Two arguments: compute the difference. + if (list2proftime(&argvars[0], &start) == FAIL + || list2proftime(&argvars[1], &res) == FAIL) + return; + profile_sub(&res, &start); + } + + if (rettv_list_alloc(rettv) == OK) + { + long n1, n2; + +# ifdef MSWIN + n1 = res.HighPart; + n2 = res.LowPart; +# else + n1 = res.tv_sec; + n2 = res.tv_usec; +# endif + list_append_number(rettv->vval.v_list, (varnumber_T)n1); + list_append_number(rettv->vval.v_list, (varnumber_T)n2); + } +# endif +} + +# ifdef FEAT_FLOAT +/* + * "reltimefloat()" function + */ + void +f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv) +{ +# ifdef FEAT_RELTIME + proftime_T tm; +# endif + + rettv->v_type = VAR_FLOAT; + rettv->vval.v_float = 0; +# ifdef FEAT_RELTIME + if (list2proftime(&argvars[0], &tm) == OK) + rettv->vval.v_float = profile_float(&tm); +# endif +} +# endif + +/* + * "reltimestr()" function + */ + void +f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv) +{ +# ifdef FEAT_RELTIME + proftime_T tm; +# endif + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; +# ifdef FEAT_RELTIME + if (list2proftime(&argvars[0], &tm) == OK) + rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); +# endif +} + +# if defined(HAVE_STRFTIME) || defined(PROTO) +/* + * "strftime({format}[, {time}])" function + */ + void +f_strftime(typval_T *argvars, typval_T *rettv) +{ + char_u result_buf[256]; + struct tm tmval; + struct tm *curtime; + time_t seconds; + char_u *p; + + rettv->v_type = VAR_STRING; + + p = tv_get_string(&argvars[0]); + if (argvars[1].v_type == VAR_UNKNOWN) + seconds = time(NULL); + else + seconds = (time_t)tv_get_number(&argvars[1]); + curtime = vim_localtime(&seconds, &tmval); + // MSVC returns NULL for an invalid value of seconds. + if (curtime == NULL) + rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); + else + { + vimconv_T conv; + char_u *enc; + + conv.vc_type = CONV_NONE; + enc = enc_locale(); + convert_setup(&conv, p_enc, enc); + if (conv.vc_type != CONV_NONE) + p = string_convert(&conv, p, NULL); + if (p != NULL) + (void)strftime((char *)result_buf, sizeof(result_buf), + (char *)p, curtime); + else + result_buf[0] = NUL; + + if (conv.vc_type != CONV_NONE) + vim_free(p); + convert_setup(&conv, enc, p_enc); + if (conv.vc_type != CONV_NONE) + rettv->vval.v_string = string_convert(&conv, result_buf, NULL); + else + rettv->vval.v_string = vim_strsave(result_buf); + + // Release conversion descriptors + convert_setup(&conv, NULL, NULL); + vim_free(enc); + } +} +# endif + +# if defined(HAVE_STRPTIME) || defined(PROTO) +/* + * "strptime({format}, {timestring})" function + */ + void +f_strptime(typval_T *argvars, typval_T *rettv) +{ + struct tm tmval; + char_u *fmt; + char_u *str; + vimconv_T conv; + char_u *enc; + + vim_memset(&tmval, NUL, sizeof(tmval)); + fmt = tv_get_string(&argvars[0]); + str = tv_get_string(&argvars[1]); + + conv.vc_type = CONV_NONE; + enc = enc_locale(); + convert_setup(&conv, p_enc, enc); + if (conv.vc_type != CONV_NONE) + fmt = string_convert(&conv, fmt, NULL); + if (fmt == NULL + || strptime((char *)str, (char *)fmt, &tmval) == NULL + || (rettv->vval.v_number = mktime(&tmval)) == -1) + rettv->vval.v_number = 0; + + if (conv.vc_type != CONV_NONE) + vim_free(fmt); + convert_setup(&conv, NULL, NULL); + vim_free(enc); +} +# endif + +# if defined(FEAT_TIMERS) || defined(PROTO) +static timer_T *first_timer = NULL; +static long last_timer_id = 0; + +/* + * Return time left until "due". Negative if past "due". + */ + long +proftime_time_left(proftime_T *due, proftime_T *now) +{ +# ifdef MSWIN + LARGE_INTEGER fr; + + if (now->QuadPart > due->QuadPart) + return 0; + QueryPerformanceFrequency(&fr); + return (long)(((double)(due->QuadPart - now->QuadPart) + / (double)fr.QuadPart) * 1000); +# else + if (now->tv_sec > due->tv_sec) + return 0; + return (due->tv_sec - now->tv_sec) * 1000 + + (due->tv_usec - now->tv_usec) / 1000; +# endif +} + +/* + * Insert a timer in the list of timers. + */ + static void +insert_timer(timer_T *timer) +{ + timer->tr_next = first_timer; + timer->tr_prev = NULL; + if (first_timer != NULL) + first_timer->tr_prev = timer; + first_timer = timer; + did_add_timer = TRUE; +} + +/* + * Take a timer out of the list of timers. + */ + static void +remove_timer(timer_T *timer) +{ + if (timer->tr_prev == NULL) + first_timer = timer->tr_next; + else + timer->tr_prev->tr_next = timer->tr_next; + if (timer->tr_next != NULL) + timer->tr_next->tr_prev = timer->tr_prev; +} + + static void +free_timer(timer_T *timer) +{ + free_callback(&timer->tr_callback); + vim_free(timer); +} + +/* + * Create a timer and return it. NULL if out of memory. + * Caller should set the callback. + */ + timer_T * +create_timer(long msec, int repeat) +{ + timer_T *timer = ALLOC_CLEAR_ONE(timer_T); + long prev_id = last_timer_id; + + if (timer == NULL) + return NULL; + if (++last_timer_id <= prev_id) + // Overflow! Might cause duplicates... + last_timer_id = 0; + timer->tr_id = last_timer_id; + insert_timer(timer); + if (repeat != 0) + timer->tr_repeat = repeat - 1; + timer->tr_interval = msec; + + profile_setlimit(msec, &timer->tr_due); + return timer; +} + +/* + * Invoke the callback of "timer". + */ + static void +timer_callback(timer_T *timer) +{ + typval_T rettv; + typval_T argv[2]; + + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = (varnumber_T)timer->tr_id; + argv[1].v_type = VAR_UNKNOWN; + + call_callback(&timer->tr_callback, -1, &rettv, 1, argv); + clear_tv(&rettv); +} + +/* + * Call timers that are due. + * Return the time in msec until the next timer is due. + * Returns -1 if there are no pending timers. + */ + long +check_due_timer(void) +{ + timer_T *timer; + timer_T *timer_next; + long this_due; + long next_due = -1; + proftime_T now; + int did_one = FALSE; + int need_update_screen = FALSE; + long current_id = last_timer_id; + + // Don't run any timers while exiting or dealing with an error. + if (exiting || aborting()) + return next_due; + + profile_start(&now); + for (timer = first_timer; timer != NULL && !got_int; timer = timer_next) + { + timer_next = timer->tr_next; + + if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused) + continue; + this_due = proftime_time_left(&timer->tr_due, &now); + if (this_due <= 1) + { + // Save and restore a lot of flags, because the timer fires while + // waiting for a character, which might be halfway a command. + int save_timer_busy = timer_busy; + int save_vgetc_busy = vgetc_busy; + int save_did_emsg = did_emsg; + int save_called_emsg = called_emsg; + int save_must_redraw = must_redraw; + int save_trylevel = trylevel; + int save_did_throw = did_throw; + int save_ex_pressedreturn = get_pressedreturn(); + int save_may_garbage_collect = may_garbage_collect; + except_T *save_current_exception = current_exception; + vimvars_save_T vvsave; + + // Create a scope for running the timer callback, ignoring most of + // the current scope, such as being inside a try/catch. + timer_busy = timer_busy > 0 || vgetc_busy > 0; + vgetc_busy = 0; + called_emsg = 0; + did_emsg = FALSE; + did_uncaught_emsg = FALSE; + must_redraw = 0; + trylevel = 0; + did_throw = FALSE; + current_exception = NULL; + may_garbage_collect = FALSE; + save_vimvars(&vvsave); + + timer->tr_firing = TRUE; + timer_callback(timer); + timer->tr_firing = FALSE; + + timer_next = timer->tr_next; + did_one = TRUE; + timer_busy = save_timer_busy; + vgetc_busy = save_vgetc_busy; + if (did_uncaught_emsg) + ++timer->tr_emsg_count; + did_emsg = save_did_emsg; + called_emsg = save_called_emsg; + trylevel = save_trylevel; + did_throw = save_did_throw; + current_exception = save_current_exception; + restore_vimvars(&vvsave); + if (must_redraw != 0) + need_update_screen = TRUE; + must_redraw = must_redraw > save_must_redraw + ? must_redraw : save_must_redraw; + set_pressedreturn(save_ex_pressedreturn); + may_garbage_collect = save_may_garbage_collect; + + // Only fire the timer again if it repeats and stop_timer() wasn't + // called while inside the callback (tr_id == -1). + if (timer->tr_repeat != 0 && timer->tr_id != -1 + && timer->tr_emsg_count < 3) + { + profile_setlimit(timer->tr_interval, &timer->tr_due); + this_due = proftime_time_left(&timer->tr_due, &now); + if (this_due < 1) + this_due = 1; + if (timer->tr_repeat > 0) + --timer->tr_repeat; + } + else + { + this_due = -1; + remove_timer(timer); + free_timer(timer); + } + } + if (this_due > 0 && (next_due == -1 || next_due > this_due)) + next_due = this_due; + } + + if (did_one) + redraw_after_callback(need_update_screen); + +#ifdef FEAT_BEVAL_TERM + if (bevalexpr_due_set) + { + this_due = proftime_time_left(&bevalexpr_due, &now); + if (this_due <= 1) + { + bevalexpr_due_set = FALSE; + if (balloonEval == NULL) + { + balloonEval = ALLOC_CLEAR_ONE(BalloonEval); + balloonEvalForTerm = TRUE; + } + if (balloonEval != NULL) + { + general_beval_cb(balloonEval, 0); + setcursor(); + out_flush(); + } + } + else if (next_due == -1 || next_due > this_due) + next_due = this_due; + } +#endif +#ifdef FEAT_TERMINAL + // Some terminal windows may need their buffer updated. + next_due = term_check_timers(next_due, &now); +#endif + + return current_id != last_timer_id ? 1 : next_due; +} + +/* + * Find a timer by ID. Returns NULL if not found; + */ + static timer_T * +find_timer(long id) +{ + timer_T *timer; + + if (id >= 0) + { + for (timer = first_timer; timer != NULL; timer = timer->tr_next) + if (timer->tr_id == id) + return timer; + } + return NULL; +} + + +/* + * Stop a timer and delete it. + */ + void +stop_timer(timer_T *timer) +{ + if (timer->tr_firing) + // Free the timer after the callback returns. + timer->tr_id = -1; + else + { + remove_timer(timer); + free_timer(timer); + } +} + + static void +stop_all_timers(void) +{ + timer_T *timer; + timer_T *timer_next; + + for (timer = first_timer; timer != NULL; timer = timer_next) + { + timer_next = timer->tr_next; + stop_timer(timer); + } +} + + static void +add_timer_info(typval_T *rettv, timer_T *timer) +{ + list_T *list = rettv->vval.v_list; + dict_T *dict = dict_alloc(); + dictitem_T *di; + long remaining; + proftime_T now; + + if (dict == NULL) + return; + list_append_dict(list, dict); + + dict_add_number(dict, "id", timer->tr_id); + dict_add_number(dict, "time", (long)timer->tr_interval); + + profile_start(&now); + remaining = proftime_time_left(&timer->tr_due, &now); + dict_add_number(dict, "remaining", (long)remaining); + + dict_add_number(dict, "repeat", + (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1)); + dict_add_number(dict, "paused", (long)(timer->tr_paused)); + + di = dictitem_alloc((char_u *)"callback"); + if (di != NULL) + { + if (dict_add(dict, di) == FAIL) + vim_free(di); + else + put_callback(&timer->tr_callback, &di->di_tv); + } +} + + static void +add_timer_info_all(typval_T *rettv) +{ + timer_T *timer; + + for (timer = first_timer; timer != NULL; timer = timer->tr_next) + if (timer->tr_id != -1) + add_timer_info(rettv, timer); +} + +/* + * Mark references in partials of timers. + */ + int +set_ref_in_timer(int copyID) +{ + int abort = FALSE; + timer_T *timer; + typval_T tv; + + for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next) + { + if (timer->tr_callback.cb_partial != NULL) + { + tv.v_type = VAR_PARTIAL; + tv.vval.v_partial = timer->tr_callback.cb_partial; + } + else + { + tv.v_type = VAR_FUNC; + tv.vval.v_string = timer->tr_callback.cb_name; + } + abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL); + } + return abort; +} + +# if defined(EXITFREE) || defined(PROTO) + void +timer_free_all() +{ + timer_T *timer; + + while (first_timer != NULL) + { + timer = first_timer; + remove_timer(timer); + free_timer(timer); + } +} +# endif + +/* + * "timer_info([timer])" function + */ + void +f_timer_info(typval_T *argvars, typval_T *rettv) +{ + timer_T *timer = NULL; + + if (rettv_list_alloc(rettv) != OK) + return; + if (argvars[0].v_type != VAR_UNKNOWN) + { + if (argvars[0].v_type != VAR_NUMBER) + emsg(_(e_number_exp)); + else + { + timer = find_timer((int)tv_get_number(&argvars[0])); + if (timer != NULL) + add_timer_info(rettv, timer); + } + } + else + add_timer_info_all(rettv); +} + +/* + * "timer_pause(timer, paused)" function + */ + void +f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED) +{ + timer_T *timer = NULL; + int paused = (int)tv_get_number(&argvars[1]); + + if (argvars[0].v_type != VAR_NUMBER) + emsg(_(e_number_exp)); + else + { + timer = find_timer((int)tv_get_number(&argvars[0])); + if (timer != NULL) + timer->tr_paused = paused; + } +} + +/* + * "timer_start(time, callback [, options])" function + */ + void +f_timer_start(typval_T *argvars, typval_T *rettv) +{ + long msec = (long)tv_get_number(&argvars[0]); + timer_T *timer; + int repeat = 0; + callback_T callback; + dict_T *dict; + + rettv->vval.v_number = -1; + if (check_secure()) + return; + if (argvars[2].v_type != VAR_UNKNOWN) + { + if (argvars[2].v_type != VAR_DICT + || (dict = argvars[2].vval.v_dict) == NULL) + { + semsg(_(e_invarg2), tv_get_string(&argvars[2])); + return; + } + if (dict_find(dict, (char_u *)"repeat", -1) != NULL) + repeat = dict_get_number(dict, (char_u *)"repeat"); + } + + callback = get_callback(&argvars[1]); + if (callback.cb_name == NULL) + return; + + timer = create_timer(msec, repeat); + if (timer == NULL) + free_callback(&callback); + else + { + set_callback(&timer->tr_callback, &callback); + rettv->vval.v_number = (varnumber_T)timer->tr_id; + } +} + +/* + * "timer_stop(timer)" function + */ + void +f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED) +{ + timer_T *timer; + + if (argvars[0].v_type != VAR_NUMBER) + { + emsg(_(e_number_exp)); + return; + } + timer = find_timer((int)tv_get_number(&argvars[0])); + if (timer != NULL) + stop_timer(timer); +} + +/* + * "timer_stopall()" function + */ + void +f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +{ + stop_all_timers(); +} + +# endif // FEAT_TIMERS + +# if defined(STARTUPTIME) || defined(PROTO) +static struct timeval prev_timeval; + +# ifdef MSWIN +/* + * Windows doesn't have gettimeofday(), although it does have struct timeval. + */ + static int +gettimeofday(struct timeval *tv, char *dummy UNUSED) +{ + long t = clock(); + tv->tv_sec = t / CLOCKS_PER_SEC; + tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC; + return 0; +} +# endif + +/* + * Save the previous time before doing something that could nest. + * set "*tv_rel" to the time elapsed so far. + */ + void +time_push(void *tv_rel, void *tv_start) +{ + *((struct timeval *)tv_rel) = prev_timeval; + gettimeofday(&prev_timeval, NULL); + ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec + - ((struct timeval *)tv_rel)->tv_usec; + ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec + - ((struct timeval *)tv_rel)->tv_sec; + if (((struct timeval *)tv_rel)->tv_usec < 0) + { + ((struct timeval *)tv_rel)->tv_usec += 1000000; + --((struct timeval *)tv_rel)->tv_sec; + } + *(struct timeval *)tv_start = prev_timeval; +} + +/* + * Compute the previous time after doing something that could nest. + * Subtract "*tp" from prev_timeval; + * Note: The arguments are (void *) to avoid trouble with systems that don't + * have struct timeval. + */ + void +time_pop( + void *tp) // actually (struct timeval *) +{ + prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec; + prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec; + if (prev_timeval.tv_usec < 0) + { + prev_timeval.tv_usec += 1000000; + --prev_timeval.tv_sec; + } +} + + static void +time_diff(struct timeval *then, struct timeval *now) +{ + long usec; + long msec; + + usec = now->tv_usec - then->tv_usec; + msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L, + usec = usec % 1000L; + fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L); +} + + void +time_msg( + char *mesg, + void *tv_start) // only for do_source: start time; actually + // (struct timeval *) +{ + static struct timeval start; + struct timeval now; + + if (time_fd != NULL) + { + if (strstr(mesg, "STARTING") != NULL) + { + gettimeofday(&start, NULL); + prev_timeval = start; + fprintf(time_fd, "\n\ntimes in msec\n"); + fprintf(time_fd, " clock self+sourced self: sourced script\n"); + fprintf(time_fd, " clock elapsed: other lines\n\n"); + } + gettimeofday(&now, NULL); + time_diff(&start, &now); + if (((struct timeval *)tv_start) != NULL) + { + fprintf(time_fd, " "); + time_diff(((struct timeval *)tv_start), &now); + } + fprintf(time_fd, " "); + time_diff(&prev_timeval, &now); + prev_timeval = now; + fprintf(time_fd, ": %s\n", mesg); + } +} +# endif // STARTUPTIME +#endif // FEAT_EVAL + +#if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO) +/* + * Read 8 bytes from "fd" and turn them into a time_T, MSB first. + * Returns -1 when encountering EOF. + */ + time_T +get8ctime(FILE *fd) +{ + int c; + time_T n = 0; + int i; + + for (i = 0; i < 8; ++i) + { + c = getc(fd); + if (c == EOF) return -1; + n = (n << 8) + c; + } + return n; +} + +#ifdef _MSC_VER +# if (_MSC_VER <= 1200) +// This line is required for VC6 without the service pack. Also see the +// matching #pragma below. + # pragma optimize("", off) +# endif +#endif + +/* + * Write time_T to file "fd" in 8 bytes. + * Returns FAIL when the write failed. + */ + int +put_time(FILE *fd, time_T the_time) +{ + char_u buf[8]; + + time_to_bytes(the_time, buf); + return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL; +} + +/* + * Write time_T to "buf[8]". + */ + void +time_to_bytes(time_T the_time, char_u *buf) +{ + int c; + int i; + int bi = 0; + time_T wtime = the_time; + + // time_T can be up to 8 bytes in size, more than long_u, thus we + // can't use put_bytes() here. + // Another problem is that ">>" may do an arithmetic shift that keeps the + // sign. This happens for large values of wtime. A cast to long_u may + // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes, + // it's safe to assume that long_u is 4 bytes or more and when using 8 + // bytes the top bit won't be set. + for (i = 7; i >= 0; --i) + { + if (i + 1 > (int)sizeof(time_T)) + // ">>" doesn't work well when shifting more bits than avail + buf[bi++] = 0; + else + { +#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4 + c = (int)(wtime >> (i * 8)); +#else + c = (int)((long_u)wtime >> (i * 8)); +#endif + buf[bi++] = c; + } + } +} + +#ifdef _MSC_VER +# if (_MSC_VER <= 1200) + # pragma optimize("", on) +# endif +#endif + +#endif + +/* + * Put timestamp "tt" in "buf[buflen]" in a nice format. + */ + void +add_time(char_u *buf, size_t buflen, time_t tt) +{ +#ifdef HAVE_STRFTIME + struct tm tmval; + struct tm *curtime; + + if (vim_time() - tt >= 100) + { + curtime = vim_localtime(&tt, &tmval); + if (vim_time() - tt < (60L * 60L * 12L)) + // within 12 hours + (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime); + else + // longer ago + (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime); + } + else +#endif + { + long seconds = (long)(vim_time() - tt); + + vim_snprintf((char *)buf, buflen, + NGETTEXT("%ld second ago", "%ld seconds ago", seconds), + seconds); + } +} diff --git a/src/uninstall.c b/src/uninstall.c index b2a20cded8..e9a9aac327 100644 --- a/src/uninstall.c +++ b/src/uninstall.c @@ -200,8 +200,7 @@ batfile_thisversion(char *path) { FILE *fd; char line[BUFSIZE]; - char *p; - int ver_len = strlen(VIM_VERSION_NODOT); + int key_len = strlen(VIMBAT_UNINSTKEY); int found = FALSE; fd = fopen(path, "r"); @@ -209,17 +208,11 @@ batfile_thisversion(char *path) { while (fgets(line, sizeof(line), fd) != NULL) { - for (p = line; *p != 0; ++p) - // don't accept "vim60an" when looking for "vim60". - if (strnicmp(p, VIM_VERSION_NODOT, ver_len) == 0 - && !isdigit(p[ver_len]) - && !isalpha(p[ver_len])) - { - found = TRUE; - break; - } - if (found) + if (strncmp(line, VIMBAT_UNINSTKEY, key_len) == 0) + { + found = TRUE; break; + } } fclose(fd); } @@ -233,6 +226,10 @@ remove_batfiles(int doit) int i; int found = 0; + // avoid looking in the "installdir" by chdir to system root + mch_chdir(sysdrive); + mch_chdir("\\"); + for (i = 1; i < TARGET_COUNT; ++i) { batfile_path = searchpath_save(targets[i].batname); @@ -249,6 +246,8 @@ remove_batfiles(int doit) free(batfile_path); } } + + mch_chdir(installdir); return found; } diff --git a/src/userfunc.c b/src/userfunc.c index ef1d42d12b..fc2161f51d 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -200,6 +200,7 @@ get_function_args( { typval_T rettv; + // find the end of the expression (doesn't evaluate it) any_default = TRUE; p = skipwhite(p) + 1; p = skipwhite(p); @@ -572,8 +573,6 @@ get_func_tv( return ret; } -#define FLEN_FIXED 40 - /* * Return TRUE if "p" starts with "" or "s:". * Only works if eval_fname_script() returned non-zero for "p"! @@ -590,7 +589,7 @@ eval_fname_sid(char_u *p) * Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory * (slow). */ - static char_u * + char_u * fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { int llen; @@ -3555,13 +3554,17 @@ ex_call(exarg_T *eap) if (eap->skip) --emsg_skip; - if (!failed) + // When inside :try we need to check for following "| catch". + if (!failed || eap->cstack->cs_trylevel > 0) { // Check for trailing illegal characters and a following command. if (!ends_excmd(*arg)) { - emsg_severe = TRUE; - emsg(_(e_trailing)); + if (!failed) + { + emsg_severe = TRUE; + emsg(_(e_trailing)); + } } else eap->nextcmd = check_nextcmd(arg); diff --git a/src/version.c b/src/version.c index d407dcc5a4..f25d195aae 100644 --- a/src/version.c +++ b/src/version.c @@ -441,11 +441,7 @@ static char *(features[]) = #else "-netbeans_intg", #endif -#ifdef FEAT_NUM64 "+num64", -#else - "-num64", -#endif #ifdef FEAT_ODB_EDITOR "+odbeditor", #else @@ -757,6 +753,114 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 273, +/**/ + 272, +/**/ + 271, +/**/ + 270, +/**/ + 269, +/**/ + 268, +/**/ + 267, +/**/ + 266, +/**/ + 265, +/**/ + 264, +/**/ + 263, +/**/ + 262, +/**/ + 261, +/**/ + 260, +/**/ + 259, +/**/ + 258, +/**/ + 257, +/**/ + 256, +/**/ + 255, +/**/ + 254, +/**/ + 253, +/**/ + 252, +/**/ + 251, +/**/ + 250, +/**/ + 249, +/**/ + 248, +/**/ + 247, +/**/ + 246, +/**/ + 245, +/**/ + 244, +/**/ + 243, +/**/ + 242, +/**/ + 241, +/**/ + 240, +/**/ + 239, +/**/ + 238, +/**/ + 237, +/**/ + 236, +/**/ + 235, +/**/ + 234, +/**/ + 233, +/**/ + 232, +/**/ + 231, +/**/ + 230, +/**/ + 229, +/**/ + 228, +/**/ + 227, +/**/ + 226, +/**/ + 225, +/**/ + 224, +/**/ + 223, +/**/ + 222, +/**/ + 221, +/**/ + 220, /**/ 219, /**/ diff --git a/src/vim.h b/src/vim.h index 7fe7294d93..3655d2ad56 100644 --- a/src/vim.h +++ b/src/vim.h @@ -18,7 +18,7 @@ #endif #ifdef MSWIN -# include "vimio.h" +# include #endif // ============ the header file puzzle: order matters ========= @@ -120,12 +120,6 @@ # endif #endif -// Visual Studio 2005 has 'deprecated' many of the standard CRT functions -#if _MSC_VER >= 1400 -# define _CRT_SECURE_NO_DEPRECATE -# define _CRT_NONSTDC_NO_DEPRECATE -#endif - /* * VIM_SIZEOF_INT is used in feature.h, and the system-specific included files * need items from feature.h. Therefore define VIM_SIZEOF_INT here. @@ -1131,20 +1125,6 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define VIMINFO_VERSION_WITH_REGISTERS 3 #define VIMINFO_VERSION_WITH_MARKS 4 -typedef enum { - BVAL_NR, - BVAL_STRING, - BVAL_EMPTY -} btype_T; - -typedef struct { - btype_T bv_type; - long bv_nr; - char_u *bv_string; - int bv_len; // length of bv_string - int bv_allocated; // bv_string was allocated -} bval_T; - /* * Values for do_tag(). */ @@ -2579,6 +2559,9 @@ typedef enum { #define FCERR_DELETED 7 #define FCERR_NOTMETHOD 8 // function cannot be used as a method +// fixed buffer length for fname_trans_sid() +#define FLEN_FIXED 40 + // flags for find_name_end() #define FNE_INCL_BR 1 // include [] in name #define FNE_CHECK_START 2 // check name starts with valid character diff --git a/src/vim9.h b/src/vim9.h index a9f0710438..a97796505f 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -130,7 +130,6 @@ typedef struct { typedef enum { JUMP_ALWAYS, - JUMP_IF_TRUE, // pop and jump if true JUMP_IF_FALSE, // pop and jump if false JUMP_AND_KEEP_IF_TRUE, // jump if top of stack is true, drop if not JUMP_AND_KEEP_IF_FALSE, // jump if top of stack is false, drop if not diff --git a/src/vim9compile.c b/src/vim9compile.c index 12400a35d5..adfcbcc8ff 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -138,7 +138,7 @@ lookup_local(char_u *name, size_t len, cctx_T *cctx) { int idx; - if (len <= 0) + if (len == 0) return -1; for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx) { @@ -160,7 +160,7 @@ lookup_arg(char_u *name, size_t len, cctx_T *cctx) { int idx; - if (len <= 0) + if (len == 0) return -1; for (idx = 0; idx < cctx->ctx_ufunc->uf_args.ga_len; ++idx) { @@ -956,11 +956,12 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount) * Return FAIL if the number of arguments is wrong. */ static int -generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount) +generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; int regular_args = ufunc->uf_args.ga_len; + int argcount = pushed_argcount; if (argcount > regular_args && !has_varargs(ufunc)) { @@ -978,9 +979,13 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int argcount) { int count = argcount - regular_args; - // TODO: add default values for optional arguments? - generate_NEWLIST(cctx, count < 0 ? 0 : count); - argcount = regular_args + 1; + // If count is negative an empty list will be added after evaluating + // default values for missing optional arguments. + if (count >= 0) + { + generate_NEWLIST(cctx, count); + argcount = regular_args + 1; + } } if ((isn = generate_instr(cctx, @@ -1681,49 +1686,60 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) char_u *p; int argcount = argcount_init; char_u namebuf[100]; + char_u fname_buf[FLEN_FIXED + 1]; + char_u *tofree = NULL; + int error = FCERR_NONE; ufunc_T *ufunc; + int res = FAIL; if (varlen >= sizeof(namebuf)) { semsg(_("E1011: name too long: %s"), name); return FAIL; } - vim_strncpy(namebuf, name, varlen); + vim_strncpy(namebuf, *arg, varlen); + name = fname_trans_sid(namebuf, fname_buf, &tofree, &error); *arg = skipwhite(*arg + varlen + 1); if (compile_arguments(arg, cctx, &argcount) == FAIL) - return FAIL; + goto theend; - if (ASCII_ISLOWER(*name)) + if (ASCII_ISLOWER(*name) && name[1] != ':') { int idx; // builtin function - idx = find_internal_func(namebuf); + idx = find_internal_func(name); if (idx >= 0) - return generate_BCALL(cctx, idx, argcount); + { + res = generate_BCALL(cctx, idx, argcount); + goto theend; + } semsg(_(e_unknownfunc), namebuf); } - // User defined function or variable must start with upper case. - if (!ASCII_ISUPPER(*name)) - { - semsg(_("E1012: Invalid function name: %s"), namebuf); - return FAIL; - } - // If we can find the function by name generate the right call. - ufunc = find_func(namebuf, cctx); + ufunc = find_func(name, cctx); if (ufunc != NULL) - return generate_CALL(cctx, ufunc, argcount); + { + res = generate_CALL(cctx, ufunc, argcount); + goto theend; + } // If the name is a variable, load it and use PCALL. p = namebuf; if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) - return generate_PCALL(cctx, argcount, FALSE); + { + res = generate_PCALL(cctx, argcount, FALSE); + goto theend; + } // The function may be defined only later. Need to figure out at runtime. - return generate_UCALL(cctx, namebuf, argcount); + res = generate_UCALL(cctx, name, argcount); + +theend: + vim_free(tofree); + return res; } // like NAMESPACE_CHAR but with 'a' and 'l'. @@ -2314,6 +2330,9 @@ compile_subscript( } else if (**arg == '[') { + garray_T *stack; + type_T **typep; + // list index: list[123] // TODO: more arguments // TODO: dict member dict['name'] @@ -2326,10 +2345,18 @@ compile_subscript( emsg(_(e_missbrac)); return FAIL; } - *arg = skipwhite(*arg + 1); + *arg = *arg + 1; if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL) return FAIL; + stack = &cctx->ctx_type_stack; + typep = ((type_T **)stack->ga_data) + stack->ga_len - 1; + if ((*typep)->tt_type != VAR_LIST && *typep != &t_any) + { + emsg(_(e_listreq)); + return FAIL; + } + *typep = (*typep)->tt_member; } else if (**arg == '.' && (*arg)[1] != '.') { @@ -3296,7 +3323,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (oplen == 3 && !heredoc && dest != dest_global && type->tt_type != VAR_STRING && type->tt_type != VAR_UNKNOWN) { - emsg("E1019: Can only concatenate to string"); + emsg(_("E1019: Can only concatenate to string")); goto theend; } @@ -3411,13 +3438,51 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) else { // variables are always initialized - // TODO: support more types if (ga_grow(instr, 1) == FAIL) goto theend; - if (type->tt_type == VAR_STRING) - generate_PUSHS(cctx, vim_strsave((char_u *)"")); - else - generate_PUSHNR(cctx, 0); + switch (type->tt_type) + { + case VAR_BOOL: + generate_PUSHBOOL(cctx, VVAL_FALSE); + break; + case VAR_SPECIAL: + generate_PUSHSPEC(cctx, VVAL_NONE); + break; + case VAR_FLOAT: +#ifdef FEAT_FLOAT + generate_PUSHF(cctx, 0.0); +#endif + break; + case VAR_STRING: + generate_PUSHS(cctx, NULL); + break; + case VAR_BLOB: + generate_PUSHBLOB(cctx, NULL); + break; + case VAR_FUNC: + // generate_PUSHS(cctx, NULL); TODO + break; + case VAR_PARTIAL: + // generate_PUSHS(cctx, NULL); TODO + break; + case VAR_LIST: + generate_NEWLIST(cctx, 0); + break; + case VAR_DICT: + generate_NEWDICT(cctx, 0); + break; + case VAR_JOB: + // generate_PUSHS(cctx, NULL); TODO + break; + case VAR_CHANNEL: + // generate_PUSHS(cctx, NULL); TODO + break; + case VAR_NUMBER: + case VAR_UNKNOWN: + case VAR_VOID: + generate_PUSHNR(cctx, 0); + break; + } } if (oplen > 0 && *op != '=') @@ -3875,7 +3940,7 @@ compile_elseif(char_u *arg, cctx_T *cctx) } cctx->ctx_locals.ga_len = scope->se_local_count; - if (cctx->ctx_skip != TRUE) + if (cctx->ctx_skip == MAYBE) { if (compile_jump_to_end(&scope->se_u.se_if.is_end_label, JUMP_ALWAYS, cctx) == FAIL) @@ -3931,13 +3996,14 @@ compile_else(char_u *arg, cctx_T *cctx) return NULL; } - if (cctx->ctx_skip != TRUE) + if (cctx->ctx_skip == MAYBE) { if (scope->se_u.se_if.is_if_label >= 0) { // previous "if" or "elseif" jumps here isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label; isn->isn_arg.jump.jump_where = instr->ga_len; + scope->se_u.se_if.is_if_label = -1; } } @@ -4372,7 +4438,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) char_u *end; char_u *pat; char_u *tofree = NULL; - size_t len; + int len; // Push v:exception, push {expr} and MATCH generate_instr_type(cctx, ISN_PUSHEXC, &t_string); @@ -4385,9 +4451,9 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) return FAIL; } if (tofree == NULL) - len = end - (p + 1); + len = (int)(end - (p + 1)); else - len = end - (tofree + 1); + len = (int)(end - (tofree + 1)); pat = vim_strnsave(p + 1, len); vim_free(tofree); p += len + 2; @@ -4600,6 +4666,44 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) // Most modern script version. current_sctx.sc_version = SCRIPT_VERSION_VIM9; + if (ufunc->uf_def_args.ga_len > 0) + { + int count = ufunc->uf_def_args.ga_len; + int i; + char_u *arg; + int off = STACK_FRAME_SIZE + (ufunc->uf_va_name != NULL ? 1 : 0); + + // Produce instructions for the default values of optional arguments. + // Store the instruction index in uf_def_arg_idx[] so that we know + // where to start when the function is called, depending on the number + // of arguments. + ufunc->uf_def_arg_idx = ALLOC_CLEAR_MULT(int, count + 1); + if (ufunc->uf_def_arg_idx == NULL) + goto erret; + for (i = 0; i < count; ++i) + { + ufunc->uf_def_arg_idx[i] = instr->ga_len; + arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i]; + if (compile_expr1(&arg, &cctx) == FAIL + || generate_STORE(&cctx, ISN_STORE, + i - count - off, NULL) == FAIL) + goto erret; + } + + // If a varargs is following, push an empty list. + if (ufunc->uf_va_name != NULL) + { + if (generate_NEWLIST(&cctx, 0) == FAIL + || generate_STORE(&cctx, ISN_STORE, -off, NULL) == FAIL) + goto erret; + } + + ufunc->uf_def_arg_idx[count] = instr->ga_len; + } + + /* + * Loop over all the lines of the function and generate instructions. + */ for (;;) { if (line != NULL && *line == '|') @@ -4642,7 +4746,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) } else { - emsg("E1025: using } outside of a block scope"); + emsg(_("E1025: using } outside of a block scope")); goto erret; } if (line != NULL) @@ -4902,7 +5006,7 @@ erret: if (errormsg != NULL) emsg(errormsg); else if (called_emsg == called_emsg_before) - emsg("E1028: compile_def_function failed"); + emsg(_("E1028: compile_def_function failed")); // don't execute this function body ufunc->uf_lines.ga_len = 0; diff --git a/src/vim9execute.c b/src/vim9execute.c index 093fbad8e3..4555748110 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -70,7 +70,7 @@ typedef struct { #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + idx) /* - * Return the number of arguments, including any vararg. + * Return the number of arguments, including optional arguments and any vararg. */ static int ufunc_argcount(ufunc_T *ufunc) @@ -78,6 +78,35 @@ ufunc_argcount(ufunc_T *ufunc) return ufunc->uf_args.ga_len + (ufunc->uf_va_name != NULL ? 1 : 0); } +/* + * Set the instruction index, depending on omitted arguments, where the default + * values are to be computed. If all optional arguments are present, start + * with the function body. + * The expression evaluation is at the start of the instructions: + * 0 -> EVAL default1 + * STORE arg[-2] + * 1 -> EVAL default2 + * STORE arg[-1] + * 2 -> function body + */ + static void +init_instr_idx(ufunc_T *ufunc, int argcount, ectx_T *ectx) +{ + if (ufunc->uf_def_args.ga_len == 0) + ectx->ec_iidx = 0; + else + { + int defcount = ufunc->uf_args.ga_len - argcount; + + // If there is a varargs argument defcount can be negative, no defaults + // to evaluate then. + if (defcount < 0) + defcount = 0; + ectx->ec_iidx = ufunc->uf_def_arg_idx[ + ufunc->uf_def_args.ga_len - defcount]; + } +} + /* * Call compiled function "cdf_idx" from compiled code. * @@ -107,23 +136,15 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx) if (ga_grow(&ectx->ec_stack, optcount + 3 + dfunc->df_varcount) == FAIL) return FAIL; -// TODO: Put omitted argument default values on the stack. - if (optcount > 0) - { - emsg("optional arguments not implemented yet"); - return FAIL; - } if (optcount < 0) { emsg("argument count wrong?"); return FAIL; } -// for (idx = argcount - dfunc->df_minarg; -// idx < dfunc->df_maxarg; ++idx) -// { -// copy_tv(&dfunc->df_defarg[idx], STACK_TV_BOT(0)); -// ++ectx->ec_stack.ga_len; -// } + + // Reserve space for omitted optional arguments, filled in soon. + // Also any empty varargs argument. + ectx->ec_stack.ga_len += optcount; // Store current execution state in stack frame for ISN_RETURN. // TODO: If the actual number of arguments doesn't match what the called @@ -142,7 +163,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx) ectx->ec_dfunc_idx = cdf_idx; ectx->ec_instr = dfunc->df_instr; estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); - ectx->ec_iidx = 0; + + // Decide where to start execution, handles optional arguments. + init_instr_idx(ufunc, argcount, ectx); return OK; } @@ -156,9 +179,9 @@ call_dfunc(int cdf_idx, int argcount, ectx_T *ectx) static void func_return(ectx_T *ectx) { - int ret_idx = ectx->ec_stack.ga_len - 1; int idx; dfunc_T *dfunc; + int top; // execution context goes one level up estack_pop(); @@ -166,17 +189,27 @@ func_return(ectx_T *ectx) // Clear the local variables and temporary values, but not // the return value. for (idx = ectx->ec_frame + STACK_FRAME_SIZE; - idx < ectx->ec_stack.ga_len - 1; ++idx) + idx < ectx->ec_stack.ga_len - 1; ++idx) clear_tv(STACK_TV(idx)); + + // Clear the arguments. dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; - ectx->ec_stack.ga_len = ectx->ec_frame - - ufunc_argcount(dfunc->df_ufunc) + 1; + top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc); + for (idx = top; idx < ectx->ec_frame; ++idx) + clear_tv(STACK_TV(idx)); + + // Restore the previous frame. ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number; ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number; ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number; - *STACK_TV_BOT(-1) = *STACK_TV(ret_idx); dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; ectx->ec_instr = dfunc->df_instr; + + // Reset the stack to the position before the call, move the return value + // to the top of the stack. + idx = ectx->ec_stack.ga_len - 1; + ectx->ec_stack.ga_len = top + 1; + *STACK_TV_BOT(-1) = *STACK_TV(idx); } #undef STACK_TV @@ -362,7 +395,7 @@ call_def_function( int idx; int ret = FAIL; dfunc_T *dfunc; - int optcount = ufunc_argcount(ufunc) - argc; + int defcount = ufunc->uf_args.ga_len - argc; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) @@ -388,17 +421,18 @@ call_def_function( copy_tv(&argv[idx], STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; } + // Make space for omitted arguments, will store default value below. + if (defcount > 0) + for (idx = 0; idx < defcount; ++idx) + { + STACK_TV_BOT(0)->v_type = VAR_UNKNOWN; + ++ectx.ec_stack.ga_len; + } // Frame pointer points to just after arguments. ectx.ec_frame = ectx.ec_stack.ga_len; initial_frame_ptr = ectx.ec_frame; -// TODO: Put omitted argument default values on the stack. - if (optcount > 0) - { - emsg("optional arguments not implemented yet"); - return FAIL; - } // dummy frame entries for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) { @@ -413,7 +447,10 @@ call_def_function( ectx.ec_stack.ga_len += dfunc->df_varcount; ectx.ec_instr = dfunc->df_instr; - ectx.ec_iidx = 0; + + // Decide where to start execution, handles optional arguments. + init_instr_idx(ufunc, argc, &ectx); + for (;;) { isn_T *iptr; @@ -964,8 +1001,7 @@ call_def_function( if (when == JUMP_IF_FALSE || when == JUMP_AND_KEEP_IF_FALSE) jump = !jump; - if (when == JUMP_IF_FALSE || when == JUMP_IF_TRUE - || !jump) + if (when == JUMP_IF_FALSE || !jump) { // drop the value from the stack clear_tv(tv); @@ -1546,15 +1582,15 @@ failed: return ret; } -#define DISASSEMBLE 1 - /* * ":dissassemble". + * We don't really need this at runtime, but we do have tests that require it, + * so always include this. */ void ex_disassemble(exarg_T *eap) { -#ifdef DISASSEMBLE + char_u *arg = eap->arg; char_u *fname; ufunc_T *ufunc; dfunc_T *dfunc; @@ -1563,18 +1599,24 @@ ex_disassemble(exarg_T *eap) int line_idx = 0; int prev_current = 0; - fname = trans_function_name(&eap->arg, FALSE, + fname = trans_function_name(&arg, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); + if (fname == NULL) + { + semsg(_(e_invarg2), eap->arg); + return; + } + ufunc = find_func(fname, NULL); vim_free(fname); if (ufunc == NULL) { - semsg("E1061: Cannot find function %s", eap->arg); + semsg(_("E1061: Cannot find function %s"), eap->arg); return; } if (ufunc->uf_dfunc_idx < 0) { - semsg("E1062: Function %s is not compiled", eap->arg); + semsg(_("E1062: Function %s is not compiled"), eap->arg); return; } if (ufunc->uf_name_exp != NULL) @@ -1587,6 +1629,7 @@ ex_disassemble(exarg_T *eap) for (current = 0; current < dfunc->df_instr_count; ++current) { isn_T *iptr = &instr[current]; + char *line; while (line_idx < iptr->isn_lnum && line_idx < ufunc->uf_lines.ga_len) { @@ -1595,7 +1638,9 @@ ex_disassemble(exarg_T *eap) msg_puts("\n\n"); prev_current = current; } - msg(((char **)ufunc->uf_lines.ga_data)[line_idx++]); + line = ((char **)ufunc->uf_lines.ga_data)[line_idx++]; + if (line != NULL) + msg(line); } switch (iptr->isn_type) @@ -1657,7 +1702,11 @@ ex_disassemble(exarg_T *eap) break; case ISN_STORE: - smsg("%4d STORE $%lld", current, iptr->isn_arg.number); + if (iptr->isn_arg.number < 0) + smsg("%4d STORE arg[%lld]", current, + iptr->isn_arg.number + STACK_FRAME_SIZE); + else + smsg("%4d STORE $%lld", current, iptr->isn_arg.number); break; case ISN_STOREV: smsg("%4d STOREV v:%s", current, @@ -1799,9 +1848,6 @@ ex_disassemble(exarg_T *eap) case JUMP_ALWAYS: when = "JUMP"; break; - case JUMP_IF_TRUE: - when = "JUMP_IF_TRUE"; - break; case JUMP_AND_KEEP_IF_TRUE: when = "JUMP_AND_KEEP_IF_TRUE"; break; @@ -1956,7 +2002,6 @@ ex_disassemble(exarg_T *eap) case ISN_DROP: smsg("%4d DROP", current); break; } } -#endif } /* diff --git a/src/viminfo.c b/src/viminfo.c index b2b7ab28b0..897e864629 100644 --- a/src/viminfo.c +++ b/src/viminfo.c @@ -26,6 +26,21 @@ typedef struct garray_T vir_barlines; // lines starting with | } vir_T; +typedef enum { + BVAL_NR, + BVAL_STRING, + BVAL_EMPTY +} btype_T; + +typedef struct { + btype_T bv_type; + long bv_nr; + char_u *bv_string; + char_u *bv_tofree; // free later when not NULL + int bv_len; // length of bv_string + int bv_allocated; // bv_string was allocated +} bval_T; + #if defined(FEAT_VIMINFO) || defined(PROTO) static int viminfo_errcnt; @@ -1087,22 +1102,24 @@ barline_parse(vir_T *virp, char_u *text, garray_T *values) s[len] = NUL; converted = FALSE; + value->bv_tofree = NULL; if (virp->vir_conv.vc_type != CONV_NONE && *s != NUL) { sconv = string_convert(&virp->vir_conv, s, NULL); if (sconv != NULL) { if (s == buf) - vim_free(s); + // the converted string is stored in bv_string and + // freed later, also need to free "buf" later + value->bv_tofree = buf; s = sconv; - buf = s; converted = TRUE; } } // Need to copy in allocated memory if the string wasn't allocated // above and we did allocate before, thus vir_line may change. - if (s != buf && allocated) + if (s != buf && allocated && !converted) s = vim_strsave(s); value->bv_string = s; value->bv_type = BVAL_STRING; @@ -2747,6 +2764,7 @@ read_viminfo_barline(vir_T *virp, int got_encoding, int force, int writing) vp = (bval_T *)values.ga_data + i; if (vp->bv_type == BVAL_STRING && vp->bv_allocated) vim_free(vp->bv_string); + vim_free(vp->bv_tofree); } ga_clear(&values); } diff --git a/src/vimio.h b/src/vimio.h deleted file mode 100644 index 402b11381a..0000000000 --- a/src/vimio.h +++ /dev/null @@ -1,19 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4 noet: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. - */ - -// Visual Studio 2005 has 'deprecated' many of the standard CRT functions -#if _MSC_VER >= 1400 -# define _CRT_SECURE_NO_DEPRECATE -# define _CRT_NONSTDC_NO_DEPRECATE -#endif - -// cproto fails on missing include files -#ifndef PROTO -# include -#endif diff --git a/src/winclip.c b/src/winclip.c index d97f776ca8..767bf1c71e 100644 --- a/src/winclip.c +++ b/src/winclip.c @@ -14,7 +14,6 @@ * Also used by Cygwin, using os_unix.c. */ -#include "vimio.h" #include "vim.h" /*